基于SpringBoot的人事管理系统设计与实现全解析
简介本资源是一套面向计算机与软件工程专业本科生的毕业设计实战项目聚焦企业级人事管理数字化需求提供基于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、status0在职/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.javacontroller 只负责接收参数和返回结果不写业务逻辑service 层做业务处理比如登录校验、薪资计算、请假审批状态的流转mapper 层只做数据库操作。这套分层规范是你论文中系统设计部分最直接的设计亮点也是答辩加分项。3. 核心模块实现与代码拆解从登录到薪资核算3.1 登录鉴权与拦截器配置登录功能是所有业务模块的前置基础。我采用的是 JWTJSON 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 错误。实现方法是继承 HandlerInterceptorAdapterpublic 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;charsetUTF-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 ResultPageEmployeeVO list(EmployeeQueryDTO queryDTO) { PageEmployee page new Page(queryDTO.getPageNum(), queryDTO.getPageSize()); LambdaQueryWrapperEmployee 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); PageEmployee result employeeService.page(page, wrapper); // 转VO补充部门名称 PageEmployeeVO voPage convertToVO(result); return Result.success(voPage); }在转 VO 的时候我会遍历员工列表通过 deptId 批量查询部门信息填充部门名称字段。注意不要在循环里逐条查询部门那样会产生 N1 查询问题性能会很差。正确做法是先把所有 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.xMaven 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?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse 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 下按 WinR 输入 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 容器化部署。先在项目根目录准备 DockerfileFROM 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 --frombuild /app/target/hr-management-1.0.0.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, app.jar, --spring.profiles.activeprod]然后用 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_URLjdbc:mysql://192.168.1.100:3306/hr_management?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai \ -e SPRING_DATASOURCE_USERNAMEroot \ -e SPRING_DATASOURCE_PASSWORDyourpassword \ hr-management:1.0Docker 部署的注意点是把数据库地址改成宿主机能访问到的 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而是一条完整搞定设计 → 开发 → 部署 → 写文档的全流程能力。这套能力是无论你去企业做开发还是继续深造做项目都绕不开的基本功。跟着上面的步骤一步步来相信你很快就能把这套系统跑起来也能收获一个拿得出手的毕设项目。本文还有配套的精品资源点击获取

相关新闻

最新新闻

日新闻

周新闻

月新闻