
每年到了毕业设计选题季总有人私信我“智能HR管理系统的设计与实现源码拿到了但是打开工程完全不知道从哪儿看起答辩的时候老师问数据库怎么设计也答不上来。”这种情况我见得太多了。这套编号 07447 的项目我前后拆过两遍也照着它的思路自己重写过一版今天干脆把整个分析过程公开出来从需求边界怎么划、表结构怎么建到考勤打卡和薪资计算的核心代码、前端驾驶舱怎么画再到“智能”到底落在哪几个功能上一次讲清楚。如果你正在做同款题目或者只是想要一套可以直接改造成自己项目的骨架这篇文章就是你的避坑地图。1. 为什么说这个题目其实是在考“分层设计”能力1.1 HR系统的真实业务流比你想的更宽很多同学拿到“智能HR管理系统”这个题目第一反应就是做员工增删改查加一张工资表做完发现撑不到答辩。实际上HR系统是企业级OA里最完整的业务闭环之一它至少横跨五个子域组织人事、考勤假勤、薪酬核算、招聘面试、系统权限。每个子域之间还有数据联动比如考勤结果影响薪资请假审批状态影响考勤统计招聘环节关联岗位编制这些联动才是这个题目的真正难度所在。所以拿到源码的第一步别急着去跑npm install先把业务流画出来。以我拆这套源码的经验来看它默认的业务主线是员工入职后分配账号和岗位日常通过打卡产生考勤记录考勤汇总后参与薪资计算同时HR可以在招聘模块发布职位、筛选简历、安排面试、发放offer。这条主线覆盖了HR日常的高频操作也自然形成了项目里的模块边界。1.2 “智能”不是玄学而是三个可落地的具体功能标题里最容易被误解的词就是“智能”。在答辩时老师最常问的一句话就是“你这个系统哪里智能了”如果你回答“系统能自动计算工资”这就是典型的自己给自己挖坑因为自动计算公式属于基本功能不叫智能。这套源码里的“智能”主要体现在三个方面一是智能考勤比如打卡时自动记录定位和时间根据上班时间窗口自动判断迟到早退二是智能排班根据员工业余时间和岗位需求自动生成排班表三是离职预警分析通过考勤频率、请假次数、绩效分数等维度给员工打一个流失风险分数。这三个点都是从业务场景里长出来的不是硬贴上去的人工智能概念答辩的时候也更容易自圆其说。1.3 需求优先级排序什么功能先做什么功能最后做我拆这套源码时把功能分成三个优先级。P0是系统基础包括登录认证、部门管理、员工管理、角色权限P1是业务核心包括考勤打卡、请假审批、薪资管理、招聘流程P2是加分项包括数据驾驶舱、离职预警、智能排班和Excel导入导出。这套顺序很合理因为P0决定系统能不能用P1决定系统好不好用P2决定答辩有没有亮点。如果你是自己从零开发也建议严格按照这个顺序推进不要一上来就做图表。2. 技术选型Spring Boot 3 Vue 3 MySQL 8 为什么能顶住这套需求2.1 为什么不是SSM也不是Python后端如果你看过市面上的毕业设计源码会发现“Spring Boot Vue”已经成了事实标准。这套07447同样用的是这个组合后端Spring Boot 3前端Vue 3数据库MySQL 8。很多同学会纠结学校老师教的是SSM那我要不要用SSM我的建议是别。SSM的配置繁琐度放在今天已经没有必要了Spring Boot的自动配置和起步依赖能把项目启动成本降到极低而且Spring Boot 3自带对Jakarta命名空间的支持代码更干净。那为什么不选Python写后端Python在算法验证和数据处理上有优势但你这个项目的核心是人事实务逻辑事务、权限、并发这些能力Java生态更成熟。更重要的是招投标和答辩场景下Java后端更容易被评审老师接受网上可参考的同类源码也更多。如果你真想用Python做“智能”合理的架构是把Python写成一个独立算法服务通过HTTP接口暴露给Spring Boot调用但这套源码没有这么做它把智能算法直接用Java实现了好处是部署简单、一个包搞定坏处是算法复杂度上不去。对于毕设规模这个取舍是明智的。2.2 前端为什么选Vue 3 Element Plus前端部分源码用的是Vue 3配合Element Plus组件库状态管理用PiniaHTTP请求用Axios图表用ECharts。Element Plus的好处不用多说表格、表单、弹窗、分页这些管理后台的标配组件都有现成的能省掉大量样式工作量。Vue 3的组合式API写起来比Vue 2的选项式更紧凑而且这套源码里的页面组件基本都用了script setup写法代码行数明显更少对新手也更友好。这里我要多说一句前端不是越花哨越好。你打开这套源码会发现它没有用各种花里胡哨的动画库页面就是经典的后台布局——左侧菜单、顶部导航、右侧内容区。这个选择很务实因为HR系统是工具型产品用户每天要高频操作界面必须清晰、稳定、响应快。答辩时老师问你为什么这么设计你可以回答管理系统以效率优先视觉上要降低信息噪音。2.3 中间件和工具库的选型清单除了前后端主框架我再把源码里涉及的中间件和工具库列一下方便你对照检查环境。MyBatis-Plus负责数据库操作它比原生MyBatis省去了大量XML配置分页查询和逻辑删除都是现成能力Redis在源码里负责存储登录令牌和验证码Hutool提供加密、日期处理和随机数生成等工具函数JWT负责登录状态的无状态校验。这些工具都不是冷门技术任何一个单独拎出来都能在答辩时展开讲讲“为什么选它”。另外开发环境上要注意JDK版本和Node版本。Spring Boot 3要求JDK 17以上Vue 3的构建工具Vite也要求Node.js 16以上。很多人拿到源码跑不起来第一步就错在环境版本太老等会儿第七节我会详细说运行步骤。3. 数据库建模从用户表到薪资明细的字段级设计3.1 核心表拆分与职责边界这套源码的数据库一共有12张表左右我不建议你再往多了加表太多会让答辩变成灾难表太少又兜不住业务。核心表可以分成四组组织架构组部门表、职位表、人员账号组用户表、员工表、考勤薪酬组考勤表、请假表、薪资表、薪资明细表、招聘流程组招聘职位表、简历表、面试记录表、Offer表。这里最关键的设计是用户表和员工表分开。用户表存储登录账号、密码、角色、状态员工表存储姓名、工号、部门、职位、入职日期、基础工资等业务属性。为什么分开因为逻辑上一个用户对应一个员工但HR系统里还存在用户未绑定员工、员工未开通账号的中间状态拆开之后账号系统和人事系统的独立性都更强。这个设计思路是你答辩时值得重点讲的一个点。3.2 考勤、请假、薪资三张表的联动逻辑三张表的联动是这套数据库设计里最有含金量的部分。考勤表attendance记录每个人每天的打卡明细字段包括员工ID、打卡日期、上班打卡时间、下班打卡时间、打卡类型、状态、经纬度、打卡照片URL。请假表leave记录请假申请字段包括员工ID、请假类型、开始时间、结束时间、审批状态、审批人ID。薪资表salary记录每个员工每月工资汇总字段包括员工ID、年月、应发工资、实发工资、社保、公积金、个税、发放状态。联动逻辑是这样的月底系统根据考勤表统计迟到、早退、缺勤天数再扣减请假表里已批准的请假时长最后算出应扣款项叠加到薪资计算里。这套源码里的薪资计算并不是简单的“基本工资 岗位工资”而是会读取考勤统计结果这一点很多同类项目都没有做到属于真正的业务闭环。我把主要表结构整理成一个速查表方便你对照源码里的建表脚本表名关键字段用途sys_userid, username, password, role_id, status登录账号与权限employeeid, user_id, dept_id, position_id, name, base_salary, hire_date员工档案与薪资基数departmentid, name, parent_id, manager_id组织架构树attendanceid, employee_id, work_date, clock_in, clock_out, status, address每日考勤明细leaveid, employee_id, type, start_time, end_time, status, approver_id请假审批salaryid, employee_id, month, gross_salary, net_salary, status月度薪资汇总resumeid, employee_id, name, phone, education, skill_tags, match_score招聘简历3.3 权限表设计RBAC还是直接写死角色我看过很多毕设源码权限设计就两种路子一种是真的做了用户-角色-菜单三张关联表另一种是在用户表里直接放一个角色字段。这套源码用的是后者角色字段直接控制前端路由和后端接口权限。说实话对于单管理端、用户量几十人的HR系统直接角色字段完全够用代码量还少业务上也容易理解。但你要做好被老师追问的准备“如果一个人既要管考勤又要管薪资你怎么办”正确回答是角色字段支持多个角色ID的存储后端在鉴权时判断是否包含目标角色前端根据角色列表动态生成菜单。这本质上是一种简化版RBAC既保留了扩展空间又不至于把联表查询搞得太复杂。如果你时间充裕可以把它升级成标准的三表RBAC工作量多半天左右含金量立刻不一样。4. 后端核心逻辑认证、考勤打卡与薪资计算怎么落地4.1 JWT认证从登录到接口鉴权的完整链路后端第一个要讲透的就是认证。这套源码的登录流程是用户提交用户名和密码后端校验通过后生成一个JWT令牌返回前端把令牌存入localStorage之后每次请求都把它放在请求头Authorization里。后端用一个拦截器统一解析令牌解析成功就把用户ID放到请求上下文里后续接口直接用CurrentUser.getId()拿到当前登录人。我摘一段它的核心逻辑思路你不需要照抄但要理解这个套路// 登录成功后生成token String token JWT.create() .withClaim(userId, user.getId()) .withClaim(roleId, user.getRoleId()) .withExpiresAt(DateUtil.offsetHour(new Date(), 24)) .sign(Algorithm.HMAC256(secretKey));// 拦截器里解析token放入ThreadLocal String token request.getHeader(Authorization); if (StrUtil.isNotBlank(token)) { DecodedJWT jwt JWTVerifier.require(Algorithm.HMAC256(secretKey)).build().verify(token); Long userId jwt.getClaim(userId).asLong(); UserContext.set(userId); }为什么用JWT而不是Session因为HR系统将来很可能要拆成前后端分离部署JWT天生适合这种无状态场景。你不用在Redis里存每个用户的会话数据服务端只负责验签。当然代价是令牌失效比较被动所以源码里给JWT设置了24小时过期时间并在前端拦截请求状态码为401时自动跳回登录页。4.2 考勤打卡接口时间窗口和位置校验考勤打卡是HR系统里最容易出细节问题的模块。源码里的设计很值得学习它不是简单记录一个时间点而是把打卡分成上班打卡和下班打卡两种类型后端通过配置的上下班时间窗口自动计算状态。比如你设定上午9点为上班时间那么在9点前打卡状态是“正常”9点零1分到11点之间是“迟到”超过11点仍未打卡就是“缺勤”。打卡接口的数据模型大致如下PostMapping(/clock) public Result clock(RequestBody ClockDTO dto) { if (attendanceService.hasClockToday(dto.getEmployeeId(), dto.getType())) { return Result.error(今日该时段已打卡请勿重复操作); } Attendance record new Attendance(); record.setEmployeeId(dto.getEmployeeId()); record.setWorkDate(LocalDate.now()); record.setClockTime(LocalDateTime.now()); record.setLatitude(dto.getLatitude()); record.setLongitude(dto.getLongitude()); record.setAddress(dto.getAddress()); record.setType(dto.getType()); // 0 上班1 下班 attendanceService.handleStatus(record); // 根据时间窗口判定状态 attendanceService.save(record); return Result.success(record); }这里有一个非常容易被忽略的坑重复打卡校验。如果没有做hasClockToday判断用户疯狂点按钮就会生成几十条打卡记录月底统计数据直接爆炸。这套源码用“员工ID 打卡日期 打卡类型”做了唯一性检查这个小细节你务必保留。另外它还记录了经纬度和地址这在答辩时就是“移动考勤防作弊”的亮点讲起来非常有说服力。4.3 薪资计算为什么必须用BigDecimal薪资模块是HR系统的技术分水岭。新手写薪资计算往往直接用double然后发现算出来的实发工资带了一串小数。这套源码在这里处理得比较规范所有涉及钱的地方一律用BigDecimal。薪资计算可以抽象成下面这个流程BigDecimal base employee.getBaseSalary(); // 基础工资 BigDecimal post employee.getPostSalary(); // 岗位工资 BigDecimal overtime calcOvertime(empId, month); // 加班费时薪 * 加班时长 * 1.5 BigDecimal deduction calcAbsenceDeduction(empId, month); // 缺勤扣款日薪 * 缺勤天数 BigDecimal socialSecurity calcSocialSecurity(base); // 社保个人缴纳比例 BigDecimal gross base.add(post).add(overtime).subtract(deduction); BigDecimal net gross.subtract(socialSecurity).setScale(2, RoundingMode.HALF_UP);简单解释一下这里的业务口径加班费是按基本工资折算时薪后乘以1.5倍一个月法定计薪天数是21.75天每天8小时所以时薪等于基本工资 / 21.75 / 8。缺勤扣款则是基本工资 / 21.75 * 缺勤天数。这些口径你最好在答辩前背下来属于人力资源领域的常识老师说“你这个扣款怎么算的”时你能答出完整公式印象分直接拉满。4.4 统一返回结果和全局异常处理最后补一个后端工程化的细节。这套源码里的接口返回值不是裸数据而是统一用Result对象包装里面包含code、message、data三个字段。前端在 Axios 响应拦截器里统一判断code是否为200不是就直接弹错误提示。这样做的好处是所有接口的风格一致前端处理逻辑统一不会出现一个接口返回字符串、另一个接口返回JSON对象的混乱局面。全局异常处理也是同样道理。用一个RestControllerAdvice捕获业务异常和未知异常业务异常返回“考勤记录不存在”“权限不足”“薪资已发放不能重复操作”这类可读信息未知异常统一返回“系统繁忙请稍后重试”。这段代码工作量不大但是对于系统健壮性的提升非常明显而且也是答辩时老师喜欢考察的点。5. 前端页面与交互登录鉴权、打卡日历和数据驾驶舱5.1 路由守卫和权限控制是怎么配合的前端不是单纯把接口渲染成表格就完了一个合格的管理系统前端必须解决“谁能看到什么页面”的问题。这套源码采用的方式是登录接口返回用户信息和角色信息前端根据角色动态生成左侧菜单同时路由守卫判断localStorage里有没有token没有就直接跳转登录页。路由守卫的代码大家应该都很熟了我提醒你一个容易踩的坑不要只在路由守卫里判断token存不存在还要判断token是否真正有效。写法是每次请求遇到401时清除本地token并跳回登录页。这套源码就是走这个方案既不用每次进页面都调一次验证接口又能保证过期令牌第一时间被清掉。5.2 考勤日历的设计从打卡记录到月度视图考勤页面是这个项目的门面。源码里的考勤模块分两个视图一个是员工本人视角今天打卡状态、本月出勤天数、迟到次数一目了然另一个是管理员视角按月查询团队考勤还能一键导出统计表。员工视角里最有意思的交互是打卡按钮。按钮会根据当前时间动态显示“上班打卡”或“下班打卡”点击后调用navigator.geolocation.getCurrentPosition获取经纬度和图片一起提交给后端。前端拿到打卡成功结果后刷新当天的状态卡片。这个交互不复杂但它是“智能考勤”的最直观体现演示时一定要现场操作一遍。管理员视角的考勤日历用的是ECharts日历图按日期着色绿色代表正常、橙色代表迟到、红色代表缺勤。日历图的好处是信息密度高一眼能看到全月情况这在答辩演示时非常抓眼球。图表配置本身不复杂核心是把后端返回的考勤日期列表转换为图表所需的[日期, 状态]数组格式。5.3 数据驾驶舱几张图把项目档次拉起来很多同类项目会把数据驾驶舱做成一个摆设页面但源码里这一块做得还不错。驾驶舱包含四个核心指标卡片和三个图表员工总数、本月入职人数、本月离职人数、考勤异常次数作为顶部指标卡部门人数分布用柱状图学历结构用饼图近六个月入职趋势用折线图。数据全部从后端一个聚合接口返回前端只负责渲染。这个页面强烈建议你保留因为它是“系统有数据可视化能力”的直接证据。答辩的时候老师只要一打开驾驶舱就会觉得这个项目完成度高。你不用把图表堆得越多越好几张图能讲清楚业务就够了。我见过有人做了十几个图表结果自己都讲不清每个图的意义反而扣分。6. “智能”到底落在哪里离职预警、简历初筛和自动排班6.1 离职预警不用机器学习也能做出预测效果离职预警是这套源码里最像“智能”的功能但用的方法却非常朴素这正好能帮你打消“AI很难”的顾虑。它的思路是给每个员工算一个流失风险分分数由四个指标加权求和当月迟到次数权重0.2、当月请假次数权重0.2、连续三个月绩效低于阈值的次数权重0.3、最近一个月登录系统频次权重0.3。得分超过预设阈值系统就在预警列表里标红。为什么不用机器学习因为毕设项目里根本没有历史离职数据可以用来训练模型。用加权评分至少具备两个优势一是规则透明分数可解释每一分都能说清楚是从哪条考勤记录来的二是算得快十几行代码就能实现。这个思路非常重要——当你的项目规模不够支撑大数据模型时用业务规则去模拟智能远比硬套一个模型更实用。6.2 简历智能初筛关键词匹配加匹配度排序招聘模块里源码把“智能”落在简历初筛上。HR导入或投递进来的简历系统会提取学历、工作年限、技能关键词和当前招聘职位的JD要求做匹配最后生成一个0到100的匹配度分数并按分数从高到低排序。具体实现上它维护了一个技能词库比如Java、Spring、Vue、MySQL、Python简历文本里每命中一个技能关键词就给10分学历达到本科加20分工作年限不低于岗位要求加20分最后再根据简历长度做一点归一化处理。这个方法简单粗暴但演示效果非常好HR发一个岗位系统自动把最匹配的简历排在最前面这就是评委眼中的“智能筛选”。6.3 自动排班贪心算法怎么处理班次冲突自动排班是源码里算法含量最高的模块。它以周为单位输入是员工可用时间段和每天的岗位最小人数需求输出是一张满足约束的排班表。源码采用贪心策略先把岗位缺口最大的时段排满每次安排员工时优先选择当天排班次数最少的人从而让工作量尽量均衡。我建议你在理解这套算法时把它当作一个“带约束问题的解”来讲而不是背代码。核心思想就两句第一优先满足最紧张的需求第二每个员工之间的工作量差异要尽量小。答辩时老师如果问你“会不会出现有人一周上7天班、有人一天都没有”的情况你就回答排班完成后会做均衡性校验超过连续上班天数上限的会触发重新分配这就是系统的智能兜底。7. 源码工程结构、部署启动与复现路径7.1 工程目录结构前后端分离的典型布局拿到源码包后你会看到它被清楚地分成backend和frontend两个目录外加一个sql目录存放初始化脚本。后端是标准的Maven工程包结构为controller/service/mapper/entity/config前端是Vite创建的标准Vue项目源码在src/views下按业务模块分子目录包括dashboard、attendance、salary、recruitment、system。我觉得最有参考价值的是它的后端controller层非常薄每个Controller基本只做参数接收和结果返回业务逻辑都写在service实现里。这个习惯一定要学否则你的Controller里几百行代码后面想做单元测试都无从下手。7.2 运行环境一个表格解决版本匹配问题我见过太多卡在环境上的情况直接把版本要求列成表按这个清单准备基本不会出错组件版本要求注意事项JDK17及以上Spring Boot 3必须8跑不起来MySQL8.05.7部分语法不兼容Redis5.0默认端口6379需启动服务Node.js16.0低于14时Vite构建报错Maven3.6用于后端依赖管理和启动7.3 关键配置application.yml里最容易改错的地方运行前最需要修改的是后端application.yml。我注意到来咨询的人中十有八九是数据库密码没改对或者Redis没启动导致登录接口直接报连接超时。源码里的配置结构大概是这样server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/hr_system?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai username: root password: yourpassword redis: host: localhost port: 6379 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl这里有两个细节值得注意第一个是数据库连接串里的serverTimezoneAsia/Shanghai如果漏掉MySQL 8会报时区错误第二个是characterEncodingutf8mb4如果写成utf8存不了特殊字符而且有可能出现乱码。这两处都是高频踩坑点启动前先核对。7.4 从零启动到跑通完整业务链路的操作顺序按下面这个顺序操作你可以在十分钟内把这个项目跑起来。第一步用Navicat或命令行创建数据库hr_system然后执行sql目录下的建表脚本和初始数据脚本。第二步启动Redis服务。第三步修改后端配置文件里的数据库账号密码在backend目录执行mvn spring-boot:run看到Tomcat启动在8080端口即可。第四步在frontend目录执行npm install装完依赖后npm run dev浏览器访问前端地址。这里我要特别强调一个顺序问题必须先导入SQL再启动后端否则后端连接数据库时会因为找不到表而直接启动失败。很多人以为后端启动报错是代码问题其实只是没导数据。跑起来之后先用管理员账号登录到系统管理里创建一个新员工并开通账号然后换员工账号试一遍打卡流程最后切回管理员账号查看考勤统计和驾驶舱数据这样才算完整复现了一条业务链路。8. 拆源码和自研过程中踩过的坑以及我的避坑清单8.1 数据库初始化脚本的坑字符集和排序规则第一坑绝对是SQL脚本。源码包里的SQL文件如果直接用默认配置导入可能在Windows环境下出现中文乱码原因不是文件本身的问题而是数据库连接没有指定UTF-8。解决办法是在执行前把表的字符集统一改成utf8mb4排序规则用utf8mb4_general_ci。建表脚本里最好显式写清楚不要依赖数据库默认值。CREATE TABLE employee ( id bigint NOT NULL AUTO_INCREMENT, name varchar(50) NOT NULL, ... PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_general_ci;判断标准很简单如果表已经建好了就用show create table employee查看字符集不是utf8mb4就alter table转换然后再导入数据。8.2 密码加密和明文存储问题很多毕设源码的初始用户密码直接以明文存在数据库里比如admin/123456。这套源码在初始脚本里用了加密值登录后也能正常校验。但你自己写项目时务必要把所有密码存储改为哈希加盐推荐用BCryptPasswordEncoder不要用简单的MD5因为MD5现在已经不能算安全了。答辩时如果老师问“用户密码安全怎么保障”你回答用的bcrypt加盐哈希和只会MD5的同学档次立刻就拉开了。8.3 薪资计算的精度问题double转BigDecimal的坑这块我要重点说因为很多人是在这里炸的。在薪资计算里如果你先用了double计算最后再转BigDecimal精度问题已经产生了后面怎么转都是错的。正确姿势是所有涉及金额的参数从一开始就是BigDecimal数据库里工资字段也用decimal(10,2)类型不要用float或double。我见过一个经典bug员工月薪计算出来是18333.334999999997就是因为某一步用了浮点数除法。修复方法就是统一BigDecimal除法指定小数位和舍入模式BigDecimal daySalary base.divide(new BigDecimal(21.75), 2, RoundingMode.HALF_UP);8.4 跨域问题的两种解法CorsFilter和Vite代理前后端分离项目一定会遇到跨域问题。前端跑在5173端口后端跑在8080端口如果不处理浏览器会直接拦截请求。这套源码后端配了一个全局CorsFilter允许指定来源和请求头。前端则在Vite的vite.config.js里配置了代理把/api开头的请求转发到后端。我建议你两种方案都掌握后端CorsFilter是兜底方案前端代理是开发环境最顺手的方案。部署到生产环境时更推荐通过Nginx反向代理把/api转发到后端服务这样前后端看起来就是同源跨域问题从源头消失。8.5 文件上传后的静态资源映射招聘模块里会有简历附件上传考勤打卡也有拍照上传这些文件如果只保存到本地磁盘某个路径前端是访问不到图片的。源码里的做法是定义一个上传目录同时把该目录映射成/upload/**的静态资源路径。如果你用的是Spring Boot 3请务必注意资源映射方式和旧版本略有差别新版更推荐直接在配置类里注册资源处理器。这个功能在演示时非常关键。你现场演示上传简历、上传打卡照片如果图片前端加载不出来评委的第一感受就是这个系统不完整。所以上传功能的验证标准不是“文件保存成功”而是“保存后还能在前端页面看到它”。8.6 时区问题数据库和服务器的时间不一致考勤系统最怕时区坑。本地开发时电脑时间、MySQL时间、Linux服务器时间可能各不相同。如果服务器默认是UTC时区而你的打卡时间用LocalDateTime.now()取的是服务器本地时间那数据库里的打卡时间就会和北京时间差8个小时导致迟到判断完全错误。解决办法是统一三层时区JVM启动参数加-Duser.timezoneAsia/ShanghaiMySQL连接串加serverTimezoneAsia/Shanghai如果部署在云服务器还要把系统时区改成东八区。这套源码里已经把连接串时区写对了但你自己重新部署时很容易忽略JVM层建议在启动命令里也显式指定。最后补一个我个人的小习惯拿到任何一份带源码的毕设项目第一件事不是急着跑起来而是先看SQL初始化和application.yml再点开前端路由表看一眼页面有哪些。这三个文件看完整个系统长什么样、技术栈是什么、数据怎么流转心里基本有数了。智能HR管理系统从题目到落地的过程最大的价值不在于代码本身而是你真正理解了HR业务流程和技术设计是怎么咬合在一起的。把这个逻辑想通了别说改题目就是换个图书管理系统、进销存系统你也能用同一套思路几天内搭出骨架来这才是带着源码做项目真正的收获。