☰
智能HR管理系统源码拆解:数据库、考勤与薪资实现
2026/10/6 9:59:35 网站建设 项目流程

每年到了毕业设计选题季,总有人私信我:“智能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组件库,状态管理用Pinia,HTTP请求用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.0+5.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?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai username: root password: yourpassword redis: host: localhost port: 6379 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

这里有两个细节值得注意:第一个是数据库连接串里的serverTimezone=Asia/Shanghai,如果漏掉,MySQL 8会报时区错误;第二个是characterEncoding=utf8mb4,如果写成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`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_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.timezone=Asia/Shanghai,MySQL连接串加serverTimezone=Asia/Shanghai,如果部署在云服务器,还要把系统时区改成东八区。这套源码里已经把连接串时区写对了,但你自己重新部署时很容易忽略JVM层,建议在启动命令里也显式指定。

最后补一个我个人的小习惯:拿到任何一份带源码的毕设项目,第一件事不是急着跑起来,而是先看SQL初始化和application.yml,再点开前端路由表看一眼页面有哪些。这三个文件看完,整个系统长什么样、技术栈是什么、数据怎么流转,心里基本有数了。智能HR管理系统从题目到落地的过程,最大的价值不在于代码本身,而是你真正理解了HR业务流程和技术设计是怎么咬合在一起的。把这个逻辑想通了,别说改题目,就是换个图书管理系统、进销存系统,你也能用同一套思路几天内搭出骨架来,这才是带着源码做项目真正的收获。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询