news 2026/9/12 4:34:34

基于Spring Boot+Vue的人事管理系统设计与实现(毕业设计案例)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Spring Boot+Vue的人事管理系统设计与实现(毕业设计案例)

简介:这是一套基于 Spring Boot 框架的人事管理系统的毕业设计完整交付包,源码、论文、答辩 PPT 一并提供,适合计算机、通信、人工智能、自动化等专业学生用于课程设计、大作业或毕业设计,也可作为 Java 入门到进阶的项目参考。系统覆盖人事管理常见业务模块,代码经调试可运行,配合论文与 PPT 能帮助理解从设计到落地的完整路径。压缩包共 300 个文件,约 90.73MB;其中 126 个 Java 源文件构成后端核心逻辑,js/css 与 png 为前端页面和界面素材,xml/properties 为配置信息,sql 为数据库脚本,doc/docx 与 pptx 提供论文和答辩材料,另有 jar、Dockerfile 便于部署研究。目前已有 157 人学习下载。对于需要快速搭建人事管理类项目、梳理毕设写作结构或准备答辩演示的读者,这套资料具有直接参考价值,也可在此基础上扩展新功能。

1. 毕设季最常见的翻车现场,不是业务代码没写完

答辩前夜还在改 bug 的同学,一定懂这个场景:数据库连上了,接口能调通,网页却白屏,F12 里全是chunk-vendors.5ce9f8b8.css这样的文件加载失败。其实这类文件名已经暴露了项目的真实技术形态——Spring Boot 只负责后端,前端是 Vue 打包后的静态资源,两者通过 Maven 构建融合进一个 jar。这套人事管理系统的价值也正在于此:它不是教科书里那种前后端写在一起的 JSP 老项目,而是一个能跑通全流程的现代 Web 工程。论文、源码、答辩 PPT 齐全,适合拿来当毕业设计,也适合做 Spring Boot 四层架构的入门样板。下面从架构、代码到部署,拆一遍这个项目真正值得抄的部分。

2. 为什么这套系统选 Spring Boot 四层架构:从依赖到分层逻辑

人事管理系统的核心业务无非是员工信息维护、部门管理、考勤与薪资记录,这类 CRUD 密集型应用,对框架的要求是「上手快、约束清晰、能快速出成果」。Spring Boot 恰好在这三点上都占优:自动配置省掉大量 XML,starter 机制让依赖管理变得线性,内嵌 Tomcat 让部署从「装环境」变成「跑一个 jar」。用 Maven 做构建工具的理由更直接——毕设环境里老师的电脑不一定装了 Gradle,但 Maven 在 Win 和 Mac 上行为一致,而且mvnw.cmd能保证没装 Maven 的机器也能构建,这一步给答辩演示省了很多麻烦。

2.1 项目骨架与核心依赖清单

拆开这个项目,目录结构是标准的 Spring Boot 单模块应用。先看pom.xml里值得抄的依赖组合:

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> </parent> <dependencies> <!-- Web 层:Controller 注解、内嵌 Tomcat、参数校验 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 持久层:MyBatis-Plus 比 MyBatis 少写大量 XML --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.5</version> </dependency> <!-- 数据库驱动 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <!-- 认证:JWT 无状态登录 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <!-- 物理删除改为逻辑删除 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>

依赖选型上有两个点值得说明。第一,MyBatis-Plus 而不是原生 MyBatis,是因为BaseMapper已经把单表 CRUD 封装好了,写一个EmployeeMapper extends BaseMapper<Employee>,增删改查方法直接就位,论文里的「数据访问层设计」章节也能多写一段 LambdaQueryWrapper 的查询构造。第二,JWT 依赖选 jjwt-api 而不是手写加密工具类,是为了避免在答辩时被评委追问「你的 Token 是怎么做到防篡改的」这种问题——用成熟库意味着签名和验签逻辑有据可查。

2.2 实体、Mapper、Service、Controller 每一层具体写什么

四层架构的关键不是包名分层,而是职责边界。以员工模块为例,entity/Employee.java只做字段映射:

@Data @TableName("employee") // 对应数据库表名 public class Employee { @TableId(type = IdType.AUTO) private Integer id; private String empNo; // 工号,业务上唯一 private String name; private String deptId; private String position; private String phone; private Integer status; // 0在职 1离职 2休假 @TableLogic private Integer deleted; // 逻辑删除标记 }

