简介:一套基于Spring和MyBatis框架实现的Java人事管理系统源码,适合高校学生、Java入门开发者以及需要快速搭建人事后台的中小团队参考使用。系统内置用户管理、部门管理、职位管理、员工管理、公告管理和下载中心等核心模块,前后端逻辑完整,可帮助读者掌握框架整合、权限拦截、文件上传下载等常见企业级开发思路;从控制器到服务层的代码结构也较为清晰。资源包共收录276个文件,大小约30.1MB,其中包含29个Java源文件、18个JSP页面、20个JavaScript脚本、7个CSS样式、4个XML配置文件,以及75张GIF演示动图;另有JAR依赖包、class编译文件与SQL数据库脚本,能够满足从阅读源码到运行调试的完整需求。目前已有1285人浏览学习,适合用于课程设计、毕业设计或企业人事管理系统的二次开发蓝本,也可继续扩展新的功能模块。
1. Java人事管理系统源码:本地第一个能跑的 Spring Boot 业务系统
如果要在最短时间内把一个“能登录、能维护员工档案、能走请假审批”的 Java 项目跑起来,最快的办法不是从零搭框架,而是先拿一份 Java 人事管理系统源码,在本地把它启动,然后对照代码理解业务分层。这份源码是一个典型的 Spring Boot + MyBatis + MySQL 组合工程,覆盖员工档案、部门管理、考勤、请假审批和工资模块,用的是大多数 Java 后端项目都在用的经典技术栈。它特别适合两类人:一类是刚开始做 Java 开发、想搞清楚真实业务系统怎么分层的新手;另一类是课程设计或接手外包项目、需要一份能跑的底子再改动的从业者。
2. 拆包先看结构:Maven 工程分层、数据库脚本与配置文件的对应关系
拿到压缩包后不要急着点启动按钮,先花十分钟把目录结构过一遍。人事管理系统这类业务项目,结构通常高度统一,看懂目录等于看懂整个系统的运行逻辑。
2.1 压缩包里的典型工程结构与每个模块的用途
解压后你会看到标准的 Maven 工程目录,核心部分集中在src/main/java和src/main/resources下。常见拆分是controller、service、mapper、entity、config这几层,外加resources里的mapper映射文件和配置文件。
hr-management-system/ ├── pom.xml ├── sql/ │ ├── hr_system.sql │ └── hr_data_init.sql └── src/ └── main/ ├── java/com/example/hr/ │ ├── HrApplication.java │ ├── controller/ │ ├── service/ │ ├── mapper/ │ ├── entity/ │ ├── interceptor/ │ └── config/ └── resources/ ├── application.yml ├── application-dev.yml └── mapper/从代码组织方式看,这是典型的 Controller → Service → Mapper → 数据库的四层结构。controller只负责接收参数和返回结果,service负责业务逻辑,mapper直接对接 SQL。这样的分层有一个明确好处:如果以后你想把 MyBatis 换成 MyBatis-Plus,或者把 MySQL 换成 PostgreSQL,改动主要集中在mapper层和配置文件,业务代码不用大动。
2.2 数据库初始化:从建库脚本到初始化数据
绝大多数人事管理系统源码的压缩包里都会带上sql目录,里面是建表语句和初始数据。不要自己在 Navicat 里手动建表,直接执行脚本更稳妥,因为表结构里可能包含外键关系、索引和一些字段注释,手敲很难保持一致。
-- hr_system.sql 片段:员工表核心字段设计 CREATE TABLE `employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `emp_no` varchar(20) NOT NULL COMMENT '员工编号', `name` varchar(50) NOT NULL COMMENT '姓名', `dept_id` int(11) DEFAULT NULL COMMENT '部门ID', `position` varchar(50) DEFAULT NULL COMMENT '岗位', `phone` varchar(20) DEFAULT NULL COMMENT '手机号', `hire_date` date DEFAULT NULL COMMENT '入职日期', `status` tinyint(4) DEFAULT '1' COMMENT '1在职 0离职', PRIMARY KEY (`id`), UNIQUE KEY `uk_emp_no` (`emp_no`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;这是一张最普通的员工表,但已经能反映出人事系统的共性:几乎每张业务表都会有一个状态字段(status),用来表示在职/离职、启用/停用,而不是直接物理删除数据。emp_no设置了唯一索引,是为了防止同一个员工编号被重复录入。执行时建议用source命令或者直接复制到 Navicat 查询窗口运行,注意选择正确的目标数据库。
2.3 配置文件里的三个关键参数
application.yml是决定系统能不能启动的核心文件。你需要关注三个部分:数据源、端口、以及是否配置了 Redis 等中间件。
server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/hr_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 redis: host: localhost port: 6379 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.hr.entityserverTimezone参数容易忽略,MySQL 8.x 默认时区与本地不一致时,连接会直接报错。mapper-locations指定了 XML 映射文件的位置,如果路径写错,启动时不会报错,但调用任何查询接口都会提示Invalid bound statement。配置文件里的数据库密码如果是加密后的密文,需要到config包里找对应的解密类,这点在后续排查时会经常遇到。
3. 把项目跑起来:JDK、MySQL 与 Redis 的版本匹配和启动步骤
源码能跑是一回事,能在你机器上跑是另一回事。人事管理系统这种基于 Spring Boot 的项目,对本地环境版本非常敏感,版本不匹配会直接在启动阶段翻车。
3.1 本机环境选择与版本检查
老实的做法是先看pom.xml里声明的 Spring Boot 版本,再决定 JDK 版本。大部分这类源码基于 Spring Boot 2.3 到 2.7 之间,对应 JDK 8 或 JDK 11。如果你本地只有一个 JDK 17,运行老工程时经常会遇到javax.servlet包找不到的问题,因为高版本 JDK 移除了部分 Java EE API。
在命令行里先确认当前环境:
java -version mvn -version mysql --versionJDK 版本以1.8开头的输出最安全,Maven 用 3.6 以上版本即可。MySQL 建议用 8.0,因为源码里的驱动类名和建表语句基本都按 8.x 来写。如果你还在用 MySQL 5.7,绝大多数情况下也没问题,但注意检查驱动类是否写成了旧版的com.mysql.jdbc.Driver。
3.2 导入工程并处理 Maven 依赖
用 IDEA 导入时选择Import Project,选中解压后的pom.xml,IDEA 会自动识别为 Maven 工程。首次导入会下载大量依赖,耗时取决于网络环境。如果一直卡在下载阶段,检查 Maven 的settings.xml是否配置了阿里云镜像。
<mirror> <id>aliyunmaven</id> <mirrorOf>central</mirrorOf> <name>Aliyun Maven Mirror</name> <url>https://maven.aliyun.com/repository/central</url> </mirror>这个镜像配置写在 Maven 安装目录conf/settings.xml或用户目录下的.m2/settings.xml里。依赖全部下载完成后,IDEA 右侧 Maven 面板点reload,能看到依赖列表中没有红叉就算通过。这里一个隐蔽的坑是 Lombok 插件版本过低,会导致后来代码里所有@Data注解的实体类编译报错,后面避坑章节细说。
3.3 先建库再改配置,最后启动
在启动应用之前,先把数据库准备好。用命令行创建数据库并导入脚本:
mysql -u root -p CREATE DATABASE hr_system DEFAULT CHARACTER SET utf8mb4; exit; mysql -u root -p hr_system < sql/hr_system.sql mysql -u root -p hr_system < sql/hr_data_init.sql数据库导入完成后,回到application.yml,把username和password改成你自己的数据库账号密码。如果你本机没有安装 Redis,而配置里又写了 Redis 连接,最简单的处理方式是把spring.redis这段配置暂时注释掉,同时找到代码里注入 Redis 的地方,也临时处理一下,具体做法在第五章统一讲。
启动顺序有一定讲究:先启动 MySQL,确认端口 3306 可以连通,再启动应用。如果端口被占用,MySQL 起不来,应用再怎么改配置也是白搭。
默认的启动方式是在 IDEA 里直接运行HrApplication.java的main方法,也可以在项目根目录执行:
mvn spring-boot:run看到类似Started HrApplication in xxx seconds的日志,就说明启动成功。此时浏览器访问http://localhost:8080,跳转到登录页,说明系统对外服务已经起来了。
3.4 首次登录验证业务链路
登录页账号密码一般在初始化脚本里,常见是admin/admin123或admin/123456,具体看hr_data_init.sql中sys_user表的插入语句。登录成功后,建议依次点开员工管理、部门管理、请假审批,每个功能都操作一遍,确认数据能正常增删改查。
这一步不是浪费时间,而是验证三个关键链路是否通畅:数据库连接是否正常、Mapper 映射是否生效、前端页面调用的接口路径是否和后端吻合。如果员工列表能显示但添加员工报错,通常是数据库字段与实体类字段对不上;如果页面样式丢失,往往是静态资源路径设置问题,这两类问题在人事管理系统里出现频率很高。
4. 业务代码阅读指南:登录、员工档案与请假审批三条主线
跑通之后,接下来要做的是读代码。读源码不需要逐行看,抓住核心业务的三到四条链路就能理解整个系统的设计思路。常见做法是选登录、员工查询、请假审批这三个点,因为它们是人事管理系统的骨架,其他模块基本是复制或扩展这三条的写法和套路。
4.1 登录认证链:从 Controller 到拦截器的完整回路
登录逻辑通常是这样一个过程:前端把用户名密码 POST 给 Controller,Service 层从sys_user表查询用户并校验密码,成功后把用户信息写入 Session,同时用拦截器拦截除登录页之外的所有请求。
@Controller public class LoginController { @Autowired private UserService userService; @PostMapping("/login") public String login(String username, String password, HttpSession session) { User user = userService.login(username, password); if (user != null) { session.setAttribute("loginUser", user); return "redirect:/index"; } return "redirect:/login?error=1"; } }这里userService.login()返回null代表账号密码错误或账号被禁用,前端根据error=1参数给出提示。值得注意的细节是:返回的是重定向而不是直接跳转页面,这样浏览器地址栏会更新,刷新时也不会重复提交登录表单。HttpSession是默认的 Session 存储方案,后续如果想换成 Redis 存储,只需替换 Session 的存储介质,业务代码不需要大改。
4.2 员工档案分页查询:MyBatis 的条件拼接与分页
员工列表是人事系统里数据量最大的模块,几乎所有源码都会做分页和模糊搜索。常见的方案是使用 PageHelper 插件,或者手写LIMIT分页。
public PageResult<Employee> queryEmployeeList(String name, Integer deptId, int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); List<Employee> list = employeeMapper.selectEmployeeList(name, deptId); return new PageResult<>(list, new PageInfo<>(list).getTotal()); }<select id="selectEmployeeList" resultType="com.example.hr.entity.Employee"> SELECT * FROM employee <where> <if test="name != null and name != ''"> AND name LIKE CONCAT('%', #{name}, '%') </if> <if test="deptId != null"> AND dept_id = #{deptId} </if> </where> ORDER BY id DESC </select>PageHelper.startPage后面必须紧跟第一条 SQL 查询,中间不能插入其他操作,否则分页会失效。<where>标签会自动处理多余的AND,但要注意deptId传 0 和传null是两种不同含义:0 可能代表“所有部门”,也可能代表“根部门”,具体取决于前端下拉框的默认值设计,这是业务边界上容易出歧义的地方。
4.3 请假审批状态机:业务系统里最常见的流转逻辑
请假模块是人事系统除工资外最复杂的业务,因为它涉及状态流转:提交 → 主管审批 → 人事归档,每一步都可能被驳回。源码里一般用status整型字段表示状态,配合时间字段记录审批节点。
public boolean approveLeave(Integer leaveId, Integer approverId, Integer action) { LeaveApply leave = leaveMapper.selectById(leaveId); // 状态校验:只有待审批状态才能审批 if (leave.getStatus() != 1) { throw new BusinessException("该申请不在待审批状态"); } // action 1通过 2驳回 LeaveApply update = new LeaveApply(); update.setId(leaveId); update.setStatus(action == 1 ? 2 : 3); update.setApproverId(approverId); update.setApproveTime(new Date()); return leaveMapper.updateById(update) > 0; }这段代码的关键点在于状态校验放在更新的最前面,而不是靠 SQL 语句里的where条件。这种写法在并发不高的小系统里够用,但如果两个人同时打开同一条请假单,前一个人审批通过后,后一个人还能审批,就会产生状态重复流转。常见做法是在表里加version字段,或者在更新 SQL 里拼接AND status = 1作为乐观锁控制。拿到源码后,建议把这个校验改到 SQL 层面,能从源头解决并发问题。
4.4 导出功能:人事系统里绕不开的 Excel 处理点
几乎所有人事源码的最后都会提供一个员工花名册导出的功能,常用的方案是直接用EasyPOI或Apache POI,把查询结果逐行写入 Excel。
public void exportEmployeeList(HttpServletResponse response, String name) throws IOException { List<Employee> list = employeeMapper.selectEmployeeList(name, null); Workbook workbook = ExcelUtil.createWorkbook(); Sheet sheet = workbook.createSheet("员工花名册"); // 省略表头设置 Row row = sheet.createRow(i); row.createCell(0).setCellValue(emp.getEmpNo()); row.createCell(1).setCellValue(emp.getName()); // ... workbook.write(response.getOutputStream()); }从实现来看,这个导出方案属于最简单粗暴的类型,优缺点都很明显:优点是没有额外依赖,拿过来就能看懂;缺点是每个字段都要手动createCell,字段一多代码就非常臃肿。如果你打算在二次开发阶段换掉它,重点看ExcelUtil是否封装了@ExcelProperty注解导出能力,有注解的话,后续只需在实体类上标注列名即可,不用再写大量重复代码。
5. 避坑与排查:本地启动人事管理系统源码最常见的五个翻车点
把一份 Java 人事管理系统源码从压缩包变成正在运行的服务,中间最容易出问题的环节往往不是业务代码本身,而是环境、配置和依赖这三类问题。下面这五条是本类源码翻车率最高的问题,按“现象 → 原因 → 解决”的顺序梳理。
5.1 登录后进入列表页,一刷新就回到登录页
- 现象:登录成功正常跳转,但按 F5 刷新页面后就跳回登录页,有些项目里操作按钮也会间歇性失效。
- 原因:Session 没有持久化到 Redis 或数据库,默认存在内存里。启动时如果配置了
spring.session.store-type=none,Session 的生成和读取逻辑会被绕开,拦截器每次拿不到用户信息。更隐蔽的原因是server.servlet.session.timeout设置太短,比如默认 60 秒,刷新间隔稍长就会被拦截器判定为未登录。 - 解决:先去配置文件里检查
session.timeout,原则上班长度项目设置 30 分钟起步。再看启动类上有没有@EnableRedisHttpSession,如果项目引入了 Redis 依赖但没启用这个注解,Session 其实还是存在本地内存里,重启应用后登录态全部丢失。
5.2 启动时报错ClassNotFoundException: com.mysql.cj.jdbc.Driver
- 现象:启动的一瞬间就弹出驱动类找不到,或者一直提示
Failed to configure a DataSource。 - 原因:JDBC 驱动包没有被打进依赖里,或者
pom.xml里只引入了mysql-connector-java的某种 scope。另一个常见原因是 IDEA 里没执行 Maven 的clean和reimport,本地仓库里根本没有对应版本的 jar。 - 解决:在
pom.xml里确认存在mysql-connector-java依赖,版本与 MySQL 版本对应。之后在 Maven 面板里执行clean,再执行compile,如果编译通过但启动还报错,检查是不是用命令行启动时classpath没包含target/classes。你可以用mvn dependency:tree | grep mysql查看依赖树里到底有没有这个驱动。
5.3 Maven 依赖下载到一半就中断,反复重试总是卡住
- 现象:IDEA 底部状态栏一直显示 downloading,进度条长时间不动,过一会儿报
Could not resolve dependencies,索引某个 jar 包找不到。 - 原因:默认中央仓库对国内网络不友好,部分包重复下载不完整,本地
repository里留有.lastUpdated后缀的脏文件,导致 Maven 认为已经下载过而跳过。 - 解决:先把
settings.xml换成阿里云镜像。然后去本地仓库目录~/.m2/repository下搜索所有*.lastUpdated文件并按时间排序删除,再回到 IDEA 执行reload All Maven Projects。如果删完还卡住,查看是不是某个 pom 依赖了一个不存在的版本号,需要核对源代码包里pom.xml的版本号和仓库里是否一致。
5.4 页面能打开,但所有列表页的中文都显示成问号
- 现象:登录页中文正常,但进入员工列表后,页面上所有中文全部变成
?或乱码,数据库里直接 SELECT 却能查出正常数据。 - 原因:建库时用了默认字符集
latin1,或者连接串里没有带characterEncoding=utf8。还有一种情况是前端页面本身是 GBK 编码,而后端返回 UTF-8,导致浏览器用错误字符集解析。 - 解决:先检查数据库字符集,执行
SHOW CREATE DATABASE hr_system;,如果看到的CHARACTER SET不是utf8mb4,按照前面的建库命令重建数据库。然后在application.yml里把连接串改为useUnicode=true&characterEncoding=utf8,重启后重新导入 SQL 脚本。如果你用的是 MySQL 8.x,注意utf8mb4才是完整支持中文和特殊符号的字符集,utf8会在某些生僻字上继续乱码。
5.5 端口被占用,启动日志提示Port already in use
- 现象:
Spring Boot启动到最后一步报错,控制台明确提示Web server failed to start. Port 8080 was already in use。 - 原因:机器上已经有一个进程占用了 8080 端口,可能是之前启动的应用没关闭,也可能是本机装了其他 Web 服务。
- 解决:最简单的方式是换端口,把
application.yml里的server.port改成8081。如果你一定要用 8080,就需要找出占用进程并关闭它。在 Windows 上执行netstat -ano | findstr 8080,记下最后一列的 PID;Linux 或 macOS 用lsof -i :8080,然后 kill 掉对应进程。但要让日志信息帮助你判断有没有其他配置覆盖了端口,比如在启动命令里带--server.port=或者在 IDEA 的 Environment variables 里配置过SERVER_PORT,这两种情况会优先于 yml 文件生效。
5.6 其他需要留意的边界点
拿到源码后,还应检查三件小事。一是sys_user表初始化时,密码是否写的明文,如果是明文,说明这个源码的教学属性大于生产属性,二次开发时务必换成 BCrypt 加密存储;二是application-dev.yml和application.yml同时存在时,spring.profiles.active是否指定了正确的环境;三是压缩包里如果带着.idea或者.iml文件,导入时以你自己的 IDEA 设置为准,不要沿用别人的编码格式配置。
6. 二次开发与加分项:从改一个功能到接你自己的工具链
源码在你本地稳定运行之后,价值才开始真正体现。人事管理系统的技术栈通用性很强,改造成本低,适合作为第一个真实项目去实践结构和重构技巧。
6.1 把 Session 登录换成 Redis 存储的改动范围
这套源码的登录校验默认走 Session,属于单体应用里最朴素的方案。如果在生产环境部署,多个实例间 Session 无法共享,通常的做法是引入 Redis 作为 Session 存储。改动点集中在两处:pom.xml增加spring-boot-starter-data-redis和spring-session-data-redis,然后在配置类上启用@EnableRedisHttpSession即可。不需要改任何登录代码,Session 的存取会被容器透明地路由到 Redis。这个改动值得做,既能学到会话共享的思路,也能为以后写分布式项目打基础。
6.2 把员工档案导出换成一个项目里能拿得出手的加分项
原版导出代码通常比较原始,除了调整列宽外,几乎没有格式处理。真正的交付层面,会要求导出带表头样式、自动列宽、冻结首行,还能按查询条件导出当页数据。建议把原版ExcelUtil替换成基于注解的方案,实体类字段上标注列名和列宽,然后通过反射动态生成单元格,写完后用sheet.setAutoFilter()给表头加筛选按钮。这个优化点很小,但每次演示系统时打开导出的 Excel 都能直观感受到差异。
6.3 关于这份源码的获取
这套 Java 人事管理系统源码压缩包里的内容足够支撑一次完整的项目复现:从数据库设计到全套 Java 代码,从员工管理到请假审批再到工资模块,拿来当课程设计底子或者入门练手都合适。如果你正好需要,直接下载Java人事管理系统源码.zip,解压后按第二章的顺序先看sql目录,再改配置文件,最后启动系统,按第三章的步骤走一遍就能跑起来。
从拿到别人源码到自己动手改造,我最大的一个教训是:永远先改配置、再改代码、最后才看业务细节。以前我贪快,拿到压缩包直接点启动,结果一连串报错浪费时间。从那以后,我对每份源码都强制先看pom.xml和application.yml,确认版本与环境匹配后才动手,这个习惯让我少踩了很多坑。希望这篇笔记能帮你避免这些弯路。
本文还有配套的精品资源,点击获取