news 2026/4/3 10:35:03

毕业设计实战:基于SpringBoot的入校申报审批系统,从需求到部署避坑全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
毕业设计实战:基于SpringBoot的入校申报审批系统,从需求到部署避坑全指南

毕业设计实战:基于SpringBoot的入校申报审批系统,从需求到部署避坑全指南

当初做入校申报审批系统时,我在“健康码、行程码双码上传校验”功能上卡了整整三天——一开始没做文件格式和大小限制,结果用户传了个100MB的视频文件,服务器直接崩了,导师看了直摇头😫 后来踩了无数坑,终于总结出这套完整开发流程。今天就把入校申报审批系统的实战经验全部分享出来,宝子们跟着做,毕设稳过!

一、需求分析别想当然!先搞懂“谁申请,谁审批”

最开始我以为做个简单的表单提交就行了,结果导师说“要考虑疫情常态化管理,要有健康检查流程”。后来才明白,入校申报系统的核心是“用户申报-管理员审批-门卫核验”的三级流程,必须抓住这三个环节的核心需求。

1. 核心用户 & 核心功能(踩坑后总结版)

入校申报审批系统有三类核心用户:普通用户(申报人)、管理员(审批人)、门卫(核验人)。千万别把“辅导员”、“院系领导”都加进去!我当初加了,审批流程变得极其复杂,最后简化成三级才顺畅。

  • 用户端(申报人,必须做的功能):

    • 个人信息管理:维护姓名、身份证号、联系方式、头像等基本信息。
    • 入校申报:这是核心中的核心
      • 填写入校时间、出校时间、入校事由。
      • 选择人员身份(学生、教职工、访客等)。
      • 提交后生成唯一的申报编号。
    • 申报记录查询:查看所有申报记录及审批状态。
    • 公告查看:浏览学校最新防疫政策和通知。
  • 管理员端(审批人,核心功能):

    • 申报审批
      • 查看待审批的入校申报列表。
      • 审核申报信息,可“通过”或“驳回”。
      • 驳回必须填写理由(这个很重要!)。
    • 用户管理:管理所有用户账号,可冻结异常账号。
    • 入校检查记录管理:查看所有入校检查记录。
    • 公告管理:发布、编辑、删除防疫公告。
  • 门卫端(核验人,简化但必要):

    • 入校检查登记
      • 扫描申报编号或输入身份证号查询申报信息。
      • 登记体温、上传健康码和行程码截图。
      • 记录是否去过风险地区。
    • 今日入校统计:查看当天已入校人员列表。

2. 需求分析避坑指南(血泪教训!)

  • 别空想流程,要画出来!用流程图工具画出完整的“申报-审批-入校检查”流程。我当初画出来后才发现,少了“驳回后用户重新提交”的环节,赶紧补上。
  • 一定要考虑异常情况
    • 用户填的出校时间比入校时间还早怎么办?(前端要做时间校验)
    • 健康码截图上传了假图怎么办?(虽然不能100%防伪,但可以做文件MD5校验)
    • 审批人长时间不审批怎么办?(可以加个“催办”功能,或者自动提醒)
  • 写清楚约束条件
    • “入校时间必须至少提前2小时申报”
    • “健康码必须为24小时内”
    • “体温超过37.3℃自动标记为异常”
    • “同一用户同一天只能申报一次入校”

3. 可行性分析(三句话说清楚)

  • 技术可行性:SpringBoot + MySQL + Vue,都是成熟技术。健康码识别可以用简单的颜色判断(绿码/黄码/红码),不需要复杂的AI识别。
  • 经济可行性:所有工具免费,部署到学校服务器或学生云服务器(学生优惠)成本极低。
  • 操作可行性:用户扫码就能申报,门卫用手机或平板就能核验,操作简单。

二、技术选型:SpringBoot是真香!

当初我看别人用传统的SSM,配置一堆XML文件。后来选择了SpringBoot 2.7 + MyBatis-Plus + Vue 2 + Element UI,开发效率提升了不止一倍!

技术栈详解与避坑

技术选择理由避坑提醒
SpringBoot 2.7.x自动配置,内嵌Tomcat,快速启动。别用3.x,部分依赖还没适配好。
MyBatis-Plus强大的CRUD操作,代码生成器好用。好好用它的LambdaQueryWrapper,写查询条件超方便。
Vue 2 + Element UI组件丰富,做管理后台界面很快。Vue 2够用了,别追求Vue 3增加学习成本。
MySQL 8.0JSON字段支持,存健康码路径方便。一定用utf8mb4字符集,否则Emoji表情会乱码。
Redis(可选)缓存申报编号,提高查询速度。如果数据量不大,可以不用,简化部署。

