SpringBoot3配合Vue3做在线捐赠系统是我这几年带实训和帮同学改毕业设计时用得最顺手的项目类型之一。整条业务链从项目发布、用户浏览、模拟捐赠、记录回显到后台统计正好把前后端分离、RESTful接口、数据库设计、权限控制、事务处理这些核心技能点串成了一条线。更难得的是这个选题天然带公益属性把“乡村儿童阅读角”“社区老人关怀”这类项目放进去展示起来比常见的图书管理系统更有感染力。针对零基础的同学我的建议是把这套项目当成一条完整的练习链路而不是一个只能“跑起来看效果”的模板。你不需要一上来就背语法先跟着环境准备步骤把项目启动再沿下面的功能拆解从头到尾走一遍这套技术栈的常用套路基本就清楚了。它适合用来做毕业设计、课程作业也适合放进自己的实训项目合集里做技术展示后续想扩展成其它公益平台的原型也顺理成章。1. 在线捐赠系统的整体设计与功能拆解1.1 为什么这个选题值得做说句实话历年毕设和实训里最多的就是“某某管理系统”。图书管理、学生管理、仓库管理代码逻辑大同小异答辩时也容易被老师追问“你的系统核心难点在哪里”。在线捐赠系统不一样它虽然还是典型的Web业务系统但业务流程更接近真实产品有用户注册登录有公益项目状态流转有金额精度控制有模拟支付的交互状态还有后台数据汇总。把这些细节讲清楚就能证明你不只是在堆积增删改查一类的基础功能。在线捐赠系统的业务闭环可以这样理解公益团队发布一个需要筹款的项目填写目标金额和项目介绍普通用户注册登录后查看项目在项目详情页填捐款金额、留言选择模拟支付方式完成支付系统记录这笔捐款同时把项目已筹金额累加用户可以在“我的捐赠”里看到历史记录管理员在后台能看到全部记录和简单的统计数字。这个过程很像一个简化版的电商下单流程但要处理的状态切换、并发问题少得多非常适合零基础上手。另外项目的社会意义也是加分项。捐赠系统的数据天然适合讲故事你可以用首页顶部的大数字展示“累计善款”“捐赠人次”“受益群体”再配上项目卡片列表视觉效果比传统管理系统好很多。演示和答辩时老师关心的是你对业务的理解、代码架构的合理性、异常情况怎么处理这套项目每个点都能接得住。1.2 角色、功能模块与页面规划整个系统按照使用角色可以拆成三块游客、普通用户、管理员。角色核心功能是否需要登录游客查看首页统计数据、项目列表、项目详情不需要普通用户注册、登录、在线捐赠、我的捐赠记录、个人累计金额需要管理员维护项目、查看全部捐赠记录、查看统计报表管理员账号用户端页面我建议这样规划首页是项目概览加顶部统计卡片项目详情页显示封面、目标金额、已筹金额、进度条和捐赠按钮捐赠表单独立做成弹窗或单独页面我的捐赠页展示捐赠列表和累计金额。管理端可以复用同一套前端通过路由区分页面是项目表格、捐赠记录表格、统计卡片三块。这样的页面数量不多但每一页都有明确的业务目的能覆盖Vue3开发里最常用的列表渲染、表单校验、状态切换、组件通信等技能。我自己在实训中给学生的任务就是先把页面原型画出来再对照功能表把接口名写出来最后才动手写代码整个过程会顺畅很多。2. 技术选型与开发环境准备2.1 SpringBoot3加Vue3为什么适合零基础技术选型方面这套项目用的是SpringBoot3、Vue3、MySQL前端构建工具是ViteUI组件库用开源生态里常见的组件库后端持久层用MyBatis-Plus。选这个组合一是因为它是目前前后端分离方向的主流搭配资料多、社区活跃遇到问题基本搜得到答案二是因为它比老一套的SSM加Vue2更简洁版本更新意味着语法更现代化学完直接能衔接到企业级项目。SpringBoot3这里要特别提醒它要求JDK必须是17及以上。很多同学机子上装的是JDK8启动项目会直接报出class文件主版本号不支持的错误。解决办法很简单装一个JDK17并且确认系统环境变量里的JAVA_HOME指向新版本。这个点我会在后面的环境清单里再强调一次。前端选Vue3而不是Vue2最大的变化是组合式API。用setup语法糖写组件有点像在写互相调用的函数逻辑复用很直观。再搭配Pinia做状态管理登录信息、用户信息放在一个全局状态里组件之间共享数据不需要一层层传props代码干净不少。Vite比Webpack的启动速度快非常多改代码之后页面几乎瞬时刷新对零基础特别友好省掉了大量等待时间。2.2 需要准备的软件与版本清单我整理了下面这张环境清单照着装就行。版本号尽量别乱改很多问题都出在版本不匹配上。软件推荐版本用途安装后验证命令JDK17或17以上运行后端项目java -versionMaven3.6以上管理后端依赖mvn -vMySQL8.0存储数据mysql --versionNode.js18以上运行前端构建工具node -v前端包管理器npm随Node自带安装前端依赖npm -v数据库客户端主流图形客户端或命令行导入SQL、查看数据无安装完成后强烈建议在命令行里逐条执行表格中的验证命令。如果你敲java -version显示的不是17说明环境变量还没生效先检查哪里装了旧版本再修改JAVA_HOME和PATH。零基础阶段花十分钟完成工具验证能省掉后面启动项目时一大半的报错。2.3 前后端分离的目录结构规划拿到项目先别急着启动先看懂目录。我的习惯是让前后端完全分开同一份仓库里放两个子目录。online-donation ├─ backend │ ├─ pom.xml │ └─ src/main │ ├─ java/com/example/donation │ │ ├─ controller # 接口层 │ │ ├─ service # 业务逻辑层 │ │ ├─ mapper # 数据访问层 │ │ ├─ entity # 实体类 │ │ └─ config # 配置类 │ └─ resources │ └─ application.yml # 数据库等配置 └─ frontend ├─ vite.config.js # 构建与代理配置 ├─ package.json └─ src ├─ main.js ├─ router # 路由 ├─ store # Pinia状态 ├─ api # Axios请求封装 ├─ utils # 工具函数 └─ views # 页面组件这个结构对应的是典型的分层思想后端Controller只负责接收请求、返回结果业务逻辑集中在Service层数据操作放在Mapper层前端按路由和功能目录组织api目录统一管理所有后端请求。零基础学习时最大的好处是出了问题定位快页面报错先看views接口报错看api和后端Controller数据不对看数据库和Mapper。3. 数据库设计与后端核心接口实现3.1 核心表结构与字段设计思路在线捐赠系统最核心的就是三张表捐赠人表donor、项目表project、捐赠记录表donation_record。表名刻意用donor而不是user是为了避开数据库里的保留字和潜在冲突。先把建表SQL列出来。CREATE TABLE donor ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, real_name VARCHAR(50), phone VARCHAR(20), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE project ( id BIGINT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100) NOT NULL, cover VARCHAR(255), description TEXT, target_amount DECIMAL(10,2) NOT NULL, raised_amount DECIMAL(10,2) NOT NULL DEFAULT 0, status TINYINT NOT NULL DEFAULT 0 COMMENT 0筹集中 1已完成 2已下线, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE donation_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, donor_id BIGINT NOT NULL, project_id BIGINT NOT NULL, amount DECIMAL(10,2) NOT NULL, message VARCHAR(200), pay_type VARCHAR(20), donate_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_donor (donor_id), INDEX idx_project (project_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里有两个细节值得零基础同学记一下。第一金额为什么用DECIMAL(10,2)而不是FLOAT或DOUBLE因为浮点数在计算机里是二进制近似表示累计多次之后可能出现精度误差而捐款涉及金额一分钱都不能差DECIMAL是精确小数适合存货币。第二donation_record表里没有设计物理外键只加了普通索引。项目中通常用逻辑关联在代码里保证id的对应关系这样删除项目或用户时不容易被数据库的约束卡住适合学习项目也方便以后扩展。3.2 后端分层与捐赠业务的核心逻辑后端的包结构已经写在目录规划里这里直接看捐赠接口是怎么落地的。先说流程用户提交捐赠请求后端先校验项目和金额然后模拟支付成功接着在当前事务里完成两件事——插入捐赠记录、累加项目已筹金额。Service层核心代码如下。Service public class DonationServiceImpl implements DonationService { Resource private DonationRecordMapper donationRecordMapper; Resource private ProjectMapper projectMapper; Override Transactional(rollbackFor Exception.class) public DonationRecord donate(DonationDTO dto) { Project project projectMapper.selectById(dto.getProjectId()); if (project null || project.getStatus() ! 0) { throw new RuntimeException(项目不存在或已结束捐赠); } if (dto.getAmount() null || dto.getAmount().doubleValue() 0) { throw new RuntimeException(捐赠金额必须大于0); } DonationRecord record new DonationRecord(); record.setDonorId(dto.getDonorId()); record.setProjectId(dto.getProjectId()); record.setAmount(dto.getAmount()); record.setMessage(dto.getMessage()); record.setPayType(dto.getPayType()); donationRecordMapper.insert(record); project.setRaisedAmount(project.getRaisedAmount().add(dto.getAmount())); projectMapper.updateById(project); return record; } }这段代码的关键就是Transactional注解。你可以把它理解成一个统一开关方法内所有数据库操作要么全部成功提交要么遇到异常全部回滚。如果没有事务一旦插入捐赠记录成功、更新项目金额失败就会出现“用户捐了钱但项目进度没变化”的数据不一致这在真实业务里是不能接受的。SpringBoot默认开启了事务管理但业务方法上必须显式加这个注解。Controller层相对简单只做参数接收和结果返回。再用一个Result对象统一包一层code和message前端判断code为200就说明成功。接口路径我习惯设计为POST /api/donation符合RESTful风格资源是捐赠记录语义清晰。3.3 模拟支付如何设计才显得完整很多同学会纠结要不要接真实支付我的建议是学习阶段完全不用。真实支付需要商户资质、密钥管理、回调验签、退款流程个人基本办不下来答辩时讲清楚也容易跑偏。模拟支付的目的是把“支付成功后的业务处理”完整走通。常用模拟方案是前端点击捐赠后弹出一个模拟支付框让用户选择一种支付方式点击“确认支付”后按钮进入loading状态延迟800毫秒再调后端生成捐赠记录接口。这样前端可以演示加载状态、防止重复提交后端照常校验、写库、更新金额。整个流程在业务层面和真实支付几乎一致只是没有真实扣款。代码里要处理好同一用户重复提交的限制最简单的做法是前端在loading期间禁用按钮后端再做一次幂等判断防止用户手抖连点产生两条记录。4. 前端Vue3页面实现与接口对接4.1 路由设计与登录权限拦截前端页面用Vue Router配合Pinia来实现。Pinia存两样东西当前用户信息和token。token在登录成功后由后端返回前端存到localStorage里刷新页面后还能保持登录状态。先看路由设计const routes [ { path: /, name: home, component: HomePage }, { path: /login, name: login, component: LoginPage }, { path: /project/:id, name: projectDetail, component: ProjectDetail, meta: { requiresAuth: true } }, { path: /my, name: myDonations, component: MyDonations, meta: { requiresAuth: true } }, { path: /admin, name: admin, component: AdminDashboard, meta: { requiresAuth: true, role: admin } } ]路由守卫是零基础同学最容易忽略却又很重要的部分。没有守卫的话游客直接输入地址也能进到项目详情页或者后台。用全局前置守卫控制router.beforeEach((to) { const authStore useAuthStore() if (to.meta.requiresAuth !authStore.token) { return { name: login, query: { redirect: to.fullPath } } } if (to.meta.role authStore.role ! admin) { return { name: home } } })这样未登录用户访问捐赠详情、我的捐赠、管理后台时会被统一踢回登录页登录成功后再跳回原目标页面。逻辑简单但答辩和作品展示时能体现出你对信息安全的意识。4.2 Axios封装、环境变量与跨域代理前后端分离开发最常遇到的一个坑就是跨域。前端端口5173、后端端口8080浏览器会拦截跨域请求解决办法是前端通过Vite的proxy把接口请求转发给后端。这样前端代码里请求地址只要写/api开头本地开发完全不用在后端单独放开跨域配置。// vite.config.js server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }同时把Axios封装成统一模块加入请求拦截器和响应拦截器。import axios from axios const request axios.create({ baseURL: /api, timeout: 10000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization token } return config }) request.interceptors.response.use( response response.data, error { if (error.response error.response.status 401) { localStorage.removeItem(token) location.href /login } return Promise.reject(error) } )统一封装的好处是以后所有接口都自动携带token遇到登录过期也只需要改拦截器一处地方。零基础先不要急着把每个请求写一遍headers用这种中央处理的方式最省事。4.3 项目列表、进度条与捐赠表单实现项目列表页是前端Vue3最典型的场景请求接口拿数据循环渲染卡片。核心逻辑如下script setup import { ref, onMounted } from vue import { getProjectList } from ../api/project const projects ref([]) const loading ref(false) const loadProjects async () { loading.value true const res await getProjectList() projects.value res.data.records loading.value false } onMounted(loadProjects) /script每张卡片显示封面、标题、目标金额、已筹金额和进度条。进度百分比直接用raised / target计算渲染成组件库里的进度条组件。这个计算逻辑本身很简单但要注意后端返回的金额是字符串还是数字如果用字符串直接除可能得到奇怪结果前端建议先转成Number再算。捐赠表单最关键的是校验规则。金额不能为空、必须大于0、不能超过单笔上限留言不能超过200字。用组件库自带的表单校验加一条自定义规则防止用户传负数或0。提交前再把按钮设成loading状态提交成功后清空表单并跳转到我的捐赠页。整个过程既演示了表单交互也演示了前端到后端的完整联调。5. 部署运行与高频问题排查5.1 从零把项目跑通的十二个步骤这部分是零基础同学最容易卡住的地方我直接按顺序写一遍可操作的清单每步都给了判断标准。安装JDK17配置JAVA_HOME。命令行执行java -version确认显示的是17。安装MySQL8记住自己设置的root密码。启动MySQL服务后用客户端工具连接测试一下。创建数据库donation字符集选utf8mb4把项目SQL文件整体导入确认三张表都建好了。打开后端项目修改application.yml里的数据库地址、用户名、密码对齐本机环境。启动后端主类。如果日志里看到Tomcat started on port 8080说明后端启动成功。在浏览器直接访问一个公共接口例如http://localhost:8080/api/project/list能返回JSON数据就说明Controller和数据库关联正常。安装Node.js18以上版本执行node -v和npm -v确认可用。在frontend目录执行npm install。这里如果慢可以临时换成镜像源。执行npm run dev看到Local: http://localhost:5173就完成了前端启动。打开前端地址注册一个测试账号并登录。用一个管理员账号登录后台在项目管理里新增一个测试项目填标题、目标金额和介绍。回到前台选择这个项目进行一次模拟捐赠。到“我的捐赠”里确认记录出现再到后台看累计金额是否更新。这十二步里任何一步失败的原因基本都能在下一节找到。零基础不要跳步尤其建议每启动一个环节就先验证上一个环节的数据。5.2 高频问题排查速查表我把实际带项目时学生踩得最多的坑整理成了一张表照着排查效率最高。现象常见原因解决办法后端启动报class文件主版本错误JDK版本低于17升级JDK并修改JAVA_HOME前端请求接口返回网络错误跨域或代理没配置检查vite.config.js中的proxy配置数据库连接失败URL、账号或密码写错对照application.yml逐项检查注意数据库名是否创建启动后表不存在SQL没有导入当前数据库重新执行建表SQL确认在donation库中执行捐赠后金额没有增加扣了款但update没执行检查service方法是否有Transactional以及updateById是否传入完整对象前端页面样式全乱UI组件库未完整引入按组件库文档确认全局引入或按需插件配置npm install报错Node版本过低或网络问题升级Node换镜像源后重试登录后停留登录页路由守卫逻辑写错或token没存上在守卫里打印authStore.token先确认localStorage是否写入这里面最容易被忽略的是“donation表插入成功但金额没更新”通常是项目表更新那一行代码没写或者事务方法没有被Spring管理。排查思路是看看Controller调用的方法真的在被Spring扫描的包路径下且ServiceImpl上有Service注解。5.3 作为毕业设计或实训项目答辩的加分细节项目能跑通只是底线答辩和作品展示的加分点其实是“思考深度”。建议提前准备下面几点。文档方面写一个简洁的README把技术栈、功能清单、运行步骤、账号说明写清楚。数据库设计图建议单独画一张ER图不需要复杂三张表的主外键关系和字段说明列出来即可。演示时先展示项目启动再从用户视角走一遍“浏览、登录、捐赠、查记录”最后切到管理后台看统计。整个过程控制在五分钟以内重点讲清你如何解决金额精度、事务一致性和登录权限这几个问题。扩展方向上可以做项目审核状态机给项目增加待审核、审核通过、拒绝三种状态也可以导出捐赠记录Excel还可以把数据统计做成可视化图表。这些方向都能作为“后续规划”在答辩里提表明你不是只会照着模板改代码。这套项目完整走通之后我的体会是它真正训练的不是某个框架的API而是拿到一个业务需求后怎么拆解、怎么建模、怎么保证数据不出错。捐赠流程里的金额校验、事务回滚、进度更新放到电商、教育、办公系统里同样是那套思路。我把这个项目反复讲给实训的同学最常说的就是一句话别急着抄代码先把“谁在用、流程怎么走、数据落在哪张表”三个问题想清楚。最后再分享一个自己的小习惯拿到任何项目源码我第一步一定是先把建库SQL跑通再去验证后端接口最后才连前端页面。顺序对了后面全是顺畅的验证顺序乱了前端报错时你根本分不清是接口问题、跨域问题还是数据库没导全。这套在线捐赠系统作为零基础入门项目最大的价值就是把“环境、数据、接口、页面”这四个层次拆得清清楚楚每走一层你都能明确知道自己到了哪一步。
阅读完成 · 觉得有帮助?