基于SpringBoot的人事管理系统设计与实现全解析
2026/8/31 15:59:08 网站建设 项目流程

简介:本资源是一套面向计算机与软件工程专业本科生的毕业设计实战项目,聚焦企业级人事管理数字化需求,提供基于SpringBoot的完整前后端分离解决方案。系统覆盖员工信息、考勤、薪资、权限及数据统计五大核心模块,集成Spring Security安全控制、MyBatis持久层与MySQL数据库,采用MVVM架构与单例/工厂/观察者等设计模式,兼顾功能性、可维护性与工程规范性。压缩包含305个文件,主体为126个Java后端逻辑文件、32个JS前端交互脚本、27个XML配置与映射文件、17个CSS样式资源及28个PNG图标素材,另有SQL建表脚本、Dockerfile容器化部署文件、论文文档(docx/pptx)及详细技术说明,总容量90.97MB。已有60人学习下载,资源附带可直接运行的源码、结构清晰的模块化目录、完整毕业论文(含需求分析、系统设计、测试用例与部署指南),助力学生高效完成毕设答辩与企业级开发能力训练。

1. 项目概览:这个人事管理系统到底能做什么

如果你正在准备毕业设计、课程设计,或者是刚入行Java后端想找一个完整的练手项目,基于SpringBoot的人事管理系统绝对是一个绕不开的经典选题。我这段时间刚好完整梳理了一遍这个项目的设计与实现,从数据库建模到接口开发,再到论文框架整理,踩了不少坑也沉淀了不少经验,这里把我整理的这套思路完整分享出来。

人事管理系统的核心价值其实很清晰:把公司里"人"相关的信息从 Excel 表格和纸质档案里解放出来,变成一套可查询、可统计、可流转的线上化流程。具体到功能层面,这套系统通常包含这么几个模块:

  • 员工信息管理:入职登记、信息修改、离职处理、员工档案查询
  • 部门管理:部门树形结构、部门人员统计、部门调整
  • 考勤管理:打卡记录、请假审批、加班登记、考勤统计
  • 薪资管理:基本工资设定、奖惩调整、月度薪资核算、工资条查看
  • 系统管理:登录登出、用户角色分配、菜单权限控制、操作日志

看到这里你可能会说,这不就是常见的 CRUD 吗?这话对也不对。人事管理系统虽然是典型的 CRUD 应用,但正是因为它功能边界清晰、业务逻辑完整、涉及的角色分明,所以特别适合作为 SpringBoot 学习的落地项目。更重要的是,这样一个系统足够支撑起一篇结构完整的毕业论文,从需求分析到系统设计再到实现测试,每一章都有实际内容可以写。

我给你的建议是:不要把这个项目单纯当成一个"交差"的任务。你在做这个项目的过程中真正掌握的"从零搭一个业务系统"的能力——表怎么设计、接口怎么划分、权限怎么控制、异常怎么处理——这些才是你以后工作中每天都要用的基本功。这篇博文我就照着这套系统的完整实现路径,把设计思路和关键代码逐层拆开讲,不管是只看论文框架还是想动手复现,你都能找到可以直接参考的内容。

2. 技术选型与架构设计:为什么这套组合最稳

2.1 核心框架选择与版本搭配

项目主框架选SpringBoot,这个基本没有悬念。SpringBoot最大的价值在于"约定大于配置",它能把你从繁琐的 XML 配置里解放出来,让你把精力放在业务代码上。但版本选择上我建议你注意一点:SpringBoot 2.7.x 系列的生态最成熟,网上资料最多,遇到问题基本都能搜到答案;SpringBoot 3.x 虽然新,但要求 JDK 17+,而且部分第三方组件的兼容性还没完全跟上,对于毕设项目来说没必要在这个地方冒险。

我这次用的是 SpringBoot 2.7.18 + JDK 8 + Maven 3.8 的组合,这套组合最大的优势是稳,就是你在网上遇到的绝大多数问题,都是基于这套环境解决的,报错信息一搜就有解决方案,不会被版本兼容问题卡住。

