毕设季又到了,后台每天都能收到一堆“考勤系统怎么做”“SpringBoot选什么版本”“小程序登录一直报错”这类问题。我自己当年做毕业设计时也是从零开始踩坑,所以干脆把这套直接可用的基于SpringBoot的单位考勤管理系统整理出来,从选题思路、技术选型到数据库设计、核心代码实现,再到部署上线和常见报错排查,一篇讲透。无论你现在是刚拿到题目还在纠结技术栈,还是代码写到一半被各种环境问题卡住,这篇文章都值得你花十分钟看完。
先说清楚这套系统到底能干什么:职工通过微信小程序完成上下班打卡、请假申请、查看个人考勤统计,管理员在Web后台维护部门与员工信息、配置班次与考勤规则、审批请假申请、查看全员的考勤报表和异常数据。整个业务闭环包含移动端、管理端、后端服务、数据库四层,技术栈以SpringBoot 2.7.x为主,配合MyBatis-Plus、MySQL、Redis和微信小程序原生框架,同时源码头也保留了Java、PHP、Python、C#等其他语言的版本以及单片机的扩展方案,方便你根据学校要求灵活切换。项目代码结构清晰、注释完整,自带初始化SQL脚本和部署文档,属于那种拿到手就能启动、跑起来就能演示的成品级毕设项目。
1. 选题思路与技术栈对比:为什么考勤系统值得做
1.1 考勤系统为什么是毕设圈的常青树
每年毕业设计题目里,考勤管理系统都会占据一席之地。我见过很多同学觉得这个题目太普通,担心答辩时被老师说“没有创新点”,但实际带过项目就知道,考勤系统能成为经典选题是有道理的。
第一,业务需求非常明确。打卡、请假、审批、统计、报表,这些功能不需要你再去“发明”需求,用户场景就摆在那里,你只需要把流程做对、做顺。相比那些凭空想象的“智能xx平台”,考勤系统的需求文档容易写,评审老师也容易理解,答辩时你不需要花大量时间解释业务背景。
第二,业务闭环完整且天然适合技术展示。一个完整的考勤系统涉及移动端开发、后端接口设计、数据库建模、权限管理、定时任务、消息通知、数据可视化等多个技术点,从广度上能展示你的综合能力。而且考勤数据天然带有时间属性和状态流转(正常、迟到、早退、缺卡、请假、外勤),这为你在深度上做文章提供了空间,比如引入Redis缓存热点考勤数据、用Quartz做定时统计、通过WebSocket推送打卡提醒等,这些都是答辩时能拿出来讲的亮点。
第三,可扩展性极强。你可以基于考勤系统向外延伸出薪资计算、绩效管理、排班管理、加班调休等模块,也可以换一套前端方案(Vue、React、小程序)来体现技术广度。我见过有同学在考勤系统基础上加了基于人脸识别的打卡验证,直接用百度AI开放平台的人脸对比接口,答辩效果就很好。
所以选题本身没有好坏之分,关键是你在实现过程中有没有真正的思考和投入。用一个成熟的项目模板快速跑通主线流程,再花时间打磨一两个亮点模块,毕业设计稳稳的。
1.2 这套系统的技术栈全貌与选型理由
项目源码的核心后端采用SpringBoot 2.7.18,这是目前兼容性和稳定性最均衡的版本,具体技术栈如下:
| 层次 | 技术选型 | 说明 |
|---|---|---|
| 后端框架 | SpringBoot 2.7.18 | 基于JDK 8,兼容性最好,学校机房和本地环境都能跑 |
| ORM框架 | MyBatis-Plus 3.5.x | 单表CRUD不用写SQL,自带分页插件 |
| 数据库 | MySQL 8.0 | 存储用户、部门、考勤记录等业务数据 |
| 缓存 | Redis 5.x+ | 缓存用户会话、打卡状态,防止重复提交 |
| 权限认证 | JWT + Spring Security | 无状态登录,小程序端更友好 |
| 定时任务 | Spring Schedule | 每日凌晨自动生成前一天的考勤汇总 |
| 移动端 | 微信小程序原生 | 无需安装App,扫码即用,方便演示 |
| 管理后台 | Thymeleaf + Bootstrap | 服务端渲染,部署简单,不用单独起前端工程 |
选这套组合的原因很直接:对毕设来说,“跑得起来”比“技术新”重要一百倍。SpringBoot 2.7.18配JDK 8是目前网上教程覆盖最全、问题解决方案最多的组合,你遇到任何报错基本都能搜到答案;MyBatis-Plus大幅减少SQL编写量;JWT替代Session解决了小程序端没有Cookie机制的问题。管理后台用Thymeleaf服务器渲染,避免引入Vue或React之后还要处理跨域和前端构建的复杂度,让整个项目保持“一个Java工程直接启动”的简单形态。
1.3 一个重要抉择:SpringBoot 2.x 还是 3.x
这里必须单独说一下版本选择的问题,因为近几年SpringBoot 3.x发布后,很多新教程都在推3.x,导致大量毕设同学跟着踩坑。
SpringBoot 3.0在2022年11月发布,它的底层是Spring Framework 6,强制要求JDK 17及以上,同时把javax命名空间全部迁移到了jakarta。这意味着如果你用3.x,就会面临两个现实问题。
第一,很多高校的毕业设计环境(实验室电脑、老师提供的服务器)装的是JDK 8,根本无法运行SpringBoot 3.x。我见过不止一个同学在自己电脑上装JDK 17开发完,结果答辩演示时换到教室电脑上直接起不来。
第二,网上大量现成的教程、博客、源码是基于SpringBoot 2.x写的,你遇到问题时搜到的解决方案大概率是“修改application.yml里的xx配置”或者“引入xx依赖”,但3.x里这些配置项可能已经被移除或改名了。尤其是Spring Security、Redis连接、MyBatis等组件的自动配置方式在3.x中变动很大,跟着老教程改代码会非常痛苦。
所以我给你的建议很明确:如果学校没有硬性要求用最新版本,老老实实选SpringBoot 2.7.x。它是2.x的最后一个版本,支持周期长、资料最全、踩坑成本最低。技术选型的核心原则永远是“用成熟稳定的方案解决问题”,而不是“用最新的方案给自己添堵”。这套源码默认也是基于SpringBoot 2.7.18,你拿到之后不需要做任何版本相关配置就能直接启动。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心功能拆解与数据库设计
2.1 核心业务闭环:打卡、审批、统计一条线
考勤系统的业务模型看起来简单,但落地到代码层面,需要把每个环节的流程彻底想清楚。
先梳理用户的日常操作路径。员工打开微信小程序,进入打卡页面,系统先获取当前位置和当前时间,然后调用后端打卡接口。后端根据员工的排班信息判断当前时间属于哪个班次的上班时间段还是下班时间段,再判断是否迟到或早退,最后写入考勤记录。员工在“我的考勤”页面能看到本月每一天的打卡状态和统计结果。
员工提交请假申请时,要选择请假类型(事假、病假、年假、调休)、起止时间、请假事由,提交后流转到部门主管或管理员的审批列表。审批通过后请假单的状态变为“已通过”,同时系统在对应日期生成一条请假记录,并参与考勤统计。这里要注意一个细节:请假通过后,请假时段内不应再生成缺卡记录,这需要在生成每日考勤汇总时做联动判断,否则员工明明请了假,系统却显示缺卡,数据就对不上。
管理员端的功能更偏重配置和统计。管理员可以维护部门结构和员工账号,给员工分配班次(早班、晚班、排班周期),配置考勤规则(迟到多少分钟算迟到、迟到几次触发警告、外勤是否需要审批等),查看每日考勤明细和月度汇总报表,以及处理异常考勤数据的申诉和修正。
整个系统的数据流是:员工打卡产生考勤记录,请假审批产生请假记录,定时任务合并两类数据生成考勤汇总,报表模块从汇总数据中统计出勤率、迟到次数、早退次数、缺卡天数等指标。核心逻辑都围绕“考勤记录”和“考勤状态”展开,搞清楚这一点,后面的数据库设计和代码实现就有了方向。
2.2 数据表设计:六张核心表的字段与关系
数据库设计是考勤系统的地基,表结构不合理,后面写代码会无比痛苦。这套源码的表结构经过多轮迭代,最终沉淀为以下六张核心表。
sys_user(用户表)保存账号信息和基本资料,核心字段包括user_id、username、password(BCrypt加密存储)、real_name、department_id、shift_id、phone、avatar、role(区分员工和管理员)、status(启用/禁用)、create_time。注意不要明文存储密码,Spring Security的BCryptPasswordEncoder是标配。
sys_department(部门表)维护组织架构,核心字段是dept_id、dept_name、parent_id(支持树形结构)、leader_id(部门负责人,用于请假审批的一级审批人)、sort_order。
att_shift(班次表)配置上下班时间规则,核心字段是shift_id、shift_name、start_time(上班时间)、end_time(下班时间)、late_threshold(迟到判断分钟数,比如上班后5分钟内不算迟到)、early_threshold(早退判断分钟数)、work_day_type(区分工作日、周末、节假日)、status。
att_record(考勤记录表)是系统的核心表,每打卡一次生成一条记录。核心字段是record_id、user_id、shift_id、clock_time(打卡时间)、clock_type(上班卡/下班卡)、attendance_status(正常、迟到、早退、缺卡、外勤)、location(打卡定位)、remark、create_date。这张表的数据量会持续增长,建议以create_date为维度建索引,按月份分表可以在后期优化,不过毕设阶段不需要做到这一步。
att_leave(请假申请表)的字段包括leave_id、user_id、leave_type(事假/病假/年假/调休)、start_time、end_time、days、reason、status(待审批/已通过/已拒绝)、approver_id、approve_comment、approve_time。
att_summary(考勤汇总表)由定时任务每天凌晨生成,保存每个员工每天最终的综合考勤状态,字段包括summary_id、user_id、work_date、work_status(正常/请假/缺勤/外勤)、first_clock_time、last_clock_time、late_count、early_leave_count、source_type(正常打卡/请假/管理员修正)、create_time。这张表最大的作用是把“打卡流水”和“最终考勤状态”解耦,报表统计直接查汇总表就行,不需要每次都对流水做复杂的聚合运算。
表之间的关系如下:用户表通过department_id关联部门表,通过shift_id关联班次表;考勤记录表通过user_id关联用户表;请假申请表通过user_id关联用户表,通过approver_id关联审批人;考勤汇总表通过user_id关联用户表。整体就是一张典型的“用户-配置-流水”结构,清晰且易于扩展。
2.3 考勤状态如何判定:迟到、早退、缺卡的计算逻辑
考勤状态判定是后端最核心的业务逻辑,不能简单粗暴地“拿打卡时间和上班时间比一下就完事”,里面有几个细节必须处理好。
先说打卡类型判断。考勤系统设计中通常把班次分为四个时间节点:上班开始时间、上班结束时间(即迟到判定截止时间)、下班开始时间(即早退判定起点时间)、下班结束时间。以早班8:30到17:30为例,通常设定0点到8:30之间打卡记为上班卡,8:30到10:00之间打卡仍记为上班卡但状态为迟到,10:00之后打卡记为缺卡(或者记为半日缺勤,具体看规则配置);16:30到17:30之间打卡记为早退,17:30到23:59之间打卡记为正常下班卡。为什么要设置这些缓冲阈值?因为员工可能早上8:20到公司,下午16:50临时有事先走,如果系统只按“8:30和17:30两个点”判断,很容易产生大量误判记录,导致员工的考勤数据看起来很差,管理员还要手动修正,非常麻烦。
再说跨天班次(比如晚班22:00到次日6:00)的处理。这种班次如果还按“当天日期”来分组考勤记录,就会把晚上10点的上班卡归到前一天,凌晨6点的下班卡归到第二天,导致数据错乱。正确做法是按“班次开始日期”作为考勤归属日期,也就是说晚班22:00属于12月10日的班次,那么12月10日当天深夜的打卡记录都归到12月10日,次日凌晨的下班卡也归到12月10日。这个逻辑在代码里就是在判断打卡记录归属日期时,根据班次是否跨天来决定使用哪个日期字段。
防重复打卡也是必须处理的场景。员工手滑连续点了两次打卡按钮,如果接口没有防重机制,就会生成两条打卡记录。实现方式有两种:一是数据库层面为user_id、create_date、clock_type建立唯一索引,重复插入直接报错;二是在Redis里以“userId + 日期 + 打卡类型”为key做setnx操作,第一次打卡成功后写入标记,第二次请求进来发现key已存在就拦截掉。我建议两种方式同时用,Redis做前置拦截提升性能,数据库唯一索引做兜底防并发穿透。
3. 手把手部署流程与核心代码实现
3.1 环境准备与项目启动
代码拿到手之后,第一步是把基础环境配好。你需要准备的环境包括JDK 8(必须是8及以上,推荐8u202或8u211)、Maven 3.6+、MySQL 8.0、Redis 5.x+,以及微信开发者工具(用于运行小程序端)。开发工具推荐IntelliJ IDEA,社区版就够用,不需要破解旗舰版。
配置步骤如下。先把项目里的SQL脚本(一般是sql/init.sql)导入MySQL。打开Navicat或命令行,执行source命令导入,脚本会自动创建数据库和六张核心表,同时插入一个管理员账号(通常是admin/admin123)和几个测试员工账号,省去你手动造数据的麻烦。然后修改application.yml里的数据库连接配置,把用户名密码改成你自己的,Redis配置同理。最后在IDEA中打开项目,等待Maven下载依赖完成后,运行AttendanceApplication主类。
启动成功后访问本地的8080端口(管理后台默认端口),用管理员账号登录,就能看到后台首页。这里有一个新手常犯的错误:访问后台时记得路径是http://localhost:8080/admin/login,只有加了/admin前缀才会进入后台页面,直接访问根路径会跳到接口文档或空白页。
小程序端的配置稍微复杂一点。用微信开发者工具导入mini-program目录,在app.js里修改后端API地址。本地调试时不能直接填localhost,因为微信开发者工具里的网络请求会经过一层转发,需要改成你电脑的局域网IP,比如http://192.168.1.100:8080。同时在小程序后台或开发者工具的“详情-本地设置”里勾选“不校验合法域名”,否则请求会被拦截。填写好这些配置后重新编译,小程序就能正常访问后端接口了。
3.2 打卡接口设计与防重复提交
打卡接口是整个系统最核心的接口,源码里实现得比较完整,这里摘出核心逻辑讲一下设计思路。
java复制@RestController
@RequestMapping("/api/attendance")
public class AttendanceController {
@Autowired
private AttendanceService attendanceService;
@PostMapping("/clock")
public Result clock(@RequestBody ClockDTO dto, @RequestAttribute("userId") Long userId) {
// 判断当前用户是否有排班
Shift shift = attendanceService.getCurrentShift(userId);
if (shift == null) {
return Result.error("当前账号未配置班次,请联系管理员");
}
// 防重复提交:Redis缓存判重
String redisKey = "attendance:clock:" + userId + ":" + LocalDate.now() + ":" + dto.getClockType();
Boolean success = redisTemplate.opsForValue().setIfAbsent(redisKey, "1", 12, TimeUnit.HOURS);
if (Boolean.FALSE.equals(success)) {
return Result.error("今日已打卡,请勿重复操作");
}
// 计算考勤状态
String status = attendanceService.calculateStatus(shift, dto.getClockTime(), dto.getClockType());
// 落库
AttendanceRecord record = new AttendanceRecord();
record.setUserId(userId);
record.setShiftId(shift.getShiftId());
record.setClockTime(dto.getClockTime());
record.setClockType(dto.getClockType());
record.setAttendanceStatus(status);
record.setLocation(dto.getLocation());
attendanceService.saveRecord(record);
return Result.success("打卡成功", status);
}
}
这里有几个值得注意的设计细节。第一,用户身份不从前端传,而是从JWT解析后由拦截器塞到RequestAttribute里,防止有人恶意伪造userId打卡。第二,Redis的setIfAbsent加过期时间是一个原子操作,能够有效防止并发情况下两个人同时提交导致的重复记录。第三,打卡状态的计算被单独抽成了calculateStatus方法,这样以后如果要调整考勤规则,只改这一个方法就行。
calculateStatus的代码逻辑大致是:先拿当前打卡时间判断是上班卡还是下班卡(通过和班次的startTime、endTime比较),如果是上班卡,打卡时间晚于startTime但不超过startTime+lateThreshold分钟,记为迟到,超过则记为缺卡;如果是下班卡,打卡时间早于endTime但晚于endTime-earlyThreshold分钟,记为早退。注意跨天班次要额外处理日期归属。
3.3 微信小程序端联调:从wx.login到用户信息
小程序端的登录流程是另一个高频出问题的点。很多同学照着网上教程写了一通,结果发现getUserInfo拿不到数据,或者调用后端登录接口一直报错。先说结论:微信官方已经从基础库2.21.2开始把getUserInfo接口调整为只能获取匿名信息,推荐做法是用wx.login换取code,再通过code到后端换取openid和session_key,最后用openid作为用户唯一标识。
小程序端代码的关键部分:
javascript复制wx.login({
success: async (res) => {
const code = res.code;
const response = await wx.request({
url: 'http://192.168.1.100:8080/api/auth/login',
method: 'POST',
data: { code: code }
});
const { token, userInfo } = response.data.data;
wx.setStorageSync('token', token);
// 拿到token后,再调用getUserProfile获取头像昵称,提交到后端更新用户资料
}
});
后端收到code后调用微信的jscode2session接口,这是一个HTTPS请求,参数包括appid、secret、js_code、grant_type。如果appid和secret不匹配,或者小程序后台没有配置好,接口就会返回errcode 40029(invalid code)。一个经常被忽略的坑是:secret不能直接配在前端代码里,必须放在后端,因为前端代码是可以在微信开发者工具里被反编译查看的,secret泄露之后任何人都能冒充你的小程序调用微信接口。
登录成功后,后端需要生成自己的JWT token返回给小程序端,小程序后续的所有请求都带上这个token(通常在请求头Authorization字段里)。注意JWT的过期时间建议设置7天,否则员工频繁需要重新登录,演示体验很糟糕。
3.4 管理后台的统计报表怎么出
管理后台的统计报表模块,核心是读att_summary表做聚合。这里给出一个实用的SQL示例:统计某部门某个月的出勤率。
sql复制SELECT
d.dept_name,
u.real_name,
COUNT(*) AS total_work_days,
SUM(CASE WHEN s.work_status = '正常' THEN 1 ELSE 0 END) AS normal_days,
SUM(CASE WHEN s.work_status = '迟到' THEN 1 ELSE 0 END) AS late_days,
SUM(CASE WHEN s.work_status = '早退' THEN 1 ELSE 0 END) AS early_days,
SUM(CASE WHEN s.work_status = '缺卡' THEN 1 ELSE 0 END) AS absent_days,
ROUND(SUM(CASE WHEN s.work_status = '正常' THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) AS attendance_rate
FROM att_summary s
JOIN sys_user u ON s.user_id = u.user_id
JOIN sys_department d ON u.department_id = d.dept_id
WHERE DATE_FORMAT(s.work_date, '%Y-%m') = '2025-06'
AND d.dept_id = 1
GROUP BY u.user_id, d.dept_name, u.real_name
ORDER BY attendance_rate DESC;
输出到前端时,代码用Thymeleaf模板渲染成表格,配合ECharts展示柱状图和折线图。这里有个实现技巧:把SQL查询结果直接封装成JSON字符串传到一个隐藏input,再由Thymeleaf的th:inline="javascript"赋值给ECharts的option,这样可以避免单独写一个图表数据接口,省掉不少代码量。报表页面的日期筛选器用laydate插件实现,支持按月份切换,切换时提交表单刷新当前页面,数据跟着月份变化。
4. 高频踩坑记录与排查方案
4.1 SpringBoot版本太高引起的连锁反应
前面已经强调过版本问题,但还是要单独列一个小节。我见过太多同学因为用了SpringBoot 3.x,然后遇到一串莫名其妙的问题:项目启动时ClassNotFoundException、javax.servlet包找不到、Spring Security配置失效、Redis连接池初始化失败。这些问题的根因基本都指向同一个:SpringBoot 3.x把javax换成了jakarta,同时很多老依赖不再自动配置。
如果你的项目已经用了3.x并且出问题了,有两个解决方案。第一个方案是降级到2.7.x,把pom.xml里的parent版本改成2.7.18,再把所有import javax.改成import jakarta.(如果代码里有的话),然后clean、重新导入依赖,大多数问题就消失了。第二个方案是继续用3.x,但把网上搜到的解决方案都改成适配3.x的写法,比如Spring Security的配置类改成基于SecurityFilterChain的Lambda写法,Redis连接改成Lettuce连接池配置。
对绝大多数毕设来说,我的建议都是降级到2.7.x,因为你的目标是完成毕设而不是升级依赖。版本这个东西,够用就好,等以后工作了再跟最新的技术也不迟。
4.2 小程序登录失败与合法域名配置
小程序联调时的报错花样很多,但归纳下来无非三类问题。第一类是wx.request被拦截,提示“url not in domain list”,原因是小程序官方要求所有请求域名必须是HTTPS且在后台配置过合法域名。本地开发时最简单的办法是在微信开发者工具的“详情-本地设置”里勾选“不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书”,这样就可以用http://localhost或局域网IP调试了。注意:这个选项只在开发工具里有效,真机预览时依然会校验域名,所以演示时尽量用开发者工具而不是真机。
第二类是登录时报错“invalid code”,也就是wx.login返回的code换不到openid。常见原因有:appid和secret不匹配,前端用的appid和后端配置的secret不是同一套;后端请求微信接口时参数格式不对,尤其是grant_type固定要传authorization_code;后端服务器时间和微信服务器时间相差太大导致code校验失败。一个排查技巧是先用Postman直接请求微信的jscode2session接口,把code贴进去看返回结果,这样能快速确认问题出在后端还是前端。
第三类是登录成功但获取不到用户头像昵称。基础库2.21.2之后,wx.getUserInfo不再返回真实头像昵称,必须用wx.getUserProfile并且要在用户点击按钮的回调里调用,不能一进页面就自动调用。如果你们的演示场景是员工扫码进小程序直接打卡,不需要头像昵称也是可以的,打卡记录只需要userId做关联。
4.3 Lombok与编译器的兼容性问题
代码里用了Lombok,这个插件在IDEA里的配置坑也不少。最常见的报错是“java: you aren't using a compiler supported by lombok, so lombok will not work”。
这个报错的根源是Lombok版本和JDK版本不兼容。Lombok 1.18.20及之前的版本不支持JDK 16+,如果你用的是JDK 17同时Lombok版本太低,就会出现这个问题。解决办法有两种:一是升级Lombok依赖到最新稳定版,二是降低JDK版本到8。对毕设场景,建议直接用JDK 8,一劳永逸。另外要注意IDEA里必须安装Lombok插件,同时确保在“Settings-Build-Compile-Annotation Processors”里勾选“Enable annotation processing”,否则即使代码编译通过,运行时也会报getter/setter方法找不到NoSuchMethodError。
有时候代码在命令行用mvn spring-boot:run能启动,但在IDEA里启动却报错,这个时候优先检查IDEA的编译配置和Lombok插件状态,八成是这两处没配好。
4.4 时区、编码、端口占用等环境老问题
这些基础问题看似简单,但每年都能坑到一批人。
MySQL连接报错或者查询到的日期比实际时间少8小时,基本是时区配置问题。在JDBC连接串里加上serverTimezone=Asia/Shanghai和useSSL=false,同时在MySQL服务端把default-time-zone设置为+8:00。SpringBoot连接MySQL 8.0时,驱动类要用com.mysql.cj.jdbc.Driver,如果用旧的com.mysql.jdbc.Driver会直接启动失败。
控制台输出乱码,通常是因为Windows控制台默认GBK编码,而项目统一使用UTF-8。解决办法是在IDEA的Help-Edit Custom VM Options里添加-Dfile.encoding=UTF-8,同时检查项目文件编码设置。如果用的是Windows命令行启动,执行chcp 65001切到UTF-8代码页。
端口被占用是另一个高频问题。改端口很简单,在application.yml里把server.port改成8081就行,但最好先查一下是谁占用了8080。Windows下用netstat -ano | findstr 8080,找到PID后到任务管理器结束进程。如果是在实验室电脑上演示,端口被其他同学的程序占用是常事,提前改端口能避免手忙脚乱。
5. 二次开发扩展建议:毕设答辩加分项
5.1 从“能用”到“有亮点”
一个能跑通的考勤系统只是完成了基本盘,如果想在答辩时拿高分,建议在以下方向中选一个做深做透。
第一,加入基于Redis的打卡实时统计。当前系统的考勤汇总每天凌晨生成一次,属于“T+1”模式。如果你能让管理后台的看板实时显示“当前已打卡人数/应打卡人数”,这个点就能体现出你对Redis缓存和WebSocket的理解。实现思路是:员工打卡时除了写数据库,同时更新Redis里当天部门打卡计数的hash结构,后台页面通过WebSocket订阅变更事件,实时刷新数字。
第二,接入人脸识别打卡。调用百度AI开放平台的在线人脸对比接口,员工打卡时上传一张自拍,后端把照片和该员工提前录入的人脸库照片做对比,相似度超过阈值才允许打卡。这个功能做出来很唬人,而且实现难度不大,百度AI有现成的SDK和免费额度。注意做之前先去申请应用获取API Key和Secret Key,接口调用频率限制也要提前测好。
第三,增加排班可视化。为管理员提供一个“按周/按月排班表”的拖拽式界面,排班结果实时同步给小程序端的员工。当前的排班功能基本是管理员在员工管理里直接绑定固定班次,如果改成可视化排班模块,功能完整度和答辩观感都会提升不少。后端需要新增一张schedule表,前端在小程序端增加“我的排班”页面,工作量大概在两周左右。
第四,导出考勤月报PDF。在报表页面增加一个“导出PDF”按钮,用itext或OpenPDF把月度考勤汇总数据渲染成格式规范的PDF文件。这个小功能实用性强,答辩现场演示导出时比单纯对着屏幕讲报表有说服力。
5.2 源码获取方式与使用注意事项
关于这套源码的获取方式,项目文件里已经附带了完整说明,这里简单提醒几个使用注意事项。
第一,拿到源码后不要直接改代码,先按3.1节的部署流程把项目跑起来,确认环境没问题后再开始阅读代码。第二,项目自带的管理员密码(admin/admin123)在正式演示前务必修改,避免答辩时被老师用初始密码登录系统。第三,源码里的数据库初始化脚本会自动插入一批测试数据,包含部门、员工、班次和近一个月的考勤记录,演示前最好把日期调整到当前月份,保证报表页面有数据可看。
如果你用的是非Java语言版本(PHP、Python、C#),部署方式和这里讲的SpringBoot不太一样,但数据库设计和业务逻辑是相通的。PHP版本适合学校服务器是Linux+Apache+Nginx环境的同学,Python版本适合想顺便展示脚本语言能力的场景,C#版本则可以配合Visual Studio和SQL Server使用。另外还有一个基于51单片机的考勤机扩展方案,用LCD1602显示时间和打卡结果,通过串口与后端通信,适合那些需要同时展示“硬件+软件”能力的同学。
最后再聊几句
做毕设这段时间,我最大的体会是:网上免费的开源项目多如牛毛,但很多同学拿到源码之后还是一头雾水,要么环境配不起来,要么跑起来不知道怎么改。问题不在代码本身,而在于缺少一份能讲清楚“为什么这么设计”的文档。所以这篇文章我花了大量篇幅讲技术选型的原因、业务逻辑的考虑、踩坑的排除思路,就是希望你能真正理解这套系统,而不是简单下载个源码交差了事。
如果你按着文章里的步骤操作,应该能在一个下午之内把项目完整跑起来。跑起来之后,好好读一读核心的几个类(AttendanceServiceImpl、AuthServiceImpl、ScheduleTask),搞清楚一条考勤记录从打卡到汇总的完整生命周期,再动手改一两个功能模块,变成属于你自己的项目。祝你毕设顺利。
