简介:这份资源是面向Java全栈开发者与计算机专业学生的医院人力资源管理系统完整源码,采用Vue3前端与SpringBoot3后端的前后端分离架构,适合作为毕业设计、课程设计或企业级项目练手的参考方案。压缩包共37个文件,约2.87MB,以10个Java业务代码文件为核心,配合4个CSS与4个JS构建前端界面,另有XML、YML配置及HTML页面、字体图标等静态资源,并附有配置说明文档与必读推荐资料,便于快速理解项目结构与部署流程。系统覆盖人员信息、劳动合同、考勤、薪酬、绩效考核、培训发展、报表统计等模块,涉及Vue Router、Vuex状态管理、Spring Security安全控制与数据持久化等实现细节,可帮助读者掌握前后端接口交互、数据库表设计与异常处理思路。目前已有37人学习下载,适合希望深入理解SpringBoot3与Vue3整合开发的中级学习者参考借鉴。
1. 医院人力资源管理系统源码拆包:Vue3 + SpringBoot3 这套组合拳能解决什么
医院的人事管理跟普通企业完全不是一个量级。一个三甲医院动辄几千号员工,编制内、合同制、规培生、进修生、实习生混在一起,科室轮转、职称晋升、执业证照有效期、排班考勤、绩效核算,每一条线都能把 Excel 拖垮。我见过某医院人事科用共享表格维护在编人员信息,结果一次误操作覆盖了三百多条职称数据,恢复花了整整两天。这套基于 Vue3 + SpringBoot3 的医院人力资源管理系统源码,瞄准的就是这类场景——把人员档案、科室编制、合同、考勤、薪酬、招聘这些模块收进一个前后端分离的 Web 系统里。
它适合谁?一是做 Java 课程设计或毕业设计的学生,SpringBoot3 + Vue3 的技术栈足够新,答辩时能讲出东西;二是中小型医院或体检中心的信息科,想低成本搭一套内部人事工具;三是想练手前后端分离架构的开发者,这套代码的模块划分和权限设计有参考价值。源码包本身是完整的工程结构,前端 Vue3 用 Vite 构建,后端 SpringBoot3 配 MyBatis-Plus,数据库 MySQL 8,权限走 JWT + RBAC。下面我从环境搭建一路拆到二次开发和排错,把能踩的坑都摆出来。
2. 环境搭建与工程结构:从 JDK17 到前后端跑通
2.1 技术栈版本锁定与依赖关系
这套源码对版本比较敏感,SpringBoot3 强制要求 JDK17 起步,Vue3 的构建工具用的是 Vite 而不是 Webpack,Node 版本建议 18 LTS。我拿到源码包后第一件事是看pom.xml和package.json里的版本声明,确认没有用到已废弃的 API。常见做法是先统一环境再动代码,否则启动报错会把你带偏。
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| JDK | 17 或 21 LTS | SpringBoot3 最低要求 17 |
| Maven | 3.8+ | 用于后端依赖管理 |
| MySQL | 8.0+ | 注意字符集用 utf8mb4 |
| Node.js | 18 LTS | Vue3 + Vite 构建需要 |
| Redis | 6.x+ | 部分模块用于缓存 token 和字典 |
后端工程一般分这几个包:controller接请求、service写业务、mapper走 MyBatis-Plus、entity对应表、config放安全配置和跨域。前端目录里src/api管接口封装,src/views放页面,src/store用 Pinia 管状态,src/router配路由和权限守卫。先把目录结构摸清楚,后面改代码才不会迷路。
2.2 数据库初始化与后端启动
数据库脚本通常在sql目录下,导入前先建库并指定字符集。我一般会手动建库而不是让脚本自己建,避免字符集不一致导致中文乱码。
-- 建库时强制 utf8mb4,否则员工姓名里的生僻字会变问号 CREATE DATABASE hospital_hr DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE hospital_hr; -- 再执行源码包里的 init.sql,注意先关外键检查避免建表顺序报错 SET FOREIGN_KEY_CHECKS = 0; SOURCE /path/to/init.sql; SET FOREIGN_KEY_CHECKS = 1;导入完成后检查几张核心表:sys_user(登录账号)、hr_employee(员工档案)、hr_department(科室)、hr_contract(合同)。如果hr_employee里没有数据,前端列表页会是空的,别以为是接口挂了。
后端启动前改application.yml里的数据库连接和 Redis 地址:
spring: datasource: url: jdbc:mysql://localhost:3306/hospital_hr?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 你的密码 data: redis: host: localhost port: 6379serverTimezone这个参数别省,MySQL 8 的时区问题会让创建时间差 8 小时。改完执行mvn spring-boot:run,看到 Tomcat 在 8080 端口启动就算成功。如果报Table 'xxx' doesn't exist,回去确认 SQL 脚本是否完整执行。
2.3 前端依赖安装与联调
前端进目录先装依赖,国内网络建议配镜像源,否则node_modules能装到你怀疑人生。
# 配置 npm 镜像加速依赖下载 npm config set registry https://registry.npmmirror.com # 安装依赖,Vue3 项目一般用 npm 或 pnpm npm install # 启动开发服务器,Vite 默认 5173 端口 npm run dev启动后浏览器打开http://localhost:5173,如果页面白屏,按 F12 看控制台。常见的是接口 404,那说明 Vite 的代理没配对。打开vite.config.js确认 proxy 指向后端 8080:
// vite.config.js 里的代理配置,把 /api 转发到后端 server: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } }changeOrigin设为 true 是为了绕过跨域校验,rewrite决定要不要去掉/api前缀,这个要跟后端context-path对齐,对不上就是 404。登录账号一般在sys_user表里,密码是加密存储的,初始密码看源码注释或 SQL 里的说明。
3. 核心模块实现:员工档案、权限与考勤的业务逻辑
3.1 员工档案模块的增删改查与字段设计
员工档案是这个系统的数据核心,表字段设计直接决定后面考勤、薪酬能不能算对。hr_employee表里几个关键字段要留意:emp_no(工号,唯一索引)、dept_id(科室外键)、job_title(职称)、employment_type(用工性质:在编/合同/规培)、hire_date(入职日期)、status(在职状态)。用工性质这个字段特别重要,医院里不同性质的人走不同的薪酬和合同逻辑。
后端接口用 MyBatis-Plus 的IService和BaseMapper就能省掉大量 CRUD 代码:
// EmployeeServiceImpl.java 继承 MyBatis-Plus 的 ServiceImpl @Service public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService { @Override public Page<EmployeeVO> pageQuery(EmployeeQuery query) { // 构造分页条件,按科室和状态过滤 LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(query.getDeptId() != null, Employee::getDeptId, query.getDeptId()) .eq(StringUtils.hasText(query.getStatus()), Employee::getStatus, query.getStatus()) .like(StringUtils.hasText(query.getName()), Employee::getName, query.getName()) .orderByDesc(Employee::getCreateTime); Page<Employee> page = this.page(new Page<>(query.getPageNum(), query.getPageSize()), wrapper); // 转 VO 时补上科室名称,避免前端再查一次 return page.convert(this::toVO); } }LambdaQueryWrapper的条件构造里,第一个布尔参数控制这个条件是否生效,这样前端传空值就不会拼进 SQL。page.convert把实体转成 VO,顺便把deptId换成科室名称,减少前端请求次数。这里有个坑:如果科室被删了但员工还挂着dept_id,转 VO 时会空指针,所以删除科室要做逻辑删除而不是物理删除。
3.2 JWT + RBAC 权限控制怎么落地
医院系统里权限必须细,人事科能看全员工资,科室主任只能看本科室的人,普通员工只能看自己。这套源码用 JWT 做认证、RBAC 做授权。登录成功后后端签发 token,前端存 localStorage,每次请求带在 header 里。
// JwtAuthenticationFilter.java 拦截请求校验 token public class JwtAuthenticationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String token = request.getHeader("Authorization"); if (StringUtils.hasText(token) && token.startsWith("Bearer ")) { token = token.substring(7); // 解析 token 拿用户信息和权限,塞进 SecurityContext Claims claims = jwtUtil.parseToken(token); UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(claims.getSubject(), null, getAuthorities(claims)); SecurityContextHolder.getContext().setAuthentication(auth); } chain.doFilter(request, response); } }OncePerRequestFilter保证一次请求只过滤一遍。getAuthorities从 token 里的角色字段解析出权限列表,Spring Security 再用@PreAuthorize("hasRole('HR')")这种注解做方法级控制。注意 token 过期时间别设太长,医院系统涉及隐私数据,一般 2 小时加刷新机制比较稳妥。前端路由守卫也要同步做,否则用户能手动敲 URL 进没权限的页面,虽然后端会拦,但体验很差。
3.3 考勤与排班的数据流转
考勤模块的逻辑是:排班表定义谁哪天该上班,打卡记录表存实际打卡时间,然后比对算出迟到、早退、缺勤。hr_schedule表存排班,hr_attendance存打卡。比对逻辑一般放在定时任务里跑,每天凌晨算前一天的考勤结果。
// AttendanceTask.java 定时核算考勤 @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨 2 点执行 public void calculateDailyAttendance() { LocalDate yesterday = LocalDate.now().minusDays(1); List<Schedule> schedules = scheduleMapper.selectByDate(yesterday); for (Schedule schedule : schedules) { Attendance record = attendanceMapper.selectByEmpAndDate(schedule.getEmpId(), yesterday); // 没打卡记录直接标记缺勤 if (record == null) { attendanceMapper.insert(buildAbsentRecord(schedule)); continue; } // 比对打卡时间和排班时间,算迟到早退 if (record.getCheckIn().isAfter(schedule.getStartTime())) { record.setStatus("LATE"); } attendanceMapper.updateById(record); } }cron表达式0 0 2 * * ?是每天凌晨两点。这里要注意时区,服务器如果是 UTC 时间,凌晨两点算出来的是前一天下午,得在配置里指定时区。另外排班跨天的情况(比如夜班)要单独处理,不能简单按日期比对,这是医院考勤最容易翻车的地方。
4. 避坑与排查:启动报错、跨域和权限失效的常见问题
4.1 后端启动报错排查
现象:mvn spring-boot:run报java.lang.UnsupportedClassVersionError。原因:JDK 版本低于 17,SpringBoot3 编译的 class 文件版本是 61,JDK8 加载不了。解决:java -version确认版本,切到 17 或 21,同时检查JAVA_HOME指向对不对。
现象:启动时报Failed to configure a DataSource。原因:application.yml里数据库配置没生效,或者密码有特殊字符没转义。解决:检查 yml 缩进,密码里如果有@或#要用引号包起来,或者改用环境变量注入。
4.2 前端跨域与接口 404
现象:前端登录请求报CORS policy或 404。原因:Vite 代理没配,或者后端context-path和代理 rewrite 规则不一致。解决:先确认后端接口实际路径,比如后端是/employee/list,前端请求写/api/employee/list,那 rewrite 就要去掉/api。两边对不上就是 404。跨域问题在开发环境用代理解决,生产环境用 Nginx 转发,别在后端无脑加@CrossOrigin。
4.3 权限注解不生效
现象:加了@PreAuthorize但没权限的用户照样能访问。原因:Spring Security 配置类里没开@EnableMethodSecurity,或者过滤器链顺序不对。解决:在 SecurityConfig 上加@EnableMethodSecurity,确认 JWT 过滤器加在UsernamePasswordAuthenticationFilter之前。另外检查 token 里的权限字段名和getAuthorities解析的是否一致。
4.4 中文乱码与时间偏差
现象:员工姓名显示问号,或者创建时间差 8 小时。原因:数据库字符集不是 utf8mb4,或 JDBC 连接没指定serverTimezone。解决:建库时指定 utf8mb4,连接串加serverTimezone=Asia/Shanghai。已经建好的库可以用ALTER DATABASE改字符集,但已有数据要重新导入。
4.5 前端打包后刷新 404
现象:npm run build部署后,刷新页面报 404。原因:Vue Router 用了 history 模式,服务器没配 fallback。解决:Nginx 里加try_files $uri $uri/ /index.html;,把找不到的路径都指回 index.html。
5. 二次开发与验证:从改一个字段到跑通完整流程
5.1 新增自定义字段的完整链路
假设医院要求员工档案加一个「执业证编号」字段,你得从数据库一路改到前端。先在hr_employee表加列:
ALTER TABLE hr_employee ADD COLUMN license_no VARCHAR(64) COMMENT '执业证编号' AFTER job_title;然后实体类加字段,MyBatis-Plus 会自动映射:
// Employee.java 加字段,注意驼峰和数据库下划线的映射 private String licenseNo;接着改 VO、前端表单和列表列。前端在src/views/employee/index.vue里找到表单的el-form-item,加一个输入框绑定form.licenseNo。列表的el-table-column加一列prop="licenseNo"。改完重启前后端,新增员工时填上编号,查列表能看到就算通了。这条链路走一遍,你就摸清了这套代码的数据流。
5.2 用接口测试验证权限边界
改完权限相关代码后,别只靠点页面验证,用 curl 直接打接口更靠谱:
# 先用人事账号登录拿 token curl -X POST http://localhost:8080/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"hr01","password":"123456"}' # 拿返回的 token 访问员工列表,应该成功 curl http://localhost:8080/employee/list?pageNum=1&pageSize=10 \ -H "Authorization: Bearer 你的token" # 换一个普通员工 token 再打,应该返回 403如果普通员工 token 也能拿到全量列表,说明权限没生效,回去查@PreAuthorize和角色配置。这种验证方式比点页面快,也更容易发现越权问题。
5.3 一个我踩过的坑
有次我改完考勤逻辑,本地测试全过,部署到测试环境后考勤结果全错。查了半天发现测试服务器时区是 UTC,LocalDate.now()取的是前一天,导致排班和打卡对不上。从那以后我每次碰时间相关的逻辑,都强制在配置里显式指定时区,并且在启动日志里打一行当前时区确认。这套源码里凡是涉及LocalDate、LocalDateTime的地方,都建议你检查一遍时区配置,别等上线了才发现日期差一天。希望帮到你。
本文还有配套的精品资源,点击获取