☰
Spring Boot毕业设计实战:高校师生疫情管理系统开发全解析
2026/9/28 5:43:40 网站建设 项目流程

刚在选题列表里翻到这个“计算机毕业设计之springboot高校师生疫情管理系统”,我第一反应是:这个题目简直是为Spring Boot入门量身定制的。它不偏门、不过度追求高并发、也没有强行堆砌微服务,只要把Spring Boot、MyBatis、MySQL这套经典组合吃透,再理清业务闭环,就能产出一个可以演示、可以答辩、可以说清原理的完整项目。

这篇博文就围绕这个项目展开,从选题拆解、技术选型到核心功能实现,再到开发踩坑和答辩准备,一次性讲透。无论你是准备拿来应急参考,还是真打算自己写一遍,按这套思路走都稳。

1. 这个题目的核心到底考你什么

1.1 项目背后的真实需求

高校人口密度高、流动性大,一个几千人的学院,每天要统计师生健康状态,靠Excel和人工接龙根本撑不住。这个毕业设计的本质,是把“信息采集—任务审批—数据汇总—异常提醒”这一整条链路搬到线上。

用业务语言翻译一下,系统要解决四件事:师生每天主动填报健康信息、辅导员和校医院查看汇总数据、请假外出走线上审批、发热或咳嗽等异常情况能快速筛出来。这不只是写几个CRUD,而是考验你能不能把一个模糊需求做成可运行的软件。

很多同学拿到题目后就急着建表写代码,结果做完发现各模块像散装零件,连不起来。正确姿势是先画出用例图,把三种角色(学生、教职工、管理员)分别能做什么列清楚,再顺着他们的日常操作路径去设计页面和接口。

1.2 功能模块怎么划分才合理

我建议按“填报端—审批端—管理端”三条线拆,每条线再往下细分成子模块,这样不管写代码还是写论文都有清晰的主线。

  • 学生/教师填报端:每日健康打卡、查看历史记录、提交请假申请、接收异常通知,这是系统使用频率最高的部分,必须保证操作简单、页面响应快。
  • 辅导员/学院审批端:查看本班或本学院的填报率、导出Excel报表、审批学生请假、标记异常状态,重点在数据筛选和批量操作。
  • 系统管理员端:用户管理、学院/班级结构维护、全校数据总览、系统参数配置,这部分最考验关联表设计。

这个分类不仅是功能划分,也决定了后面数据库表怎么建、接口权限怎么控制。比如学生只能查自己的记录,辅导员只能看自己管辖范围的数据,这就要在Mapper查询条件上统一加上“组织归属”的过滤逻辑,不能靠前端隐藏按钮来兜底。

1.3 为什么用Spring Boot而不是Servlet或者SSH

如果你只是想在答辩时说“因为Spring Boot简化了配置”,那还差一层意思。用Spring Boot的深层价值在于:它把项目从“配置驱动的开发模式”切到了“约定优先”,内嵌Tomcat让程序一键启动,自动装配替你把大量底层组件都做好了,你能把精力放在业务逻辑上。

这就给毕业设计带来一个看得见的好处:演示现场打开IDEA,点一下运行,Swagger接口文档自动带出来,浏览器里敲localhost:8080就能看到登录页。整个过程不需要额外启动Tomcat、不需要手动配置数据源XML,现场翻车概率大幅降低,而稳定演示对毕业设计来说比什么都重要。

2. 关键技术点的拆解与选型逻辑

2.1 Spring Boot自动装配是怎么回事

很多同学在简历里写“熟悉Spring Boot”,但一问自动装配原理就卡壳。这里必须搞懂,因为这是最高频的答辩问题。

Spring Boot启动类上有个@SpringBootApplication,它实际上组合了@Configuration、@ComponentScan和@EnableAutoConfiguration三个注解。后者的核心是一个AutoConfigurationImportSelector,它会去读取spring.factories或META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports里声明的所有自动配置类。

每个自动配置类上都有条件注解,比如@ConditionalOnClass判断classpath里有没有某个依赖,@ConditionalOnMissingBean判断容器里是否已有用户自定义的Bean。只有条件全部命中,自动配置才生效。