Service 层在这里有讲究。常见做法是让EmployeeService extends ServiceImpl<EmployeeMapper, Employee>,这样既拿到了 MyBatis-Plus 提供的saveupdateByIdpage方法,又能在addEmployee这类自定义业务里加上工号唯一性校验。Controller 层只做两件事:接收参数、返回统一结果。被很多人忽略的是参数校验一定要放在 Controller 层入口做,否则脏数据会直接穿透到数据库。

@RestController @RequestMapping("/api/employee") public class EmployeeController { private final EmployeeService employeeService; @PostMapping("/add") public Result add(@RequestBody @Valid Employee employee) { employeeService.addEmployee(employee); return Result.success("添加成功"); } }

这段代码的逻辑说明:@RequestBody把前端 JSON 反序列化为 Employee 对象,@Valid触发字段校验注解,Service 层只处理业务。需要强调的参数是三处,第一是@RequestMapping("/api/employee")统一了模块前缀,第二是@PostMapping("/add")明确这是 POST 请求,第三是Result是自定义的响应包装类,里面必须包含codemessagedata三个字段——论文里的「接口统一返回格式设计」小节可以直接用这个类。如果答辩时演示接口测试,Postman 里能看到所有接口都是{ "code": 200, "message": "成功", "data": {} }的结构,这就是规范性的直观证据。

2.3 application.yml 里那些容易被扣分的配置项

配置文件的完整程度,直接影响项目能不能在另一台电脑上直接跑起来。核心配置如下:

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/hr_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted

配置说明:serverTimezone=Asia/Shanghai是必填的,否则 MySQL 8.x 驱动会报时区错误;map-underscore-to-camel-case让数据库的emp_no自动映射为empNologic-delete-field声明逻辑删除字段后,MyBatis-Plus 会在所有查询里自动追加deleted = 0。这里要特别提醒一个坑:如果直接手写 SQL 关联查询,逻辑删除条件是不生效的,必须自己在 XML 里写deleted = 0,很多人的债就是这么欠下的——答辩时老师操作离职员工查找,发现列表里还能查到,这种 bug 一旦暴露,评审分直接受影响。

3. 前端产物与 jar 包融合:为什么资源文件里全是 chunk 开头的文件名

项目压缩包里chunk-vendors.5ce9f8b8.csschunk-vendors.5ce9f8b8.cssapp.35a1c3ae.css这些文件,初看像乱码,实际是 Vue CLI 构建产物。chunk-vendors是第三方依赖(Vue、Element Plus、axios 等)统一打包后的文件名,app是业务代码,后面的哈希值5ce9f8b8是内容指纹——文件内容变了哈希就变,用来解决浏览器缓存问题。这一整层前端代码开发时是独立的 Vue 工程,npm run build之后才输出这些文件。

3.1 前端静态资源放进 Spring Boot 的两种可行方式

项目交付时没有前端源码目录,只有构建产物,说明作者在开发时做了前后端分离,交付时把产物合进了 Spring Boot。常见做法是直接把整个dist目录复制到src/main/resources/static/下,Spring Boot 会把这里的文件映射为根路径资源。另一种更工程化的方式是使用frontend-maven-plugin在 Maven 打包时自动构建前端,但这个项目既然已经给出构建后的文件,采用第一种即可。

部署后的访问路径有个容易踩的误区。因为前端有index.html,而它内部通过相对路径引用了jscss,所以如果给 Controller 加一个@RequestMapping("/view")来跳转页面,反而会导致资源加载路径错乱。正确的做法是配置一个 WebMvc 的视图映射,或者干脆什么也不配——Spring Boot 会自动把localhost:8080/映射到static/index.html

3.2 联调阶段的后端配置:CORS 与接口前缀

