毕业设计选了SpringBootVueMySQL做一套高校物品捐赠管理系统做完之后我最大的感受是这类系统真正难的点不在技术而在把捐赠—审核—认领—交付的业务链路想清楚并且每一步都能说出设计理由。这套平台的核心功能包括用户注册登录、物品信息发布、管理员审核、学生认领、订单状态流转、站内消息通知、数据统计和角色权限管理技术栈锁定在SpringBoot 2.7.x Vue 2.7Element UI MySQL 8.0。本文从选题思路、数据库建模、后端关键模块、前端联调、服务器部署到答辩准备完整复盘我自己的实现过程也会把踩过的坑单独拉出来讲正在做同类型毕设或者想自己动手折腾一个前后端分离项目的同学可以直接参考。1. 选题逻辑高校物品捐赠系统解决了什么问题1.1 为什么这个题目适合毕业设计先说选题。每年毕业季、换宿舍的时候大量教材、台灯、收纳箱、甚至自行车被直接扔掉另一边又有不少贫困生或者低年级同学需要这些东西。线下捐赠存在几个很现实的问题捐赠信息靠朋友圈和群聊传播零散且容易过期没有审核环节捐的东西质量参差不齐受赠人不知道去哪领管理人员也缺乏统计手段。所以一套物品在线登记、管理员统一审核、学生按需认领的平台从需求上讲是真实存在的不是凭空造出来的。从毕业设计评分角度看这个题目覆盖了前后端分离开发、RESTful接口设计、关系型数据库建模、权限控制、状态机设计、文件上传、部署运维这些常见考点。评委想考察的技术点它基本都能装下但又不会像电商秒杀系统那样把并发、分布式、缓存等重概念全塞进来做完的把握大很多。我当时的判断是与其做一个功能单薄的图书管理系统应付了事不如选一个业务流程稍长、能讲出业务故事的题目答辩时也更有内容可讲。1.2 核心角色与功能需求梳理需求层面我按角色拆成了三类普通学生用户、管理员、系统运营者这里运营者和管理员可以合并用一个角色状态字段区分就行不必过度设计。学生用户需要能注册登录、发布捐赠物品、浏览和搜索物品、提交认领申请、查看自己的捐赠与认领记录管理员需要审核物品是否可上架、审核认领申请是否合理、管理用户状态、处理举报与反馈、查看统计数据。功能清单最终收敛为八个模块用户认证、物品管理、分类管理、认领订单、消息通知、数据统计、反馈管理、系统管理。每个模块再往下拆比如物品管理要包含图片上传、物品描述、成色成新度、领取方式等字段。这个粒度对毕设来说刚刚好既撑得起系统的完整性又不至于把工作量铺得太大。2. 技术栈选型SpringBootVueMySQL的取舍与版本陷阱2.1 后端选SpringBoot的理由SpringBoot的核心价值是约定大于配置。对于我这种需要把大量时间花在业务逻辑而非配置上的场景它的自动配置、起步依赖和嵌入式容器非常友好。一个标准的SpringInitializr项目结构就能直接跑起来不需要像旧SSH那样配一堆XML。具体到模块选型上我用了SpringBoot Web做接口层、SpringAOP做日志切面、SpringValidation做参数校验、MyBatis-Plus做数据访问、JWT做无状态登录令牌。MyBatis-Plus特别适合这种中小型管理系统单表CRUD几乎不用写SQL自带分页插件、条件构造器和逻辑删除能省下不少时间。分页这里我直接用的Plus自带的分页拦截器没有单独去踩PageHelper的坑。2.2 前端为什么选Vue而不是别的Vue的上手曲线平缓组件化开发思路清晰中文资料多遇到问题几乎都能搜到答案。这次我用的是Vue 2.7 Element UI组合原因很务实ElementUI对Vue2的支持最成熟表格、表单、对话框、分页这些后台管理高频组件开箱即用写出来的页面虽然谈不上惊艳但胜在稳定、规范。如果你是新开项目Vue3ElementPlus也可以但如果是参考网上大量现成的毕设源码Vue2的存量资源明显更多跟着改起来更顺手。2.3 MySQL版本选择与jdbc连接隐藏问题数据库选MySQL没悬念免费、普及率高、面试常考。但版本这里我专门提醒一句你本机装的是MySQL 8.0.x项目里驱动依赖用的也是8.0.x这两者必须匹配。很多同学报Communications link failure或者SSL连接错误八成就是因为驱动版本不匹配或者连接串少加了useSSLfalseserverTimezoneAsia/Shanghai参数。我用的是MySQL 8.0.29 mysql-connector-java 8.0.29驱动坐标已经改名为com.mysql.cj.jdbc.Driver别再写旧版的com.mysql.jdbc.Driver新版已经移除了。另外有些教程让你在application.yml里配置password: root如果你恰好连接串里没加allowPublicKeyRetrievaltrueMySQL 8默认的caching_sha2_password认证会让程序直接报Public Key Retrieval is not allowed。这个参数在本地开发时加上就行生产环境再考虑去掉。3. 数据库建模捐赠系统的表结构设计与状态机3.1 核心表清单与设计思路数据库是整个项目的地基表结构设计不好后面写Service层会到处别扭。我的核心表最终定为七张用户表、角色表、物品表、物品分类表、认领订单表、消息通知表、反馈表。加上用户与角色关联表一共八张。用户表字段id、用户名、密码BCrypt加密存储、真实姓名、学号/工号、手机号、邮箱、头像、角色id、状态、创建时间、更新时间。物品表字段id、发布用户id、分类id、标题、描述、图片URL列表、成色全新/九成新等、领取方式自提/配送、状态、审核意见、发布时间、更新时间。认领订单表字段id、物品id、认领用户id、认领理由、联系方式、状态、管理员意见、创建时间、完成时间。有一个容易忽略的设计点物品图片我用的是JSON字符串存一个URL列表字段而不是单独拆一张图片表。因为一个物品的图片数量一般就1到5张拆表反而多了关联查询。如果是电商那种海量图片、需要独立维护的场景拆表更合理但毕设项目JSON字段足够。3.2 状态字段的设计很关键状态字段建议都用tinyint不要用字符串。原因有三个第一数字比较比字符串快第二前端可以维护一个状态枚举映射统一渲染第三后续状态扩展只要加枚举值不需要改表结构。物品状态我设计了四个0待审核、1已上架、2已认领、3已下架。订单状态也是四个0待审核、1已通过、2已拒绝、3已完成。这里有一个业务逻辑细节物品状态和订单状态是联动的学生提交认领申请后物品状态要立刻从已上架改成认领中否则两个学生同时提交管理员两边都审核通过就会出现一物多送的冲突。我最终用了两个状态来表达这个流程——物品先进入认领中可以在原状态位上扩展为4管理员通过某条订单后物品置为已认领其余待审订单自动驳回。这个逻辑答辩时讲出来评委一眼就能看出你有考虑并发一致性。3.3 索引、外键与逻辑删除索引方面物品表我建了category_id、status、publish_user_id三个普通索引认领订单表建了item_id和claim_user_id索引。查询场景无外乎按分类看物品按状态筛选查某人发布的物品索引覆盖这几个高频路径就够了。外键我没有建物理外键只保留逻辑关联。原因有二一是物理外键在批量操作、逻辑删除时容易产生锁冲突和迁移麻烦二是MyBatis-Plus做连表查询本来就更倾向于手写SQL控制。但逻辑关联字段必须有索引不然删除分类时扫全表会很慢。逻辑删除字段deleted我加在了用户表和物品表上认领订单表没加因为订单属于流程数据需要留痕用户和物品删除了但历史订单记录不能丢。这里建议初写系统的人别一上来就给所有表都加逻辑删除只有确实存在用户误删需要恢复或者关联数据不能物理丢的场景才需要。4. 后端实现从分层架构到核心业务代码4.1 分包结构与统一响应体后端分包我参考了常见的Controller-Service-Mapper三层加上config、common、entity、dto、vo几个辅助包。Controller只做参数接收和响应转发业务逻辑全部下沉到Service层Mapper层只管数据访问entity对应数据库表结构dto用于接收前端参数vo用于返回给前端的数据结构。这样分层的好处是答辩时能清晰讲出每一层职责也方便后面扩展。统一响应体ResultT是这类管理系统的标配我定义的字段是code、msg、data。code200表示成功400表示参数错误401表示未登录或令牌过期500表示服务器异常。所有Controller方法一律返回Result对象全局异常处理器RestControllerAdvice统一兜底。这个小设计看起来不起眼但前后端联调时能少吵很多架——前端axios拦截器只需要判断code是不是200根本不用关心HTTP状态码。4.2 登录鉴权方案JWT还是Session我最终选了JWT但这里要说清楚JWT不是唯一选择甚至对纯管理类系统来说Session可能更简单。我选JWT主要是两个原因第一后端接口天然无状态以后要是想加微信小程序端登录态可以直接复用第二答辩时讲JWT的生成、解析、拦截器校验技术点更集中。实现上是这么做的登录成功后用用户id角色编码生成token过期时间设24小时前端把它存在localStorage每次请求在header带Authorization: Bearer token。后端写了一个拦截器放行登录接口和注册接口其余接口全部校验token并把解析出来的用户信息放进ThreadLocalService层直接取当前用户。权限控制我用的是角色编码判断比如PreAuthorize(hasRole(ADMIN))这种方式没有引入Spring Security而是自己写了一个简单的注解AOP判断。对于只有两个角色的毕设项目引入完整的Security框架反而会带来一堆配置噪音。如果你时间充裕用Spring SecurityJWT的经典组合也可以但从做完这个目标出发轻量级方案更划算。4.3 捐赠流程的状态流转实现这条业务链路是整个项目最核心的地方代码不复杂但逻辑顺序必须想清楚。学生发布物品时状态置为0待审核管理员审核通过后变1已上架。学生看到已上架的物品点击申请认领后端做三步操作校验物品状态必须是1、生成认领订单状态0、把物品状态改为4认领中。这里一定要用事务三层操作要么全成功要么全回滚。管理员审核订单时如果通过把订单状态改为1已通过、物品状态改为2已领出同时把同一物品下其他待审订单批量置为2已拒绝、通知对应学生。如果拒绝只把订单状态改为2已拒绝把物品状态改回1已上架这样其他同学还能继续申请。这个用状态机管理并发认领冲突的思路我在文档里画了图答辩时直接投影出来讲逻辑非常清楚。消息通知我用的是简单方案通知表存接收用户id、标题、内容、是否已读。用户登录后拉取最近未读消息已读做的是懒更新——用户点开消息列表时标记已读。没有用WebSocket实时推送因为管理系统的消息实时性要求没那么高轮询接口就够了。这块答辩时如果被问为什么不做实时推送就用这个理由回答反而显得你考虑过取舍。4.4 文件上传与XSS过滤的坑物品图片上传我是存本地磁盘的配置了一个虚拟路径映射上传后返回URL给前端。如果你的服务器有对象存储条件用MinIO或者OSS更好但毕设本地存储完全够用。上传这块最容易被忽略的是文件类型校验只校验前端传的Content-Type很不安全因为Content-Type可以被改必须同时校验文件扩展名和文件头字节。我实测用MultipartFile传一个伪装成jpg的脚本文件是能绕过的所以在后端加了文件头白名单判断图片只允许jpg、png、gif、webp四种格式。上传PDF相关的XSS问题要特别留意。有些同学做毕设时会有上传PDF附件、预览附件的需求如果你把PDF文件直接返回给浏览器文件名里带恶意HTML内容就可能被浏览器解析。正确做法是给静态资源接口设置Content-Disposition: attachment强制下载而不是内联预览并且对文件名做HTML转义。我就是在这个接口上栽过一次明明功能正常安全测试一测就出来存储型XSS后来才搞明白问题不在PDF内容本身而在响应头没设对。5. 前端Vue实现页面结构、路由守卫与接口联调5.1 脚手架与环境配置前端我用Vue CLI 4.x创建的项目选型时特意没上Webpack 5和Vite因为网上的毕设源码和教程大部分基于Vue CLI复制配置出问题概率低。Node版本建议14.x到16.x太新的Node配合旧CLI可能出现依赖编译报错。创建完项目后我从node_modules里删过好多次依赖重新装最稳的做法是装完依赖后尽快跑一次npm run serve确认基础环境没问题再开始写页面不然写完一堆代码才发现环境跑不起来排查效率极低。配置上最需要提前搞定的是开发代理。后端接口统一前缀/api前端开发服务器配置proxy代理到http://localhost:8080把接口请求转发过去。这样能完美避开前后端分离项目最常见的CORS跨域问题。生产环境则是让Nginx把/api反向代理到后端地址整个链路在本地和服务器保持一致前端代码几乎不需要改。5.2 路由设计与权限拦截页面路由分两块访客和登录用户都能访问的公开页面以及只有管理员能进的系统管理页面。用户端路由包括首页物品列表搜索、物品详情、登录注册、个人中心我的发布、我的认领、消息列表、发布物品。管理端路由包括仪表盘统计、物品审核、订单审核、用户管理、分类管理、反馈管理。权限控制用的是Vue Router的全局前置守卫router.beforeEach。每次跳转先判断目标路由的meta.requiresAuth和meta.requiresAdmin再结合本地存储的token和角色编码做拦截。这里有个关键细节路由里写死角色判断但如果用户被管理员封禁角色不会变前端只看role字段是拦不住的。所以我在后端加了一个获取当前用户完整信息的接口前端启动时请求一次把status字段也存到store里守卫里同时判断角色和状态被封禁的用户统一跳转到登录页并提示账号状态异常。5.3 axios封装与联调中的常见问题axios我封装了一个request.js统一做了三件事请求拦截器挂载token、响应拦截器统一判断业务code、超时时间统一设为30秒。遇到401就清掉本地登录态并跳登录页遇到500就把msg弹出来。别小看这个封装我见过很多同学在每个页面里重复写axios请求和错误处理后面接口一多改个路径前缀要改几十处封装好之后只动一个文件。联调阶段最容易踩的坑有这几个第一前端传的JSON字段和后端entity字段大小写不一致尤其是驼峰命名前端用itemId、后端用item_id不写好映射就查不到数据第二时间字段格式不一致后端返回的是2025-06-01T12:00:00这种带T的格式前端直接显示很难看我用了一个全局格式化函数统一转成YYYY-MM-DD HH:mm:ss第三分页参数名对不上前端传pageNum和pageSize后端用的是current和sizeMyBatis-Plus默认联调前先在后端写好参数映射或者前端统一适配别两边各改各的。5.4 页面实现的重难点首页物品列表用ElementUI的Card组件做卡片式展示图片懒加载加状态标签筛选栏支持分类下拉、关键字搜索、成色下拉。物品详情页除了展示信息和图片轮播核心是认领入口的按钮态控制物品状态不是已上架时按钮置灰防止用户提交无效申请点提交后弹出认领理由表单带上联系方式。管理端的物品审核表格用el-table加自定义列给每行放通过/驳回操作驳回时需要填审核意见这个意见会通过消息通知发给发布者。数据统计页我用了ECharts画折线图和饼图显示近30天发布量趋势、分类占比、认领转化率。ECharts的坑在于图表容器初始化时如果页面还没渲染完成会拿不到宽高需要把初始化放在nextTick里这个我调了一个晚上才反应过来。6. 部署上线与答辩前的最后准备6.1 本地打包注意事项后端打包用Maven执行mvn clean package -DskipTests最终生成一个可运行的jar。这里提醒几个容易翻车的地方第一application.yml里如果有本地绝对路径的虚拟映射配置打包部署前记得改成相对路径或者改为服务器路径第二放行跨域如果在后端配置了CORS部署后前后端不在同源域名下还是会有问题实际上生产环境我是直接删掉后端CORS配置统一交给Nginx处理端口和域都收敛到一层问题少很多第三数据库地址别写死成localhost部署时要改成服务器IP或者直接用内网地址。前端执行npm run build生成dist目录这个目录就是纯静态文件丢给Nginx托管就行。构建前检查一下public/index.html里的资源路径是否是相对路径如果写的是/assets这种绝对路径部署在子路径下就会有白屏问题改成相对路径或保持根路径部署都能解决。6.2 服务器部署流程服务器环境我是先用宝塔面板快速装好的装好Nginx、MySQL 8.0、JDK 8、Redis我项目里用到了Redis存验证码如果没用可以省略然后手动建库。导入数据库脚本时要注意字符集建库语句指定utf8mb4不然中文可能变成问号。后端启动用nohup java -jar donation-0.0.1.jar app.log 21 日志里看到Started Application in x.x seconds就说明启动成功。Nginx配置核心部分是这样的location /指向dist目录做前端静态资源location /api/用proxy_pass转发到后端服务注意proxy_pass后面带不带路径后缀会影响转发的URL拼接我因为多写了一个/导致后端接口路径变成了//api/login排查了很久才发现是代理配置多了一个斜杠。前端我用80端口直接访问后端监听8080端口只允许内网访问安全性和访问便利性都能照顾到。6.3 论文写作与答辩准备的经验论文的章节结构我参考了学校给的模板核心是需求分析、总体设计、详细设计、系统实现、系统测试五章。很多同学论文写成了操作手册通篇是截图这个一定要避免。正确的做法是每张截图配一段为什么这么做和关键实现方式比如截图物品审核页面就要讲这条审核逻辑的分支处理、状态变更和消息通知是如何协作的。答辩前我做了两件实事。第一把数据库导出语句重新执行一遍确认在新库上跑得通不存在只有我本机能跑的脚本第二把整个流程走了一个demo视频从注册→发布物品→审核上架→认领→审核通过→完成捐赠每一步的截图和核心SQL都放在PPT里。评委最喜欢问的几个问题——物品和订单状态如何保持一致为什么用JWT不用Session如果两个人同时认领怎么办——我在正文和代码里都提前埋好了答案实际答辩时确实被问到了状态设计相关的问题当场画状态图就能很快讲明白。7. 踩坑合集一周调试记录的浓缩版7.1 MySQL相关的三个高频报错第一个是error 2002 (HY000): Cant connect to local MySQL server through socket /tmp/mysql.sock这个报错我之前见了好几个人问。典型原因是MySQL服务没启动或者你用了localhost连接但MySQL监听的是socket而非TCP。解决办法分两步先systemctl status mysqld确认服务状态再检查连接串改成127.0.0.1而不是localhost后者走TCP基本能绕开socket路径问题。第二个是前面提过的Public Key Retrieval is not allowed连接串加allowPublicKeyRetrievaltrue解决。第三个是时区报错我记得报错信息里有serverTimezone的提示连接串加serverTimezoneAsia/Shanghai就行。7.2 SpringBoot版本过高引发的连锁问题有一次我按教程引入了某个依赖版本结果项目启动直接报Unsupported class file major version查来查去是SpringBoot版本太高自带的依赖要求和JDK版本不匹配。SpringBoot 3.x要求JDK 17起步而大部分毕设项目用的还是JDK 8。我的建议是参考网上源码时先确认对方的JDK版本我最终固定为JDK 8 SpringBoot 2.7.x这套组合网上资料最多遇到的坑基本上都有人踩过且给出过解法。如果你非要用SpringBoot 3.x很多第三方starter的兼容性要重新查一遍这会多耗很多时间。7.3 前后端分离联调的白屏与403排查白屏问题多数出现在部署阶段本地开发时更多遇到的是接口403或404。403我遇到过一次原因是我在SpringSecurity当时还没删掉的配置里把/api/item/list排除忘了加接口被拦前端一直显示无权限。排查这类问题时记住一个顺序先用浏览器直接访问后端接口地址看返回如果后端正常再把问题定位于Nginx或前端代理反过来前端页面能打开但接口报错则优先看浏览器Network面板的请求URL确认代理有没有生效。404问题则要检查后端Controller的RequestMapping路径和前端请求路径是否完全一致包括大小写和斜杠。这里有一个排查技巧后端日志里如果打出404看Tomcat记录的Request URL和前端Network面板的URL做个对比一眼就能看出是拼错还是代理配置问题。接口联调这种事还原最原始的方式一步步试比瞎改配置要高效得多。个人经验总结毕业设计不求炫技但求把每个技术选型都讲出为什么。这套物品捐赠管理系统做完我从选题时的需求分析、到数据库状态机设计、到前后端联调踩坑、再到部署上线等于把软件工程分析—设计—实现—测试—部署的全流程完整走了一遍。对正在做这个题目的同学我的建议是尽早把核心业务状态流转跑通再用文档把每一步决策记下来答辩时拿出这些过程和踩坑记录比任何华丽的功能截图都有说服力。