2020年开始,高校的疫情防控变成了一项常态化管理工作,通知怎么发、健康数据怎么收、异常情况怎么排查,全压在辅导员和行政老师的肩上。当时微信群刷屏、Excel表格来回传是常态,信息分散、统计困难、回溯麻烦,光靠人工已经扛不住。我自己的毕业设计就选了“安康学院新型冠状病毒肺炎疫情防控专题网站的设计与实现”这个题目,本质上是给学校搭建一个统一的防控信息平台,把通知发布、每日健康上报、异常预警、数据统计这些事收敛到一个系统里。今天把完整的设计思路、开发过程和踩坑记录整理出来,给后面做类似选题的同学一个参考,也顺便聊聊毕业论文、PPT和演示视频这些材料该怎么准备。
这个项目看起来是个标准的Web应用开发,但真正做完之后你会发现,它比一般的商城系统、图书管理系统复杂的地方在于:需求边界不清晰、数据敏感度高、使用场景特殊、汇报材料要求完整。论文+PPT+源代码+演示视频这套组合,其实对应的是“系统设计能力、工程实现能力、学术表达能力”三件事的综合考核,每一项都有具体的方法和坑。下面我按自己的实际操作顺序来拆。
1. 项目背景与需求分析
1.1 高校疫情防控专题网站到底要解决什么问题
先说清楚这个系统为什么值得做。高校的人员密度高、流动性大,学生来自全国各地,返校、请假、实习、外出这些场景都会带来潜在风险。单纯靠人工管理,有三个非常痛的问题:
第一是信息不对称。通知发在微信群里,几分钟就被刷过去,学生到底看没看到、落实到什么程度,老师完全没数。第二是数据离散。每天的体温、健康状况、行程轨迹散落在不同的Excel表格和问卷链接里,统计一次全校数据要花半天,还容易错。第三是追溯困难。一旦出现异常情况,需要倒查某个学生过去十四天的位置和健康记录时,人工翻聊天记录根本不现实。
所以这个专题网站的核心定位不是“展示型官网”,而是“业务型管理平台”。它要服务的角色有三个:学生(日常填报和查看通知)、辅导员/管理员(审核、统计、管理本班数据)、校级管理员(全局数据监控和配置管理)。搞清楚这个用户模型,后面的功能设计和权限设计才有依据。
我当时做需求调研的时候,分别访谈了辅导员、学工处老师和几个学生代表,整理出来的核心诉求就四条:一是学生填报要简单,手机能打开就行,两分钟内完成;二是辅导员要能一眼看出“谁没填”;三是每日上报的数据要能按学院、班级维度自动汇总;四是要有异常提醒,体温超标或者填了异常状况的,系统要能标红。
1.2 功能模块拆分与优先级判断
需求梳理清楚之后,我按照“必须做、尽量做、可以不做”三个级别展开。必须做的是这样几块:
- 用户认证与角色权限:学生账号由系统批量导入,管理员拥有后台管理权限。用户登录时区分角色,跳转到不同界面。
- 每日健康上报:填报内容包括体温、健康状况(正常/发热/咳嗽等)、当前所在地、是否接触过疑似人员、是否有中高风险地区旅居史,当天只能提交一次,允许修改但保留修改记录。
- 通知公告发布:管理员发布防控通知、文件、防疫知识,前端列表展示,支持置顶,用户端可查看详情。
- 数据统计看板:按学院、年级、班级统计填报率、异常人数、未填报名单,支持导出Excel。
- 后台管理:用户管理、学院班级管理、公告管理、上报记录查询与导出。
尽量做的有:返校申请与审批流程、隔离人员跟踪管理、消息提醒(站内消息+短信)。可以不做的是:在线问诊、心理咨询预约等扩展功能。做毕业设计最忌讳的就是功能堆砌,一个学期做不完不说,论文还写不深。把这个优先级定下来,后续开发基本不会跑偏。
1.3 论文选题的切入角度与工作量预估
如果你是在导师给定大方向的情况下自由细化题目,建议把“创新点”和“工作量”这两件事想清楚。这个题目的创新点可以落在三个方向:一是业务流程设计上的合理性,比如异常闭环处理机制;二是数据可视化层面的对比分析,比如用图表展示全校填报趋势;三是工程化程度,比如接口设计规范、前后端分离、多角色权限等。
工作量方面,我建议按时间倒推进度:需求分析1周,系统设计2周,前后端开发5到6周,测试修漏洞2周,论文撰写3周,PPT和演示视频1周。整个下来大概需要13到15周,正好覆盖一个学期。如果基础比较薄弱,开发周期要预留得更足,论文和材料一定不要拖到最后两周才动手,那会非常狼狈。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型与系统架构设计
2.1 前后端技术方案的选择与理由
技术选型是毕业设计答辩时老师最喜欢问的第一个问题。很多同学上来就选自己会的语言,完全不考虑场景,答辩的时候被问一句“为什么用这个”就愣住了。我当时的选型是:后端Spring Boot 2.x + MyBatis Plus + MySQL 5.7,前端Vue 2 + Element UI + Axios。
为什么这么选?第一,Spring Boot是目前高校毕设中使用最广泛的后端框架,生态成熟、资料多,遇到问题很容易在社区找到解决方案;第二,MyBatis Plus把单表CRUD操作简化了很多,MyBatis Plus特别适合这种业务逻辑清晰、以单表操作为主的项目,可以把大量样板代码省掉;第三,Vue + Element UI的组合上手快、组件全,做后台管理类页面效率极高,表格、表单、日期选择器、弹窗这些都有现成组件。
有的同学会问,用JSP + Servlet这种传统方案行不行?也可以,但如果你想让系统有更好的扩展性、并且论文里能写“前后端分离架构”,那还是用Spring Boot + Vue。答辩时老师认可这套方案的程度明显更高。还有一点,尽量不要用PHP写这种管理系统,不是说写不了,而是从学术角度来讲,技术栈的“现代感”很重要。
2.2 数据库设计与核心表结构
数据库设计是这个项目里最见功夫的部分。一张合理的表结构能让你少写一半的后端代码。我最终设计了七张核心表:用户表、学院表、班级表、健康上报表、通知公告表、公告阅读记录表、操作日志表。
最核心的是健康上报表,这里有一个关键设计:用(user_id, report_date)作为联合唯一索引,从数据库层面保证一个用户一天只能报一次。如果不加这个约束,代码里查一次再插入一次,在高并发或者重复提交的场景下很容易产生脏数据。另外,体温字段用DECIMAL(4,2)类型,符合体检设备常见的数据精度。健康状况这类选项字段,用TINYINT存0/1/2这种枚举值,不要直接存中文,后面统计会非常麻烦。
用户表的设计也有一点讲究:学生用户不设密码,初始状态用身份证后六位作为默认密码,首次登录强制修改。这样做的好处是避免管理员挨个初始化密码的重复劳动。管理员的角色用role字段区分,1代表超级管理员、2代表学工处老师、3代表辅导员,权限级别不同,能看到的数据范围也不同。
2.3 系统架构与部署方案
系统的整体架构是典型的三层结构:浏览器端(Vue SPA前端)、应用服务层(Spring Boot)、数据层(MySQL)。开发环境下前端通过Axios请求后端的/api接口,使用Vue Cli的devServer做跨域代理,避免开发时反复配置CORS。生产环境打成jar包部署在服务器上,用Nginx同时托管前端dist目录和反向代理/api路径。
这里有一个很多同学容易忽略的点:部署方式要在论文里写清楚。我建议将jar包部署和Nginx配置截图都放进论文的“系统部署”章节,不仅可以凑篇幅,还能体现工程完整度。数据备份上,我是每天凌晨用crontab自动执行mysqldump备份一次,备份文件保留最近七天。虽然是毕设项目,但既然做的是疫情防控系统,数据的可靠性问题上态度要摆正。
3. 核心功能模块设计与实现
3.1 用户登录与权限控制
这个模块普通人可能觉得无脑,其实坑很多。登录接口的逻辑顺序是:前端把用户名和密码交给后端,后端先查用户是否存在,再比对密码。密码存储一定不能明文,我用的是MD5加盐的方式,盐值是用户名加上固定的随机字符串。有同学可能会说现在都推荐BCrypt,但在毕设论文里MD5加盐也说得过去,重点是你要能讲清楚为什么要加盐,以及和明文存储的区别是什么。
登录成功后,后端返回一个包含用户基本信息和角色标识的JSON,同时用JWT生成token返回给前端,前端把token存在本地,每次请求时放在请求头里。需要特别注意的是前端路由的拦截器:如果未登录就去访问首页或后台管理页面,必须强制跳转到登录页。管理端的页面还需要根据角色再做一次菜单过滤,比如辅导员看不到校级数据大屏入口。
权限控制的代码实现,核心是后端拦截器里对每个接口做角色校验。我这里用的是自定义注解@RequireRole配合Spring MVC的Interceptor实现,只写了一次拦截逻辑,后面所有接口只要在方法上加一行注解就能生效。这部分很有写头,论文里可以展开讲一讲。
3.2 每日健康上报模块
这是整个系统的高频使用模块,也是逻辑最复杂的部分。学生端页面打开后,系统自动带上他的姓名、班级,他只需填体温、选健康状况、选所在地,点提交就完成了。我们这边设计的是提交之后页面显示“今日已上报”,后面再次进入表单直接置灰。
“当天只能上报一次”这个逻辑,我在前后端各做了一层校验:前端在提交成功后用本地标志位阻止再次提交,后端在插入前先按user_id和当前日期查一次,如果已有记录就返回错误码。同时数据库层面用UNIQUE KEY兜底,三层防护保证不会因为用户反复点击或者同时打开多个页面产生重复数据。
修改记录这条需求,是用户调研时老师提出的:学生填错体温想改怎么办?所以我在设计时允许学生在当天24点前修改上报信息,但每次修改都会在health_report_log表中写入一条记录,记录修改前和修改后的值。虽然这个设计会增加开发量,但论文里写出来是非常加分的,因为它体现了需求细节的考量。
另外,凡是涉及体温超37.3℃、接触过疑似人员、中高风险地区旅居史四项中任何一项异常,后端会自动把这条记录标记为异常,并在管理端异常列表中显示红色高亮。这个自动判定不需要机器学习,用规则引擎就足够了,但你需要把判定规则写成配置,而不是写死在代码里,这样后期调整阈值(比如从37.3改成37.5)时不用重新发版。
3.3 通知公告与信息发布
这个模块相对简单,就是一个标准的内容管理系统。管理端支持富文本编辑、分类选择、置顶操作,用户端按发布时间倒序展示。我额外做了一个“公告阅读记录”功能:公告详情页加载时,前端调一个接口记录当前用户和公告的浏览关系。这样辅导员在后台就能看到每一条通知有哪些学生没读,配合一键提醒功能,非常实用。
考勤类通知和日常通知的处理逻辑其实可以区分开,比如紧急的防控通知需要弹窗强制提醒,一般的可以只在列表中显示通知图标。这个功能我演示的时候评委老师专门问了一下,认为需求把握得很细。
3.4 数据统计与可视化看板
统计看板是辅导员和校级管理员最看重的功能。前端用ECharts绘制图表,包含全校每日填报率折线图、各学院填报率柱状图、异常状况类型饼图。后端接口负责按时段、学院、班级分组聚合,返回结构化的图表数据。
这里有一个非常关键的设计点:统计数据不要每次打开页面都实时从明细表里汇总。因为随着系统使用时间增长,health_report表会积累大量数据,每次都跑GROUP BY虽然数据量不大时没问题,但作为毕设还是应该写出一点优化意识。我的做法是:建了一张report_daily_summary统计汇总表,每天由定时任务把前一天各学院、各班的填报总量、异常量计算好写入汇总表,图表接口直接读汇总表。这样实时接口的响应时间从几百毫秒降到了几十毫秒,论文里也能写“引入了轻量级的数据仓库思想”,虽然是过度包装,但思路是合理的。
4. 开发实操与关键代码解读
4.1 从零到一搭建开发环境
环境搭建有几个要注意的版本匹配问题。Spring Boot我用的是2.3.4,JDK用的1.8,MySQL 5.7,Vue CLI 4.5,这些版本是我实测过不用改配置就能直接跑的。不要一上来就装最新的Spring Boot 3.x配JDK 17,因为MyBatis Plus等配套框架可能还没有跟上,到处报错会让你怀疑人生。毕设项目选稳定版本即可,没必要追求最新。
前端创建项目用vue create命令,勾选Router、Vuex、Axios,然后执行npm install element-ui。后端用IDEA新建Spring Initializr项目,勾选Web、MySQL、MyBatis Plus依赖。这两个部分骨架搭好后,先打通一个最简单的test接口,确保前后端联调环境正常,再开始写业务模块。很多同学一上来就开始写业务代码,遇到环境问题夹在业务代码里排查,效率非常低。
4.2 后端接口设计与代码实现
接口风格我统一采用RESTful风格,返回结构统一为{code, message, data}。成功的code为200,业务错误用自定义code区分,前端根据code做统一提示。这个封装看起来不起眼,但是写前端的时候你会感激这个决定,因为大部分交互只需要判断code和读取data,不需要为每个接口单独写异常处理。
健康上报接口是核心,粘贴一下关键代码供参考:
java复制@PostMapping("/submit")
public ResultVO submit(@RequestBody HealthReportVO vo, HttpServletRequest request) {
User currentUser = getCurrentUser(request);
// 校验上报日期是否合法
if (!isValidReportDate(vo.getReportDate())) {
return ResultVO.error(400, "上报日期不在允许范围内");
}
// 查重:当天是否已上报
LocalDate today = LocalDate.now();
LambdaQueryWrapper<HealthReport> queryWrapper = Wrappers.lambdaQuery();
queryWrapper.eq(HealthReport::getUserId, currentUser.getId())
.eq(HealthReport::getReportDate, today);
HealthReport existing = healthReportMapper.selectOne(queryWrapper);
if (existing != null) {
// 记录修改日志
healthReportLogMapper.insert(buildLog(existing, vo));
// 更新原记录
BeanUtils.copyProperties(vo, existing);
existing.setUpdateTime(new Date());
healthReportMapper.updateById(existing);
} else {
HealthReport report = new HealthReport();
BeanUtils.copyProperties(vo, report);
report.setUserId(currentUser.getId());
report.setCreateTime(new Date());
healthReportMapper.insert(report);
}
return ResultVO.success();
}
这段代码的逻辑是:先通过当前登录用户拿到user_id,再判断是新增还是修改。这里需要你额外处理的事务点是,修改场景下需要同时写log表和更新主表,所以要在方法上加@Transactional注解,保证两个操作要么一起成功要么一起失败。这是答辩时老师爱问的知识点。
管理端的数据统计接口我用了MyBatis Plus的QueryWrapper做分组查询,分组条件拼接了时间过滤和学院过滤。需要注意的一个坑是:多表联查字段的别名在ServiceImpl里可能对不上,建议先写SQL在Navicat里测试通过后再映射到Mapper。后期数据量就上来了,如果不注意别名问题,联表查询出来的字段会全部堆在Map里,类型转换还容易出错。
4.3 前端页面实现与交互细节
前端页面的核心是几个列表页和表单页,这里主要说一下交互层面的细节。常用的页面有:登录页、学生填报页、学生通知列表页、辅导员工作台、管理员数据看板。每个页面我都遵循了同一个设计规范:页面加载时先检查token失效状态,token过期自动跳转登录页并弹出提示。
健康上报页要做得极简,不要放复杂表格,下拉框+单选+一个提交按钮就够了。为了让学生在这里少停留,我把“今日是否已上报”做成一个明显的卡片状态,同时把上次填报时间放在显眼位置。这些细节虽然代码量不大,但写论文的时候有具体的场景描述可写,课程实践型论文最喜欢这种细节。
还有个交互体验的通用技巧:所有表格数据都采用分页加载,不要一次性把上万条记录都渲染出来。前端用Element UI的Pagination组件,后端分页参数传pageNum和pageSize。很多同学在这一步不以为然,等到实测时的数据量到了一万条左右,页面直接卡死,再去优化就是舍近求远。
4.4 毕业论文撰写与PPT制作经验
论文结构我是按标准软件工程模板走的:绪论、相关技术介绍、需求分析、系统设计、系统实现、系统测试、总结与展望。这里要提醒的是,论文的核心创新点不要写高大上的空话,而是落地到“这个系统里哪一个具体的问题你是怎么处理的”。我写的是“基于规则引擎的异常自动判定机制”和“基于用户行为的通知触达闭环”,标题一看就很具体。
PPT控制在15到20页,逻辑线是:研究背景→需求分析→系统架构→功能演示(放截图)→核心模块讲解→测试结果→总结。演示视频最好用录屏软件先录一遍全过程操作,再剪辑到8分钟以内。视频里要覆盖三种角色的完整操作流程,配合语音解说。这里有个经验:录屏时把鼠标指针设置为可见并放大,观众才能看清楚你在操作什么。视频导出选1080p、H.264编码,答辩老师的老电脑也能流畅播放,千万不要用4K超高码率格式,现场播放会卡成PPT循环。
5. 常见问题排查避坑记录
5.1 并发与重复提交问题
系统上线测试时最典型的问题是上午8点全校同时上报时,高峰期数据库连接池被打满,部分学生提交时提示“系统繁忙”。排查后发现是默认的HikariCP连接池最大连接数配置成10,而我们同时在线填报超过500人时就会触发等待。解决方案是把最大连接数调到了100,同时在接口上加了读操作走从库、写操作走主库的设计(实际开发时是直接光改参数)。另外一个隐藏的问题是前端没有做按钮防抖或Loading锁定,导致双击提交按钮就会产生两条重复请求。前端在提交方法里加一个isSubmitting标志位,请求未返回前阻止再次点击。
5.2 数据统计口径不一致
管理后台连续两次导出同一时间段的数据,偶尔出现数据不一致。这个问题的根源在于:我一开始统计的时候实时查上报明细表,而管理端的首页看板读的是每天的汇总表,两者算出来的结果天然会差异。后来我把所有统计口径都改成汇总表,并定时任务每小时刷一次当日数据,保证各处展示的数据一致。这个坑非常隐蔽,建议数据统计类功能在设计阶段就要定好统一的数据口径。
5.3 跨域与会话保持问题
开发时前端跑在8080,后端跑在9090,跨越请求必须处理好。一开始我尝试在后端加CorsFilter开放所有请求,但设置了allowCredentials后和allowedOrigins偏严格会冲突,总是报跨域错误。后来改用前端vue.config.js里的devServer代理,把请求由前端服务器转发到后端,既解决了跨域又保持了Cookie的一致性。生产部署用Nginx反向代理,同样避免了跨域问题。
5.4 打包部署与演示环节的细节坑
打jar包之前一定要确认application.yml里的数据库连接配置是生产环境的,不然拿去部署才发现连的是本地库,那就是社死现场。部署的时候我遇到一个印象很深的坑:MySQL的时区偏移导致代码里用LocalDate.now()取到的日期跟服务器日期不一致,上报日期总是显示为前一天。这个坑是因为MySQL连接字符串里没加serverTimezone=Asia/Shanghai,加上就正常了,排查过程倒是很简单,但测试阶段确实会对用户造成困扰。
演示环节还有个小建议:准备一台演示专用电脑,把环境和项目提前全部跑通,关闭无关软件和更新弹窗,浏览器只打开需要的标签页。不要拿自己日常用的电脑临时演示,因为答辩现场出幺蛾子的概率非常高,关掉通知、断开无关外设,能少折腾就少折腾。
做这个项目前后差不多花了四个多月,最深的体会是毕业设计最大的价值不在于把代码写完,而是逼着你把一个模糊的问题从需求到部署完整走了一遍。很多细节在没上手之前会觉得“这不就是个网站吗”,真正做下来才发现,哪怕是“每日上报一次”这么简单的业务规则,在数据库设计、接口防重、前端交互、统计口径四个层面都要分别落实。这个思路如果掌握了,后面去公司做业务系统开发时上手会快很多。最后再分享一个小技巧:论文里的每张截图、每个表格背后都要有对应的一张真实数据或一段可执行的代码,不能为了凑内容造数据,否则答辩时老师问到细节你很容易露馅。就写到这,希望对要选这个题目或者类似题目的同学有点帮助。
