
去年接了个本科毕设辅导的活儿学生选的题目就是SpringBootVue的疫情防控管理系统。一开始我心想这不就是一个标准的CRUD项目嘛后台管理加个信息填报能有多少东西。但真正动手拆解需求、设计表结构、写业务逻辑的时候才发现这个题目看似普通做扎实了涉及的细节其实比想象中多得多——权限怎么分、打卡数据怎么校验、异常数据怎么预警、前端表格怎么联动每一步都有可以深挖的空间。本文就基于这个典型的毕设/课设选题把我从前端到后端、从数据库到部署的完整设计思路和落地过程写下来给正在做类似管理系统的同学一个可以直接参考的模板。这套系统最终跑起来的效果是这样的普通用户登录后可以每日填报健康状况体温、健康码颜色、行程轨迹、是否接触风险人群管理员登录后可以看到全部用户的数据汇总、风险预警列表、各区域填报统计还能发布公告和配置风险地区。技术栈就是标题里写的SpringBoot Vue MySQL前后端完全分离接口走RESTful风格前端用Vue全家桶后端用SpringBoot做业务MySQL存数据。整个项目结构清楚代码量适中非常适合拿来当毕设、课设或者当做学习前后端分离开发的入门案例。1. 从需求到模块这套系统到底该管哪些事1.1 先把角色和权限捋清楚做管理系统第一步不是写代码而是想明白谁在用这套系统、每个人的操作边界在哪。我在设计时把用户分成两类对应的界面和权限完全不同。普通用户学生/员工登录后能看到自己的健康档案填写每日健康打卡表单查看自己历史填报记录查看管理员发布的公告修改个人密码。普通用户看不到别人的任何数据也不会有管理入口。系统管理员除了拥有普通用户的基础功能外还可以进入管理后台。后台里面能看到全部用户的列表可以重置用户密码、启用或禁用账号能看到所有用户的打卡记录支持按姓名、日期、健康状态等维度筛选能查看异常健康状态的预警清单能维护风险地区列表能发布和下线公告。这个权限模型用一句话概括就是用户管自己的事管理员管所有人的事。在开发时我建议不要在前端简单用v-if去藏按钮来做权限控制前端隐藏只是体验层面的处理真正的权限校验必须在后端接口层完成。后端用一个拦截器统一校验JWT令牌再从令牌中解析出用户角色每写一个接口都要问一句这个接口谁有权限调如果角色不匹配直接返回403。这是毕设答辩时评委大概率会追问的一个点提前把这一层想清楚回答起来会从容很多。1.2 核心业务流程打卡、预警、公告系统里最核心的一条业务链是用户填报 - 数据入库 - 异常判定 - 管理员处理。每日健康打卡是整个系统的高频操作所以流程设计必须简单直接不能让用户点好几下才能提交成功。我在设计打卡流程时做了一处细节处理一张表单同时涵盖今日填报和历史记录查询两个功能。用户进入健康打卡页面后系统会先查询当天是否已经提交过如果提交过就直接展示当天填报的详情并禁用提交按钮防止一天提交多条如果没提交就显示表单让用户填写。这个逻辑本质上就是先查后写一个简单的查询接口就能避免数据冗余放在答辩时讲出来也是一个亮点。预警流程的逻辑是打卡记录落库之后后端会在提交接口内部顺手做一次健康状态的自动判定。只要体温大于等于37.3度、健康码不是绿码、或者14天内去过中高风险地区这条记录就自动标记为异常同时把异常记录写入预警表。管理员登录后台时看到的就是这个预警表按未处理状态倒序排列管理员可以逐条处理填写处理意见把状态从待处理改成已处理。整个过程不需要定时任务去跑因为是提交时同步判定的实时性很好代码也简单。公告流程没有太多复杂的逻辑就是管理员写标题、写正文、选择是否置顶然后保存。用户端在一个公开页面看到的就是置顶公告排前面非置顶按发布时间倒序排列。注意公告表里不要存储HTML富文本直接存纯文本加换行前端用pre-wrap样式渲染既安全又省事。如果要处理富文本需要额外做XSS过滤对毕设项目来说必要性不大不用给自己挖坑。2. 数据库设计与建表落地五张核心表怎么规划2.1 表结构一览与关键字段解释数据库设计是很多同学容易马虎的部分但恰恰是评阅老师最先翻看的内容。我的方案一共五张核心表用户表、健康打卡表、预警记录表、公告表、风险地区表。每张表都加入了一些看起来不起眼但很有用的公共字段。用户表t_user主要字段id自增主键、username唯一登录名、passwordBCrypt加密后的密文严禁明文存储、real_name真实姓名、phone手机号、role角色USER/ADMIN、status状态1正常/0禁用、create_time创建时间。这里实际开发中踩过一个坑如果直接存明文密码一旦数据库被导出所有用户信息就全泄了所以哪怕只是毕设项目我也强烈建议把BCrypt加密的依赖加上代码就是多写一行的问题但安全意识立马体现出来了。健康打卡表t_health_report主要字段id主键、user_id用户ID逻辑外键存用户的id不建物理外键约束是因为后期如果要做分表分库物理外键会带来很多额外的改造成本毕设阶段用逻辑外键完全够用这也是企业开发里我的个人习惯、report_date填报日期、temperature体温、health_code健康码颜色GREEN/YELLOW/RED、is_touched_risk是否接触过风险人群0/1、travel_history行程轨迹文本、is_abnormal是否异常0/1、submit_time提交时间。这里需要注意report_date和user_id需要建一个联合唯一索引保证一个用户一天只能有一条记录数据层面的兜底比接口层的判断更可靠。预警记录表t_alert主要字段id主键、report_id对应的打卡记录ID、user_id用户ID、alert_type预警类型发热/黄码红码/轨迹风险、alert_desc预警描述、status处理状态0待处理/1已处理、handle_remark处理意见、handle_time处理时间。异常数据单独拆一张表目的是让管理员的后台查询走独立的数据源不跟全量打卡记录混在一起查询性能更好逻辑也清晰。公告表t_notice和风险地区表t_risk_region的结构就更简单了。公告表就是id、title、content、is_top、create_time风险地区表是id、region_name、region_level高风险/中风险、create_time、status。风险地区表主要服务于一个近14天到访地区的联动校验严格来说这个表在答辩时可以作为一个功能亮点来讲就说系统支持动态配置风险地区并自动匹配用户的行程轨迹进行预警。2.2 为什么我不建议加外键约束和触发器有一类错误是很多自学的同学容易犯的建表时把所有外键约束都加上、把联动更新的逻辑都写在数据库触发器里。这种做法的初衷是好的想保证数据一致性但在前后端分离的项目架构下其实是在给自己增加不必要的麻烦。后端应用层完全有能力保证数据的一致性而且应用层做校验能给出更友好、更具体的错误提示。假设用户提交打卡时传了一个不存在的user_id应用层在Service里第一行就可以查出这个用户是否存在不存在直接抛业务异常返回用户不存在的提示而数据库外键约束报出来的是一个拗口的SQL错误码前端拿到之后还得再做一层翻译。触发器同理虽然可以自动写入预警表但这个自动行为对开发人员是隐性的出了问题排查起来非常难受。不如在代码里显式地写清楚这个流程虽然多几行代码但是可读性和可维护性高一个档次。我在建表时追求的是结构尽量简单、字段尽量清晰、索引尽量够用这三条原则。给参与毕设的同学一个实测建议建表脚本一定要手写不要用Navicat的可视化界面随便点两下就完事手写SQL的过程能帮你把字段类型、长度、索引、缺省值这些概念再过一遍答辩的时候如果被问到某个字段为什么这么设计你脑子里是有东西的。3. 后端SpringBoot开发中的关键设计与代码实现3.1 工程结构与统一响应体后端工程我按标准的SpringBoot分层来组织controller接收请求参数调用service返回统一结果service / service.impl业务逻辑层处理具体的业务判断和事务mapper数据访问层配合MyBatis-Plus使用entity实体类对应五张表dto / vo参数接收对象和视图返回对象严格分开不要混用configWebMvc配置、拦截器配置、跨域配置utilsJWT工具类、统一响应工具类核心的一个类是统一响应体Result 。这个类内部就三个字段code业务状态码200成功400参数错误401未登录403无权限500服务器错误、message提示信息、data响应数据。再配一个静态方法success(data)和error(code, message)。所有接口返回值统一用它包装前端Axios的响应拦截器根据code做统一处理比如code为401就跳到登录页。这种写法在企业开发里是标配在毕设项目里用上之后代码会显得特别规范答辩时也能大大方方介绍自己的统一异常处理方案。3.2 登录认证与权限校验JWT 拦截器本来不想多写鉴权这一块但考虑这个项目会被用于毕设答辩而登录之后怎么保证接口安全是高频问题所以这部分还是要详细说明。登录接口的逻辑前端传username和password后端先查用户表用户不存在直接返回用户名或密码错误注意这里不要把用户不存在和密码错误分开提示防止攻击者遍历用户名用户存在则用BCrypt的matches方法校验密码校验通过后生成JWT令牌令牌的payload里放userId和role两个信息加上过期时间这里我设置的过期时间是12小时作为演示项目完全够用最后把token返回给前端。前端拿到token后存到localStorage中之后每次请求在Axios请求拦截器里带上请求头Authorization: Bearer token。后端这边写一个LoginInterceptor实现HandlerInterceptor接口在preHandle方法中从请求头取token调用JWT工具类解析解析失败返回401成功就把userId和role塞到request的attribute中方便后续的业务代码取用。注册拦截器时配置要拦截的路径/api/user/、/api/admin/。管理员的接口统一放在/api/admin/**下拦截器里再加一个角色判断如果token里的role不是ADMIN就返回403。这样一来普通用户即使拿到了带token的请求也无法访问后台接口因为角色校验过不了。关于跨域前端和后端是分离部署的开发时前端跑在8080端口后端跑在8081端口前端发起请求必然触发跨域。解决的方案是在后端写一个CorsFilter或者实现WebMvcConfigurer的addCorsMappings方法允许的origins写http://localhost:8080允许的methods写GET、POST、PUT、DELETE、OPTIONS。注意别用允许所有来源的配置安全评分的时候会被挑刺。3.3 健康打卡接口的一个核心细节事务与自校验打卡接口是业务上最重要的接口因为它牵涉插入打卡记录 插入预警记录两步操作。这里必须加Transactional注解保证要么都成功、要么都失败。我在实际测试环境里专门验证过这个场景让程序主动在写入预警记录之后抛一个运行时异常然后看打卡表里有没有数据残留。加了事务之后数据干干净净不加的话就会出现打卡记录存在但预警记录丢失的脏数据状态。自校验逻辑也要在这一层体现调用方传的user_id要从token里取而不是信任前端传参。后端拿当前登录用户的ID去查这个用户存不存在、状态是不是正常的存在且正常才允许提交。健康状态判定是同步做的体温大于37.3度或者健康状态不是绿码就额外生成一条预警记录。这些判断逻辑写得直白一点没关系关键是场景覆盖要全。我在代码注释里会专门标出此处为异常自动判定逻辑方便学习的人快速定位。4. 前端Vue部分从搭建到核心页面落地4.1 项目结构与路由设计前端工程我用的是Vue2生态Vue版本2.6、Vue Router 3、Vuex 3、Element UI 2这一套组合在毕设项目里最稳网上的资料也最多遇到问题最容易搜到解决方案。工程结构如下src/api按业务模块拆分的接口请求文件src/router路由配置src/storeVuex状态管理src/views页面级组件比如login、userHome、userReport、adminUser、adminReport、adminAlert、adminNotice等src/components公共组件比如侧边栏、上传组件等src/utilsrequest.js封装Axios实例路由设计的关键在于嵌套布局。我做了两层布局登录成功后进入一个MainLayout组件内部左侧是菜单、右侧是内容区。内容区通过router-view渲染子路由。这种方式的好处是菜单和整体布局只写一次子页面切换时只替换内容区域。管理员的菜单是仪表盘、用户管理、打卡记录、预警处理、风险地区、公告管理普通用户的菜单是健康打卡、我的记录、公告列表。路由配置里还要写一个守卫在router.beforeEach里面判断如果访问的页面需要登录但本地没token直接redirect到登录页如果已经登录但访问的是登录页直接redirect到首页。4.2 前端状态管理与接口封装状态管理这一块我特意强调一下很多毕设项目把登录用户信息散落在各个页面组件里今天这个页面存一遍localStorage明天那个页面又自己解析一遍token代码写得很乱。我这边统一用Vuex管理用户状态在store里维护一个userInfo对象和一个token属性。登录成功后调用store.commit(setUserInfo, data)和store.commit(setToken, token)然后页面上需要读取当前用户名称、角色等信息时通过mapState取出来。这样后期如果有需要比如要判断是否显示某个按钮只需要在组件里取角色字段用v-if判断即可。接口封装方面我在utils/request.js里创建了一个Axios实例baseURL设置成http://localhost:8081/api请求拦截器做两件事从store里取token有则加到Authorization请求头没有则不动。响应拦截器做统一处理code等于200直接返回datacode等于401就清空本地登录信息并跳转到登录页其他code通过Element UI的Message提示错误信息。所有具体业务的请求都放在src/api目录下比如user.js里面是login、getUserInfo、submitReport、getMyReportsadmin.js里面是getAllUsers、getAllReports、getAlertList、handleAlert等。这样页面组件里就看不到任何axios相关的代码组件的职责只负责调用接口和渲染数据代码可读性会高一大截。4.3 核心页面的交互实现打卡表格与数据展示健康打卡页面的前端实现有个值得讲的小点表单是用Element UI的el-form组件实现的字段包括体温、健康码颜色、是否接触风险人群、近14天行程。提交前做前端校验体温必须是一个合理范围内的数字我用的是35.0到42.0不在这个范围内直接给出校验提示不用麻烦后端。这样其实就在前后端各设了一道防线。历史记录页面的数据表格我用的el-table组件。需要注意的一点是这个表格的数据不是一次性全查出来的而是后端做了分页。前端每次点击页码时调用selectMyReports接口并传入currentPage和pageSize参数后端返回一个分页对象包含总条数和当前页的数据列表。这样做的原因很现实一个用户打卡半年就有180条记录如果全部返回前端渲染会越来越卡接口响应也会越来越慢。分页是管理系统里的基本功这一块建议多花点时间理解Page对象是怎么构造的MyBatis-Plus有内置的Page对象配合selectPage方法两行代码就能实现分页查询。管理端的数据看板页面我是用几个统计卡片加上一张走势图构成的。统计卡片的数据从后端管理接口取用户总数、今日打卡数、今日异常数、待处理预警数。走势图我用了ECharts展示最近7天每天的打卡人数横轴是日期纵轴是人数。ECharts的引入方式也简单npm安装echarts后在需要的组件里import然后把后端返回的日期数组和人数数组填进option配置即可。这个图表页面是整个前端里视觉效果最好的页面很多同学答辩演示时都会先展示这个页面所以建议把数据准备好图表别是空的。5. 部署运行与踩坑记录别让环境问题卡住项目交付5.1 本地运行的整体流程不管项目代码写得多好跑不起来就等于零。我按实际操作顺序整理了一份从零到能跑起来的步骤清单照着做基本上不会有问题。第一步准备环境。后端要装的工具是JDK 1.8或11和Maven 3.6以上版本前端要装的是Node.js 14以上版本。装的时候注意环境变量配置JDK配JAVA_HOMENode要确保npm命令可用。不会配环境变量的同学可以直接用IDEA自带的JDK和Maven省事很多。MySQL装5.7或8.0都可以但注意连接驱动在pom.xml里要对应版本。第二步初始化数据库。用Navicat或命令行执行项目里提供的init.sql脚本脚本会创建database并导入表结构和初始化数据。初始数据里面包含一个管理员账号admin和一个测试用户user密码都是123456不过这个密码在脚本里存的是BCrypt加密后的密文。这里提醒一句如果直接手动在数据库里插一条密码为123456的记录登录接口会用BCrypt去校验结果肯定是登录失败。当年我给一个学生远程调试时就卡在这个坑上他自己用Navicat手动改了数据库的密码字段导致登录一直报密码错误排查半天才反应过来。第三步启动后端。用IDEA打开后端工程等Maven把依赖下载完修改application.yml里的数据库连接信息数据库名、用户名、密码直接运行启动类。看到控制台打印出Tomcat started on port(s): 8081就说明启动成功了。第四步启动前端。命令行进入前端工程目录依次执行npm install安装依赖和npm run serve启动开发服务器。看到编译成功并且提示Local: http://localhost:8080就知道前端起来了。浏览器访问8080端口登录页就能正常显示。第五步联调验证。用admin登录看后台页面是否正常加载出统计数据用user登录提交一条健康打卡去后台查看是否出现对应记录。如果这些都通了整个项目就算跑通了。5.2 我在部署过程中碰到过的三个高频问题问题一前端npm install速度慢到怀疑人生甚至直接报错。这个问题十有八九是npm默认源在国外导致的。解决方法就是把npm源切换成国内的镜像源执行一行命令即可npm config set registry https://registry.npmmirror.com。切换之后重新install速度会有质的提升。顺便提一句node_modules目录如果出现损坏导致启动报错最简单的处理方式是把node_modules整个删掉重新install千万别手动去改里面的文件。问题二后端启动报数据库连接失败。先看MySQL服务有没有启动Windows下直接在服务管理里查看再看application.yml里的url配置的端口是不是3306密码有没有填对。有一个细节MySQL 8.0的驱动类名是com.mysql.cj.jdbc.Driver如果pom.xml里引入的mysql-connector-java版本是5.x需要手动指定8.x版本或者改driverClassName。问题三前端页面能打开但所有接口请求报错或者干脆请求失败。检查两处一是后端的跨域配置有没有生效最简单的验证方式是用浏览器F12看Network面板如果某个请求的响应头里没有Access-Control-Allow-Origin说明后端跨域配置有问题二是请求地址的baseURL是否写对前端如果是http://localhost:8080请求路径应该是http://localhost:8081/api/xxx端口对不上那肯定不行。问题四是一个容易被忽略的细节非常值得单独拿出来讲——代码层面没任何问题但是上传服务器后有些接口能通有些接口404。排查了一圈发现是打包后放行路径的问题。举例来说后端接口的路径如果是/api/admin/getAllUsers在服务器上部署时如果通过nginx反向代理把/admin前缀过滤掉了就可能导致404。处理方案是让后端接口路径固定为/api/开头nginx代理时原样转发不去动路径结构。5.3 如何把项目改成带独立风格的作品避免千篇一律毕设和课设最忌讳的就是所有同学交上来的项目长得一模一样相同的页面结构、相同的代码命名、相同的表结构。我接过的辅导案例中很多学生拿到开源代码后就直接提交了结果同班同学里好几个排一起答辩评委一眼就看出来是同一个来源印象分会大打折扣。所以我给大家三个低成本的个性化改造点。第一个是换主题。前端用Element UI的官方主题定制工具改主色变量把默认蓝色改成别的颜色比如偏医疗感的青色或者偏科技感的深蓝紫。这个改动只涉及几处变量大概一个下午能完成但是视觉效果会完全不同。第二个是加一个数据导出功能。管理员在打卡记录页面加一个导出Excel按钮后端用EasyExcel或者Hutool的Excel导出工具把符合条件的打卡记录生成Excel文件返回给前端下载。这个功能实际使用频率很高而且能体现你考虑了真实业务场景在答辩时是一个很自然的加分项。第三个是加一个登录验证码。在登录页面加一个图形验证码后端用Hutool的CaptchaUtil工具类生成验证码图片把图片的base64返回给前端同时把验证码答案存进Redis或者一个Map缓存登录时校验。验证码这个功能在很多评委眼里是区分照着demo做和用心设计的分水岭虽然实现不复杂但会显得你的系统完整度更高。6. 项目二次开发建议与学习路径参考资料以后端Java这块为例推荐的学习路线是先掌握Java核心语法和面向对象思想然后学Spring框架的IOC和AOP机制再过渡到SpringBoot的自动配置原理和Web开发。做这个毕设项目时至少需要了解SpringBoot的注解式开发、Controller层怎么写、Service层的事务处理、MyBatis-Plus的CRUD用法。这些知识点不是一蹴而就的但通过一套完整的项目跑下来你会对它们形成一个具体的、连贯的认知。比如说不再纠结IOC是什么因为你在Service里使用Autowired注入Mapper时已经不知不觉地在用IOC容器了。前端Vue部分的自学建议是不要一上来就去啃Vue3的新语法组合式API先从Vue2的传统选项式API开始理解核心概念数据绑定、指令、组件通信、生命周期这些基础打牢之后再去看Vue3会发现其实改动并不难理解。这个项目里用到的Vue2语法都是最基本的非常适合用来建立框架思维。这个项目还可以往哪些方向扩展我想到的有加入定时统计任务每天零点自动统计前一天各地区的打卡率和异常率生成报表加入消息通知管理员处理预警后给对应用户推送系统消息加入审批流程高风险人群的隔离申报需要管理员逐级审批加入数据可视化大屏用ECharts做一个大屏展示全区域的健康分布状况这些方向哪一个都能作为答辩时的系统亮点去展开讲而且实现难度都不算高是在现有架构上做加法不需要动核心设计。最后说一句心里话做这类管理系统的价值不在于把页面做得多么花哨而在于你能不能用工程化的思路把一个完整业务链条捋顺。你的建模能力、逻辑梳理能力、前后端协作能力才是这门课或者这次毕业设计真正要考察的东西。代码可以复制但是能力是属于自己的。把这套SpringBootVue的疫情防控管理系统从头到尾自己敲一遍、跑通一遍、改出一点自己的东西你就已经有了独立完成一个全栈小项目的能力这比答辩拿高分更值钱。