放到这个疫情管理系统里,你可以这样举例:你引入了spring-boot-starter-data-redis,就自动帮你创建了RedisTemplate;你引入了MyBatis的starter,只要配好数据源信息,SqlSessionFactory就自动装配好。这和你手写XML配置的效果一样,但省掉了流程时间。

2.2 后端分层架构和环境搭配

推荐结构是标准的四层:Controller、Service、Mapper、Entity。这个分层不是学究气,而是你后面遇到报错时能快速定位。曾经就有同学把SQL写在Controller里,结果改一个联查逻辑要把Controller整个看一遍,相当于把厨房设计在卧室里,难维护。

推荐技术栈组合如下:

组件选型建议备注
JDK8或者11尽量和你本机其它项目统一
Spring Boot2.7.18稳定、资料丰富、兼容性好
ORMMyBatis-Plus内置分页插件、代码生成,效率高
数据库MySQL 5.7/8.0免费、教学资源多
认证方案JWT + 拦截器 或 Shiro二选一即可,别去碰过于复杂的权限框架
前端Vue 2 + Element UI前后端分离,方便展示接口能力
工具Maven、Lombok、HutoolLombok减少样板代码,Hutool处理日期和Excel

MySQL 5.7还是8.0,如果开发机和服务器版本不一致,注意驱动差异。用8.0时com.mysql.cj.jdbc.Driver,5.7用com.mysql.jdbc.Driver,依赖也不要混用。这类版本不匹配的问题,很常见但很好排查。

2.3 分页插件用法与原理

数据量一大,必然要分页。MyBatis-Plus提供了一个现成的分页插件,用法很简单:

@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); PaginationInnerInterceptor pagination = new PaginationInnerInterceptor(DbType.MYSQL); pagination.setMaxLimit(500L); interceptor.addInnerInterceptor(pagination); return interceptor; } }

查询时只需要:

Page<User> page = new Page<>(current, size); IPage<User> result = userMapper.selectPage(page, new QueryWrapper<User>() .eq("role", "student") .orderByDesc("update_time"));

很多同学一开始会漏掉@Bean配置,直接在Mapper里调用带Page参数的方法,结果发现返回的全量数据,以为插件不生效。其实原理在于分页插件是一个拦截器,它会对Executor执行SQL之前进行拦截,改写为目标数据库方言的分页语句。比如MySQL会被改写成带有LIMIT ?,?的语句,再执行一次SELECT COUNT(*)查询总数。

答辩如果被追问,就往“拦截器改写SQL”这个方向答,基本能过关。

2.4 登录认证与权限控制怎么设计

系统有三种角色,权限差异明显。我的建议是用JWT做无状态认证,配合拦截器做角色校验,简单且容易解释。

大概流程是:登录成功后,用用户的ID和角色生成一个token,放进响应头返回给前端;前端每次请求把token放到Authorization头里;后端拦截器先解析token,再把用户信息放进ThreadLocal,方便Controller直接获取。

关键代码类似:

public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (token == null || !JwtUtils.verify(token)) { return JsonUtils.writeError(response, 401, "未登录或登录已过期"); } String userId = JwtUtils.getUserId(token); UserContext.set(userId); return true; } }