开发环境一步到位

# 1. 用Spring Initializr创建项目# 勾选:Web、MyBatis、MySQL、Redis(可选)# 2. 配置application.ymlspring: datasource: url: jdbc:mysql://localhost:3306/ruxiao_system?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 username: root password:123456driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB# 限制上传文件大小max-request-size: 10MB# 3. 集成MyBatis-Plusmybatis-plus: mapper-locations: classpath:mapper/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

三、数据库设计:状态流转是关键!

我当初的坑:把审批状态和检查状态混在一个表里,结果逻辑混乱。后来分成了入校申报表(管审批)和入校检查表(管核验),清晰多了。

核心表结构设计(重点!)

-- 入校申报表(核心表)CREATETABLE`ruxiaoshenbao`(`id`intNOTNULLAUTO_INCREMENT,`ruxiaoshenbao_uuid_number`varchar(50)NOTNULLCOMMENT'申报编号:RX+年月日+6位随机数',`yonghu_id`intNOTNULLCOMMENT'申报用户',`zhuanye_types`intDEFAULT1COMMENT'人员身份:1学生,2教职工,3访客',`shiyou`textCOMMENT'入校事由',`ruxiaoshenbao_time`datetimeNOTNULLCOMMENT'计划入校时间',`cuxiao_time`datetimeCOMMENT'计划出校时间',`ruxiaoshenbao_yesno_types`intDEFAULT1COMMENT'审批状态:1待审批,2通过,3驳回',`ruxiaoshenbao_yesno_text`textCOMMENT'审批意见',`create_time`datetimeDEFAULTCURRENT_TIMESTAMP,PRIMARYKEY(`id`),UNIQUEKEY`uk_uuid`(`ruxiaoshenbao_uuid_number`),KEY`idx_user`(`yonghu_id`),KEY`idx_time`(`ruxiaoshenbao_time`)-- 按时间查询加索引)ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT='入校申报表';-- 入校检查表(核验记录)CREATETABLE`ruxiaojiancha`(`id`intNOTNULLAUTO_INCREMENT,`ruxiaoshenbao_id`intNOTNULLCOMMENT'关联的申报记录',`tiwen`decimal(3,1)COMMENT'体温',`ruxiaojiancha_photo`varchar(500)COMMENT'健康码图片路径',`xingcheng_photo`varchar(500)COMMENT'行程码图片路径',`jiancha_result`intDEFAULT1COMMENT'检查结果:1正常,2异常',`ruxiaojiancha_content`textCOMMENT'检查详情',`create_time`datetimeDEFAULTCURRENT_TIMESTAMPCOMMENT'检查时间',PRIMARYKEY(`id`),KEY`fk_shenbao`(`ruxiaoshenbao_id`),CONSTRAINT`fk_shenbao`FOREIGNKEY(`ruxiaoshenbao_id`)REFERENCES`ruxiaoshenbao`(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT='入校检查表';-- 用户表CREATETABLE`yonghu`(`id`intNOTNULLAUTO_INCREMENT,`yonghu_name`varchar(100)NOTNULLCOMMENT'姓名',`yonghu_phone`varchar(20)NOTNULLCOMMENT'手机号',`yonghu_id_number`varchar(18)NOTNULLCOMMENT'身份证号',`xueyuan`varchar(100)COMMENT'学院/部门',`banji`varchar(50)COMMENT'班级',`yonghu_delete`intDEFAULT0COMMENT'0正常,1已删除',PRIMARYKEY(`id`),UNIQUEKEY`uk_phone`(`yonghu_phone`),UNIQUEKEY`uk_idcard`(`yonghu_id_number`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT='用户表';

设计亮点

  1. 申报编号生成规则RX20240520001234(RX+年月日+6位随机数),唯一且有意义。
  2. 状态分离:审批状态在申报表,检查结果在检查表,逻辑清晰。
  3. 索引优化:给常用的查询字段加索引,提高查询速度。

四、功能实现:抓住核心流程,做出亮点

1. 用户端:入校申报(核心体验)

关键逻辑:时间校验、重复申报校验、生成唯一编号。

前端实现要点(Vue + Element UI)

<template> <div class="shenbao-form"> <el-form :model="form" :rules="rules" ref="formRef"> <el-form-item label="计划入校时间" prop="ruxiaoshenbao_time"> <el-date-picker v-model="form.ruxiaoshenbao_time" type="datetime" :picker-options="timeOptions" placeholder="选择入校时间" /> <div class="tip">需至少提前2小时申报</div> </el-form-item> <el-form-item label="人员身份" prop="zhuanye_types"> <el-select v-model="form.zhuanye_types" placeholder="请选择"> <el-option label="学生" :value="1"></el-option> <el-option label="教职工" :value="2"></el-option> <el-option label="访客" :value="3"></el-option> </el-select> </el-form-item> <el-form-item label="入校事由" prop="shiyou"> <el-input type="textarea" v-model="form.shiyou" :rows="4" placeholder="请详细说明入校事由" maxlength="500" show-word-limit /> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm" :loading="submitting"> 提交申报 </el-button> </el-form-item> </el-form> </div> </template> <script> export default { data() { // 时间校验:只能选择未来时间,且至少提前2小时 const validateTime = (rule, value, callback) => { if (!value) { callback(new Error('请选择入校时间')); } const now = new Date(); const twoHoursLater = new Date(now.getTime() + 2 * 60 * 60 * 1000); if (value < twoHoursLater) { callback(new Error('入校时间需至少提前2小时')); } callback(); }; return { form: { ruxiaoshenbao_time: '', zhuanye_types: '', shiyou: '' }, rules: { ruxiaoshenbao_time: [ { required: true, validator: validateTime, trigger: 'change' } ], zhuanye_types: [ { required: true, message: '请选择人员身份', trigger: 'change' } ], shiyou: [ { required: true, message: '请输入入校事由', trigger: 'blur' }, { min: 10, message: '事由描述至少10个字', trigger: 'blur' } ] }, timeOptions: { disabledDate(time) { // 不能选择今天之前的日期 return time.getTime() < Date.now() - 24 * 60 * 60 * 1000; } }, submitting: false }; }, methods: { async submitForm() { try { await this.$refs.formRef.validate(); this.submitting = true; // 检查今天是否已申报过 const hasToday = await this.checkTodayApplication(); if (hasToday) { this.$message.warning('您今天已提交过入校申报,请勿重复提交'); return; } // 提交申报 const res = await this.$api.shenbao.submit(this.form); this.$message.success(`申报成功!您的申报编号:${res.data.uuidNumber}`); this.$router.push('/my-applications'); } catch (error) { console.error('提交失败:', error); } finally { this.submitting = false; } }, async checkTodayApplication() { const today = new Date().toISOString().split('T')[0]; const res = await this.$api.shenbao.checkToday({ date: today }); return res.data.hasApplication; } } }; </script>

后端关键代码(SpringBoot)

@ServicepublicclassRuxiaoshenbaoServiceImplimplementsRuxiaoshenbaoService{@AutowiredprivateRuxiaoshenbaoMapperruxiaoshenbaoMapper;@Transactional@OverridepublicResultsubmitShenbao(RuxiaoshenbaoFormform,IntegeruserId){// 1. 检查今天是否已申报LocalDatetoday=LocalDate.now();LambdaQueryWrapper<Ruxiaoshenbao>wrapper=newLambdaQueryWrapper<>();wrapper.eq(Ruxiaoshenbao::getYonghuId,userId).ge(Ruxiaoshenbao::getCreateTime,today.atStartOfDay()).lt(Ruxiaoshenbao::getCreateTime,today.plusDays(1).atStartOfDay());longcount=this.count(wrapper);if(count>0){returnResult.error("您今天已提交过入校申报");}// 2. 生成唯一编号StringuuidNumber=generateUuidNumber();// 3. 保存申报记录Ruxiaoshenbaoentity=newRuxiaoshenbao();BeanUtils.copyProperties(form,entity);entity.setYonghuId(userId);entity.setRuxiaoshenbaoUuidNumber(uuidNumber);entity.setRuxiaoshenbaoYesnoTypes(1);// 待审批this.save(entity);// 4. 记录操作日志(可选)logService.addLog(userId,"提交入校申报","编号:"+uuidNumber);returnResult.success("申报提交成功",uuidNumber);}privateStringgenerateUuidNumber(){// RX + 年月日 + 6位随机数StringdateStr=LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));StringrandomStr=String.format("%06d",newRandom().nextInt(999999));return"RX"+dateStr+randomStr;}}

2. 管理员端:申报审批(核心业务)

关键逻辑:批量审批、驳回必须填理由、审批记录可追溯。

审批页面设计要点

  • 待审批列表:表格显示所有待审批记录,可多选批量审批。
  • 审批操作弹窗
    • 显示申报详情(用户信息、入校时间、事由)。
    • 单选框:“通过”或“驳回”。
    • 文本域:“审批意见”(驳回时必须填写)。
    • “提交审批”按钮。
  • 审批历史:可查看每条申报的审批记录。

批量审批后端代码

@PostMapping("/batchApprove")@ResponseBody@TransactionalpublicResultbatchApprove(@RequestBodyBatchApproveRequestrequest){// request包含:申报ID列表、审批结果、审批意见if(CollectionUtils.isEmpty(request.getShenbaoIds())){returnResult.error("请选择要审批的申报");}if(request.getResult()==3&&StringUtils.isBlank(request.getReason())){returnResult.error("驳回必须填写理由");}List<Ruxiaoshenbao>updateList=newArrayList<>();for(IntegershenbaoId:request.getShenbaoIds()){Ruxiaoshenbaoshenbao=ruxiaoshenbaoService.getById(shenbaoId);if(shenbao!=null&&shenbao.getRuxiaoshenbaoYesnoTypes()==1){shenbao.setRuxiaoshenbaoYesnoTypes(request.getResult());shenbao.setRuxiaoshenbaoYesnoText(request.getReason());updateList.add(shenbao);// 发送审批结果通知(微信/短信)noticeService.sendApproveResult(shenbao.getYonghuId(),request.getResult());}}if(!updateList.isEmpty()){ruxiaoshenbaoService.updateBatchById(updateList);}returnResult.success("批量审批完成");}

3. 门卫端:入校检查(移动端友好)

关键逻辑:扫码核验、双码上传、体温异常预警。

移动端核验页面

<!-- 简洁的核验页面,适合手机/PAD操作 --><divclass="check-page"><divclass="scan-section"><button@click="startScan">扫码核验</button><divclass="or"></div><inputv-model="searchText"placeholder="输入申报编号/身份证号"><button@click="search">查询</button></div><divv-if="shenbaoInfo"class="info-section"><h3>{{ shenbaoInfo.yonghuName }}</h3><p>申报编号:{{ shenbaoInfo.uuidNumber }}</p><p>计划入校:{{ shenbaoInfo.planTime }}</p><divclass="check-form"><inputtype="number"v-model="tiwen"placeholder="测量体温(℃)"step="0.1"><divclass="upload-section"><label>健康码:</label><inputtype="file"accept="image/*"@change="uploadHealthCode"><imgv-if="healthCodeUrl":src="healthCodeUrl"class="preview"></div><divclass="upload-section"><label>行程码:</label><inputtype="file"accept="image/*"@change="uploadTravelCode"><imgv-if="travelCodeUrl":src="travelCodeUrl"class="preview"></div><button@click="submitCheck":disabled="!canSubmit">完成核验</button></div></div></div>




五、系统测试:重点测这些场景

核心测试用例

测试场景测试步骤预期结果重要性
重复申报同一用户同一天提交两次申报第二次提示“今天已申报过”
时间校验选择1小时后入校的时间提示“需至少提前2小时”
双码上传上传非图片文件(如PDF)提示“请上传图片文件”
体温异常输入体温37.5℃自动标记为“异常”,需要额外确认
批量审批选择多条记录,批量通过所有选中记录状态更新为“通过”
扫码核验用已过期的申报编号扫码提示“申报已过期”

压力测试(简单做)

用JMeter模拟50个用户同时提交申报,看系统响应时间。目标:95%的请求在2秒内响应。

六、部署与上线

1. 服务器准备

  • 学生优惠:阿里云/腾讯云学生服务器,¥10/月。
  • 配置:1核2G,CentOS 7.6。
  • 必备软件:JDK 1.8、MySQL 8.0、Nginx(反向代理)。

2. 一键部署脚本

#!/bin/bash# deploy.shecho"开始部署入校申报系统..."# 1. 备份旧版本if[-d"/app/ruxiao"];thenmv/app/ruxiao /app/ruxiao_backup_$(date+%Y%m%d)fi# 2. 创建新目录mkdir-p /app/ruxiaocptarget/ruxiao-system.jar /app/ruxiao/# 3. 复制配置文件cpapplication-prod.yml /app/ruxiao/# 4. 启动应用cd/app/ruxiaonohupjava -jar ruxiao-system.jar --spring.profiles.active=prod>app.log2>&1&echo"部署完成!"

3. Nginx配置

server { listen 80; server_name ruxiao.yourschool.edu.cn; location / { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # 静态文件缓存 location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { expires 30d; add_header Cache-Control "public, immutable"; } }

七、答辩准备:讲好这个故事

  1. 演示流程要完整
    “大家好,我演示一个完整的入校申报流程。首先,学生张三登录系统(展示),填写明天上午9点入校的申请,事由是‘实验室做实验’(展示表单校验)。提交后生成申报编号。接着,管理员李老师登录,在待审批列表看到这条申请(展示),审核后通过。最后,门卫王师傅用平板电脑扫描张三的申报二维码(展示移动端页面),登记体温36.5℃,上传双码,完成入校核验。”

  2. 重点讲“你的设计亮点”

    • “我设计了‘申报编号’规则,方便门卫快速核验。”
    • “做了严格的时间校验,必须提前2小时申报,避免临时申请。”
    • “双码上传做了文件类型和大小限制,防止恶意上传。”
    • “体温异常自动预警,需要门卫额外确认。”
  3. 准备好问答

    • Q:如果用户造假怎么办?A:系统不能100%防止造假,但我们可以记录所有操作日志,事后可追溯。另外可以和学校统一身份认证系统对接,提高可信度。
    • Q:数据量大怎么办?A:申报记录可以按月份分表存储,历史数据可以归档。查询时通过索引优化。
    • Q:系统安全性如何?A:所有密码MD5加密存储,接口有防重复提交和SQL注入防护,文件上传做了安全限制。

最后:一点真心话

入校申报系统看起来简单,但要把疫情管理的严谨性和用户体验的便捷性平衡好,需要很多细节考虑。关键是把“申报-审批-核验”这个核心流程做顺畅,把异常情况考虑周全。

需要完整源码数据库脚本部署文档的宝子,可以在评论区留言。

觉得这篇干货有帮助,记得点赞收藏!祝大家毕设顺利,轻松毕业!🎓

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/26 20:44:37

毕业设计实战:基于SpringBoot+MySQL的校园疫情防控系统设计与实现,从需求到测试全流程避坑指南!

毕业设计实战&#xff1a;基于SpringBootMySQL的校园疫情防控系统设计与实现&#xff0c;从需求到测试全流程避坑指南&#xff01; 谁懂啊&#xff01;当初做校园疫情防控系统毕设时&#xff0c;光“健康表”和“学生表”的外键关联就卡了2天——一开始没给健康表设“学生id”外…

作者头像 李华
网站建设 2026/3/31 12:43:12

毕业设计实战:SpringBoot教学资料管理系统,从0到1完整开发指南

毕业设计实战&#xff1a;SpringBoot教学资料管理系统&#xff0c;从0到1完整开发指南 当初做教学资料管理系统时&#xff0c;我在“多格式文件上传与在线预览”功能上卡了整整一周——一开始只支持PDF&#xff0c;结果老师传了个Word课件&#xff0c;学生打不开&#xff0c;导…

作者头像 李华
网站建设 2026/3/29 9:21:25

comsol三维微波等离子体放电模型,电子密度分布和空间电场分布,石英管内通氩气放电仿真

comsol三维微波等离子体放电模型&#xff0c;电子密度分布和空间电场分布&#xff0c;石英管内通氩气放电仿真氩气在石英管里被微波场电离的瞬间&#xff0c;总让我想起实验室里那台老式微波炉——不过这次玩的可不是加热剩饭。在COMSOL里搭建三维等离子体放电模型时&#xff0…

作者头像 李华
网站建设 2026/4/2 10:09:50

AI原生智算云:不止是算力池,更是智能时代的“数字基建引擎”——让每个企业都能“开箱即用”AI生产力

我们正身处一个由大型语言模型&#xff08;LLM&#xff09;和生成式AI引爆的智能奇点。从ChatGPT的惊艳问世到Sora的颠覆想象&#xff0c;AI不再是实验室里的遥远概念&#xff0c;而是正以前所未有的速度渗透到千行百业的毛细血管中。然而&#xff0c;在这场波澜壮阔的智能化浪…

作者头像 李华
网站建设 2026/3/25 22:53:59

SSH连接深度解析:从握手失败到安全加固的完整指南

引言&#xff1a;当现代SSH遇见传统系统 “Unable to negotiate with 10.xxx.xxx.xxx port 22: no matching host key type found. Their offer: ecdsa-sha2-nistp256” - 这个错误信息是否让你感到熟悉&#xff1f;在OpenSSH版本不断演进、安全标准日益严格的今天&#xff0c;…

作者头像 李华