持久层框架我用的是 MyBatis-Plus。这里多说一句,很多教程会让你用 Spring Data JPA,但如果你的目标是毕业后进企业做 Java 开发,MyBatis-Plus 的使用频率明显更高。MyBatis-Plus 在 MyBatis 基础上提供了 BaseMapper 通用方法,单表 CRUD 一句 SQL 都不用写,分页查询也做了封装,比纯 MyBatis 省事很多,同时又保留了手写 SQL 的灵活性,适合做报表类统计查询。

数据库方面选 MySQL 8.0,免费、主流、资料多,没理由不选。前端我这次用的是 Thymeleaf + Bootstrap 服务端渲染方案,好处是一套 SpringBoot 项目直接跑起来就能看效果,不需要额外启动前端工程。如果你前端基础比较好,也可以改成前后端分离的 Vue + SpringBoot 模式,这个我会在后面单独说明差异。

2.2 数据库表设计:一张图看懂表关系

人事管理系统数据库设计是整篇论文里最能体现"设计能力"的部分,也是答辩时老师最喜欢追问的地方。我设计的核心表一共有7张,这里把每张表的职责和关键字段捋一遍:

  • sys_user:系统用户表,存储登录账号、密码(BCrypt加密)、用户状态。注意:不要把员工的业务信息塞进这张表,用户表和员工表分离是规范做法。
  • dept:部门表,字段包括 dept_id、parent_id、dept_name、sort_order。parent_id 是为了支持部门树形结构,顶级部门 parent_id 为0。
  • employee:员工表,字段包括 emp_id、emp_no(工号)、name、gender、birthday、phone、email、dept_id、position、entry_date、status(0在职/1离职)。dept_id 关联部门表形成隶属关系。
  • attendance:考勤记录表,字段包括 attend_id、emp_id、attend_date、check_in_time、check_out_time、status(正常/迟到/早退/缺卡)。
  • leave_request:请假申请表,字段包括 leave_id、emp_id、leave_type(事假/病假/年假/调休)、start_date、end_date、reason、status(待审批/通过/驳回)、approver。
  • salary:薪资表,字段包括 salary_id、emp_id、base_salary、bonus、deduction、settle_month、actual_salary。actual_salary 由薪资计算逻辑自动生成。
  • sys_role、sys_menu、sys_user_role、sys_role_menu:这四张是权限相关的辅助表,用于 RBAC 权限模型。

员工表和部门表的关系是"多对一",一个部门下有多个员工,一个员工只属于一个部门。员工表和考勤表、薪资表的关系是"一对多",一个员工有多条考勤记录、多个月份的薪资记录。请假申请表通过 emp_id 关联员工,通过 status 字段驱动审批流程。

这里我踩过一个坑:一开始我把部门信息直接冗余在员工表里,用 dept_name 字符串存储。结果等到做部门改名功能时,所有员工的部门名都要跟着改,数据一致性很难维护。所以千万记住:能用外键关联的不要冗余存储,这是表设计的第一原则。

2.3 后端分层结构:包结构决定代码上限

很多学生项目写到最后代码一团乱,问题出在包结构设计上。我建议你严格遵循 Controller-Service-Mapper 三层架构,同时引入 DTO(数据传输对象)和 VO(视图对象),做到参数接收、业务处理、数据返回三者解耦。

com.example.hrmanagement ├── controller │ ├── EmployeeController.java │ ├── DeptController.java │ ├── AttendanceController.java │ ├── SalaryController.java │ └── LoginController.java ├── service │ ├── EmployeeService.java │ ├── EmployeeServiceImpl.java │ ├── DeptService.java │ ├── DeptServiceImpl.java │ ├── AttendanceService.java │ ├── SalaryService.java │ └── UserService.java ├── mapper │ ├── EmployeeMapper.java │ ├── DeptMapper.java │ ├── AttendanceMapper.java │ ├── SalaryMapper.java │ └── UserMapper.java ├── entity │ ├── Employee.java │ ├── Dept.java │ ├── Attendance.java │ ├── Salary.java │ ├── User.java │ └── LeaveRequest.java ├── dto │ ├── LoginDTO.java │ ├── EmployeeQueryDTO.java │ └── SalaryQueryDTO.java ├── vo │ ├── EmployeeVO.java │ ├── LoginVO.java │ └── ResultVO.java ├── config │ ├── MybatisPlusConfig.java │ ├── WebMvcConfig.java │ └── InterceptorConfig.java ├── common │ ├── Result.java │ ├── ResultCode.java │ └── GlobalExceptionHandler.java └── HrManagementApplication.java

