Spring Boot+Vue企业工资管理系统设计与实现详解
发布时间:2026/9/24 23:38:34来源:尧图网络
在企业里摸爬滚打过的朋友应该都有感触工资核算这件事看起来简单真正做起来却是一堆细碎又敏感的活儿。绩效系数、五险一金基数、个税专项附加扣除、考勤扣款、补贴项……每一处都容不得半点马虎。以前靠Excel表格手工核算不仅效率低还容易出错碰上月份特殊比如年终奖发放、调薪生效更是焦头烂额。正因如此一个可复用的企业工资管理系统在课程设计、毕业设计甚至小型企业实际落地中都是非常受欢迎的选题。今天我就结合手头这套基于Spring Boot Vue的企业工资管理系统含源码、数据库、文档把从设计思路到关键技术实现、再到部署交付的完整链路拆开讲清楚帮大家少走弯路。这套系统是典型的前后端分离架构后端用Spring Boot 2.x提供RESTful API前端用Vue 2.x Element UI搭建管理界面数据库采用MySQL 5.7。整套项目包含员工管理、工资项目管理、工资核算、工资条发放、统计报表、用户登录与权限控制等功能模块压缩包里还自带了完整的SQL脚本和部署文档属于那种拿到手就能跑起来、边看代码边学习整体业务流的好素材。无论你是准备做Java课程设计的在校生还是想快速搭建内部工具的技术人员这篇文章都会对你有用。1. 项目整体设计与技术选型1.1 为什么选择Spring Boot Vue这套组合先说后端。Spring Boot在Java生态里的地位基本不需要我多强调它通过自动配置把过去Spring MVC项目里大量的XML配置消掉了起步依赖机制也很方便想加什么功能直接引入对应的starter即可。对企业工资管理系统这种典型CRUD 业务计算 报表展示的项目来说Spring Boot的快速开发特性和稳定的生态支持都是最合适的。再说前端。Vue 2.x Element UI的组合在中小型管理后台中应用得非常广。Vue的响应式数据绑定让页面状态管理变得简单Element UI则提供了一套开箱即用的表格、表单、弹窗、日期选择器等组件做后台管理页面基本就是“搭积木”。相比React Ant Design的组合Vue的模板语法对初学者更友好社区中文资料也丰富上手成本更低。这套前后端分离的架构还有几个额外的好处后端只负责数据接口和业务逻辑前端只负责展示和交互职责边界清楚后期维护不乱。前后端可以并行开发接口定义好之后各做各的效率提升明显。前端打包成静态文件后可以部署到Nginx后端打jar包独立运行生产环境部署灵活。1.2 系统核心功能模块拆解在动手写代码之前先把系统要做什么想清楚这是整个项目中最值得花时间的事情。工资管理系统的核心不是代码多复杂而是业务边界要清晰。这套系统的功能模块划分如下模块核心功能角色权限登录认证用户名密码校验、Session/Token管理所有用户员工管理员工信息的增删改查、部门维护管理员工资项目管理基础工资、绩效、补贴、扣款项配置管理员工资核算根据员工和工资项自动生成工资单管理员、财务工资条查询员工查看个人工资明细普通员工统计报表部门工资汇总、月度趋势图表管理员、财务用户管理账号分配、角色设置、密码重置管理员角色权限这里建议做成最简单的三表模型用户表、角色表、用户角色关联表不需要引入Spring Security的完整RBAC但要在后端接口层做拦截判断避免低权限用户直接绕过前端调接口。1.3 项目目录结构与代码组织拿到源码后先别急着跑建议先把项目结构看清楚。后端是标准的Maven项目包结构一般按照controller、service、mapper、entity、config来分包com.company.salary ├── controller // 接收前端请求返回JSON数据 ├── service // 业务逻辑层工资计算、统计等都在这里 ├── mapper // MyBatis接口层操作数据库 ├── entity // 实体类对应数据库表结构 ├── config // 配置类如CORS跨域配置、拦截器配置 ├── common // 公共类统一返回结果、异常处理、工具类 └── SalaryApplication.java // Spring Boot启动类前端Vue项目用Vue CLI创建src目录下分为api接口请求封装、router路由配置、views页面组件、components公共组件、storeVuex状态管理几个部分。把公共请求方法统一封装到request.js里每个页面对应一个views下的文件这套规范写在文档里后面扩展功能时也方便按图索骥。2. 数据库设计与核心表结构2.1 核心数据表拆解工资系统最核心的资产就是数据数据库表设计的好不好直接决定后续开发的顺利程度。这套系统的表设计我拆开看主要围绕“员工—工资项—工资单—用户”四条线展开。员工表employeeCREATE TABLE employee ( id int(11) NOT NULL AUTO_INCREMENT, emp_no varchar(20) NOT NULL COMMENT 员工工号, emp_name varchar(50) NOT NULL COMMENT 员工姓名, department varchar(50) DEFAULT NULL COMMENT 所属部门, position varchar(50) DEFAULT NULL COMMENT 岗位, entry_date date DEFAULT NULL COMMENT 入职日期, base_salary decimal(10,2) DEFAULT NULL COMMENT 基础工资, status tinyint(4) DEFAULT 1 COMMENT 在职状态 1在职 0离职, PRIMARY KEY (id), UNIQUE KEY uk_emp_no (emp_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;工号emp_no建议设置为唯一索引后续工资核算、统计报表都依赖这个字段关联。员工状态字段很重要离职员工不做删除而是修改状态这样历史工资数据才能留存。工资项目表salary_item这个表的设计在整个系统里属于特别容易忽略但极其关键的地方。工资项目不写死在代码里而是做成一张配置表好处是后续想增加“高温补贴”“全勤奖”这类新项目时不需要改代码数据库里加一条记录就能出现在核算页面中。CREATE TABLE salary_item ( id int(11) NOT NULL AUTO_INCREMENT, item_name varchar(50) NOT NULL COMMENT 项目名称, item_type tinyint(4) NOT NULL COMMENT 类型 1加项 2扣项, item_default decimal(10,2) DEFAULT 0.00 COMMENT 默认金额, is_editable tinyint(4) DEFAULT 1 COMMENT 是否允许调整, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;item_type的正负逻辑建议在代码里统一处理数据库中统一存正数加项加钱扣项减钱最后汇总时按类型判断。这样比存负数更直观也避免出现“负负得正”的低级错误。工资单表salary_recordCREATE TABLE salary_record ( id int(11) NOT NULL AUTO_INCREMENT, emp_no varchar(20) NOT NULL, salary_month varchar(7) NOT NULL COMMENT 工资月份 如2025-06, item_name varchar(50) NOT NULL, item_type tinyint(4) NOT NULL, amount decimal(10,2) NOT NULL, remark varchar(255) DEFAULT NULL, PRIMARY KEY (id), KEY idx_emp_month (emp_no, salary_month) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里需要重点说下设计取舍。工资明细有两种存储方式一种是一条工资单记录存一行汇总数据员工、月份、总应发、总实发另一种是每个员工每个月的每个工资项都单独存一条记录。这套系统的表结构采用的是明细存放方案也就是每个工资项单独一条记录然后通过SQL聚合出工资条的汇总数据。我个人的观点是明细方案虽然数据行数多一些但灵活性和可追溯性更好。后期做“为什么这个员工这个月工资和上个月不一样”的时候直接对着明细记录一目了然。而且索引建好之后idx_emp_month查询性能基本不会成为瓶颈。2.2 视图与统计SQL的设计除了业务表数据库脚本中建议把常用的汇总查询封装成视图。比如部门月度薪资汇总视图CREATE VIEW v_department_salary AS SELECT e.department, r.salary_month, SUM(CASE WHEN r.item_type 1 THEN r.amount ELSE 0 END) AS total_add, SUM(CASE WHEN r.item_type 2 THEN r.amount ELSE 0 END) AS total_minus, SUM(CASE WHEN r.item_type 1 THEN r.amount ELSE -r.amount END) AS final_salary FROM salary_record r LEFT JOIN employee e ON r.emp_no e.emp_no GROUP BY e.department, r.salary_month;视图的好处在于把复杂的聚合逻辑在数据库中固化好后端代码只需要简单查询视图不需要反复嵌套子查询。同时视图还能起到一定程度的权限隔离作用——比如普通员工账号不给直接查询salary_record表的权限只给查询个人视图的权限。2.3 演示数据的准备方法源码包里自带的salary_db.sql文件里除了建表语句还预置了20个左右的员工和两个月的工资项数据。这个设计对快速跑通项目非常有用尤其是做课程设计答辩时如果数据库里一张演示数据都没有你很难向老师展示“报表功能”“趋势图”这些亮眼模块的实际效果。所以我强烈建议大家拿到SQL脚本后不要急着删掉演示数据先把系统跑起来看看各个模块在“有数据”的状态下是什么效果。以后想换成自己的数据再执行DELETE清空业务表保留配置表的数据即可。用户表里的管理员账号密码一般是admin/admin123是MD5加密存储的千万别直接改数据库密码字段然后发现自己登不进去。3. 后端Spring Boot核心实现3.1 项目初始化与依赖配置后端项目的依赖配置很朴素基本上就是Spring Boot做Web服务、MyBatis做持久层、MySQL驱动连数据库、Druid做连接池这几样。关键的pom.xml依赖如下dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.2.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.49/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-starter/artifactId version1.2.8/version /dependency这里有个容易踩坑的地方如果本地安装的是MySQL 8.x版本mysql-connector-java要用8.0以上的版本同时驱动类名和URL参数也有区别。MySQL 8的驱动类名是com.mysql.cj.jdbc.DriverURL中还要追加serverTimezoneAsia/Shanghai参数否则会报时区错误。源码默认按MySQL 5.7配置如果你用的是MySQL 8记得同步修改pom.xml和application.yml两个地方。application.yml里主要配置端口、数据源、MyBatis映射路径server: port: 8080 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/salary_db?useUnicodetruecharacterEncodingutf8useSSLfalse username: root password: 123456 type: com.alibaba.druid.pool.DruidDataSource mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.company.salary.entity configuration: map-underscore-to-camel-case: truemap-underscore-to-camel-case这个配置建议打开数据库字段emp_no会自动映射到Java属性empNo省去一堆Results注解。3.2 统一返回结果与异常处理前后端分离项目中接口返回的数据格式必须统一否则前端拿到数据后无法做通用处理。我通常会在common包下定义一个Result类public class ResultT { private Integer code; // 200成功 500失败 401未登录 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; } }所有Controller方法的返回值都包装成Result对象前端request.js里统一做拦截判断。配合自定义异常类和RestControllerAdvice全局异常处理器可以把业务异常直接抛出由全局处理器捕获后转成统一的错误JSON代码里就不需要到处写try-catch了。3.3 工资核算的核心逻辑实现工资核算这块是整个项目中最有技术含量的部分也往往是课设答辩时老师最喜欢提问的地方。核心流程是前端传入核算月份后端遍历在职员工根据工资项目配置结合员工的基础工资数据生成该员工该月度的工资明细记录。删掉重来是这里一个很重要的设计细节。工资核算应该是幂等的——同一个月份你点击一万次核算按钮结果都应该一样。所以核算的第一步不是新增记录而是先删除该月份已有的旧数据Override Transactional(rollbackFor Exception.class) public boolean calculateSalary(String salaryMonth) { // 第一步先删除该月份已有数据保证幂等 salaryRecordMapper.deleteByMonth(salaryMonth); // 第二步查询所有在职员工 ListEmployee employees employeeMapper.selectAllActive(); // 第三步遍历员工生成工资明细 for (Employee emp : employees) { ListSalaryItem items salaryItemMapper.selectAll(); boolean hasBaseSalary false; for (SalaryItem item : items) { SalaryRecord record new SalaryRecord(); record.setEmpNo(emp.getEmpNo()); record.setSalaryMonth(salaryMonth); record.setItemName(item.getItemName()); record.setItemType(item.getItemType()); record.setAmount(item.getItemDefault()); // 基础工资项特殊处理金额取员工表中的基础工资 if (基础工资.equals(item.getItemName())) { record.setAmount(emp.getBaseSalary()); hasBaseSalary true; } salaryRecordMapper.insert(record); } // 如果配置表中没有基础工资项自动补一条 if (!hasBaseSalary) { SalaryRecord record new SalaryRecord(); record.setEmpNo(emp.getEmpNo()); record.setSalaryMonth(salaryMonth); record.setItemName(基础工资); record.setItemType(1); record.setAmount(emp.getBaseSalary()); salaryRecordMapper.insert(record); } } return true; }Transactional注解在这个方法上必须加上保证整个核算过程要么全部成功、要么全部回滚。如果中途某条记录插入失败而前面已经插入了大半数据事务回滚之后数据还是干净的不会出现“半个工资表”的脏数据状态。工资计算的拓展思路是如果你希望系统更智能一点可以在工资项表里加一个item_formula字段存计算表达式。例如“绩效基础工资*0.2 500”后端用脚本引擎解析这个表达式就能实现灵活配置的工资计算。这样系统的灵活性和课程设计的答辩亮点会明显上一个档次。3.4 登录认证与权限拦截实现登录这块项目采用了比较轻量级的方案没有引入Spring Security全家桶而是用拦截器 Session来做。登录成功后把用户信息存入Session同时写一个LoginInterceptor拦截器public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session request.getSession(); Object user session.getAttribute(loginUser); if (user null) { // 未登录返回401状态码 response.setStatus(401); response.setContentType(application/json;charsetutf-8); response.getWriter().write({\code\:401,\message\:\未登录或会话已过期\}); return false; } // 管理员接口校验权限 if (request.getRequestURI().startsWith(/api/admin/)) { User loginUser (User) user; if (!admin.equals(loginUser.getRole())) { response.setStatus(403); response.getWriter().write({\code\:403,\message\:\无权限访问\}); return false; } } return true; } }在WebConfig中注册拦截器并放行登录接口和静态资源Configuration public class WebConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns(/api/**) .excludePathPatterns(/api/user/login, /api/user/logout); } }这套轻量级方案有它的适用场景。对于课设项目而言逻辑简单、代码量少、讲解方便比引入Spring Security更贴合“课程设计”的定位。但如果你打算在企业生产环境中真正使用这套系统还是建议把Spring Security JWT那套整合进来尤其是要考虑Token过期、密码加密强度建议加盐、接口防刷等问题。4. 前端Vue实现与交互细节4.1 Vue环境搭建与项目初始化前端开发环境建议使用Vue CLI 3.x/4.x来创建项目。创建完成后首先是安装项目依赖Element UI、Axios、Vue Router是核心依赖如果做图表还需要安装EChartsnpm install npm install element-ui -S npm install axios -S npm install vue-router3 -S npm install echarts -S提醒一下Vue 2.x对应的Vue Router必须是3.x版本如果你不小心装了Vue Router 4项目启动时会直接报错——Vue Router 4只兼容Vue 3。这是新手朋友经常会踩的坑装依赖之前务必看清版本兼容性。在main.js中全局注册Element UI和路由import Vue from vue import App from ./App.vue import ElementUI from element-ui import element-ui/lib/theme-chalk/index.css import router from ./router Vue.use(ElementUI) Vue.config.productionTip false new Vue({ router, render: h h(App) }).$mount(#app)4.2 路由设计与页面骨架前端路由设计建议跟后端菜单结构一一对应。为了管理方便把需要登录后访问的页面放在一个Layout组件下通过嵌套路由实现侧边栏布局const routes [ { path: /login, component: () import(../views/Login.vue) }, { path: /, component: () import(../layout/Layout.vue), redirect: /dashboard, children: [ { path: dashboard, component: () import(../views/Dashboard.vue) }, { path: employee, component: () import(../views/Employee.vue) }, { path: salary-item, component: () import(../views/SalaryItem.vue) }, { path: salary-calc, component: () import(../views/SalaryCalc.vue) }, { path: salary-query, component: () import(../views/SalaryQuery.vue) }, { path: report, component: () import(../views/Report.vue) }, { path: user, component: () import(../views/User.vue) } ] } ]路由懒加载component: () import(...)是实际开发中一个必须注意的细节。打包时每个页面会拆成独立的JS文件首屏加载速度会有明显改善。对课设演示来说更重要的是能让项目结构看起来更规范。4.3 Axios请求封装与拦截器前端所有接口请求要统一封装不能每个页面都直接写axios.get完整地址。基本的request.js如下import axios from axios import { Message } from element-ui import router from ../router const request axios.create({ baseURL: /api, timeout: 10000 }) // 请求拦截器统一携带登录凭证 request.interceptors.request.use(config { const user sessionStorage.getItem(loginUser) if (user) { config.headers[Content-Type] application/json } return config }) // 响应拦截器统一处理返回结果和错误 request.interceptors.response.use( response { const res response.data if (res.code 200) { return res } else if (res.code 401) { Message.error(登录状态已过期请重新登录) router.push(/login) return Promise.reject(new Error(未登录)) } else { Message.error(res.message) return Promise.reject(new Error(res.message)) } }, error { Message.error(网络请求失败) return Promise.reject(error) } ) export default request这里需要特别说明baseURL的配置。开发环境下前端通过Vue CLI的proxy代理解决跨域问题在vue.config.js中配置module.exports { devServer: { port: 3000, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }生产环境部署时则把前端打包后的静态文件放在Nginx下Nginx配置反向代理把/api开头的请求转发到后端服务。这样前后端分离的项目最终也能以同一个域名对外提供服务规避跨域问题。4.4 核心业务页面实现要点员工管理页面和工资核算页面是这套系统里最具代表性的两个页面。员工管理页面本质上是典型的CRUD表格页——表格展示员工列表弹窗嵌套表单实现新增编辑功能删除操作加一个确认框防止误操作。这里我建议用Element UI的el-table配合el-dialog实现代码结构清晰且完全不复杂。工资核算页面的交互稍微复杂一点。页面顶部放一个月份选择器el-date-picker的month类型点击“开始核算”按钮后调用后端接口。核算完成后在同页面的下方表格展示本次核算的结果统计包括参与核算人数、应发总额、实发总额等汇总数据。为了更好的用户体验核算过程用loading状态盖住按钮防止用户重复点击。工资核算这个操作本身很快但万一数据量大导致接口响应时间超过2秒loading状态的提示能避免用户误以为页面卡死。统计报表页面推荐直接用ECharts实现柱状图和折线图。部门月度薪资汇总用柱状图近6个月薪资趋势用折线图。ECharts的配置项不复杂就是数据聚合处理好后setOption传进去即可。ECharts的初始化要在mounted生命周期中执行组件销毁时记得调用chart.dispose()释放内存。5. 项目运行中的常见问题与排查经验5.1 后端启动失败的几种典型场景后端跑不起来的报错五花八门但九成以上是环境问题。我总结几个高频场景场景一端口被占用Spring Boot默认使用8080端口如果本地有其他服务占用了8080启动日志中会出现Port already in use的报错。解决方式有两种要么把占用8080的进程关掉要么在application.yml中修改server.port。场景二数据库连接失败报错信息类似Cannot create PoolableConnectionFactory或Access denied for user。前者是MySQL服务没启动或连接URL写错后者是用户名密码不对。这里教大家一个快速排查方法——先用Navicat或命令行工具直接连接MySQL数据库如果能连上说明数据库本身没问题问题出在Spring Boot配置或驱动上如果命令行都连不上优先检查MySQL服务是否启动、账号权限是否正常。场景三MyBatis映射文件位置错前端项目开发中接口请求报404或500的排查会比后端稍微复杂一些。如果你的controller路径和前端请求路径对不上最直观的排查手段是打开浏览器的开发者工具切到Network面板看请求的URL、请求方法、请求体内容是否和后端接口定义完全一致。前后端联调时养成先看Network再猜问题这样的习惯能帮你节省大量无意义的排查时间。5.2 前端跨域问题三板斧前端调用后端接口报跨域错误浏览器控制台出现CORS字样时按以下顺序排查先看Nginx或开发代理配置。开发环境下Vue CLI的proxy代理是最佳方案一定要确保vue.config.js中proxy路径与请求baseURL对应。再看后端CORS配置。如果不走代理直接请求后端地址后端要开启跨域支持Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }如果前后端同域名部署则检查Nginx配置中的location /api代理块确认配置正确。最后检查浏览器请求方式。如果是PUT/DELETE请求触发跨域预检OPTIONS请求失败确认后端接口是否正确处理了OPTIONS请求。在Spring Boot中Spring MVC默认支持OPTIONS请求处理通常不需要额外关注。5.3 数据库字符集导致的乱码问题中文乱码问题在项目中很常见通常表现在数据库存储乱码或前端展示乱码两个层面。数据库层面建表语句中统一使用utf8mb4字符集确保表字段能存储emoji表情和中文字符。JDBC连接URL中加上characterEncodingutf8参数。前端层面确保所有HTML页面和JS文件的编码都是UTF-8Vue CLI创建的项目默认就是UTF-8不用额外处理。排查乱码时有一个实用的小技巧先用数据库客户端直接执行SQL插入一条中文数据再去前端页面看能否正常显示。如果能正常显示说明数据库本身没问题问题出在程序中数据传输的过程中可能出现乱码如果数据库客户端都显示乱码那就是数据库表字符集或连接参数的问题。5.4 页面数据刷新与Session过期问题菜单切换后数据没有更新的问题很多时候是前端缓存或者生命周期钩子使用不当导致的。例如在Vue中从A页面跳转到B页面时会执行B页面的created/mounted钩子但如果B页面之前被keep-alive缓存了再次进入时不会重新执行mounted需要配合activated钩子或者在离开页面时主动销毁组件。课设项目一般不会用keep-alive所以通常不需要担心这个。Session过期问题则是另一个常见情况。后端在用户长期不操作后Session会自动过期用户再次点击页面上的按钮时请求返回401状态码。前端响应拦截器检测到401后自动跳转到登录页这是API统一封装的好处。如果页面一直停留在打开状态没有发起请求后端Session可能已经过期这不影响已经加载出来的静态页面但点击任何需要调用接口的按钮时就会被自动踢回登录页。这个逻辑在答辩演示时最好提前说清楚避免被误认为是“Bug”。6. 部署交付与文档配套6.1 项目启动的完整流程这套系统的部署流程不算复杂但建议严格按照文档中的步骤来。第一步是创建数据库并导入初始数据使用Navicat或命令行工具连接到MySQL执行salary_db.sql脚本完成建库建表和初始数据导入。第二步是修改application.yml中的数据库连接配置将数据库地址、账号、密码改成你本机的配置。第三步是启动后端Spring Boot应用在项目根目录执行mvn spring-boot:run或者用IDE直接运行SalaryApplication主类。第四步是启动前端Vue应用在vue目录下执行npm install安装依赖再执行npm run serve启动开发服务器。最后浏览器访问http://localhost:3000用admin账号登录系统就完整跑起来了。这套流程务必在答辩前完整走一遍并且把每一步涉及的关键命令记清楚。很多时候不是系统本身有问题而是演示时太紧张在环境上卡住了。提前演练三遍以上比多背十页PPT都管用。6.2 Maven打包与前端构建正式的交付物中建议打包部署而不是直接跑开发服务器。后端打包命令mvn clean package -DskipTests打包之后在target目录下得到salary-system.jar文件使用java -jar salary-system.jar即可启动。注意如果打包时引用了外部配置文件可以放到jar包同级目录下通过spring.config.location参数指定java -jar salary-system.jar --spring.config.locationfile:./application.yml前端打包命令npm run build打包完成后在dist目录下生成静态文件把dist目录下的所有文件拷贝到Nginx的html目录下配置Nginx反向代理server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }try_files这行配置很重要它的作用是让前端路由在刷新页面时始终回到index.html由Vue Router接管页面渲染否则直接访问http://localhost/employee这个路径时Nginx会返回404。6.3 配套文档与后续扩展方向源码包里自带的文档通常包含需求分析、系统设计、数据库设计、接口说明和操作手册几个部分。文档的套路是标准的软件工程遵循流程但在实际写文档时我建议大家重点补充两块内容一是接口说明要写清楚请求参数和响应示例这样后续自己维护或别人接手都不用重新看代码二是操作手册要有截图步骤特别是数据库配置和启动这两步因为对新手来说卡住的地方往往都在跑环境上。这个项目后续还有不少可以扩展的方向。工资报表加导出Excel功能可以引入EasyPoi或阿里EasyExcel员工自助服务平台可以增加个人信息修改、请假申请和工资条确认签收功能系统集成方面可以对接钉钉或企业微信的免登录。这套代码的基础架构比较清晰在这些方向上做扩展不会太痛苦。对在校学生来说选其中一两个扩展点作为论文的创新点也很有说服力。我自己的实际体会是企业工资管理系统虽然看起来是一个常见的课设题目但把“核算幂等、数据留痕、权限隔离”这三件事做扎实了系统的完成度和可用性就能明显超过同期的大部分作品。很多人在做这个题目时只顾着把CRUD写完忽略了业务核心的特殊性做出来的东西更像一个通用的增删改查模板。把工资核算背后的约束不可重复执行、数据可追溯、金额敏感想透再回头去写代码你的设计思路和实现方案都会有本质上的不同。希望这篇文章对你动手实践这个项目有帮助。
网站建设高端定制企业官网