开发阶段前后端分离跑在两个端口上(Vue 默认 8080,后端 8080),必然遇到跨域问题。项目里的后端配置了全局 CORS 策略,相当于告诉浏览器「我允许前端页面跨端口访问我的接口」。实际代码是在config/CorsConfig.java里重写WebMvcConfigurer.addCorsMappings,允许的路径是/**,允许的请求头需要包含Authorization——因为 JWT 就放在这个头里。欠考虑的是allowCredentials(true)必须与具体的allowedOrigins配合使用,如果写成*,浏览器会直接拒绝携带凭证的请求。这个细节经常被人忽略,等项目部署到服务器上才发现登录后所有请求都报错。

如果不需要浏览器直接访问后端接口,还有一个更省事的方案:生产环境把前端产物放进 jar,后端不再单独开端口,自然不存在跨域。这个项目最终交付形态就是这样。开发阶段跨域配置继续保留,因为论文里「系统测试」章节通常要展示前端开发服务器的联调截图,这个配置能保证截图环境一致。

4. 认证授权与员工业绩查询:JWT 拦截器、管理员权限和数据权限实现

人事管理系统比一般 CRUD 项目多出来的复杂度,集中在「谁能访问这个接口」和「谁能看这些数据」两个问题上。如果把这个模块做扎实,论文的「系统设计」部分会立刻有层次。项目采用的是 JWT 无状态认证,不依赖 Session,后端只负责签发 Token 和验签,登录状态保存在客户端。相比 Spring Security 那套完整的过滤器链,JWT 拦截器在答辩时更容易讲清楚,因为每行代码都是可见的。

4.1 JWT 生成与拦截器校验的实现细节

先看登录接口里生成 Token 的核心代码:

public String generateToken(Integer userId, String username, Integer role) { return Jwts.builder() .setSubject(username) .claim("userId", userId) .claim("role", role) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 8)) .signWith(secretKey, SignatureAlgorithm.HS256) .compact(); }

这段代码的逻辑说明:setSubject放用户名,claim放自定义载荷(用户 ID 和角色),setExpiration设置 8 小时有效期,signWith用密钥做 HS256 签名。这里唯一需要保管好的是secretKey,项目里通常写在配置文件的jwt.secret下。答辩时要能回答「Token 如果被盗用怎么办」——常见做法是把过期时间设短(比如 2 小时),同时提供刷新接口。

拦截器的工作方式是继承HandlerInterceptorAdapter或者实现HandlerInterceptor,在preHandle里取请求头的Authorization字段,去掉 Bearer 前缀后调用Jwts.parser()验签。验签失败返回 401,成功就把userId塞进request.setAttribute("userId", ...)。需要特别注意的是,/api/login/api/register这两个路径必须在注册拦截器时排除掉,否则登录请求都会被拦下来,造成「系统无法登入」的假象。

@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor) .addPathPatterns("/api/**") .excludePathPatterns("/api/login", "/api/register"); }

这段配置的含义是拦截所有/api/开头的接口,放行登录和注册。如果项目里还有静态资源路径,比如/doc.html/swagger-ui/**,也要加入白名单。这里的边界是:拦截器管的是「你是谁」,@RequiresPermissions这类注解管的才是「你能干什么」,两者叠加才是完整的权限模型。

4.2 MySQL 中权限与数据的查询设计:管理员怎么看到全部、员工只能看自己

后台管理端有管理员与普通员工两种角色,权限控制直接落到查询维度。餐厅老板通过部门过滤查看薪酬报表,部门主管看本部门,普通员工查自己的工资料,这就是典型的数据权限问题。避免为「谁能看什么数据」写多套 Controller 的常用方案是引入 MyBatis-Plus 的@InterceptorIgnore配合LambdaQueryWrapper动态拼接条件:

public Page<Employee> queryEmployeePage(int page, int size, String deptId, Integer role, Integer currentUserId) { LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(StringUtils.isNotBlank(deptId), Employee::getDeptId, deptId); // 普通成员只能看到自己的数据 if (role == 2) { wrapper.eq(Employee::getId, currentUserId); } return employeeService.page(new Page<>(page, size), wrapper); }

这段代码的逻辑说明:eq(StringUtils.isNotBlank(deptId), ...)这种写法,第一个参数是布尔条件,条件成立才拼进 SQL,这样无论deptId是否为空,查询都不会报错。role == 2时强制追加id = currentUserId,把查询范围锁死在当前用户。参数表需要记清三件套:page是页码从 1 开始,size是每页条数,wrapper是 MyBatis-Plus 的条件构造器。如果直接拼 SQL,比如"select * from employee where dept_id = '" + deptId + "'",一旦deptId传的是"1 OR 1=1",整张员工表全部泄露,答辩现场演示这个漏洞会产生很好的安全加分,反面的例子也值得写进论文。

4.3 Actuator 暴露面:人事系统也有不该开门的服务

Spring Boot 自带 Actuator 监控组件,它默认暴露/actuator/health等端点,而/actuator/env/actuator/heapdump如果被外部访问,会泄露数据库密码、JVM 内存快照等敏感信息。这个项目的 production 环境配置中把management.endpoints.web.exposure.include限定为health,info两个最小端点,并给/actuator/**加了 IP 白名单,从源头上减少被扫描工具列目录的风险。这个内容在答辩中可以对应「系统安全性设计」一节,但建议不要在论文里展开过多,以免评委顺着话题追问具体绕过方式,超出范围和准备深度反而被动。

5. 答辩演示前:用 mvnw.cmd 打包、Windows 下部署与 PPT 讲解顺序

项目带的mvnw.cmd是 Maven Wrapper 的 Windows 脚本,它保证电脑上没有安装 Maven 也能拉取指定版本并用它执行构建。打开终端进入项目目录,执行mvnw.cmd clean package,首次运行会先下载 Maven 和依赖,耐心等几分钟。输出里出现BUILD SUCCESS后,target目录下会生成一个可执行 jar,名字类似hr-system-0.0.1-SNAPSHOT.jar。整个打包流程不依赖 IDE,这一点在答辩现场特别好用——即使用老师的电脑,只要能联网就能构建。

命令执行的具体步骤如下:第一步mvnw.cmd -v验证 wrapper 是否正常;第二步mvnw.cmd clean package -DskipTests跳过测试打包;第三步看target目录。与mvn原生命令的区别在于mvnw.cmd用的是项目锁定的 Maven 版本,避免出现老师电脑上 Maven 3.9 与项目依赖不兼容的怪问题。

Windows 上部署这个系统只需要三步:本地 MySQL 里执行sql目录下的建库脚本;确认application.yml的数据库账号密码匹配;然后java -jar target/hr-system-0.0.1-SNAPSHOT.jar,浏览器访问localhost:8080。端口被占用时改用--server.port=8081即可。

答辩 PPT 的讲解顺序,我建议完全反着来:先放系统运行截图和演示视频,让评委 30 秒内建立「它真的能跑」的认知;再讲核心表和接口设计;最后才提技术选型理由。因为评委最烦的是从头讲 Spring Boot 是什么,那是对 PDF 复读,不是答辩。高频追问里的「MyBatis-Plus 和 MyBatis 区别」「JWT 能防止 CSRF 吗」「数据量到百万级怎么优化」,分别需要在 PPT 里预埋一张对比表、一行防 CSRF 说明、一条索引优化说明——employee表的emp_no字段建唯一索引,这是最简单的优化证据,讲清楚「为什么唯一索引能加速查询」,比背十页概念管用得多。

最后一个实用技巧:演示时把 MySQL 命令行窗口开着,随机执行一条SELECT * FROM employee,向评委展示数据实时变化。这比任何架构图都有说服力。这套项目里该复用的复用、该避开的坑避开,从答辩到实际部署就不会有出其不意的翻车点。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 4:33:24

阿里云MySQL选型决策框架:RDS与PolarDB对比实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 4:28:20

B站数据爬虫实战:异步抓取与反爬策略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 4:27:50

Node.js与SQLite构建高效运维文档管理系统

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 4:27:36

论文写作前的准备怎么配齐?工具按环节配齐,先分清三类准备项

论文动笔前准备不足会反复返工&#xff0c;问题通常不在能力&#xff0c;而在没分清哪些准备项当下就要定死。知学术AIPaperGPT 把准备分成既定项、迭代项、增量项三类&#xff0c;再按选题、文献、大纲、工具四个环节各自配齐。免费智能大纲的入口放在文末。完整流程怎么走、按…

作者头像 李华
网站建设 2026/9/12 4:27:17

达梦与人大金仓Prometheus监控利器:sql_zh_exporter深度解析

简介&#xff1a;这是一款面向达梦与人大金仓等国产数据库的Prometheus SQL监控导出器&#xff0c;主要解决这两类数据库监控指标难以接入Prometheus生态的问题。通过自定义YAML配置文件&#xff0c;使用者可灵活设定需采集的指标项与采集频率&#xff0c;按需监控CPU、内存、事…

作者头像 李华
网站建设 2026/9/12 4:27:16

ProtocolBuffer核心特性与高效数据交换实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华