尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于SpringBoot的Java公司考勤系统设计与实现

基于SpringBoot的Java公司考勤系统设计与实现 又到了一年毕设季后台好多同学都在问同一个题目——基于SpringBoot的Java公司考勤系统。说实话这个题目在计算机毕设里属于经典中的经典几乎每年都会出现但它一点都不“水”。考勤系统看起来就是一个打卡、统计、请假的小工具可真正把它做成一个“企业级全流程管理平台”涉及的领域逻辑、权限设计、数据一致性、报表统计这些点几乎覆盖了一家企业级Java应用的全部核心知识点。这篇文章就围绕这个题目好好拆解一下。不管你是打算直接拿这个题目做毕设还是想借这个项目补一补SpringBoot的企业级开发经验都能从这里拿到一套可以直接落地的设计方案。我会从需求分析、数据库设计、核心流程实现、权限安全、常见坑位一直讲到答辩怎么准备全程都是实际开发中的经验和取舍逻辑。1. 项目定位与整体设计思路1.1 考勤系统到底在解决什么问题很多同学一上来就开始写代码结果写着写着发现“打卡表”和“统计报表”对不上原因就是没有先想清楚考勤系统的业务本质。考勤系统的核心痛点有三类第一企业需要准确记录员工每天的实际出勤情况包括到岗时间、离岗时间、迟到早退第二考勤规则不是固定的不同部门、不同岗位可能有不同的班次和上下班时间第三考勤结果要和请假、加班、调休这些业务流程联动最终形成每月薪资核算的依据。所以它本质上不是“一个打卡小程序”而是一个包含数据采集、规则引擎、流程审批、统计报表的完整业务系统。在毕设答辩时把这一层业务逻辑讲清楚比单纯演示“我能登录、能打卡”要有说服力得多。用户角色上也比很多同学想象的要复杂。至少需要三类角色普通员工打卡、请假、查看自己的考勤、部门主管审批、查看部门出勤情况、系统管理员排班、维护员工信息、配置考勤规则、查看全局报表。这三类角色对数据和操作权限的要求完全不一样这就天然引出了权限管理的设计需求。1.2 为什么技术栈选了 SpringBoot MyBatis-Plus MySQLSpringBoot在今天已经不是什么新东西了但选它作为毕设技术栈仍然是最稳妥的选择。原因不复杂SpringBoot把Spring家族繁琐的XML配置几乎全部替代掉了通过自动配置和起步依赖几分钟就能跑起来一个Web项目。对毕设来说你不需要花大量时间去折腾环境可以把精力集中在业务代码和系统设计上。配合SpringBoot持久层我用的一直是MyBatis-Plus而不是原生MyBatis。原因也很现实考勤系统里有大量单表CRUD操作比如员工信息维护、打卡记录查询MyBatis-Plus的BaseMapper直接内置了这些方法省掉了很多重复的XML映射编写。同时它还提供了分页插件做考勤记录的列表分页时非常方便。很多公司实际项目里也在用MyBatis-Plus所以这个选型写在简历上也不会显得业余。数据库用MySQL这个没太多悬念。MySQL对事务的支持很成熟考勤系统里打卡记录写入、审批状态更新这些操作都有强一致性的需求。而且MySQL在毕设答辩的机器上部署也简单导出SQL脚本就能完整演示整个数据库结构。提示如果你是零基础做毕设尽量不要在这个阶段引入过重的技术栈比如微服务、分布式事务、ES搜索引擎。考勤系统的业务复杂度用单体应用完全能承载把单体应用做深做透在答辩时依然能拿高分。1.3 整体功能模块与角色权限划分功能模块建议按下面的方式拆分每个模块对应清晰的业务边界。模块核心功能主要角色登录认证模块账号密码登录、验证码、权限校验所有用户员工管理模块员工信息维护、部门维护、账号绑定管理员排班管理模块班次定义、员工排班、节假日设置管理员考勤打卡模块上下班打卡、打卡记录、打卡状态实时计算普通员工请假管理模块请假申请、审批流、请假记录员工、主管加班管理模块加班申请、审批流、加班时长统计员工、主管考勤统计模块日汇总、月汇总、部门报表、异常提醒主管、管理员系统管理模块角色管理、菜单权限、操作日志管理员模块拆分时要注意一个原则每个模块尽量只做自己领域内的事。比如打卡模块只负责打卡记录的生成和状态判定不要把请假扣薪的逻辑塞进来统计报表模块负责聚合查询但它不应该直接改打卡数据。这样划分的好处是后续扩展功能时不会牵一发动全身写代码时也更容易理解和维护。2. 数据库设计与核心表结构2.1 核心表设计一张员工表如何撑起整个系统数据库设计是考勤系统最见功力的地方。我的建议是至少要设计这几张核心表员工表、部门表、班次表、排班表、打卡记录表、请假申请表、加班申请表、考勤规则配置表。员工表是整个系统的用户基础一般会包含账号、密码、姓名、手机号、邮箱、入职日期、部门ID、职位、状态等字段。这里有个细节不要把员工信息直接当登录账号用建议分开设计员工表存基本人事信息登录账号字段也放在员工表里面并设置唯一约束这样一套表结构就能支撑登录和人事两个场景。部门表比较简单但要注意支持树形结构。有些公司有二级部门、三级部门如果只设计成单层后面做部门考勤汇总时会非常痛苦。我习惯用一个parent_id字段实现自关联配合注释说明层级关系。班次表是很多同学容易忽略的。考勤系统里“上班时间”不应该是写死在代码里的常量而是数据库中可配置的数据。班次表至少要包含班次名称、上班时间、下班时间、午休开始时间、午休结束时间、迟到阈值分钟、早退阈值分钟、是否跨天。跨天这个字段很重要有些班次是晚班晚上十点上班第二天早上六点下班如果没有跨天标识计算下班时间时就会出大问题。2.2 考勤规则怎么落进数据库“考勤规则”这个词听着抽象落进数据库其实就是一张规则配置表。我建议单独建一张attendance_rule表用来存公司级或部门级的通用考勤参数例如月度统计周期自然月还是自定义周期、旷工判定标准、迟到多少次算旷工、每月允许的补卡次数、补卡审批是否需要主管确认等。这些规则如果写死在代码里每次调整都要重新发版。而考勤规则在企业里是经常变化的比如公司把上班时间从九点改成九点半、迟到多少分钟以内不算迟到等。把这些参数通过管理后台做成可配置项不仅代码更优雅答辩时也是一个很好的功能亮点——“我们的考勤规则支持热更新不需要改代码”。规则表和员工表的关联也要想清楚。最简单的方案是公司只有一个统一规则规则表只有一行数据但更合理的是支持“部门级规则覆盖”也就是员工表或部门表里加一个rule_id字段查询时优先取员工绑定规则没有绑定则取默认规则。这样既灵活又不至于过度设计。2.3 关键索引与数据一致性设计考勤记录表的数据量增长很快一个月下来可能就是几万行索引设计不好后面查询很容易慢。打卡记录表里最常见的查询条件组合是员工ID 日期范围 状态。所以我建议在这个表上建一个联合索引比如(employee_id, clock_date)再把状态字段作为辅助条件。如果是MySQL 8.0可以直接用函数索引或覆盖索引优化统计查询。数据一致性方面最容易出问题的是打卡记录表。同一个员工同一班次不应该有两条重复的打卡记录这个约束要靠唯一索引兜底。比如建立(employee_id, attendance_date, shift_id)的联合唯一索引数据库层面直接杜绝重复数据。很多同学只在代码里做判断这是不够的并发场景下两次请求同时进来代码判断挡不住必须靠数据库约束保证。事务方面也要特别注意。请假审批通过后要同步更新考勤月度汇总表这个操作必须放在同一个事务里。还有删除部门时如果有员工还挂在部门下面应该给出友好提示而不是直接外键报错。这些细节都是答辩时老师会盯着看的点。3. 核心流程实现与关键代码思路3.1 打卡流程一次打卡请求背后发生了什么打卡是整个系统使用频率最高的操作也是最容易出bug的地方。一次打卡请求到达后端需要经过这几个步骤第一步是参数校验。前端传到后端的数据至少包含员工ID、打卡类型上班/下班、打卡时间。时间到底以哪个为准有讲究如果直接信任客户端时间员工把手机时间一改就能作弊所以最稳妥的做法是后端以服务器当前时间作为实际打卡时间前端传的时间只做展示参考。第二步是查询这个员工当天有没有排班。没有排班就直接提示“今日无需打卡”。有排班的话再查询是否已经有打卡记录根据打卡类型判断是第一次打卡还是重复打卡重复打卡要给出友好提示。第三步是写入打卡记录并实时计算打卡状态。打卡状态一般有五种正常、迟到、早退、缺卡、异常。状态计算规则是上班打卡时间晚于上班时间加上迟到阈值算迟到下班打卡时间早于下班时间减去早退阈值算早退只打了上班卡没有下班卡当天先记为缺卡。这里我强烈建议“先落库再计算”也就是先把原始打卡记录保存下来然后通过一个状态机或策略类去计算状态而不是在保存前做一堆if else。原因后面会讲。核心代码结构上建议把“状态计算”单独抽成一个类比如AttendanceStatusCalculator里面根据班次、打卡时间、规则参数计算出状态。这样不同班次类型的判定逻辑可以独立扩展而不是堆在一个Service方法里。3.2 考勤统计的三层计算逻辑考勤统计是答辩时必然会问到的模块也是最容易暴露问题的地方。统计逻辑我习惯分成三层来算。第一层是异常状态补全。每天定时任务跑一遍把昨天缺卡的记录找出来看有没有人忘记打下班卡或者只有下班卡没有上班卡统一标记为异常状态。这个定时任务用SpringBoot自带的Scheduled就能实现每天凌晨跑一次。第二层是日汇总。根据打卡记录和请假记录生成每个员工每天的一条汇总数据包括出勤状态、迟到次数、早退次数、请假小时数、加班小时数等。为什么要单独生成一张汇总表而不是每次查询时实时计算因为实时计算在大数据量下性能太差而且每天的汇总结果其实变化不大没必要反复算。第三层是月汇总。月底跑一个Job把当月所有日汇总数据聚合成月度数据作为薪资核算的依据。月汇总结果建议单独落表比如attendance_monthly_summary保存员工ID、月份、出勤天数、迟到次数、请假时长、加班时长等字段。这样人力资源导出工资数据时一条SQL就能拿到结果不需要实时扫描几万条原始打卡记录。聚合查询时注意SQL的性能。月汇总如果直接用SQL的GROUP BY去扫描打卡记录表数据量大了之后会非常慢。有了日汇总表做中间层月汇总只需要扫描30行日汇总数据效率完全不在一个量级。3.3 审批流怎么设计才不复杂请假和加班审批是企业考勤系统里流程味道最重的模块。如果为了“显得高级”引入Activiti或Flowable工作流引擎我只能说毕设没必要这么折腾。工作流引擎的学习成本很高而且考勤审批流本质上是单级或多级审批用一张表加一个状态字段完全能搞定。审批表的设计建议settled一个通用方案申请单主表请假单/加班单 审批记录表。主表存申请人、申请类型、开始时间、结束时间、时长、事由、当前状态、当前审批人审批记录表存审批人、审批意见、审批时间、审批结果。这样设计的好处是任何一级审批的历史记录都能追溯打印审批流信息时也很直观。状态字段用整数或字符串常量表示比如0待审批、1已通过、2已驳回、3已撤销。每次审批操作就是一个简单的Update语句把状态从“待审批”改成“驳回”或“通过”同时插入一条审批记录。这里要注意并发问题两个主管同时审批同一个单子时可能出现状态覆盖。最简单的解决方案就是UPDATE语句带上条件WHERE status 0如果更新的行数为0说明已经被别人处理过了直接提示“该申请单已被处理”。4. 权限控制与安全设计4.1 Shiro还是Spring Security毕设怎么选权限控制是考勤系统绕不开的模块也是毕设评审老师重点关注的地方。很多同学纠结选Shiro还是Spring Security我直接说结论如果是自己从零搭建建议Apache Shiro如果项目里已经用了Spring Security相关的Spring Cloud生态组件那就顺着用Spring Security。为什么推荐Shiro因为Shiro的API设计更直观认证和授权两个核心概念非常清晰。写一个自定义Realmoverride三个方法认证、授权、会话就能完成登录校验和角色权限控制。对毕设来说理解和答辩都很友好。Spring Security功能更强大但它的过滤器链机制对新手来说学习曲线比较陡配置不好可能出现“登录成功后请求仍被拦截”这种让人崩溃的问题。权限模型用RBAC基于角色的访问控制就够了。五张表用户表、角色表、菜单表、用户角色关联表、角色菜单关联表。登录时把用户的角色和权限码查出来放进Session或Redis然后在Controller层用注解比如RequiresPermissions(attendance:export)来拦截没有权限的操作。这个模型简单、经典、面试时也拿得出手。4.2 密码加密与接口防刷这些细节不能省安全方面的细节哪怕做的是毕设也不能稀里糊涂。第一个就是密码存储绝对不能用明文也不能用简单的MD5因为MD5已经被彩虹表破解得很彻底了。Spring Security自带BCryptPasswordEncoderShiro也可以配合使用BCrypt。BCrypt的特点是每次加密结果不同但校验时能验证是否匹配而且自带盐值安全性远高于MD5加固定盐的方案。第二个是登录验证码。考勤系统一般部署在内网但登录接口仍然需要防暴力破解。简单的做法是引入一个验证码生成工具比如Hutool的CaptchaUtil登录时生成验证码图片存到Session或Redis提交时校验。同时做一个简单的登录失败次数限制连续失败5次就锁定账号15分钟防止恶意尝试。第三个是接口层面的防刷。打卡操作不需要太复杂的防刷策略但要考虑幂等性。一个最简单的方案是前端按钮点击后立即置灰后端配合数据库唯一索引。如果是移动端打卡或者外勤打卡可以再配合时间戳参数做一次简单的防重校验。5. 前端页面与交互设计5.1 页面框架选择VueElement UI还是Thymeleaf前端方案上毕设一般就两条路服务端渲染的Thymeleaf模板或者前后端分离的VueElement UI。如果你对前端的定位是“能展示功能就行”Thymeleaf足够了。它可以直接在HTML里写Java语法开发速度非常快不用处理跨域、token传递这些问题。SpringBoot整合Thymeleaf也极其简单加一个依赖、在templates目录下放HTML文件就行。如果想把项目做成前后端分离用Vue3 Element Plus Axios是比较成熟的组合。前端一套独立工程通过Axios调用后端接口配合Vue Router做页面路由Vuex/Pinia做状态管理。前后端分离在答辩时的展示效果会更好因为页面观感明显更现代交互也更流畅。代价是需要额外处理跨域配置和登录token传递。我的建议是如果你对前端不熟选Thymeleaf把精力全部放在后端业务上如果你前端本身就有基础选VueElement Plus项目完整度和美观度会高一个档次。考勤系统这种后台管理类项目用Element Plus做出来的表格、表单、日期选择器非常贴合场景基本不用怎么写CSS。5.2 数据可视化报表怎么做考勤统计结果如果只用表格展示low了点。加几张可视化图表答辩时效果立刻不一样。前端图表库主推ECharts功能强大、中文文档齐全、开箱即用。可以做三张核心图表第一张是月度出勤趋势图用折线图展示每天应出勤人数、实际出勤人数、迟到人数、请假人数的曲线变化第二张是各班组出勤率对比图用柱状图横向比较不同部门或班组的出勤率第三张是异常类型分布图用饼图展示迟到、早退、缺卡、异常的比例。图表的数据来源后端要提供一个聚合接口比如GET /api/report/monthly返回一个月内的每日汇总数据。这个接口内部建议走日汇总表而不是原始打卡记录表否则一次性查几万条记录再聚合接口响应时间会很难看。返回结构可以按日期分组组装成一个Map或List前端拿到数据后直接交给ECharts渲染。6. 常见问题与排查技巧实录6.1 时间处理时区与跨天问题考勤系统的时间问题绝对是踩坑重灾区。最常见的一个坑是服务器部署在国外时区或者云服务器默认时区不是Asia/Shanghai导致打卡时间全部错乱明明9点上班被记成3点。解决办法是统一时区。首先在数据库连接URL上加serverTimezoneAsia/Shanghai让JDBC连接使用指定时区其次在SpringBoot的application.yml里设置spring.jackson.time-zone: GMT8保证JSON序列化时时间正确最后在启动类上加上PostConstruct方法设置默认时区或者直接在JVM参数里加-Duser.timezoneAsia/Shanghai。三层都设置一遍基本就能消除时区问题。跨天班次是另一个大坑。比如晚班22:00到第二天06:00如果只记录一个日期统计时就会因为日期错位导致上下班时间对不上。我建议打卡记录表里同时设计“班次日期”和“实际打卡时间”两个概念。班次日期指这班对应的工作日比如晚班从6月1日22点上到6月2日6点班次日期是6月1日。统计时统一按班次日期汇总就不会出现数据被切到两天导致的下班时间缺失问题。6.2 并发打卡与重复提交一个经常被问到的场景员工同一个班次连续点了两次“上班打卡”结果生成了两条打卡记录。解决思路有两层第一层是业务判断查询当天该员工该班次是否已有上班记录有就直接提示“今日已打卡”但这里存在并发竞态两个请求同时进来时业务判断可能同时通过依然会插入两条数据。因此必须在数据层面兜底。最简单有效的方法就是前面说的唯一索引在打卡记录表上给(employee_id, attendance_date, shift_id, clock_type)建联合唯一索引。这样即便代码里判断漏了数据库也会拒绝第二次插入并抛出DuplicateKeyException捕获后转成友好提示即可。讲清楚这两层思路基本就能证明你具备生产环境的开发意识。6.3 懒加载与JSON序列化的问题MyBatis-Plus的关联查询如果配置了懒加载或者JPA/Hibernate项目里用到ManyToOne懒加载那么在Controller层直接把实体对象转成JSON返回时很容易报出LazyInitializationException或fastjson的序列化错误。原因是事务已经关闭会话外的懒加载无法触发。解决办法有几个最简单的就是实体转VO/DTO只查询需要返回的字段不让JPA去懒加载关联对象另外一个是在事务中完成数据组装比如Service层把所有需要的数据查好并封装把组装后的对象返回给Controller避免在Controller层再触发懒加载如果是Jackson序列化导致的死循环双向关联可以配置JsonIgnoreProperties或使用DTO。这个坑几乎每个做SpringBoot项目的人都会遇到提前踩了就知道怎么处理。6.4 部署和运行环境的隐藏问题本地运行好好的部署到服务器或者换一台电脑就崩了这类问题大多是环境差异导致的。最常见的有三个版本不对SpringBoot 3.x对应JDK 17如果本机是JDK 8pom.xml里引入了SpringBoot 3.0以上的依赖启动时直接报ClassNotFound数据库字符集不对建库时没指定utf8mb4插入中文变成问号或报错端口被占用8080被其他程序占用导致启动失败。我的建议是pom.xml里显式指定SpringBoot版本和JDK版本数据库建库语句统一用utf8mb4字符集启动遇到端口冲突时先排查占用进程。另外把所有配置项都收敛到application.yml中并且写好注释这样换环境时只需要改配置文件不用改代码。7. 扩展方向与答辩准备7.1 可以加分的可选扩展点如果你的毕设时间比较充足想在基础功能之外加一些亮点可以考虑下面几个方向。第一个是引入Redis做缓存。比如把班次规则、考勤规则配置缓存到Redis查询打卡状态时先走缓存再查数据库把登录用户的Session信息放到Redis中实现分布式会话管理。SpringBoot整合Redis非常简单加一个spring-boot-starter-data-redis依赖就行。这一项就能在答辩时带出“缓存穿透”“缓存一致性”等可以聊的点。第二个是引入消息队列比如RabbitMQ或RocketMQ。考勤统计如果允许异步化可以这样设计打卡成功之后发送一条MQ消息消费者接收后异步更新日汇总和月汇总。这样打卡接口的响应速度会很快因为耗时统计被异步任务承接了。不过这一点对单体考勤系统来说有点“杀鸡用牛刀”更适合作为职业规划聊。第三个是Docker化部署。写一个Dockerfile用docker-compose一键启动SpringBoot应用和MySQL容器再配合Nginx做反向代理。这块内容能体现你对现代部署方式的理解虽然不是核心业务逻辑但面试时很加分。7.2 答辩高频问题怎么准备答辩官最常问的几个问题提前准备好现场就不慌。第一个是“你为什么用这个技术栈”不要只回答“大家都用SpringBoot”要从自动配置、生态成熟、快速开发、适合中小型业务系统这几个维度展开最好能加一句“和SSM相比SpringBoot大幅减少了配置文件让我能把更多时间用在业务逻辑设计上”。第二个是“考勤系统的核心难点是什么”可以说异动数据的处理和状态计算。比如迟到早退判定规则多、排班跨天、请假加班和考勤结果的联动每一项都能展开讲具体实现方案。第三个是“如果打卡量暴增比如几万人同时打卡系统怎么优化”这个问题考察你的系统设计能力。可以从几个层面回答数据库层面加索引、读写分离、分表应用层面加缓存、异步写入、消息队列削峰部署层面横向扩容、负载均衡。不需要真的实现能讲清楚方案就够。第四个是“权限控制怎么实现的”讲清RBAC模型、Shiro的认证授权流程、密码加密方式再补充一下接口防刷策略基本就是满分答案。7.3 代码规范和文档沉淀很重要毕设不只是写代码代码规范和文档同样是评分点。Git仓库里建议按模块提交代码commit message写清楚本次改动比如“feat: 完成打卡状态计算逻辑”“fix: 修复跨天班次统计错误”。答辩之前把README文档写好内容包括项目介绍、技术架构、功能清单、部署步骤、演示账号。接口文档用Swagger生成Controller方法写好Api和ApiOperation注解这样启动项目后访问/swagger-ui.html就能在线查看接口文档。这些细节会让答辩老师觉得你的工程化素养很好而不只是“能跑就行”。我个人在做这类项目复盘时有个习惯把每一步踩过的坑单独记在一个文档里从数据库时间差、Tomcat版本导致的启动报错到跨域配置漏了、懒加载序列化失败全部记下来。到最后这些坑就成了自己最有价值的经验沉淀也是写简历时“项目难点”一栏的最好素材。考勤系统这个题目做出来不难做得好需要下功夫。只要把业务逻辑梳理透、数据库设计合理、核心流程实现扎实再配上几个说得清的扩展点它完全能成为一份高质量的毕设作品。
返回列表