ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Spring Boot学生考勤管理系统实战:从配置到部署的完整指南

Spring Boot学生考勤管理系统实战:从配置到部署的完整指南 简介这是基于Spring Boot开发的学生考勤管理系统完整源码包适合Java开发者、毕业设计或课程设计人员学习参考。系统涵盖用户身份验证、学生信息管理、签到签退记录、出勤统计与异常处理等模块并支持课程安排与数据报告生成能够有效提升学校考勤管理效率。资源共428个文件压缩包大小约15MB主要包含107个java源码、43个vue前端页面、21个js脚本、14个xml配置及SQL、yml等环境配置另有docx文档和PPT说明便于快速理解项目结构与部署流程。目前已有49人学习下载。源码结构清晰分层合理附带项目启动脚本及数据库脚本读者可据此搭建运行环境并结合文档掌握从安装到使用的完整流程对于希望了解Spring Boot整合Vue前后端分离开发、权限控制或考勤业务逻辑的开发者具有不错的参考价值。1. 拿到这个 zip先想清楚它对应哪一类 Spring Boot 工程学生考勤管理系统是典型的 CRUD 加状态流转项目这个 zip 里一般是源码、数据库脚本和一段 README。常见组合是 Spring Boot 框架做后端MyBatis-Plus 操作 MySQLRedis 做缓存和防重复签到前端用 Thymeleaf 或者打包好的 Vue 静态文件。它要解决的业务很明确把学生的签到、签退、请假、缺勤统计从 Excel 挪到网页上让系统自己算出每个人某一天是正常、迟到还是缺勤。适合拿来做 springboot 毕业设计也适合小团队内部直接二次开发。真正决定这个 zip 能不能跑起来的往往不是代码写得多好而是配置和环境的匹配。JDK 版本、MySQL 账号、Redis 是否启动这三样比代码更容易让整个系统卡死在启动阶段。2. 拆开 zip 之前用 pom.xml 和目录结构判断 Spring Boot 项目的成色拿到压缩包后的第一件事不是解压后双击运行而是先判断它是不是一个完整的 Maven 工程依赖有没有写全版本体系是不是一致。这一步能省掉后面大量“启动不了”“找不到类”“端口冲突”的排查时间。2.1 先看文件清单里有没有这些关键文件在终端里解压并查看结构unzip springboot项目学生考勤管理系统.zip -d attendance cd attendance find . -maxdepth 2 -type f | sort输出里至少应该看到pom.xml、src/main/java、src/main/resources/application.yml或application.properties以及至少一个.sql文件。没有pom.xml的项目通常是用 Gradle 构建对应文件是build.gradleIDEA 导入方式不同。如果 zip 里只有源码没有 SQL 脚本后面需要自己重建表工作量会明显增加。还有一种常见情况是 README 里写了“导入 IDEA 直接运行”却没有说数据库初始化方式。这种项目即使代码没有编译错误启动后一查接口就是 500。正确的做法是先看src/main/resources目录确认有没有db/init.sql、doc/或根目录下的*.sql。三个关键文件pom.xml、application.yml、SQL 脚本都在这个 springboot 项目才具备本地运行的基础。顺便检查有没有.git目录如果有说明源码历史保留完整后续改挂了还可以 diff 回来。2.2 从 pom.xml 读出 Spring Boot 版本和依赖族pom.xml 的 parent 部分直接决定整个项目的技术栈基线parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.13/version relativePath/ /parent2.7.13是 Spring Boot 2.7.x 系列默认支持 JDK 8/11/17Servlet API 是 javax 命名空间MyBatis-Plus 一般搭配 3.5.x。如果是 3.2.x 或 3.3.x那 JDK 必须是 17所有javax.servlet都要替换成jakarta.servlet。很多“ClassNotFoundException: javax.servlet”的报错本质是 Spring Boot 版本和 JDK 版本不匹配。判断版本后还要看依赖考勤系统最常出现的是这几个spring-boot-starter-web提供 REST 接口和内置 Tomcat。mybatis-plus-boot-starter数据库 ORM继承BaseMapper后开箱即用。spring-boot-starter-data-redis缓存、幂等、Session 共享。spring-boot-starter-validation参数校验。spring-boot-starter-actuator健康检查和监控端点。如果 pom.xml 里没有spring-boot-maven-plugin打包成可执行 jar 时会有问题可以手动补到build节点build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /buildSpring Boot 自动装配原理在这里可以直接用上引入 starter 后框架靠spring.factories2.x或AutoConfiguration.imports3.x自动加载配置类。比如引入 Redis starterRedisAutoConfiguration就会生效给你创建StringRedisTemplate和RedisTemplate。但这不代表 Redis 一定连得上连接参数由 application.yml 控制配置错时启动不报错第一次访问缓存才报错。Spring Boot 主版本JDK 要求Servlet API常见 MyBatis-Plus 版本2.7.x8 / 11 / 17javax.servlet3.5.x3.2.x17jakarta.servlet3.5.52.3 三层架构和常用注解怎么对应考勤场景考勤系统基本都是 controller-service-mapper 三层用几个常用注解就能判断代码写得到不到位SpringBootApplication public class AttendanceApplication { public static void main(String[] args) { SpringApplication.run(AttendanceApplication.class, args); } }SpringBootApplication是SpringBootConfigurationEnableAutoConfigurationComponentScan的合成注解。它从启动类所在包开始扫描组件所以启动类必须放在 controller、service、mapper 包的最外层。放错位置会出现“类都在但接口全部 404”的情况。Controller 层的典型写法RestController RequestMapping(/api/attendance) public class StudentAttendanceController { PostMapping(/checkin) public Result checkIn(RequestBody CheckInDTO dto) { return attendanceService.checkIn(dto.getStudentId()); } }RestController直接让返回值变成 JSONRequestBody把前端 JSON 绑定到 DTOPostMapping限定 POST 方法。Service 层用Service标记Mapper 层用Mapper或启动类上的MapperScan注册到 Spring 容器。这一层是 springboot 面试题的高发区Spring 的声明式事务Transactional默认只对 RuntimeException 回滚受检异常不会自动回滚。考勤系统的签到和写记录必须放在同一个事务里否则会出现签到了但记录没落库这个细节在答辩或评审时被问到的概率很高。3. 本地跑通Spring Boot 配置、MySQL 和 Redis 的最小可用组合3.1 先解决 JDK 和 Maven 环境再谈 springboot 配置本地跑不起来的第一个原因通常是 JDK 版本和代码无关。如果你用 IDEA 新建 Spring Boot 项目默认选到 3.3然后照搬 2.7 的配置就会遇到 springboot 版本太高带来的兼容性问题。比如项目是 Spring Boot 2.7本机是 JDK 21跑起来大概率出现UnsupportedClassVersionError或者反射访问异常。解决办法不是改代码而是给这个项目单独指定 JDK 8 或 11。用 IDEA 打开项目后在 Project Structure 里把 Project SDK 和 Modules 的 language level 切到对应版本再把 Maven 的 runner 默认 JRE 也切过去三个地方不一致时 Maven 还是会用系统 JDK 编译。推荐先跑一次编译mvn clean compile这一步把所有依赖从这个 zip 对应的 Maven 仓库拉下来能提前暴露依赖下载失败、仓库地址不可达的问题。很多别的项目会把settings.xml一起压进 zip如果你直接放到~/.m2下面可能指向内网私服本地环境访问不到就会卡在Could not resolve dependencies。这时候把settings.xml里的 mirror 改成阿里云公共仓库就够用。springboot 配置不是“装一个框架”的概念它的本质是把 starter 依赖的自动装配参数填到application.yml。所以环境问题解决后重点就落在配置上。3.2 application.yml 里最容易改错的三组参数一个最小可用的考勤系统配置如下server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/attendance_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver data: redis: host: localhost port: 6379 database: 0 timeout: 3000ms mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0第一组容易错的是数据库 URL 里的serverTimezone。MySQL 8 驱动必须有serverTimezoneAsia/Shanghai否则启动时直接报The server time zone value Öйú is unrecognized。如果项目还连 SQL Server连接串又完全是另一种写法不要混用。第二组是 Redis 的database参数。本地 Redis 默认有 16 个库项目里可能用的 database 1而配置写 database 0。这种错误不报异常但读写缓存全不命中。可以把timeout调短到 3000ms连接异常会更快暴露。第三组是 MyBatis-Plus 的逻辑删除。如果实体类上有TableLogic的deleted字段而全局配置没写logic-delete-fieldMyBatis-Plus 生成 SQL 时不会自动追加deleted0删除就变成物理删除考勤记录一旦删了就找不回来。注意Spring Boot 2.x 的 Redis 配置前缀是spring.redis3.x 是spring.data.redis两套配置不能直接混用。如果拿高版本项目抄低版本配置Redis 连不上但不报错排查时要先看启动日志里的配置打印。3.3 初始化 SQL学生、考勤记录、请假单怎么建表在 zip 里找到 SQL 就执行找不到就自己建。下面是三张最核心的表CREATE DATABASE IF NOT EXISTS attendance_db DEFAULT CHARACTER SET utf8mb4; USE attendance_db; CREATE TABLE student ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(32) NOT NULL UNIQUE COMMENT 学号, name VARCHAR(64) NOT NULL, class_name VARCHAR(64), deleted TINYINT DEFAULT 0, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE attendance_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL, work_date DATE NOT NULL, check_in_time DATETIME, check_out_time DATETIME, status VARCHAR(20) COMMENT NORMAL/LATE/ABSENT/LEAVE, deleted TINYINT DEFAULT 0, UNIQUE KEY uk_student_date (student_id, work_date) ); CREATE TABLE leave_request ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL, leave_type VARCHAR(20), start_time DATETIME, end_time DATETIME, reason VARCHAR(255), approved TINYINT DEFAULT 0, create_time DATETIME DEFAULT CURRENT_TIMESTAMP );utf8mb4必须加不然后面插中文会报Incorrect string value。uk_student_date唯一键是防重复签到的最底层保障即使代码出现并发数据库也会拒绝同一天同一个学生的第二条记录。设计上把签到记录做成“一天一行”再通过check_in_time和check_out_time表示当天两次打卡如果以后要支持一天多次进出再改成打卡明细表。执行 SQL 的方式mysql -uroot -p init.sql执行完用SHOW TABLES;确认三张表都在。如果项目里有admin_user表登录账号的密码加密方式要看清楚常见的是 BCrypt也有项目用 MD5两者无法互相登录。3.4 启动验证看日志而不是只看端口启动项目前确认 MySQL 和 Redis 都在运行redis-cli ping mysqladmin -uroot -p status然后启动 Spring Bootmvn spring-boot:run看到Started AttendanceApplication in 5.8 seconds且没有 ERROR才算启动成功。不要只看到Tomcat started on port(s): 8080就以为端到端通了数据源和 Redis 是在启动阶段初始化的如果它们有问题启动会直接失败。Spring Boot 日志里要重点看有没有 MyBatis-Plus 的版本警告以及数据源初始化有没有异常。启动成功后调用一个最基础的接口curl http://localhost:8080/api/student/list返回[]而不是 500说明数据库连接和表映射都通了。联调时把 SQL 日志打开就是前面配置里的StdOutImpl控制台会打印每条 SQL 和参数。如果没有打印检查mybatis-plus.configuration.log-impl是否生效。也可以接着看curl http://localhost:8080/actuator/health返回{status:UP}说明健康检查通过。如果没有引入 actuator这个地址是 404不用纠结。4. 把考勤业务做成 Spring Boot 接口签到、统计、定时任务4.1 考勤的 3 张核心表和状态机上一章建好了表这章看业务。考勤系统的核心不是“增删改查”而是状态怎么流转。一个学生的当天状态可以用这个表来表达状态触发动作前置条件NORMALcheckIn 成功且时间早于规定时刻当天无记录LATEcheckIn 成功但时间晚于规定时刻当天无记录LEAVEleave_request 被审批通过审批字段 approved1ABSENT定时任务在当天结束后计算无 check_in_time 且无审批通过的请假这里有一个设计取舍不要把状态直接交给前端来传后端要根据时间和服务端数据自己推导。前端传什么就存什么会被人用工具直接改成“NORMAL”绕过迟到判定。所以签到接口只接收 studentId状态由后端判断。请假审批通过后要同步影响考勤状态。比较简单的做法是不直接 update 考勤记录而是在计算日报时把未签到但有有效请假的记录判定为 LEAVE。这样考勤记录表始终只存“实际打卡”的原始事实统计表存“推导结果”两边不打架。4.2 用 MyBatis-Plus 写签到 / 签退接口MyBatis-Plus 的 Mapper 继承BaseMapperT后单表 CRUD 不用写 SQL。签到的核心方法可以这么写Service public class AttendanceService { Autowired private AttendanceRecordMapper recordMapper; Transactional public AttendanceRecord checkIn(Long studentId) { LocalDate today LocalDate.now(); AttendanceRecord record recordMapper.selectOne( new LambdaQueryWrapperAttendanceRecord() .eq(AttendanceRecord::getStudentId, studentId) .eq(AttendanceRecord::getWorkDate, today)); if (record null) { record new AttendanceRecord(); record.setStudentId(studentId); record.setWorkDate(today); record.setCheckInTime(LocalDateTime.now()); record.setStatus(LocalTime.now().isBefore(classStartTime) ? NORMAL : LATE); recordMapper.insert(record); } return record; } }LambdaQueryWrapper是 MyBatis-Plus 中避免 SQL 拼写错误的关键方法引用AttendanceRecord::getStudentId在编译期就能检查字段名。Transactional保证 check_in_time 写入失败时不会留下半条脏数据。注意 selectOne 在查询到多条记录时会抛异常所以数据表唯一键uk_student_date在这里是第二道保险。签退接口和签到几乎一样区别是把check_out_time更新到已有记录上Transactional public void checkOut(Long studentId) { LocalDate today LocalDate.now(); AttendanceRecord record recordMapper.selectOne( new LambdaQueryWrapperAttendanceRecord() .eq(AttendanceRecord::getStudentId, studentId) .eq(AttendanceRecord::getWorkDate, today)); if (record ! null) { record.setCheckOutTime(LocalDateTime.now()); recordMapper.updateById(record); } }如果 record 为 null说明没签到就直接签退可以抛出业务异常由全局异常处理器转成统一返回值。大多数 springboot mybatis-plus 的项目都会配一个RestControllerAdvice异常处理器避免把堆栈直接返回给前端。4.3 Redis 在考勤里到底缓存什么以及怎么设置过期时间考勤系统的 Redis 只缓存两类数据学生基本信息和签到幂等标记。考勤记录本身不缓存因为查询量不大而且数据实时性要求高。缓存学生信息是为了避免每次下拉列表都查 MySQLAutowired private StringRedisTemplate redisTemplate; public ListStudent listStudents() { String key attendance:student:list; String json redisTemplate.opsForValue().get(key); if (json ! null) { return JSON.parseArray(json, Student.class); } ListStudent list studentMapper.selectList(null); redisTemplate.opsForValue().set(key, JSON.toJSONString(list), Duration.ofMinutes(10)); return list; }Duration.ofMinutes(10)表示学生列表 10 分钟过期避免数据更新后看不到最新结果。另一个更关键的应用是防止重复签到public boolean tryLockCheckIn(Long studentId) { String key attendance:checkin: studentId : LocalDate.now(); return Boolean.TRUE.equals( redisTemplate.opsForValue().setIfAbsent(key, 1, Duration.ofHours(12))); }setIfAbsent是原子操作同一个 key 只有第一次调用能设置成功第二次会返回 false。如果并发请求同时进来只有真正允许的请求能写 MySQL另一个直接返回“已签到”。这个方案和数据库唯一键形成两层防护即使 Redis 失效数据库也不会产生重复记录。注意 springboot 整合 redis 时如果直接用RedisTemplate而不是StringRedisTemplate要注意序列化方式否则存进去的是二进制乱码。4.4 用 Spring Boot 定时任务把“应到/实到/请假”算成日报每天结束后需要统计今天多少人应到、多少人实到、多少人迟到、多少人请假、多少人缺勤。用Scheduled实现最直接EnableScheduling SpringBootApplication public class AttendanceApplication { // ... }任务类Component public class AttendanceDailyJob { private final AttendanceRecordMapper recordMapper; public AttendanceDailyJob(AttendanceRecordMapper recordMapper) { this.recordMapper recordMapper; } Scheduled(cron 0 30 23 * * ?) public void buildDailySummary() { LocalDate today LocalDate.now(); ListAttendanceRecord records recordMapper.selectList( new LambdaQueryWrapperAttendanceRecord() .eq(AttendanceRecord::getWorkDate, today)); long normal records.stream().filter(r - NORMAL.equals(r.getStatus())).count(); long late records.stream().filter(r - LATE.equals(r.getStatus())).count(); // 应到人数需要从 student 表读取未打卡且无请假的人标记为 ABSENT } }cron 0 30 23 * * ?表示每天 23:30 执行避开当天课程结束前还有晚自习的情况。Spring Boot 定时任务默认在一个线程上跑任务多了会互相阻塞。如果同一个项目里还有其他定时任务需要在配置文件里调大线程池spring.task.scheduling.pool.size5定时任务里不要直接对考勤记录做物理删除或全表更新最好把汇总结果写入一张attendance_daily_summary表保留历史用于导出。任务执行失败时要能看日志所以可以在 Job 里加上 try-catch 并用日志输出错误。定时任务的重跑也要考虑幂等先按work_date删掉旧汇总再插入。5. 交付前最后的收尾日志、隔离、打包与常见报错处理5.1 别把 Actuator 和 Heapdump 暴露到公网如果 pom.xml 里有 actuator本地调试很舒服但交付时记得限制端点暴露范围。/actuator/env会把application.yml里的数据库密码打出来/actuator/heapdump能直接下载 JVM 堆内存里面可能含 Redis 连接串、用户信息等敏感数据这也是 springboot heapdump 敏感信息泄露漏洞的常见入口。上线前把 exposure 收敛到 health 和 info 就够了management: endpoints: web: exposure: include: health,info5.2 打包成可运行 zip 的检查清单交付前按这个清单过一遍检查项验证方法spring-boot-maven-plugin存在查看 pom.xml build 节点生产环境数据库密码未被硬编码检查 application-prod.ymlSQL 脚本和 README 放在 zip 内find 命令确认README 写明 JDK、MySQL、Redis 版本cat README.md本地启动后再用远程环境验证java -jar启动一次执行打包mvn clean package -DskipTests java -jar target/attendance-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod-DskipTests跳过测试--spring.profiles.activeprod指定生产环境配置。打包后直接把 jar 和init.sql、README 放一起压缩比把整个源码目录丢进去更友好。5.3 三个高频报错和对应处理Access denied for user rootlocalhost。MySQL 8 默认 root 账号可能使用 auth_socket 或远程访问限制。开发环境最简单的做法是给 root 设置密码ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY root;然后刷新权限。Unable to connect to Redis。先redis-cli ping看 Redis 进程是否正常再看配置前缀是spring.redis还是spring.data.redis。Spring Boot 3.x 只认spring.data.redis前缀错了不会启动失败只是运行时连接超时。Invalid bound statement (not found)。Mapper 接口没有被扫描到或者 XML 文件没有配置。启动类上加MapperScan(com.xxx.mapper)再把mapper-locations指向 XML 目录就能解决。最后一个建议把java -jar跑起来后按签到、签退、请假、统计日报四条流程各走一遍再压缩交付。这个验证动作比任何代码审查都更接近真实场景。本文还有配套的精品资源点击获取
返回列表