
1. 这个题目为什么经典班级事务系统的业务边界与角色需求每年到毕业设计选题的时候“SpringBoot 高校 班级事务管理”这类题目都会出现。我第一次看到“河北水利电力学院班级事务管理系统”这个课题时第一反应是这不就是一个带增删改查的学生管理系统吗但真正把需求拆开之后才发现班级事务管理和传统意义上的“学生管理系统”完全是两码事。学生管理系统管的是人员档案、学籍状态是学校视角。而班级事务管理系统管的是班级内部每天都会发生的琐碎事情今天谁没上课、下周班级活动怎么报名、班费还剩多少、请假条批到哪一步、辅导员的通知有没有人看。它的服务对象是学生、班长、辅导员和院系管理员核心价值是“把班级里那些用 Excel、微信群、纸质登记表处理的事务变成一条条可查询、可统计、可追溯的记录”。这类项目非常适合做毕设有几个原因业务不复杂但也不是简单到只有一个登录技术点覆盖面广SpringBoot、MyBatis-Plus、MySQL、Vue、文件上传、权限拦截、报表统计都能用到演示效果也很直观因为每个功能都能对应到真实场景。如果要把角色需求列清楚基本是下面这张表角色关心的事情系统里对应的功能学生是否有新通知、请假是否通过、活动怎么报名、班费有没有记录通知查看、请假申请、活动报名、班费明细查询班长班级信息维护、发布通知、记录考勤、收班费、组织活动班级成员管理、考勤管理、班费管理、活动管理辅导员审批请假、查看班级考勤异常、发布院系通知、了解班费情况请假审批、考勤统计、通知管理、数据看板院系管理员管理班级、查看多个班级的对比数据、维护基础字典班级管理、用户管理、全院数据统计从这张表能看出来系统不是把“学生”当成一个实体去管理而是把“班级日常发生的事”当成业务主线。明白这一点后面的数据库设计、接口设计都不会跑偏。2. 技术栈选择的真实理由为什么SpringBoot Vue MySQL最稳毕设选型有一个很现实的原则不是选最流行的也不是选最新的而是选你自己能在三个月内完全讲清楚的。对于这类管理系统“SpringBoot Vue MySQL”是我认为最稳妥的组合。2.1 SpringBoot解决的核心问题SpringBoot 在这个项目里解决的不是业务复杂度而是“配置地狱”。传统 SSM 项目光配置 applicationContext.xml、spring-mvc.xml、mybatis-config.xml 就能劝退一大半人SpringBoot 通过自动装配把这些配置改成约定。比如你想连数据库只需要在 application.yml 里写数据源地址你想写接口一个 RestController 就搞定。这种“低配置 快速启动”的特性正好适合课程设计、毕业设计这种开发时间有限的场景。选择 SpringBoot 版本时要注意 JDK 环境。如果你本机是 JDK 8建议用 SpringBoot 2.7.x如果是 JDK 17可以用 SpringBoot 3.x。很多同学在网上找教程结果 3.x 的项目在 JDK 8 环境下一启动就报错其实就是版本和 JDK 不匹配。2.2 数据访问层MyBatis-Plus 比 MyBatis 更合适传统 MyBatis 每写一个查询都要配 XML、写 resultMap开发效率低。MyBatis-Plus 在保留 MyBatis 能力的同时提供了 BaseMapper像 selectById、selectPage、lambdaQuery 这些操作根本不需要写 SQL。班级事务系统里有大量“按班级查成员”“按学生查请假记录”“按时间查考勤”的简单查询用内置方法就能完成。但要注意MyBatis-Plus 不是万能的。报表统计里的“每个班本周旷课人数”“班费按月支出对比”这类带聚合函数和连表查询的需求还是需要手写 SQL。所以项目里我的建议是简单 CRUD 用 MyBatis-Plus复杂统计用 Select 注解方法很清晰答辩也讲得明白。2.3 前端为什么选 Vue Element UI后台管理系统的界面要求不高重点是表格、表单、弹窗、侧边栏这些组件。Vue 的响应式数据和组件化开发非常适合Element UI 又是现成的后台组件库一个 el-table 绑定数据就能出列表一个 el-form 加 rules 就能做校验。如果你不想自己画界面甚至可以找一个开源的 Vue 后台模板比如 vue-element-admin 的简化版改改路由和页面就行。前端项目建议做成前后端分离单独跑在 8080 端口后端跑在 8081 端口。这样部署和答辩演示时逻辑清楚一种是因为前端利用 Nginx 托管 dist 目录后端打成 jar 包整体就是“静态页面 API 服务”的结构非常符合现在企业开发的习惯。3. 数据库设计把“班级事务”翻译成数据表数据库设计是这类系统最见功底的地方。很多人的表设计是“用户表 班级表 随便几个业务表”结果写着写着发现通知发给了谁查不到、考勤补签没有记录、班费支出对不上账。我这里直接给一套我在类似项目里实际验证过的表结构思路。3.1 基础信息表用户、院系、专业、班级用户表不要只存字段还要考虑角色查询。我的建议是一张 sys_user 表包含 user_id、username、password、real_name、role、student_no、phone、email、class_id、college_id、major_id、status 等字段。password 必须存加密后的密文推荐使用 BCrypt。role 可以用字符串或者数字比如 0 管理员、1 辅导员、2 班长、3 学生不要动辄设计五六张权限表。班级表 class_info 的核心字段是 class_id、class_name、grade、college_id、major_id、head_teacher、counselor_id、monitor_id。这里 monitor_id 指向 sys_user 表用来标识班长。表面上这只是一个普通字段但它能让你在写“班长操作自己班级事务”的接口时不需要额外查角色表。院系、专业这两张表可以合并到基础字典但作为独立表更直观也方便做下拉筛选。3.2 业务表通知、考勤、请假、班费、活动业务表是系统的重头戏逐一说一下。通知表 noticenotice_id、title、content、type、publisher_id、class_id、attachment_url、create_time。如果是面向全院的公告class_id 为空如果是班级通知class_id 指定某个班。还可以加一个 notice_read 关联表记录“谁看了这条通知”这样辅导员能知道通知到底有没有传到人。考勤表 attendance 和 attendance_item这是最容易设计错的地方。如果直接把每个学生的出勤状态作为一行存一次 40 人的考勤就要插 40 行而且每次查“某天某节课谁缺勤”都费劲。正确做法是分两层attendance 表记录一次考勤事件比如“2025年6月10日第3节课 计科2101班考勤”attendance_item 表记录每个学生的出勤结果状态分为正常、迟到、早退、请假、缺勤。请假表 leave_infostudent_id、leave_type、start_time、end_time、reason、attachment_url、status、approver_id、approve_time、comment。这里特别注意 start_time 和 end_time 要精确到节次否则学生请假“下午”这种模糊描述会导致考勤统计时无法判断到底算不算请假。班费表 class_feefee_id、class_id、fee_type收入/支出、amount、category、occur_date、operator_id、description。amount 用 DECIMAL(10,2)category 可以写成“班费收缴”“集体活动”“打印材料”这些字典值。班费这块最容易出问题的是没有余额字段其实余额不一定要存查询时用 SUM(CASE WHEN fee_type收入 THEN amount ELSE -amount END) 就能实时算出。活动表 activity 和 activity_signupactivity 表存活动标题、时间、地点、内容、负责人activity_signup 表存报名记录。如果还要记录活动是否实际参与可以在 signup 表里加 status 字段。3.3 索引和字段规范所有外键关联字段都建议加普通索引比如 class_id、student_id。时间字段统一用 datetime 类型Java 端用 LocalDateTime 接收。逻辑删除字段 deleted 建议每张表都预留MyBatis-Plus 的 TableLogic 可以自动实现。这样万一误删数据还能从数据库里恢复。4. 核心功能编码登录、考勤、班费、请假的一条龙实现数据库设计好之后业务编码其实就是把这些表串联起来。下面我挑几个核心功能把实现思路和关键代码讲清楚。4.1 登录认证与权限拦截班级事务管理系统不要求高并发也不涉及复杂的第三方认证所以不一定要引入 Spring Security。用“JWT 拦截器”足够而且代码更容易讲清楚。登录接口的大致逻辑是前端传 username 和 password后端从 sys_user 表查出用户用 BCrypt 校验密码通过后生成 token返回给前端。token 里可以只放 user_id、role、class_id过期时间设置为 24 小时。我用的是 jjwt 0.11.5生成 token 的代码大致如下String token Jwts.builder() .setSubject(user.getUserId().toString()) .claim(role, user.getRole()) .claim(classId, user.getClassId()) .setExpiration(new Date(System.currentTimeMillis() 86400000)) .signWith(Keys.hmacShaKeyFor(secret.getBytes()), SignatureAlgorithm.HS256) .compact();然后写一个拦截器继承 HandlerInterceptorAdapter在 preHandle 里从请求头 Authorization 里取 token解析成功就把 userId 放到请求域里解析失败直接返回 401。注册拦截器时注意排除登录接口和静态资源registry.addInterceptor(new AuthInterceptor()) .addPathPatterns(/api/**) .excludePathPatterns(/api/auth/login);权限控制不用做太复杂。在 Controller 方法上通过注解或者手动判断角色即可比如班长才能创建考勤if (!2.equals(currentUser.getRole())) { throw new BusinessException(只有班长可以执行此操作); }4.2 考勤一次事件 多条明细的写入考勤是体现事务控制的好例子。班长选择班级、日期、节次然后勾选正常/迟到/缺勤状态点击提交。后端要做两件事往 attendance 表插一条事件记录往 attendance_item 表批量插入每个学生的明细。这两步必须在一个事务里否则会出现“考勤事件创建了但学生明细缺失”的脏数据。用 MyBatis-Plus 的 saveBatch 可以一次性插入 List代码如下Transactional(rollbackFor Exception.class) public void submitAttendance(AttendanceAddDTO dto) { Attendance attendance new Attendance(); attendance.setClassId(dto.getClassId()); attendance.setAttendanceDate(dto.getAttendanceDate()); attendance.setSection(dto.getSection()); attendance.setOperatorId(dto.getOperatorId()); attendanceMapper.insert(attendance); ListAttendanceItem items dto.getItems().stream().map(item - { AttendanceItem ai new AttendanceItem(); ai.setAttendanceId(attendance.getAttendanceId()); ai.setStudentId(item.getStudentId()); ai.setStatus(item.getStatus()); return ai; }).collect(Collectors.toList()); attendanceItemService.saveBatch(items); }查询的时候如果要做“某学生一个月缺勤多少次”的话直接连表统计SELECT student_id, COUNT(*) AS absent_count FROM attendance_item WHERE status 缺勤 AND attendance_id IN ( SELECT attendance_id FROM attendance WHERE attendance_date BETWEEN #{start} AND #{end} ) GROUP BY student_id;4.3 班费每一笔进出都要能说清班费功能的核心不是增删改查而是“结余计算”。我的建议是不允许修改和删除只能红冲。所谓红冲就是如果记错了一笔支出不要删掉而是再记一笔负数支出或者做作废标记。这样流水账永远完整答辩时如果评委问“有人不小心录错了怎么办”你也能答得有理有据。班费列表页需要展示余额可以直接在 SQL 里算SELECT SUM(CASE WHEN fee_type 收入 THEN amount ELSE -amount END) AS balance FROM class_fee WHERE class_id #{classId} AND deleted 0;如果需要按月统计收支可以用 DATE_FORMAT(occur_date, %Y-%m) 分组后端返回给前端用 ECharts 画柱状图这个功能展示效果很好建议保留。4.4 请假审批流程清晰、状态可追溯学生提交请假申请辅导员审批。这个功能看起来简单但边界条件很多。比如请假开始时间不能晚于结束时间请假时间不能和已有请假时间冲突请假状态只能从“待审批”变为“通过/驳回”审批通过后需要附上审批人和审批时间。审批状态我建议用整数枚举0 待审批、1 通过、2 驳回。前端按钮根据状态控制显示如果已经是通过状态就不能再显示“通过”按钮。后端接口也要做校验不要只靠前端隐藏按钮因为接口是可以直接调用的。另外请假和考勤是关联的。考勤统计时如果某个学生当天在请假时间段内状态应该自动识别为“请假”而不是“缺勤”。这可以在考勤查询 SQL 里做子查询判断但如果做起来复杂也可以在生成考勤时手动勾选“请假”并关联请假单号。毕设阶段推荐后者逻辑简单答辩容易说明。4.5 通知公告已读未读是亮点通知功能如果想做出亮点就加已读未读。建一张 notice_read 表每次学生查看通知详情时插入一条记录。列表页给每条通知显示“已读人数/班级总人数”的进度条。这个需求实现成本很低效果却很好建议作为默认功能写进项目里。5. 我自己实测最容易翻车的5个地方这类系统代码本身不难但我在带项目和帮人排查问题的过程中发现翻车点非常集中。提前避开这些坑能帮你省下大量调试时间。5.1 跨域问题前端调不通接口的第一大原因前后端分离后前端请求 http://localhost:8081/api/... 会触发跨域。解决方式是在后端写一个 CorsFilter而不是前端代理。配置时注意如果允许携带 token 等认证信息allowedOrigins 不能写成 “*”必须指定具体地址比如 http://localhost:8080。5.2 时间字段格式化混乱很多同学用 java.util.Date接口返回给前端的时间格式是一串数字前端还要自己格式化。正确做法是实体类里用 LocalDateTimeSpringBoot 里配置spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8这样接口直接返回格式化好的字符串省去前端大量处理。5.3 文件上传大小限制如果在通知功能里支持上传图片、附件SpringBoot 默认只允许 1MB 文件。200KB 的限制改一下spring: servlet: multipart: max-file-size: 10MB max-request-size: 20MB上传的目录建议放在项目外部比如 D:/upload 或者 /data/upload不要放在 resources 里否则重新打包会丢失。访问图片时可以通过配置静态资源映射Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceLocations(file:D:/upload/); } }5.4 事务注解没生效像考勤这种需要同时操作两张表的接口一定要把 Transactional 加在 public 方法上并且是类通过 Spring 注入后调用才能生效。自己 new 出来的对象方法上加 Transactional 是无效的这是排查“为什么只插了一张表”时最容易踩的坑。5.5 数据库时间与服务器时间不一致部署到服务器后数据库连接字符串建议加上 serverTimezoneAsia/Shanghai否则 MySQL 和 Java 程序之间会出现 8 小时时差导致考勤日期和实际日期对不上。6. 交付与答辩部署包、论文结构和演示脚本最后一个环节也是很多同学最不重视但最影响最终成绩的环节交付和答辩。代码写完了只是第一步要让它顺利跑起来、能讲清楚还需要做几件事。6.1 把项目构建成可以直接运行的 jar 包SpringBoot 项目最终交付一定是一个可执行的 jar 包而不是在 IDEA 里点启动按钮。用 Maven 打包时如果用了外部依赖先执行 mvn clean再执行 mvn package。打包后 target 目录下会生成 xxx.jar运行命令java -jar class-affair-system.jar --server.port8081如果你是使用 Gradle 构建的项目也可以用 gradle bootJar 得到等价产物。答辩时只需要提前把 MySQL 数据导入、jar 包启动浏览器打开前端页面就能演示不容易出幺蛾子。6.2 论文结构建议论文不要按模块流水账写而应该按“问题—方案—实现—验证”的逻辑写。我建议的结构是绪论背景、意义、国内外现状、相关技术介绍、系统需求分析、系统设计总体架构、功能设计、数据库设计、系统实现核心代码和截图、系统测试功能测试用例和结果、总结。其中“系统设计”和“系统实现”至少占全文一半数据库设计部分要把表结构、E-R 图展示出来尽量画清楚实体之间的关系。6.3 演示脚本和答辩问题准备演示的时候不要一上来就登录管理员账号看一堆列表。按角色演示效果最好先用学生账号登录看到班级公告、报名活动、提交请假再切换到辅导员账号审批请假、查看考勤统计、看到通知已读情况最后用管理员账号查看全院班级数据对比。这就是一条完整的故事线评委看得懂你也有话讲。常见答辩问题也要提前准备为什么用 SpringBoot 而不是 SSM为什么不用 Spring Security班费余额怎么计算考勤数据如何避免重复提交通知已读未读是怎么实现的如果你的项目真的自己动手写过这几个问题都能答得上来。6.4 如果参考代码是一份 jar 包很多同学会从学长那里拿到一份打包好的 jar 包想通过反编译还原出项目。我不建议直接照搬反编译代码去改但可以用反编译工具看它的表结构和接口思路用来帮助你设计自己的数据库和接口。至于你自己的代码尽量一行一行写出来或者至少把核心逻辑完全看懂否则答辩一问就露馅。最后再分享一点我自己的体会做这类“班级事务管理”系统最容易失误的地方不是技术而是把需求做浅了。如果你只是把学生信息、班级信息做了增删改查那它就和一个普通管理系统没什么区别。真正能拿高分的项目一定是在请假审批、考勤统计、班费流水、通知触达这些“事”上面做出了细节。先花一天时间把班级里真实会发生的事务列清楚再去动手建表写代码你会发现后面开发顺畅得多。