controller 只负责接收参数和返回结果,不写业务逻辑;service 层做业务处理,比如登录校验、薪资计算、请假审批状态的流转;mapper 层只做数据库操作。这套分层规范是你论文中"系统设计"部分最直接的设计亮点,也是答辩加分项。

3. 核心模块实现与代码拆解:从登录到薪资核算

3.1 登录鉴权与拦截器配置

登录功能是所有业务模块的前置基础。我采用的是 JWT(JSON Web Token)方案做身份认证。整体流程是:用户提交用户名密码,后端校验通过后生成 token 返回给前端,前端在后续请求的 Header 中携带 token,后端通过拦截器校验 token 是否有效。

JWT 的结构是"Header.Payload.Signature"三段式,核心代码用 jjwt 库实现:

// JwtUtil.java @Component public class JwtUtil { @Value("${jwt.secret}") private String secret; @Value("${jwt.expire}") private Long expire; public String generateToken(String username) { Date now = new Date(); Date expireDate = new Date(now.getTime() + expire * 1000); return Jwts.builder() .setHeaderParam("typ", "JWT") .setSubject(username) .setIssuedAt(now) .setExpiration(expireDate) .signWith(SignatureAlgorithm.HS256, secret) .compact(); } public String getUsernameFromToken(String token) { return Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody() .getSubject(); } public boolean validateToken(String token) { try { Jwts.parser().setSigningKey(secret).parseClaimsJws(token); return true; } catch (Exception e) { return false; } } }

密钥和过期时间放到 application.yml 里管理,不硬编码在类里面,这是规范做法。JWT 的过期时间我设为 24 小时,也就是 86400 秒,这个时长对内部管理系统来说合适,太短会导致用户频繁重新登录,太长又会增加 token 泄露后的风险。

拦截器配置是另一个关键点。我需要让未登录用户访问受保护接口时直接被拦截,返回 401 状态码,而不是跳转到登录页或者报 500 错误。实现方法是继承 HandlerInterceptorAdapter:

public class JwtInterceptor implements HandlerInterceptor { @Autowired private JwtUtil jwtUtil; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!(handler instanceof HandlerMethod)) { return true; // 放行静态资源 } String token = request.getHeader("Authorization"); if (StringUtils.isNotBlank(token) && token.startsWith("Bearer ")) { token = token.substring(7); } if (StringUtils.isNotBlank(token) && jwtUtil.validateToken(token)) { String username = jwtUtil.getUsernameFromToken(token); request.setAttribute("username", username); return true; } response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("{\"code\":401,\"message\":\"未登录或登录已过期\"}"); return false; } }

然后在 WebMvcConfig 里注册拦截器,同时放行登录接口、静态资源和 Swagger 文档路径:

@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private JwtInterceptor jwtInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor) .addPathPatterns("/**") .excludePathPatterns( "/api/login", "/api/register", "/doc.html", "/webjars/**", "/swagger-resources/**", "/static/**" ); } }

这里有个细节你要注意:拦截器只是做"是否已认证"的校验,真正判断"是否有权限操作某个功能"要靠后端的角色权限控制。我后续通过自定义注解 @RequirePermission 配合 AOP 实现按钮级的权限控制,这个设计在你的论文里可以作为一个亮点展开。

3.2 员工信息管理:主表单 CRUD 与列表分页

