news 2026/10/1 12:44:41

SpringBoot+Vue班级事务管理系统:考勤、班费、请假全流程设计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot+Vue班级事务管理系统:考勤、班费、请假全流程设计

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 业务表:通知、考勤、请假、班费、活动

业务表是系统的重头戏,逐一说一下。

通知表 notice:notice_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_info:student_id、leave_type、start_time、end_time、reason、attachment_url、status、approver_id、approve_time、comment。这里特别注意 start_time 和 end_time 要精确到节次,否则学生请假“下午”这种模糊描述会导致考勤统计时无法判断到底算不算请假。

班费表 class_fee:fee_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_signup:activity 表存活动标题、时间、地点、内容、负责人,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); List<AttendanceItem> 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,接口返回给前端的时间格式是一串数字,前端还要自己格式化。正确做法是实体类里用 LocalDateTime,SpringBoot 里配置:

spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8

这样接口直接返回格式化好的字符串,省去前端大量处理。

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 数据库时间与服务器时间不一致

部署到服务器后,数据库连接字符串建议加上 serverTimezone=Asia/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.port=8081

如果你是使用 Gradle 构建的项目,也可以用 gradle bootJar 得到等价产物。答辩时只需要提前把 MySQL 数据导入、jar 包启动,浏览器打开前端页面就能演示,不容易出幺蛾子。

6.2 论文结构建议

论文不要按模块流水账写,而应该按“问题—方案—实现—验证”的逻辑写。我建议的结构是:绪论(背景、意义、国内外现状)、相关技术介绍、系统需求分析、系统设计(总体架构、功能设计、数据库设计)、系统实现(核心代码和截图)、系统测试(功能测试用例和结果)、总结。其中“系统设计”和“系统实现”至少占全文一半,数据库设计部分要把表结构、E-R 图展示出来,尽量画清楚实体之间的关系。

6.3 演示脚本和答辩问题准备

演示的时候不要一上来就登录管理员账号看一堆列表。按角色演示,效果最好:先用学生账号登录,看到班级公告、报名活动、提交请假;再切换到辅导员账号,审批请假、查看考勤统计、看到通知已读情况;最后用管理员账号查看全院班级数据对比。这就是一条完整的故事线,评委看得懂,你也有话讲。

常见答辩问题也要提前准备:为什么用 SpringBoot 而不是 SSM?为什么不用 Spring Security?班费余额怎么计算?考勤数据如何避免重复提交?通知已读未读是怎么实现的?如果你的项目真的自己动手写过,这几个问题都能答得上来。

6.4 如果参考代码是一份 jar 包

很多同学会从学长那里拿到一份打包好的 jar 包,想通过反编译还原出项目。我不建议直接照搬反编译代码去改,但可以用反编译工具看它的表结构和接口思路,用来帮助你设计自己的数据库和接口。至于你自己的代码,尽量一行一行写出来,或者至少把核心逻辑完全看懂,否则答辩一问就露馅。


最后再分享一点我自己的体会:做这类“班级事务管理”系统,最容易失误的地方不是技术,而是把需求做浅了。如果你只是把学生信息、班级信息做了增删改查,那它就和一个普通管理系统没什么区别。真正能拿高分的项目,一定是在请假审批、考勤统计、班费流水、通知触达这些“事”上面做出了细节。先花一天时间把班级里真实会发生的事务列清楚,再去动手建表写代码,你会发现后面开发顺畅得多。

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

Linux第一次作业:环境搭建、命令查询与脚本编写指南

兄弟&#xff0c;如果你刚交完或者正准备做人生的第一次 Linux 作业&#xff0c;我先给你交个底&#xff1a;这门课从来不是在考你背了多少条命令&#xff0c;它真正的作业其实是——让你在真实的环境里完成一系列“小到不能再小”的任务&#xff0c;然后通过这些任务把“Linux…

作者头像 李华
网站建设 2026/10/1 12:44:32

FastAPI文档页白屏?从CDN替换到离线部署的完整方案

如果你把一个 FastAPI 服务部署到公司内网&#xff0c;大概率会遇到一个让人头疼的场景&#xff1a;业务代码跑得好好的&#xff0c;但打开 /docs 页面时一片空白&#xff0c;F12 里飘着十几个红色加载失败。问题十有八九出在 Swagger UI 的 CDN 资源上——FastAPI 默认从公共…

作者头像 李华
网站建设 2026/10/1 12:44:21

Matlab实现BEMT螺旋桨性能分析:从叶片单元动量理论到工程扫参实践

做螺旋桨选型或者飞行器动力评估的人&#xff0c;多少都绕不开叶片单元动量理论这四个字。它不像CFD那样能追着每个涡跑&#xff0c;但胜在计算速度快、物理图像清楚、参数扫描方便&#xff0c;特别是做方案对比和趋势判断的阶段&#xff0c;一套BEMT程序顶得上你在网格上面熬好…

作者头像 李华
网站建设 2026/10/1 12:42:43

百度二面:ThreadLocal 传参如何使用?2 万字深度详解

开场&#xff1a;为什么百度面试官总爱追问 ThreadLocal 传参很多人会把 ThreadLocal 理解成一个「线程专属的全局变量」或者「线程本地缓存」&#xff0c;但要真的把它讲透&#xff0c;面试官经常会从「传参」这个非常具体的切入口&#xff0c;一路追问到底层实现、内存模型、…

作者头像 李华
网站建设 2026/10/1 12:41:53

TensorFlow.js 浏览器端实时目标检测:架构设计、后端调度与工程实践

项目代号我起了个名字叫 Omni&#xff0c;核心是用 TensorFlow.js 在浏览器端做实时目标检测。起因是当时做的远程损伤评估系统&#xff0c;用户上传现场照片后&#xff0c;要等服务器返回检测框和置信度。前端的体验倒还能接受&#xff0c;可一压测就露馅了&#xff1a;高并发…

作者头像 李华
网站建设 2026/10/1 12:41:46

【C++笔记】从 C 到C++:核心过渡 (上)

前言C 和 C 的关系经常被两种极端说法描述&#xff1a;一种说"C 就是 C 加上了类"&#xff0c;另一种说"C 是全新的语言&#xff0c;C 的写法都不作数"。两种都不准确。C 确实脱胎于 C&#xff08;早期叫 "C with Classes"&#xff09;&#xff…

作者头像 李华