这里有个细节:不同角色的接口访问控制在拦截器里判断路径前缀就好,比如/api/admin/**必须管理员,/api/teacher/**允许教职工和管理员。别硬上Spring Security的大套筒,毕业设计里把拦截器逻辑讲清楚,比挂一个自己都不明白的Security配置更受评委认可。

2.5 全局过滤器与XSS防护

系统里有大量用户输入文本,比如每日打卡的备注、请假事由,如果不做XSS过滤,别人往页面里注入一段脚本,后果很严重。Spring Boot里可以用一个Filter统一处理,比如用Jsoup来清洗参数。

实际代码可以写一个OncePerRequestFilter,通过包装类重写getParameter和getInputStream方法,把特殊字符转义掉:

@Component public class XssFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { XssHttpServletRequestWrapper wrapped = new XssHttpServletRequestWrapper(request); chain.doFilter(wrapped, response); } }

然后在包装类里清洗字符串,比如把<script>转成&lt;script&gt;。这里要注意:不能对所有字段都做HTML转义,否则将来遇到要传富文本的公告就麻烦了。所以更稳妥的做法是设置一个白名单,只针对name字段为remark、reason这样的文本字段做过滤。

设计这个系统时,另外一个容易被忽略的坑是上传文件场景。虽然疫情管理系统一般只涉及Excel导入或头像上传,但只要有文件,就得检查文件后缀和大小,别让用户传一个可执行文件伪装成图片。

3. 核心功能与前后端实现过程

3.1 数据库表设计思路

建表是整个项目的地基,地基歪了后面全是灾难。按模块拆,核心表大概有这些:

  • 用户表(user):id、用户名、密码、姓名、角色、所属班级/学院ID、电话
  • 健康打卡表(health_report):id、用户ID、打卡日期、体温、是否咳嗽、是否发热、行程说明、备注、打卡时间
  • 请假申请表(leave_request):id、用户ID、开始时间、结束时间、事由、状态、审批人ID、审批意见
  • 异常记录表(exception_record):id、关联用户ID、异常类型、处理状态、处理意见
  • 学院班级表(organization):id、父级ID、层级类型、名称

特别注意:用户表里存储学院/班级关系的字段,会直接影响统计功能好不好写。如果你让用户表只存一个class_id,那统计某个学院的数据时要先查学院下所有班级的ID,再查这些班级下所有人,做起来非常绕。建议直接用冗余的字段,比如college_id和class_id都存,写入时冗余保存,查询统计时就省去大量子查询。

密码一定不要明文存,用BCrypt加密;每张表都留create_time、update_time字段,MyBatis-Plus开启自动填充,避免到处手动set当前时间。

3.2 每日健康打卡模块的实现

打卡是系统最高频的接口,很可能一个学院几千人同时提交,所以要控制好事务边界和重复提交问题。

同一用户同一天应该只能提交一次,这个约束不可以在代码层靠先查询再判断来做,会产生并发问题。正确做法是在数据库层面加唯一索引,例如在health_report表上建(user_id, report_date)唯一键,再在插入前先查,兜底用try-catch捕获唯一键冲突。

空间上,在校的提交地址,也可以选填。考虑到这个系统是毕业设计,建议不做复杂的地图API对接,开放一个文本输入框,让学生填写所在位置或宿舍楼栋就可以了。倒不是技术做不到,而是把精力放在核心业务上更划算。

打卡接口伪代码如下:

@PostMapping("/api/report") public Result submit(@RequestBody HealthReportVO vo) { Long userId = UserContext.getUserId(); if (healthReportService.hasReportedToday(userId)) { return Result.error("今日已打卡,请勿重复提交"); } vo.setUserId(userId); healthReportService.submitReport(vo); return Result.ok(); }

体温字段建议用BigDecimal,避免浮点数比较的坑。温度异常阈值放到系统配置表里,而不是写死在常量里,这样答辩时可以灵活演示“将阈值从37.3改成37.5,系统立即生效”,算是一个加分的小亮点。

3.3 请假审批与异常上报

请假流程要推动态审批的概念:学生提交申请,状态为“待审批”;辅导员登录后看到待办列表,选择同意或驳回;学生端同步显示审批状态。这个模块不复杂,但需要两张表联动,主要触发点是更新状态时写入审批意见。

在实现时,关于权限有个细节。辅导员只能看到自己班级的申请,所以在列表查询的SQL里必须加人数过滤。我见过直接把where user_id = ?写死成当前登录用户的做法,结果辅导员只能看到自己的请假记录。必须像下面这样写:

<select id="selectPendingList" resultType="LeaveRequestVO"> SELECT lr.*, u.name AS user_name, u.class_name FROM leave_request lr LEFT JOIN user u ON lr.user_id = u.id WHERE lr.status = 'PENDING' AND u.class_id IN (SELECT class_id FROM user WHERE id = #{auditorId}) ORDER BY lr.create_time DESC </select>

异常上报模块我建议稍微扩展一点,做成“打卡异常自动触发”:如果打卡体温超过阈值,自动生成一条异常记录,提示辅导员处理。这能突出系统的“智能化”程度,写论文时也能构造出“系统检测→人工复核→闭环处置”的整套流程,比单调的CRUD有说服力得多。

3.4 数据统计与前端展示

统计报表可以分三个维度:按班级展示打卡率、按日期展示打卡趋势、按学院展示异常人数柱状图。

前端如果是Vue + Element UI,用ECharts画折线图和饼图,效果非常直观。而后端接口直接返回聚合好的JSON数据就行,比如:

@GetMapping("/api/stats/trend") public Result getTrend(@RequestParam Integer days) { return Result.ok(statService.getReportTrend(days)); }

聚合统计的SQL要重点打磨,这是毕业设计的熟面孔。比如统计每个学院最近7天的打卡率:

SELECT o.id AS org_id, o.name AS org_name, COUNT(DISTINCT u.id) AS total_students, COUNT(DISTINCT CASE WHEN hr.report_date >= ? THEN hr.user_id END) AS reported_count FROM organization o LEFT JOIN user u ON u.college_id = o.id AND u.role = 'student' LEFT JOIN health_report hr ON hr.user_id = u.id GROUP BY o.id, o.name

这条SQL的逻辑核心是先用LEFT JOIN把学院、学生、打卡记录连起来,再用CASE WHEN按时间段过滤,就能同时拿到学生总数和近期打卡人次,减少反复查询。这一步做明白,不仅简历里可以写“具备复杂SQL编写经验”,答辩时也扛得住追问。

前端展示时,打卡率做得好的还可以用进度条颜色区分:高于90%绿色,70%到90%橙色,低于70%红色,一眼就能看到风险点。

4. 开发过程中最常踩的坑和排查方法

4.1 版本兼容性问题

Spring Boot 3.x系列从javax.servlet换成了jakarta.servlet,很多2.x时代的拦截器、第三方工具类在你升级后直接编译失败。如果你跟着网上教程拿到了一个Spring Boot 2.7.18的模板,但依赖里混了2.3或者1.5的写法,又会碰到各类反射异常。

最省心的做法是锁定统一版本:打开项目的pom.xml,确认Spring Boot父工程版本是2.7.x,MyBatis-Plus版本用3.5.x,MySQL驱动版本跟着Spring Boot的依赖管理走。不要手动指定很多无谓的版本号,让父工程统一管理能少消耗很多时间。

4.2 MyBatis和数据库相关的疑难杂症

时区问题是重灾区。连接表明细里没加serverTimezone=Asia/Shanghai,本地连接MySQL 8.0能跑,但服务器部署后可能报The server time zone value错误。建议URL长这样:

jdbc:mysql://localhost:3306/epidemic_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false

还有一个非常迷惑的问题:财务字段显示乱码,原因挺多,但最常见的不是代码问题而是连接参数没设编码。jdbc URL加了characterEncoding=utf8也不代表MySQL建库时建对了,还得确保库和表的字符集是utf8mb4而不是utf8,否则Emoji或生僻字直接变问号。

4.3 前端联调和跨域问题

前后端分离开发时,前端8080端口调后端8090接口,必然遇到CORS。如果只是打开前端页面,直接传location是避不开的,最简单的办法是后端创建一个全局配置类,放行跨域请求:

@Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedOriginPattern("*"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }

注意allowCredentials(true)之后,allowedOrigin不能写*,要用allowedOriginPattern("*"),这个坑能卡一帮人。

还有一个很经典的“白屏”问题:前端接口请求成功了,但页面就是空白的。检查浏览器Console,多半是接口响应里有一个字段渲染不存在的属性,Vue直接抛错阻止渲染。调起来其实没有技术门槛,耐心看Console报错信息就行。

4.4 部署与演示环境的准备

毕业设计演示尽量在本地跑,别轻易挑战线上环境的复杂流程。如果导师要求必须部署,推荐用Docker,把MySQL和容器化应用编排在一起。

打包命令是mvn clean package -DskipTests,打出来的JAR放服务器上,用java -jar xxx.jar启动基本无压力,但有几个前提:服务器MySQL要允许远程连接,端口要放开防火墙限制,配置文件里的数据库地址要改成服务器IP,账号密码不要写在代码里,而是通过环境变量传入。

演示前还有一套自检清单:

  • 先用浏览器无痕窗口登录一次学生账号,填一次打卡
  • 用辅导员账号审批请假,看状态变化
  • 切换管理员查看统计报表
  • 关掉服务再启动,验证JWT过期逻辑有没有bug

这套流程跑通了,演示环节就能顺利通关。

5. 论文和答辩环节怎么把这个项目讲出深度

5.1 论文结构建议

论文不要写成“说明书”,要有一个明确的问题驱动。建议主线定为:现状与痛点→需求分析→系统设计→核心功能实现→系统测试,每一章都要扣住“为什么这么做”。

在系统设计部分,除了结构图之外,一定要补两张图:E-R图和时序图。E-R图画清楚实体之间的关系,时序图拿“每日打卡”或“请假审批”举例,会极大减轻评委读论文的负担。很多同学只放截图不放架构图,论文看起来就缺乏工程感。

核心功能实现部分不要堆代码。挑两到三个有代表性的功能写清楚,比如分页插件如何配置、JWT拦截器如何实现、统计SQL如何设计,配合核心代码段加解释文字就行,没必要把Controller里每个方法都贴进去。

5.2 评委爱问的问题要怎么准备

根据答辩的经验,高频追问点就这几个:

  • Spring Boot自动装配的原理
  • 为什么不能把密码存明文,加密方式用的什么
  • 分页插件的底层实现原理
  • 同一用户重复提交重复打卡怎么解决
  • 系统是怎么做权限控制的(对应答辩测试点)
  • 如果打卡人数从几千涨到几万,系统怎么优化性能

前五个问题上面都提到了,重点说第六个。不要一听到“高并发”就慌,这是考察你的性能意识,可以这样答:先考虑加索引,比如打卡表的有唯一索引;再考虑把热点数据加Redis缓存,比如班级统计结果可以缓存60秒;接着可以考虑异步写操作,打卡返回成功不一定要求事务实时落库,先丢消息队列再消费。

这个答案不一定真的实现了,但你展示了清晰的性能优化思路,比一句“没想过”强太多。分布式锁、Redis缓存都是加分点,前提是你真的了解基础原理,别在追问中露馅。

5.3 怎么让项目在众多毕设中显得不普通

有三处小的创新点可以让项目眼前一亮:第一,把异常规则做成可配置化,管理员可以在后台设置体温阈值,不用改代码;第二,接入ECharts图表,展示打卡趋势和填报率,视觉效果好;第三,提供Excel导出功能,每月报表可以直接导出归档。

我建议把更多的精力放在“数字化管理闭环”这个表述上:填报数据→汇总分析→异常预警→闭环处置。任何一项单独看都不复杂,但能把它连贯起来,说明你对业务的理解不止停留在写代码层面。

6. 实操建议和个人心得

这个项目的最佳开发周期是四周左右:第一周搭框架和建表,第二周做打卡和用户管理,第三周做请假和统计,第四周写论文和PPT。时间很紧张,所以脚手架直接用MyBatis-Plus的代码生成器建好Controllers、Services、Mappers的雏形,是明智的选择。但生成归生成,关键逻辑一定自己手写过一遍,否则答辩被追问时容易脑海一片空白。

很重要的一点经验:开发过程中保持一个能运行的版本备用。具体做法是每完成一个模块就顺手提交到Git仓库,或者至少把单机能跑的JAR包备份一份。有一次我在改权限拦截器时把登录逻辑写坏了,依赖的模块全不可用,要不是有前一天能跑的版本,演示前心态早就崩了。毕业设计项目不需要装GitLab,新建私有仓库就行,提交信息写清楚,后期回溯比用文件名带日期备份的方式省心得多。

另外,尽早准备演示数据和截图。很多同学最后几天才发现没有学生、教师、管理员三种角色的示例账号,也没有几天的打卡数据,导致统计报表光秃秃的,演示效果大打折扣。建议预留一套标准演示用例:一个学院下面三个班,每班五六个学生,提前录入近两周的打卡数据,包含一两个历史异常和一条待审批请假。这份细心在答辩现场非常加分。

最后再送一条我自己的经验:遇到报错先冷静看内部异常的第一行Caused by,不要满屏日志往上翻。Spring Boot的报错信息通常已经把定位信息标明得很清晰,比如数据库连接异常会直接告诉你用户名或主机名有问题。耐心一点,这个项目里的坑90%靠“认真读日志”就能解决,剩下的10%搜索一下也基本有现成答案。

把这个系统完整做一遍,你收获的不只是一篇能过审的毕业论文,而是一套从数据建模、接口设计到权限控制、统计查询的完整后端工程能力。这套能力放在任何业务系统里都通用,这也是为什么这类题目能常做常新。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询