员工管理是整套系统的核心业务模块,涵盖新增员工、编辑员工、删除员工、分页查询、条件筛选和按部门统计等功能。列表分页我用了 MyBatis-Plus 的分页插件,配置方式极简单:

@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); PaginationInnerInterceptor pagination = new PaginationInnerInterceptor(DbType.MYSQL); pagination.setMaxLimit(500L); interceptor.addInnerInterceptor(pagination); return interceptor; } }

分页查询接口的设计思路是:前端传入 pageNum、pageSize 以及可选的条件参数(员工姓名、部门ID、入职日期范围),后端使用 QueryWrapper 构建条件,返回总记录数和当前页数据:

@GetMapping("/list") public Result<Page<EmployeeVO>> list(EmployeeQueryDTO queryDTO) { Page<Employee> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize()); LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>(); if (StringUtils.isNotBlank(queryDTO.getName())) { wrapper.like(Employee::getName, queryDTO.getName()); } if (queryDTO.getDeptId() != null) { wrapper.eq(Employee::getDeptId, queryDTO.getDeptId()); } if (queryDTO.getEntryDateStart() != null) { wrapper.ge(Employee::getEntryDate, queryDTO.getEntryDateStart()); } if (queryDTO.getEntryDateEnd() != null) { wrapper.le(Employee::getEntryDate, queryDTO.getEntryDateEnd()); } wrapper.orderByDesc(Employee::getCreateTime); Page<Employee> result = employeeService.page(page, wrapper); // 转VO,补充部门名称 Page<EmployeeVO> voPage = convertToVO(result); return Result.success(voPage); }

在转 VO 的时候,我会遍历员工列表,通过 deptId 批量查询部门信息,填充部门名称字段。注意不要在循环里逐条查询部门,那样会产生 N+1 查询问题,性能会很差。正确做法是先把所有 deptId 收集起来,用一次 IN 查询批量取回部门信息,再映射到 VO 中。

新增和修改员工时要做字段级别的校验,比如手机号格式、邮箱格式、必填项检查。这些校验逻辑放在 service 层做,如果有校验失败的地方直接抛业务异常,由全局异常处理器统一包装成 Result 对象返回给前端。

3.3 考勤与薪资:从记录到计算的一体化流程

考勤模块最简单直接的应用是打卡记录管理。系统每天生成当天的考勤记录,员工可以在系统里进行上下班打卡,后端通过打卡时间判断状态是"正常""迟到"还是"早退"。具体判断规则是这样的:上班打卡在 09:00 之前为正常,之后为迟到;下班打卡在 18:00 之后为正常,之前为早退。如果没有打卡记录,则标记为"缺卡"。

考勤统计报表用了一条 SQL 按员工分组统计每月的出勤情况:

SELECT emp_id, DATE_FORMAT(attend_date, '%Y-%m') AS month, COUNT(*) AS total_days, SUM(CASE WHEN status = '正常' THEN 1 ELSE 0 END) AS normal_days, SUM(CASE WHEN status = '迟到' THEN 1 ELSE 0 END) AS late_days, SUM(CASE WHEN status = '早退' THEN 1 ELSE 0 END) AS early_leave_days, SUM(CASE WHEN status = '缺卡' THEN 1 ELSE 0 END) AS missing_days FROM attendance WHERE attend_date BETWEEN #{startDate} AND #{endDate} GROUP BY emp_id, DATE_FORMAT(attend_date, '%Y-%m')

薪资核算逻辑是另一个体现业务能力的地方。每个月的薪资由基本工资、奖金、补贴等加分项和社保扣款、个人所得税、缺勤扣款等减分项共同决定。我设计了一套计算公式:

