ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Spring Boot薪资管理系统毕业设计:核心模块、实现与答辩指南

Spring Boot薪资管理系统毕业设计:核心模块、实现与答辩指南 1. 选题背后的门道为什么薪资管理系统值得做计算机毕业设计最怕什么不是不会写代码而是选了一个自己都讲不清楚的题目。薪资管理系统这个方向我接触过不少从本科生到在职提升的都有人选最后能做出彩的往往不是技术堆得最猛的而是把业务逻辑吃得最透的。Spring Boot 在这个题目里几乎成了标准答案生态成熟、案例多、招人喜欢更重要的是薪资这个场景天然自带“计算规则 权限控制 数据报表”三大模块每一块都能撑起论文的核心章节。很多人上来就纠结“我这个题目是不是太简单了”。我直接说结论薪资管理系统一点都不简单但要看你做到什么程度。如果只是做一个增删改查把员工表和工资表绑在一起那确实撑不起一篇像样的毕业设计论文。可如果你把工资计算规则、社保公积金扣除、个税累计预扣、工资条发放、权限分级、报表导出这些环节都理清楚这个题目的深度完全不输给那些花里胡哨的“基于某某框架的某某平台”。选这个题还有一个隐性的好处薪资结构每个学校、每个公司都不一样这意味着你可以在论文里名正言顺地写“本系统针对XX场景设计”不用怕查重也不用怕答辩时被问住。答辩老师最常问的一句话就是“你这个工资是怎么算出来的”只要业务逻辑是你自己梳理的这个问题你就能答得比背代码流畅得多。从评分角度看毕业设计一般看三样东西工作量、创新点、系统完成度。薪资管理系统在这三方面都有天然的着力点。工作量方面员工管理、部门管理、薪资项目配置、月考勤汇总、工资计算、历史工资查询、统计图表随便一列就是六七个模块。创新点方面你可以做电子工资条的加密查看也可以做薪资变动的审批流还可以做基于历史数据的薪资趋势预测。完成度方面Spring Boot 加 Vue 的前后端分离方案已经很成熟照着规范的流程走很少会翻车。2. 技术选型的权衡Spring Boot 不是唯一答案但一定是最稳的答案2.1 后端框架为什么选 Spring Boot 而不是 SSM 或者微服务这个题目如果你去搜索引擎里翻十个里有八个是 Spring Boot 做的。原因很简单Spring Boot 把配置的复杂度降下来了让你把精力放在业务实现上。SSM 时代你要写一堆 XML 配置光 Spring、Spring MVC、MyBatis 三者的整合就能折磨掉你两周时间而这些工作对毕业设计来说没有任何加分。Spring Boot 的自动装配机制把这些约定俗成的配置都处理掉了你只需要关注自己写的代码。我见过一些同学上来就想搞 Spring Cloud 微服务、分布式事务、消息队列觉得这样显得水平高。说实话毕业设计阶段搞微服务大概率是给自己挖坑。薪资管理系统本质上是企业内部系统并发量不会高到哪里去单体应用完全够用。微服务带来的服务拆分、配置中心、链路追踪这些问题每一个都能让你在答辩前夜崩溃。老老实实用 Spring Boot 单体架构把代码写得干净利落比什么都强。版本选择上我多说一句不要一上来就装最新版。Spring Boot 3.x 对 JDK 版本有要求而且部分第三方组件的兼容性不如 2.x 稳定。我做这个项目的时候用的是 Spring Boot 2.7.x JDK 1.8这套组合经过了大量的生产验证网上能搜到的坑和解决方案也最多。如果你非要用新版本也要保证自己的 JDK 版本跟得上别装了个 Spring Boot 3.2 还在用 JDK 8启动都会报错。2.2 前端方案前后端分离还是服务端渲染薪资管理系统这种项目前端有两种典型做法。第一种是传统的服务端渲染用 Thymeleaf 模板引擎后端把数据填到 HTML 里返回给浏览器。第二种是前后端分离后端只提供 JSON 接口前端用 Vue 或者 React 单独开发最后打包成静态文件部署。我给的建议是如果你前端基础一般选前后端分离反而更容易通过答辩。这个逻辑听起来反直觉但实际情况是前后端分离是目前企业开发的主流形态论文里可以写的技术点更多。你可以光明正大地写“前端采用 Vue 3 Element Plus后端采用 Spring Boot通过 RESTful API 进行数据交互”。这句话在技术描述里非常加分。而且 Vue 的学习曲线没那么陡照着 Element Plus 的文档做表单和表格几天就能上手。前端打包之后的部署也别慌Vue 项目执行npm run build后会在dist目录下生成静态文件。有两种部署方式一种是把dist文件夹放到 Nginx 下配置反向代理到后端接口另一种是把静态文件直接放进 Spring Boot 项目的src/main/resources/static目录下打成 Jar 包后一个进程跑起来浏览器直接访问 8080 端口就能看到页面。第二种方式对毕设演示更友好不用额外装 Nginx打个包就能在答辩现场的电脑上跑起来。2.3 持久层框架MyBatis-Plus 是省时间的神器持久层你肯定会纠结用 MyBatis 还是 MyBatis-Plus我的态度很明确做毕设就用 MyBatis-Plus。它把单表的 CRUD 操作全都封装好了你不需要写那些重复的 insert、update、selectById只需要定义一个继承了BaseMapperT的接口就能直接调用这些方法。更重要的是它的条件构造器LambdaQueryWrapper查询员工列表、按部门过滤、按薪资区间筛选写起来非常直观也容易在论文里展示。有个细节要注意MyBatis-Plus 的分页插件需要单独配置一个PaginationInnerInterceptor不配置的话Page对象虽然能创建出来但实际查出来的数据是全表分页不生效。这个地方我当年踩过坑在答辩演示的时候发现“下一页”按钮点了没有反应排查了半天才发现是拦截器没有注册。2.4 项目结构一个能让你在答辩时讲得清楚的包划分项目结构的好坏直接决定你答辩时讲代码的流畅程度。我建议采用标准的controller/service/mapper/entity四层结构再加一个config包放配置类一个common包放通用返回结果和异常处理。具体如下com.example.salary ├── controller # 接口层接收前端请求 ├── service # 业务层处理核心逻辑 ├── mapper # 数据访问层MyBatis-Plus的Mapper接口 ├── entity # 实体类对应数据库表 ├── dto # 数据传输对象接收前端参数 ├── vo # 视图对象返回给前端的数据 ├── config # 配置类如拦截器、CORS配置 ├── common # 公共类如统一返回结果、异常处理 └── utils # 工具类如Excel导出工具这里重点说一下dto和vo的区别。很多同学分不清这两个东西其实很简单dto是前端传给你的参数对象比如新增员工时传过来的EmployeeAddDTOvo是你返回给前端的数据对象比如工资条详情SalaryDetailVO。把这两个分开好处是接口的参数和返回值不会跟着实体类走你改数据库表结构的时候不会把前端接口也带崩。答辩的时候老师问“为什么需要 DTO”你能说出“为了避免实体类直接暴露给前端同时也是为了参数校验统一”这样的话印象分会高不少。3. 业务核心拆解薪资计算的来龙去脉3.1 需求梳理从零开始画出系统的完整模块薪资管理系统看着简单真正做起来模块可不少。我按照自己实现过的方案把核心模块梳理了一遍模块名称核心功能难易程度员工管理员工信息的增删改查、部门调动、入职离职状态管理简单部门管理部门树形结构、部门负责人设置简单薪资项目管理配置基本工资、岗位工资、绩效奖金、补贴等薪资项中等考勤汇总从考勤数据计算出勤天数、请假天数、加班时长中等薪资计算根据薪资项目和考勤数据结合社保公积金规则计算应发工资难工资条管理生成工资条、员工查看自己的工资明细、工资条导出中等用户管理登录用户、角色分配、菜单权限控制中等统计报表部门薪资汇总、月度薪资趋势、人员成本分析中等需求梳理阶段最容易犯的错误是把所有的功能一把抓什么都想做结果什么都没做精。这里我给一个非常实用的建议先画出核心流程再围绕流程补外围功能。核心流程就是“员工入职 → 每月考勤 → 月底薪资计算 → 工资条发布 → 员工查看确认”。围绕着这个流程你会发现真正必须的只有员工管理、考勤汇总、薪资计算、工资条这四个环节其他的都是锦上添花。3.2 数据库设计的核心思路宁可多拆表不要全塞一起数据库设计是我最想强调的部分。很多人的表结构设计出来一个employee表恨不得放下所有人的信息一个salary表既有应发工资又有实发工资还有个税社保这样的设计后期一定返工。数据库设计的核心原则就是高内聚低耦合一个表只做一件事。对于薪资管理系统我推荐至少设计这几张表-- 员工表 CREATE TABLE employee ( id BIGINT PRIMARY KEY AUTO_INCREMENT, emp_no VARCHAR(20) NOT NULL UNIQUE COMMENT 工号, name VARCHAR(50) NOT NULL COMMENT 姓名, dept_id BIGINT COMMENT 部门ID, position VARCHAR(50) COMMENT 岗位, phone VARCHAR(20), email VARCHAR(50), hire_date DATE COMMENT 入职日期, status TINYINT DEFAULT 1 COMMENT 1在职 0离职, create_time DATETIME, update_time DATETIME );-- 薪资项目表 CREATE TABLE salary_item ( id BIGINT PRIMARY KEY AUTO_INCREMENT, item_name VARCHAR(50) NOT NULL COMMENT 项目名称, item_type TINYINT COMMENT 1固定项 2计算项 3扣除项, formula VARCHAR(200) COMMENT 计算公式描述, sort_order INT COMMENT 排序, is_active TINYINT DEFAULT 1 );-- 员工薪资项目关联表 CREATE TABLE employee_salary_item ( id BIGINT PRIMARY KEY AUTO_INCREMENT, emp_id BIGINT NOT NULL, item_id BIGINT NOT NULL, amount DECIMAL(10,2) DEFAULT 0 COMMENT 固定金额, effective_date DATE COMMENT 生效日期 );这里有一个很重要的设计思想不要把薪资直接写成员工表的一个字段而是用“薪资项目”的方式来配置。为什么因为工资结构是会变的——这个月多了个交通补贴下个月绩效调整了如果直接在员工表上加减字段改表结构会非常痛苦。用“员工-薪资项目”关联表你就可以动态地给不同员工配置不同的薪资项数据库不需要动业务上还灵活。3.3 工资计算规则把业务逻辑讲清楚比写代码更重要工资计算是整个系统最核心也最容易让答辩老师追问的地方。很多同学的工资表就是“基本工资 绩效 - 请假扣款”这样太简单了经不起推敲。我建议你把计算规则设计得稍微细一点哪怕实现的时候简化一些但设计上要有层次感。我当时的设计是这样每个月工资 应发工资 - 社保个人部分 - 公积金个人部分 - 个人所得税 补贴。应发工资 基本工资 岗位工资 绩效工资 加班费。这些项目中基本工资和岗位工资是从员工薪资配置里取的绩效工资是绩效分数乘以绩效基数加班费是加班时长乘以小时工资率。请假扣款 请假天数 * 日工资日工资 基本工资 / 当月应出勤天数。个税部分如果不想做得太复杂可以用最新的累计预扣法但核心计算过程要讲清楚。哪怕你的系统只实现了“按月度税率表计算当月个税”在论文里也要写明采用的是哪种方式为什么这样设计。答辩老师不会要求你把全套税务算法都做出来但你要让他知道你理解这个业务而不是只会调库。3.4 角色权限与数据隔离越简单越要防漏洞薪资数据属于敏感数据权限控制做不好答辩的时候会被追问得体无完肤。最基础的要求是管理员可以查看所有员工的薪资可以配置薪资项目可以执行薪资计算和发放部门经理只能查看本部门员工的薪资普通员工只能查看自己的工资条这种三级权限模型不需要引入 Spring Security 这种重量级框架你可以用一个简单的拦截器来实现。在HandlerInterceptor里检查当前登录用户的角色然后结合 URL 的规则来决定是否放行。比如/api/salary/detail/**只允许本人访问/api/salary/list需要部门经理以上权限/api/salary/calculate只能是管理员。拦截器实现有一个很容易忽略的细节数据级别的权限过滤一定不能只在前端做。比如部门经理查看本部门员工薪资前端界面上你可以只显示本部门的数据但后端接口也必须做校验——前端传来的deptId参数不能直接信要拿当前登录用户的部门 ID 去比对。否则别人模拟请求一下就能看到其他部门的薪资数据。4. 核心模块实现从配置到代码的关键细节4.1 项目初始化的关键依赖创建 Spring Boot 项目时pom.xml里这几个依赖是少不了的。我的版本组合是 Spring Boot 2.7.8 MyBatis-Plus 3.5.3 Hutool 5.8.x EasyExcel 3.x没有用最新的版本就是为了稳定。dependencies !-- Web 相关 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- MyBatis-Plus -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency !-- MySQL 驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency !-- Hutool 工具类加密、日期处理等 -- dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.8.22/version /dependency !-- EasyExcel 导入导出 -- dependency groupIdcom.alibaba/groupId artifactIdeasyexcel/artifactId version3.3.2/version /dependency !-- Lombok 简化代码 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies这里要特别说一句hutool-all真的很适合毕设项目。它的SecureUtil.md5()可以快速做密码加密DateUtil可以方便地处理日期加减ExcelUtil虽然不如 EasyExcel 灵活但做简单的导入模板生成也很顺手。这种工具类能帮你省掉大量重复代码在论文里写“使用 Hutool 工具类提高开发效率”也是一句话亮点。4.2 工资计算 Service 的代码实现工资计算的核心逻辑我建议放在一个独立的SalaryCalculateService里。这个方法要经历这么几步查询员工的薪资项目配置、查询当月的考勤汇总、计算各种补贴和扣款、把结果组装成工资明细插入工资表。用一个简化版的代码来讲解Service public class SalaryCalculateService { Autowired private EmployeeSalaryItemMapper employeeSalaryItemMapper; Autowired private AttendanceSummaryMapper attendanceSummaryMapper; Transactional public CalculateResult calculate(int year, int month) { // 1. 查询所有在职员工 ListEmployee employees employeeMapper.selectList( new LambdaQueryWrapperEmployee() .eq(Employee::getStatus, 1) ); for (Employee employee : employees) { // 2. 查询员工薪资配置项 ListEmployeeSalaryItem items employeeSalaryItemMapper.selectList( new LambdaQueryWrapperEmployeeSalaryItem() .eq(EmployeeSalaryItem::getEmpId, employee.getId()) .eq(EmployeeSalaryItem::getEffectiveDate, year - month -01) ); // 3. 查询考勤汇总 AttendanceSummary attendance attendanceSummaryMapper.selectOne( new LambdaQueryWrapperAttendanceSummary() .eq(AttendanceSummary::getEmpId, employee.getId()) .eq(AttendanceSummary::getMonth, year - month) ); // 4. 遍历薪资项目累加计算 BigDecimal baseSalary BigDecimal.ZERO; BigDecimal bonus BigDecimal.ZERO; BigDecimal deduction BigDecimal.ZERO; for (EmployeeSalaryItem item : items) { switch (item.getItemType()) { case 1: baseSalary baseSalary.add(item.getAmount()); break; case 2: bonus bonus.add(item.getAmount()); break; case 3: deduction deduction.add(item.getAmount()); break; } } // 5. 扣考勤缺勤 if (attendance ! null attendance.getAbsentDays() 0) { BigDecimal daySalary baseSalary.divide( BigDecimal.valueOf(attendance.getShouldWorkDays()), 2, RoundingMode.HALF_UP ); deduction deduction.add( daySalary.multiply(BigDecimal.valueOf(attendance.getAbsentDays())) ); } // 6. 汇总结果 SalaryDetail detail new SalaryDetail(); detail.setEmpId(employee.getId()); detail.setMonth(year - month); detail.setBaseSalary(baseSalary); detail.setBonus(bonus); detail.setDeduction(deduction); detail.setNetSalary(baseSalary.add(bonus).subtract(deduction)); // 保存明细 } return result; } }有几个细节值得讲一下。第一BigDecimal一定要用String或者int构造不要用double构造不然会出现金额精度问题。第二除法运算必须指定精度和舍入模式divide(BigDecimal.valueOf(day), 2, RoundingMode.HALF_UP)表示小数点后保留两位四舍五入。第三整个计算方法必须加上Transactional因为工资计算是一个多步骤的批量操作如果中间某一步出错了前面插入的数据要全部回滚不然就会产生脏数据。4.3 统一返回结果与全局异常处理写接口的时候一定要有一个统一的返回格式不然前后端联调时你会疯掉。我习惯定义这样一个ResultT类Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(操作成功); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } public static T ResultT error(Integer code, String message) { // 自定义错误码 } }配合RestControllerAdvice做全局异常捕获这样 Controller 里就不用到处写 try-catch 了。答辩的时候老师如果问“你的系统是怎么处理异常的”你可以盯着当前项目的GlobalExceptionHandler把RestControllerAdvice的原理讲清楚再把常见的业务异常如何映射到错误码说一遍这一题就稳了。4.4 定时任务如何做到月底自动算薪薪资系统有一个很自然的加分功能定时任务。每个月 1 号凌晨自动计算上月工资生成工资条。Spring Boot 里做定时任务非常简单只要在启动类上加上EnableScheduling然后在方法上标注Scheduled(cron 0 0 1 1 * ?)表示每月 1 号的 01:00:00 执行。Component public class SalaryScheduleTask { Autowired private SalaryCalculateService salaryCalculateService; Scheduled(cron 0 0 1 1 * ?) public void autoCalculateSalary() { LocalDate lastMonth LocalDate.now().minusMonths(1); salaryCalculateService.calculate( lastMonth.getYear(), lastMonth.getMonthValue() ); } }这里值得注意的坑是定时任务不能重复执行。如果系统部署在多台机器上或者同一台机器启动了多个实例每个实例都会执行业务代码导致工资数据重复计算。一般的解决方案是加一个分布式锁但毕设场景下最简单的方案就是用数据库唯一键约束——工资明细表上加一个(emp_id, month)的唯一索引重复插入会报错在代码里捕获一下就行。5. 实操全过程记录从空项目到运行成功5.1 环境准备JDK、Maven、IDEA 的版本匹配很多同学项目跑不起来的第一个原因就是环境版本不匹配。这里我列一个我自己实测没问题的组合工具推荐版本说明JDK1.8即 8启动 Spring Boot 2.x 最稳的版本Maven3.8.x3.9 也可以但 3.8 更常见IDEA2021.x 以上社区版也能用但专业版功能更全MySQL5.7 或 8.08.0 注意驱动要选com.mysql.cj.jdbc.DriverSpring Boot 3.x 需要 JDK 17 以上如果看到启动报错“Unsupported class file major version”大概率就是 JDK 版本不对。遇到版本问题优先检查java -version和mvn -version确认两个命令指向的版本一致。IDEA 里可以打开Project Structure重新指定 JDK 路径和项目语言级别。5.2 数据库初始化与配置新建一个salary_db数据库把表结构脚本导进去后application.yml配置如下server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/salary_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true global-config: db-config: id-type: autotime-zone和jackson的时间格式这两个配置特别容易漏。不配的话数据库返回的DATETIME类型传到前端会变成一串时间戳或者少 8 个小时答辩论到时候你就会发现页面上的时间全是乱的。map-underscore-to-camel-case一定要设为 true这样数据库里的emp_no字段就能自动映射到 Java 里的empNo属性不用写一堆TableField注解。启动项目后可以在日志里看到 MyBatis 打印的 SQL 语句。这一步很有用因为你可以直观地看到每次请求实际执行了什么 SQL定位“数据查不到”或者“数据多出来”的问题。生产环境里一般会关掉这个日志但毕设阶段建议开着。5.3 前端项目的运行与联调Vue 项目的启动比较简单进入前端目录执行npm install安装依赖然后npm run serve启动开发服务器。前后端联调的时候会遇到一个跨域问题——前端跑在 8081后端跑在 8080浏览器默认不允许这种跨域请求。解决办法是在后端加一个 CORS 配置类Configuration public class CorsConfig { Bean public CorsFilter corsFilter() { CorsConfiguration config new CorsConfiguration(); config.addAllowedOriginPattern(*); config.addAllowedMethod(*); config.addAllowedHeader(*); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration(/**, config); return new CorsFilter(source); } }加了 CORS 配置之后前端调用后端接口就不会被浏览器拦截了。但你要清楚一个概念跨域问题只存在于浏览器环境Postman 里测试接口是不会有跨域的。所以在联调的时候优先用 Postman 验证后端接口是否正常然后再去排查前端的问题不要混在一起排查。5.4 项目打包如何打成可运行的 Jar 包最后的部署环节我建议使用 Maven 的 package 命令打成 Jar 包。在 IDEA 右侧的 Maven 面板里双击package或者在命令行执行mvn clean package -DskipTests完成后在target目录下会生成一个salary-system-0.0.1-SNAPSHOT.jar。把这个 Jar 包复制到一台装了 JDK 8 的电脑上在命令行执行java -jar salary-system-0.0.1-SNAPSHOT.jar等待几秒看到Started Application的日志整个系统就跑起来了。如果前端 Vue 项目也已经构建并放到了static目录下直接访问http://localhost:8080就能看到完整的系统界面。打包过程中容易踩的坑有两个。第一前端文件要放在src/main/resources/static下再执行打包不要先打包再把文件塞进 Jar 包——那样文件不会生效。第二打包后的 Jar 包如果找不到数据源多半是application.yml被 IDEA 的target/classes缓存了旧配置执行一下mvn clean再重新 package。6. 毕设开发中的高频问题与解决实录6.1 Spring Boot 版本太高导致的启动失败这个问题在毕设群里出现的频率极高。Spring Boot 3.x 发布之后很多同学图新鲜直接用了 3.2然后发现项目启动报错上网一搜全是老版本的解决方案对不上号。最简单的解决办法是回到 Spring Boot 2.7.x。如果你的项目已经用了 3.x 的代码也不用推倒重来改一下pom.xml中的parent版本号再调整一下依赖的坐标即可。MyBatis-Plus 的 starter 到了新版本里改名了如果你用的是mybatis-plus-boot-starter在 3.x 里需要换成mybatis-plus-spring-boot3-starter这个细节很容易忽略。6.2 端口被占用启动时如果看到Port 8080 was already in use说明 8080 端口被其他进程占了。Windows 上执行netstat -ano | findstr 8080拿到 PID 之后在任务管理器里结束对应进程或者执行taskkill /PID 1234 /F强制结束。如果不是很严重的端口冲突也可以在application.yml里改一个端口号比如 8081避免占用冲突。6.3 金额计算出现 0.30000000000000004 这种数据这是所有做支付、薪资、财务系统的人都会遇到的问题。原因在于浮点数在计算机里是用二进制存储的0.1 0.2的结果并不是精确的0.3。解决办法只有一个涉及金额的字段一律使用BigDecimal并且通过字符串构造函数创建。BigDecimal amount new BigDecimal(3000.50); // 正确 BigDecimal wrong new BigDecimal(3000.50); // 错误另外数据库里金额字段应该用DECIMAL(10,2)不要用FLOAT或者DOUBLE。前端拿到金额之后也尽量不要做加减运算如果需要展示直接原样呈现计算逻辑都放到后端完成。6.4 事务不生效的几种可能性薪资计算这种多步骤操作必须加事务但有时候你明明加了Transactional数据却还是没有回滚。常见原因有三个第一方法被 private 修饰。Spring 的声明式事务是基于 AOP 代理的代理只能拦截 public 方法如果是 private 方法Transactional直接失效。第二同类内部调用。同一个类里的 A 方法调用 B 方法B 方法上的Transactional不生效因为调用发生在对象内部没有经过代理对象。第三异常被捕获了。事务回滚默认只在抛出RuntimeException时触发如果代码里捕获了异常并做了处理事务就感知不到错误。这里简单提一句代理机制Spring Boot 默认使用的是 CGLIB 代理它会生成一个目标类的子类来覆盖方法。所以使用Transactional的方法不能是final的否则无法生成代理子类。这个话题如果深入讲可以做一篇完整的博客但毕设阶段你只需要记得上面这三个坑就行。6.5 前端页面表格数据绑不上查接口返回 null联调的时候经常遇到这种情形后端接口返回的数据在 Postman 里是正常的但前端表格里就是显示不出来。排查思路是先看控制台报什么错然后在浏览器开发者工具里切到 Network 选项卡找到对应请求查看响应体。常见的原因有两种一种是后端返回的字段名和前端表格模板里的字段名对不上比如后端是empNo前端写的是empNo但是组件绑定的是emp_no。第二种是数据确实是 null说明后端的“查询关联”没做好。查一下后端日志里打印的 SQL看 join 条件是不是失效了或者外键对应的数据不存在了数据查出来就是空的。这种问题我在做部门经理查看本部门员工薪资的时候踩过。当时前端传过来的是部门 ID后端的 SQL 里员工表添加了dept_id作为外键但新导入的测试员工数据没有写dept_id查出来的薪资列表就只有几个人。后来把测试数据补齐问题就解决了。给你的建议是先造好完整的测试数据再开始联调不要边联调边造数据问题会混在一起。7. 论文撰写与答辩准备最后一公里的关键动作7.1 论文框架怎么搭毕设论文不像技术博客它有一套约定俗成的框架。薪资管理系统这篇论文我的建议是绪论 → 相关技术介绍 → 系统需求分析 → 系统设计 → 系统实现 → 系统测试 → 总结与展望。这套结构几乎适用于所有管理系统类毕设照着写不会出大错。需求分析部分要注意不要只写“本系统需要员工管理功能”要写“本系统需要支持员工的入职、离职、转岗操作需要记录员工的部门调动历史需要支持按照部门进行员工信息的筛选”。需求描述越具体越说明你做了认真的调研答辩时也更容易回答老师关于“你的系统解决了什么问题”的追问。系统设计部分除了数据库表设计最好画清楚用例图、E-R 图、系统架构图。这步要求你会用工具画图不要求你画得多专业但用例图画清楚设备管理、薪资项目维护、工资条查看这些核心流程会让整个论文加分不少。7.2 答辩前必须模拟的 5 个问题经验之谈答辩的时候老师问的问题基本都是围绕这几类提前准备答案现场就不会卡壳。“你的薪资计算流程是什么”——按“薪资项目配置 → 考勤汇总 → 应发工资计算 → 扣除社保公积金 → 计算实发工资 → 生成工资条”这个顺序讲最好配合流程图讲清楚每一步的数据来源。“你用了几个表为什么这么设计”——这个问题就看你对数据库设计的理解。答出来每个表的核心用途和表之间的关联关系再把“薪资项目与员工解耦”的设计亮点讲出来就能拿分。“权限控制是怎么做的”——回答用拦截器实现分管理员、部门经理、普通员工三级权限并说明数据权限在后端进行了二次校验防止越权。“项目有什么不足”——这个问题如果答“没有不足”反而危险。你可以说“当前系统没有接入人脸识别打卡考勤数据依赖手动录入个税算法没有完全覆盖最新政策未来可以引入薪资趋势分析和电子签收功能”。这样的回答既坦诚质量又暗示了你思考过系统的演进方向。“你用什么版本呢为什么选 Spring Boot 2.7 而不是 3.x”——答出来版本选择的原因是考虑第三方组件兼容性和社区资料丰富程度能反映出你调研过。7.3 最后再分享一个小经验做完这个项目之后我最深的感受是毕设项目的难点从来不在技术而在业务梳理和自我管理。技术上的问题网上一搜基本都有答案最难的是你能不能静下心来把每一个模块的逻辑走通把每一个异常场景处理掉。薪资管理系统这种题目不像人工智能那么显眼也不像电商系统那么大众但它的业务足够清晰做完之后你对数据库设计、事务机制、权限控制这些专业知识的理解会远超那些只会复制粘贴代码的同学。如果你正在纠结选题或者已经开始写代码但被某个问题卡住了我的建议就是坚持把这个题做完。做到“能讲清楚为什么这么设计能演示出来能回答上老师的追问”这个项目就算成功了。
返回列表