public BigDecimal calculateSalary(Long empId, String settleMonth) { // 1. 查询员工基本信息 Employee employee = employeeMapper.selectById(empId); // 2. 查询该员工的基础薪资标准 SalaryStandard standard = salaryStandardMapper.selectByEmpId(empId); // 3. 统计本月考勤情况 AttendanceStat stat = attendanceMapper.statMonthly(empId, settleMonth); // 4. 计算缺勤扣款(假设日薪 = 月基本工资 / 21.75) BigDecimal dailySalary = standard.getBaseSalary() .divide(BigDecimal.valueOf(21.75), 2, RoundingMode.HALF_UP); BigDecimal absenceDeduct = dailySalary.multiply( BigDecimal.valueOf(stat.getAbsenceDays())); // 5. 计算实发工资 = 基本工资 + 奖金 + 补贴 - 社保 - 个税 - 缺勤扣款 BigDecimal actualSalary = standard.getBaseSalary() .add(standard.getBonus()) .add(standard.getSubsidy()) .subtract(standard.getSocialSecurity()) .subtract(calculateTax(standard.getBaseSalary() + standard.getBonus() - standard.getSocialSecurity())) .subtract(absenceDeduct); return actualSalary.setScale(2, RoundingMode.HALF_UP); }

注意薪资计算里的 BigDecimal 使用规范:金额必须用 BigDecimal 而不是 double 或 float,这是为了防止精度丢失。21.75 是劳动法规定的月计薪天数,在论文的需求分析部分可以把这个计算依据写进去,能体现你对业务场景的真实理解。

3.4 前端页面设计与交互流程

前端我用 Thymeleaf 模板引擎 + Bootstrap 5 + jQuery 的组合。页面结构分为登录页、主框架页和各个业务页面。主框架页采用经典的左侧菜单栏 + 右侧内容区的布局,顶部显示当前登录用户和退出按钮。

每个列表页的标准交互流程是:页面加载时请求分页接口渲染表格,搜索栏输入条件后点击查询重新加载表格,点击新增或编辑按钮弹出模态框填写表单,提交后刷新列表。这套交互逻辑用 jQuery 的 ajax 就能实现,不需要额外引入前端框架。以员工管理列表页为例:

function loadPage(pageNum, pageSize) { $.ajax({ url: '/api/employee/list', type: 'GET', data: { pageNum: pageNum, pageSize: pageSize, name: $('#searchName').val(), deptId: $('#searchDeptId').val() }, dataType: 'json', success: function(result) { if (result.code === 200) { renderTable(result.data.records); renderPagination(result.data.total, result.data.current, result.data.size); } } }); }

这里有个跨页查询的坑:列表分页之后,如果你在第二页点击编辑用户,修改完成后再刷新列表,跳回第一页会丢失之前的查询条件。解决办法是在刷新列表之前把搜索条件存到 sessionStorage 里,回退时重新读取。

如果你决定用前后端分离方案,前端换成 Vue 3 + Element-Plus,后端接口保持 RESTful 风格不变,数据结构统一用 Result 包装,前端通过 axios 拦截器统一处理 token 注入和 401 跳转。两种方案在你写论文时可以任选其一阐述,我建议时间紧就选 Thymeleaf,时间充裕且想展示更多技术栈就选 Vue 分离方案。

4. 论文写作框架:把项目代码变成毕业设计的得分点

4.1 论文结构设计与每章写作要点

很多同学代码写完了但论文不知道怎么写,其实论文的逻辑和你设计的系统是完全对应的。我给你的建议是按照"背景与意义→技术介绍→需求分析→系统设计→系统实现→系统测试→总结与展望"的七章结构来组织,这是计算机毕业设计论文最常见也最稳妥的框架。

第一章绪论要回答三个问题:为什么要做人事管理系统(背景)、当前人事管理存在哪些痛点(现状分析)、这套系统能带来什么价值(意义)。这部分要引用一些实际的数据和场景,比如"传统 Excel 管理方式在员工数量超过500人后更新效率明显下降"这类论述,不要空喊口号。

第二章相关技术介绍分别介绍 SpringBoot、MyBatis-Plus、MySQL、Thymeleaf。每个技术写两到三页,包含技术简介、核心特性和在本系统中的应用场景。注意不要写成技术文档的搬运,要用"本系统采用该框架提供的XX能力来实现XX功能"的句式把技术和你自己的项目结合。

第三章需求分析是论文中最容易拿分的部分。你要画出用例图,详细描述每个角色(管理员、普通员工)能执行的操作。功能需求和非功能需求要分开写,非功能需求包括系统响应时间(页面响应不超过3秒)、安全性(密码加密存储、接口鉴权)、可用性(7x24小时稳定运行)这些。

第四章系统设计要包含架构设计、功能模块设计、数据库设计和接口设计。架构图用一个分层结构图展示表现层、业务逻辑层、数据访问层和数据存储层。数据库设计要给出所有表的建表语句和 E-R 图,注意在论文里放一张完整的 E-R 图是基本要求,画图工具用 PowerDesigner 或者 draw.io 都可以。

4.2 把实现过程转成论文素材的方法

论文第五章系统实现不是贴代码,而是用截图 + 核心代码片段 + 文字说明的方式,描绘每个功能模块是怎么实现的。每一个功能点建议按"页面功能描述 → 后端处理流程 → 关键代码 → 实现效果图"四段式结构写。

我拿员工管理模块给你举个例子。先描述这个页面有什么功能:左侧是部门树,右侧是员工列表,支持按部门筛选和关键字搜索,支持新增、编辑、删除和导出 Excel。然后说明后端处理流程:前端点击部门树节点时,把 deptId 作为参数传给后端,后端根据 deptId 查询该部门下的员工列表并返回。接着贴一段关键代码。最后放一张页面的运行截图。这样一个功能模块写下来有800字到1000字,整篇论文正文很容易就达到两万字以上。

论文里还有一个容易被老师挑刺的点是"核心业务逻辑的描述"。以薪资计算为例,你不仅要效果上图,还必须写出计算逻辑的文字描述,比如:基本工资 8000 元,当月请假 5 天,按月计薪天数 21.75 计算日薪为 367.82 元,缺勤扣款 1839.08 元,加上绩效奖金 2000 元,再扣除社保公积金 1200 元和个人所得税 280 元,最终实发工资为 6680.92 元。这种有具体数字的计算过程,能够直观展示你对业务的理解,非常加分。

4.3 测试章节和数据准备技巧

第六章系统测试要体现完整的测试流程和测试结果。测试用例表建议包含以下要素:测试编号、测试模块、测试用例名称、前置条件、测试步骤、预期结果、实际结果、是否通过。核心功能的测试用例设计参考:

测试编号测试模块测试用例预期结果是否通过
TC-001登录模块输入正确用户名密码登录成功,跳转主页面通过
TC-002登录模块输入错误密码提示"用户名或密码错误"通过
TC-003登录模块未登录访问业务接口拦截并返回401通过
TC-004员工管理新增员工(所有字段合法)保存成功,列表刷新出现新记录通过
TC-005员工管理新增员工(手机号格式错误)提示手机号格式不正确通过
TC-006员工管理删除在职员工提示不允许删除在职员工通过
TC-007考勤管理按月份统计考勤正确返回当月出勤汇总通过
TC-008薪资管理含请假扣款薪资计算实发金额与手工计算结果一致通过

测试数据的准备也有讲究。你的数据库里至少要有 10 个以上员工、3 个部门、每个员工至少 2 个月的考勤和薪资记录,这样页面展示才不会空,截图效果也更好。测试数据可以考虑用一个 SQL 脚本批量生成,我当时的做法是写了一个 Python 脚本循环生成随机数据插入数据库,节省了很多手工造数据的时间。

5. 源码部署与问题排查:从 idea 到上线的完整记录

5.1 本地开发环境搭建

部署这套系统前,你要保证本地环境满足以下要求:

  • JDK 8 及以上(推荐 JDK 8 或 JDK 11,对应 SpringBoot 2.7.x)
  • Maven 3.6 以上
  • MySQL 8.0 及以上
  • IDEA 2021 以上版本(社区版和专业版均可)

第一步是导入数据库脚本。在 MySQL 中创建数据库 hr_management,然后执行项目根目录下的 hr_management.sql 脚本,系统会自动创建数据表并插入初始管理员账号。初始账号一般是 admin / 123456,密码用 BCrypt 加密存储在数据库里,这也是论文安全设计部分的一个写作点。

第二步是修改配置文件。打开 src/main/resources/application.yml,把数据库地址、账号、密码改成你本地的配置:

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/hr_management?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB max-request-size: 50MB mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 jwt: secret: your-secret-key-please-change-in-production expire: 86400

这里重点提醒:数据库连接的 serverTimezone 参数一定要设置成 Asia/Shanghai,否则 MySQL 8.0 连接时会报时区相关的异常。useSSL 建议设置 false,本地开发不需要 SSL 加密连接。

第三步是启动项目。在 IDEA 中打开项目,等待 Maven 加载完依赖后,运行 HrManagementApplication 类的 main 方法。控制台出现 "Started HrManagementApplication" 的日志就说明启动成功,浏览器访问 http://localhost:8080 即可看到登录页面。

5.2 常见启动报错与解决方案

我在部署和帮别人排查这套系统的过程中,整理了这份高频问题清单,你照着排错就行。

问题一:springboot版本太高导致启动失败

SpringBoot 3.x 要求 JDK 17,如果你本机装的是 JDK 8,启动会直接报 "java.lang.UnsupportedClassVersionError" 之类的错误。解决方案是统一使用 SpringBoot 2.7.x 版本,同时在 IDEA 的 Project Structure 里检查 Project SDK 是否为 1.8。

问题二:数据库连不上,报 Access denied for user

这个大概率是密码不对,或者 MySQL 账号没有远程访问权限。先确认 application.yml 里的用户名密码和本地 MySQL 完全一致,然后用命令行直接连接测试:mysql -u root -p。另外检查一下 MySQL 服务有没有启动,Windows 下按 Win+R 输入 services.msc 找到 MySQL80 确认服务状态。

问题三:端口被占用

启动时日志显示 "Port 8080 was already in use",说明 8080 端口被其他程序占了。解决方法有两个:要么进任务管理器找到占用端口的进程把他结束掉,要么在 application.yml 里把 server.port 改成 8081。

问题四:MyBatis-Plus 分页查不出数据

分页插件没生效通常是配置类没被扫描到。检查 MybatisPlusConfig 类是否放在 SpringBoot 启动类的子包下,确保能被 @ComponentScan 扫描到,或者在启动类上手动加上 @MapperScan("com.example.hrmanagement.mapper") 注解。

问题五:Thymeleaf 页面加载不出样式

大多数情况是静态资源的访问路径写错了。Thymeleaf 模板中引用 CSS/JS 文件一定要用 th:href="@{/static/css/style.css}" 的语法,不要直接写 href="/static/css/style.css"。前者会根据上下文自动拼接项目根路径。

问题六:文件上传大小超限报错

SpringBoot 默认的最大上传文件大小是 1MB,如果你做员工头像上传功能,超过这个大小就会报 MaxUploadSizeExceededException。你看我在配置文件里已经设置了 max-file-size: 10MB,这个参数按项目实际情况调整。

5.3 Docker 部署实战:把系统打成镜像

如果你想让系统部署到 Linux 服务器上,我建议直接用 Docker 容器化部署。先在项目根目录准备 Dockerfile:

FROM maven:3.8-jdk8 AS build WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests FROM openjdk:8-jdk-alpine WORKDIR /app COPY --from=build /app/target/hr-management-1.0.0.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar", "--spring.profiles.active=prod"]

然后用 docker-build 脚本完成构建和启动:

mvn clean package -DskipTests docker build -t hr-management:1.0 . docker run -d --name hr-management-app \ -p 8080:8080 \ -e SPRING_DATASOURCE_URL="jdbc:mysql://192.168.1.100:3306/hr_management?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai" \ -e SPRING_DATASOURCE_USERNAME=root \ -e SPRING_DATASOURCE_PASSWORD=yourpassword \ hr-management:1.0

Docker 部署的注意点是把数据库地址改成宿主机能访问到的 IP,不要再用 localhost,因为容器内的 localhost 指向的是容器自身,连不到宿主机上的 MySQL。另外生产环境的 JWT 密钥等敏感信息通过环境变量传入,不要写死在配置文件里。这部分部署过程写进论文的"系统环境部署"小节,也是挺有分量的实践内容。

5.4 系统安全防护与常见攻击应对

信息安全这块虽然在毕设论文里占比不高,但确实是现在企业面试时会被追问的重点。我在这个系统里做了这样几层防护:

第一层:SQL 注入防护。使用 MyBatis-Plus 预编译机制,所有 SQL 参数都通过 #{} 绑定,避免字符串拼接导致的注入风险。项目中不要使用 ${} 直接拼接变量,这是安全红线。

第二层:XSS 防护。对所有用户输入的字符串做 HTML 标签过滤,使用commons-text 库的 StringEscapeUtils.escapeHtml4 对富文本字段做转义处理,防止用户提交恶意脚本。你可以在全局异常处理器里加一个统一入口,对请求参数做清洗。

第三层:密码安全。用户密码用 BCrypt 加密存储,BCrypt 算法自带盐值,每次加密结果都不同,即使数据库泄露也无法反推出明文密码。登录校验时用 BCrypt 的 matches 方法比对密码。

第四层:接口防刷。对登录接口做最基本的限流处理,同一个 IP 在单位时间内连续登录失败超过 5 次就锁定账号 15 分钟。这个逻辑用简单的计数器 + Redis 过期时间就能实现,成本低效果好。

这些安全设计写进论文的"系统安全设计"小节,无论是指导老师还是答辩评委都会觉得你的考虑很周全。

6. 实操心得与避坑指南

项目都做完了,我再回头看,有几个点想特别提醒你,都是基于真实开发经验总结的。

第一个是关于时间规划。如果你是在做毕业设计,我强烈建议你按"先搭框架 → 再做核心模块 → 再补边缘功能 → 最后写论文"的顺序推进。核心模块指的是登录、员工管理、部门管理这三个,做完这三个框架就算是通了,剩下考勤、薪资、请假这些模块都是在这套框架上的扩展。不要一上来就想把所有功能一次性做完,那样一天写不了几个接口,很容易焦虑。

第二个是基于实际操作的体会是:数据库字段的命名一定要保持统一。我建议所有表都包含 create_time、update_time、deleted 三个公共字段,create_time 和 update_time 用 MyBatis-Plus 的自动填充功能,deleted 是逻辑删除字段。这样你在写查询条件时能统一处理"只查未删除数据"的逻辑,而且整体代码风格会很规范。

第三个要提醒你的是,做项目过程中一定要及时拍照和记录。系统跑起来后每个页面截一张图,每完成一个功能写一段文字说明,这些素材是你写论文时最宝贵的一手资料。我就是因为前期没有养成记录的习惯,后期写论文时还要重新打开系统截图,费了不少时间。如果时间允许,把每个模块的测试过程和结果也记录下来,测试章节的内容就能直接使用这些资料。

最后一个建议是关于代码注释。不要觉得注释是给别人看的,写注释最大的受益者其实是三个月后的你自己。我习惯在每个核心方法的上面加三行注释:方法作用、参数说明、返回值说明。重要业务逻辑(比如薪资计算)在方法内部加上分步注释。这个习惯在你写论文的时候,会让你的代码截图有更强的可读性,答辩时也能自信地解释每一段逻辑。

这套系统做下来,你掌握的不只是 SpringBoot 的 CRUD,而是一条完整搞定"设计 → 开发 → 部署 → 写文档"的全流程能力。这套能力是无论你去企业做开发还是继续深造做项目,都绕不开的基本功。跟着上面的步骤一步步来,相信你很快就能把这套系统跑起来,也能收获一个拿得出手的毕设项目。

本文还有配套的精品资源,点击获取

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

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

立即咨询