news 2026/10/22 8:16:31

SpringBoot+Vue前后端分离人事系统:设计与部署全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot+Vue前后端分离人事系统:设计与部署全解析

一直想找一套能直接落地的人事系统参考,前后端分离、代码完整、还能照着部署跑通。折腾过不少开源项目,要么结构太老,要么文档跟代码对不上,真正能把SpringBoot+Vue+MyBatis+MySQL这套技术栈串明白、又能用于实际业务的,确实不多。这套人事系统我前前后后跑了两遍,把源码结构、核心逻辑、部署步骤都梳理了一遍,也踩了不少环境上的坑。这篇就把整个系统的设计思路、关键代码实现、部署过程和排坑记录一次写完,给正在做毕业设计、或者公司内部要快速搭一套人事管理后台的同学做个参考。涉及的项目代号统一用“模拟项目X”代替,代码片段均源自项目源码的合理改编。

1. 项目整体设计与功能拆解

1.1 这套人事系统到底解决了什么问题

不少中小型公司的人事管理还停留在Excel和纸质审批单的阶段,人员信息散落在各个表格里,请假审批靠口头或者聊天记录,薪资核算每到月底就手忙脚乱。这套系统要解决的正是这堆实际问题:把员工档案、部门岗位、考勤请假、薪资报表、系统权限这些事情集中到一个Web平台里,人事专员、部门主管、普通员工各干各的事,数据实时共享,审批流程线上跑。

从技术角度看,它又是一个非常典型的前后端分离项目。后端用SpringBoot提供RESTful接口,前端用Vue全家桶做单页应用,MyBatis负责数据库操作,MySQL存数据。这个组合在中小企业内部系统里出场率极高,学透这一套,基本就能应对大部分管理类Web项目的开发需求。对于正在做毕业设计的学生来说,它覆盖了选题、架构设计、编码实现、部署上线的完整链路,能说的内容非常多;对于刚入职的初级开发来说,它又是一个很好的练手项目,可以看看企业级代码是怎么组织、权限是怎么控制的、审批流是怎么设计的。

1.2 功能模块划分与核心需求解析

整个系统的功能可以拆成六个大模块:

  • 系统管理:用户管理、角色管理、菜单管理。这个模块是系统的基础骨架,解决“谁能登录、登录后能看到什么、能做什么”的问题。
  • 员工管理:员工档案的增删改查、批量导入导出、员工状态管理(在职、离职、休假等)。这条线是人事业务的核心数据源。
  • 部门管理:部门树形结构维护、部门负责人设置、部门人数统计。树形结构是这里的重点,涉及到递归查询和层级展示。
  • 考勤管理:打卡记录、请假申请、审批流转、考勤统计报表。这是日常使用频率最高的模块。
  • 薪资管理:薪资项配置、工资条生成、历史薪资查询。这块涉及敏感数据,需要做单独的权限控制,不能让普通员工随便看到别人工资。
  • 个人中心:个人信息查看与编辑、修改密码、查看自己的考勤和薪资。

需求拆解时要特别注意一个细节:不同角色的关注点差异很大。普通员工只需要操作自己的请假申请、查看自己的工资条;部门主管还要处理下属的审批申请和部门考勤统计;系统管理员则要承担组织架构和权限配置的工作。所以设计时不能只做CRUD,要把角色和数据范围这两个维度刻进设计里。

1.3 为什么选择SpringBoot+Vue这套组合拳

这个选型可以说是当前Java后端管理系统的最优解之一。SpringBoot简化了Spring的配置地狱,内嵌Tomcat让打包部署变得异常简单,一个jar包就能跑起来。MyBatis作为持久层框架,半自动化的特性在复杂SQL场景下反而更灵活,比如员工表关联部门表、岗位表的多表查询,用MyBatis写动态SQL非常顺手,比全自动的JPA更可控。

前端选择Vue的原因更直接:生态成熟、上手曲线平缓。配合Element UI组件库,后台管理系统的表格、表单、弹窗、树形控件全都有现成组件,开发效率非常高。Vue的双向数据绑定特性在处理表单回显、列表筛选这类场景时体验极好。

还有一点很实际——前后端分离意味着前后端可以并行开发和独立部署。我在实际开发中,后端接口还没写完的时候,前端就可以用Mock数据先跑页面,两边互不阻塞。部署时前端构建成静态文件丢到Nginx,后端打包成jar独立运行,任何一个挂了都不影响另一个的静态资源访问,排查问题也方便不少。

2. 核心技术栈选型与架构思路

2.1 SpringBoot后端架构的分层设计

后端代码的组织方式会影响后续的维护体验。这套系统的后端遵循经典的三层架构:Controller层、Service层、Mapper层,外加一个entity实体包和common通用包。

com.company.hr ├── controller // 接口入口,只做参数接收和结果封装 ├── service // 业务逻辑,事务控制在这里 ├── mapper // MyBatis的Mapper接口 ├── entity // 数据库实体类 ├── dto // 前后端交互的数据传输对象 ├── common // 通用返回结果、异常处理、工具类 └── config // 配置类,如拦截器、CORS配置

这种分层的核心原则是单向依赖:Controller调Service,Service调Mapper,不让下层反向依赖上层。好处很明显——每个类职责清晰,改数据库字段时只需要动entity和Mapper,改业务逻辑时只需要动Service,不影响接口层。我见过一些项目把业务逻辑全写在Controller里,接口类几百行代码,后期根本没法维护,加一个字段要牵连好几个文件。

Service层还有两个容易被忽略的要点。一是事务管理,操作多张表的业务(比如新增员工时同时插入员工表和用户表)必须加@Transactional注解,保证要么全部成功要么全部回滚。二是异常处理,我习惯在Service层抛自定义的业务异常,再通过全局异常处理器统一返回给前端,这样Controller层就不会出现大段的try-catch。

2.2 数据库设计:核心表结构解析

MySQL库一共设计了十来张表,其中最关键的是五张:员工表、部门表、用户表、角色表、菜单表,外加一组关联表和业务表。

员工表(employee)的核心字段包括:工号、姓名、性别、手机号、邮箱、部门ID、岗位、入职日期、员工状态。这里特别注意工号要设置唯一索引,因为它是业务上的自然人标识,不能重复。部门ID走逻辑外键,不建物理外键约束——这是很多企业项目的惯例,为了避免删数据时的外键约束麻烦,关联关系的完整性由业务层保证。

用户表(sys_user)和角色表(sys_role)、菜单表(sys_menu)这三张是权限模型的基础。用户和角色多对多,角色和菜单多对多,各需要一张中间表。查询权限时先根据用户ID查角色,再根据角色查菜单,最后把菜单转换成前端路由和按钮权限标识。这个模型虽然多走两次关联查询,但扩展性极好,新增一个角色只需要配菜单,不用改代码。

考勤表和薪资表属于高频写入的业务表。考勤表记录每天的上班时间、下班时间、考勤状态(正常、迟到、早退、缺卡)。薪资表记录每个员工每个月的各项薪资明细,设计时把基本工资、绩效、补贴、扣款项拆成独立字段,方便后期汇总和报表输出。这两类表都要按月建索引,否则数据量上来之后查询会明显变慢。

2.3 前端Vue项目结构与路由权限设计

前端项目的组织方式同样要清晰:

src ├── api // 接口请求封装,按模块拆文件 ├── assets // 静态资源 ├── components // 公共组件 ├── router // 路由配置 ├── store // Vuex状态管理 ├── views // 页面组件,按模块分目录 ├── utils // 工具函数,如request.js封装axios └── App.vue

路由权限设计是前端的核心难点。我的实现思路是在Vuex里维护一个菜单列表,这个列表由后端根据当前用户的角色动态返回。前端拿到菜单数据后,通过router.addRoutes动态添加路由,配合路由守卫做登录校验和权限校验。

这里有一个经验之谈:动态路由千万别在每次页面刷新时重新注册,否则会出现路由重复或者白屏。正确的做法是:在路由守卫里判断Vuex中是否已有菜单数据,没有才请求后端获取并动态添加,刷新页面时通过Vuex持久化(存localStorage)来保留状态。

2.4 前后端接口约定与数据交互格式

前后端分离项目里,接口约定比代码本身更重要。这套系统统一规定了返回格式:

{ "code": 200, "message": "操作成功", "data": { } }

code为200表示成功,非200表示失败,message是给前端提示的文本,data是业务数据。分页接口返回的是{ total: 总条数, rows: 当前页数据 }结构。所有接口遵循这个格式后,前端的axios拦截器就可以统一处理——code为200直接返回data,非200弹错误提示,HTTP 401跳转登录页。后端用自定义注解@ResponseBody配合统一返回类封装,不用每个Controller都写一遍返回逻辑。

3. 核心代码实现与关键逻辑解析

3.1 JWT登录认证与权限控制实现

登录认证用的是JWT(JSON Web Token),流程如下:用户提交用户名密码,后端校验通过后生成一个token返回,前端把token存在localStorage里,每次请求时在请求头带上Authorization字段。后端通过拦截器解析token并校验合法性。

// JWT工具类核心方法 public String createToken(Long userId, String username) { return Jwts.builder() .setSubject(username) .claim("userId", userId) .setExpiration(new Date(System.currentTimeMillis() + 7 * 24 * 3600 * 1000)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); } // 拦截器中的token校验 String token = request.getHeader("Authorization"); if (StringUtils.isEmpty(token)) { throw new BusinessException("未登录或登录已过期"); } Claims claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody(); request.setAttribute("userId", claims.get("userId"));

注意几个细节:token有效期我设置为7天,实际项目里可以根据安全要求调整,比如管理后台可以缩短到2小时并要求定期重新登录。SECRET_KEY要单独放到配置文件中,不能硬编码在代码里。拦截器只做认证不做授权,某个接口具体需要什么角色权限,我用自定义注解@RequirePermission标注在方法上,由AOP切面去校验。这样权限控制逻辑集中且灵活,不会在拦截器里写一堆if-else。

3.2 MyBatis动态SQL处理复杂查询

员工列表查询是典型的动态SQL场景:查询条件可能包括员工姓名、部门ID、在职状态、入职时间范围,用户可能只填其中一部分。如果为每种组合写一条SQL,组合数量会爆炸。MyBatis的<where>和<if>标签就是为这种场景设计的:

<select id="selectEmployeeList" resultType="com.company.hr.entity.Employee"> SELECT e.*, d.name AS deptName FROM employee e LEFT JOIN department d ON e.dept_id = d.id <where> <if test="keyword != null and keyword != ''"> AND (e.name LIKE CONCAT('%', #{keyword}, '%') OR e.job_number LIKE CONCAT('%', #{keyword}, '%')) </if> <if test="deptId != null"> AND e.dept_id = #{deptId} </if> <if test="status != null"> AND e.status = #{status} </if> </where> ORDER BY e.create_time DESC </select>

注意<if>标签的test表达式里,参数为null和空串都要判断,否则前端传个空字符串过来会导致SQL拼接错误。LEFT JOIN而不是INNER JOIN,是因为有些员工可能还没分配部门,用内连接会把这些员工丢掉。分页用MyBatis的分页插件PageHelper,一行代码搞定传pageNum和pageSize,不用手动拼接LIMIT。

3.3 前端Vue组件化开发与状态管理

前端最重要的两个业务页面是员工列表和考勤审批,它们的实现方式代表了两种典型模式。

员工列表页是“表格+搜索表单”的组合。搜索表单用Element UI的el-form配合el-input、el-select、el-date-picker收集查询条件,点击查询按钮时重新调用接口并重置分页。表格用el-table绑定数据,操作列放编辑、离职、删除按钮。整个页面的逻辑不复杂,核心在于把查询条件、分页参数、表格数据之间的关系理清楚。

一个值得借鉴的细节是弹窗表单的复用。新增员工和编辑员工共用一个弹窗组件,组件内部通过props传入的employee对象是否为null来区分当前是新增还是编辑。这样做避免了写两套几乎一样的表单代码,维护成本低很多。

考勤审批页则涉及更复杂的交互:主管看到的是一个待审批列表,点击每条记录可以展开查看详情(申请人、日期、请假类型、事由),然后选择同意或驳回。这个页面用el-dialog嵌套el-descriptions展示详情,审批操作调用不同的接口。审批状态的变化需要实时刷新列表,我用Vuex配合mixins做了一个列表刷新机制,审批完成后自动重新拉取数据。

状态管理方面,Vuex主要放三类数据:用户信息(登录后从接口获取并存储)、菜单列表(用于动态路由)、系统字典(如员工状态、请假类型这些枚举值)。字典数据放Vuex里避免了每个页面单独请求一遍,刷新时重新拉取即可。

3.4 数据权限与敏感信息控制

人事系统的特殊之处在于数据敏感度高,尤其是薪资数据,绝对不能出现越权访问。简单的做法是:普通员工只能查自己的工资单,部门主管能查本部门员工的工资单,HR角色能查全公司工资单。这个逻辑不能只靠前端隐藏按钮实现,后端接口必须做数据权限校验。

薪资查询接口的实现思路:

public PageResult<SalaryDetailVO> querySalaryList(SalaryQueryDTO dto) { // 获取当前登录用户信息 LoginUser loginUser = SecurityUtils.getCurrentUser(); // 根据角色决定数据范围 if (loginUser.isHr()) { // HR可查所有 } else if (loginUser.isManager()) { // 主管只能查本部门,强制拼接部门ID dto.setDeptId(loginUser.getDeptId()); } else { // 普通员工只能查自己,强制拼接员工ID dto.setEmployeeId(loginUser.getEmployeeId()); } return salaryMapper.selectPage(dto); }

这个模式的关键点在于:权限控制是在后端强制执行的,不是靠前端传参。普通员工改了请求参数里的employeeId也没用,后端会用登录用户的employeeId覆盖。这种“服务端强制数据范围”的做法是管理系统的底线要求,无论如何都不能省。

4. 环境搭建与最终部署过程全记录

4.1 本地开发环境准备清单

用到的环境版本建议如下:

  • JDK 8或11(SpringBoot 2.x版本都支持,我用的JDK 8)
  • Maven 3.6+(依赖管理用)
  • MySQL 5.7或8.0(推荐8.0,注意8.0的驱动配置略有不同)
  • Node.js 14+和npm
  • Nginx不是本地调试必需,但部署时需要

数据库方面,项目提供了初始化SQL脚本,按顺序执行即可。这里提醒一句:脚本要区分表结构脚本和初始数据脚本,先跑表结构再跑数据,不然外键关联的表会报错。虽然我建议不用物理外键,但表结构脚本中仍然保留了逻辑关联,数据脚本的插入顺序还是要注意部门表先于员工表。

4.2 后端打包与启动配置修改

后端打包前必须修改的配置文件是application.yml,重点改三处:数据库连接信息、JWT密钥(生产环境一定要换掉默认值)、端口号。

server: port: 8081 spring: datasource: url: jdbc:mysql://localhost:3306/hr_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver hr: jwt: secret: your_custom_secret_key_here expire-days: 7

MySQL驱动这几个参数很容易踩坑:serverTimezone必须指定,否则会报时区错误;characterEncoding要指定utf8,防止中文乱码。如果数据库密码包含特殊字符(比如@、#),建议用单引号包起来,或者直接修改数据库密码为简单字符串,省得解析出问题。

打包命令很简单:mvn clean package -DskipTests。跳过测试是必要的,因为有些测试类会尝试连数据库,环境不对时直接导致打包失败。打包完成后target目录下会生成一个jar包,用java -jar hr-system.jar就能跑起来。

4.3 前端构建与Nginx配置细节

前端构建依赖node_modules依赖完整。初次执行npm install时可能会因为网络原因失败,建议配置淘宝镜像源:

npm config set registry https://registry.npmmirror.com

依赖安装完成后执行npm run build,构建产物会输出到dist目录。这里有个关键配置:前端代码里有个环境变量文件(.env.production),里面配置了后端接口的基础地址。开发环境用/api走代理,生产环境必须改成后端实际的访问地址,比如http://你的服务器IP:8081。如果不改这个配置,部署上线后前端请求会404。

Nginx配置文件的关键部分:

server { listen 80; server_name your_domain_or_ip; # 前端静态资源 location / { root /usr/share/nginx/html/dist; index index.html; try_files $uri $uri/ /index.html; } # 后端接口反代 location /api/ { proxy_pass http://127.0.0.1:8081/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

try_files $uri $uri/ /index.html;这一行是前后端分离项目最关键的Nginx配置,必须加上。如果不加,用户刷新页面时,前端路由路径(比如/employee/list)在Nginx里找不到对应的物理文件,直接返回404。加上这行后,所有路径都回退到index.html,交由前端路由接管。

4.4 云服务器部署完整操作实录

服务器部署的完整流程我按步骤记录一下:

  1. 安装基础环境:yum安装JDK、MySQL,或者用宝塔面板这种图形化工具一键安装,效率更高。
  2. 导入数据库:把SQL脚本上传到服务器,执行mysql -u root -p < hr_system.sql导入。
  3. 上传后端jar包,使用nohup java -jar hr-system.jar > run.log 2>&1 &后台启动。注意nohup不会自动重启进程,生产环境建议用systemd管理服务,这样服务器重启后后端能自启动。
  4. 上传前端dist目录到服务器,解压到Nginx配置的目录下。
  5. 配置Nginx并重启:nginx -t先检查配置语法,再nginx -s reload重载。

部署过程中最容易出的问题:MySQL远程连接权限。默认root用户只允许localhost访问,需要执行授权命令让远程主机能连。但更安全的做法是通过安全组策略只放行必要端口,同时MySQL的bind-address要设置成127.0.0.1,只允许本机访问,后端接口通过代理访问数据库而不是直接暴露3306端口。

5. 实战踩坑记录与常见问题排查

5.1 前后端联调阶段的高频问题

前后端联调时遇到最多的是跨域问题。浏览器同源策略会拦截前端向不同端口的后端发起请求,表现就是F12控制台报错“Access-Control-Allow-Origin”。解决方案有几种:最简单的是后端配置CORS,允许指定来源的跨域请求。但也有一种更推荐的方案——通过Nginx把前后端放在同一个域名下,用路径区分,这样根本没有跨域问题。我推荐用后者,因为生产环境早晚要这么做,不如开发阶段就按生产环境的方式调试。

联调时还有一个常见问题:接口字段名对不上。前端要的是deptName,后端返回的是dept_name。这个问题的根治方法是后端返回统一的驼峰命名JSON,在application.yml里配置:

mybatis: configuration: map-underscore-to-camel-case: true

开启这个配置后,数据库的dept_name字段会自动映射到实体的deptName属性,JSON输出自然就是驼峰。很多新手项目卡在“前端拿到数据是null”的坑上,多半是这个配置没开。

5.2 权限模块的典型逻辑漏洞

权限控制最容易出漏洞的地方,不是登录校验,而是“登录后会越权操作”。新手最容易犯的错误是:前端登录后把用户的角色ID存到localStorage里,后端接口完全信任前端传的角色信息。这非常危险,用户改一下localStorage就能变成管理员。后端的正确做法是:每次请求都从JWT里解析用户ID,从数据库里查用户的真实角色和权限,而不是相信前端传来的任何角色信息。

另一个常见问题是角色菜单缓存。管理员改了角色权限后,用户需要重新登录才能生效,这是因为前端把菜单数据存在localStorage里且没有过期时间。解决思路是:后端在用户登录时记录一个权限版本号,前端每次校验路由时对比版本号,变了就重新拉取菜单。这个小功能看起来很不起眼,但实际使用中直接影响权限变更的时效性。

5.3 部署环境与数据库迁移问题

数据库连接失败是最常见的部署拦路虎,优先检查的三件事:MySQL服务是否启动、密码是否正确、网络是否能通。其次要确认MySQL驱动版本。SpringBoot 2.7.x默认的MySQL驱动版本是8.0.x,如果数据库是5.7也没关系,驱动是兼容的。反过来如果数据库是8.0但驱动是5.x,会出现连接失败或者认证错误,这时候检查pom里的依赖版本。

这里有一个连老手都容易忽视的点:Linux服务器上Tomcat或SpringBoot应用访问MySQL时,有时会碰到DNS反解慢的问题,表现是接口响应偶尔会卡几秒钟。解决方法是在MySQL的my.cnf里加上skip-name-resolve。不过加了这个参数后,账号权限表里的host字段就只能用IP,不能用主机名,需要把相关账号的host从localhost改成127.0.0.1。

5.4 前端构建部署的两个隐藏坑

第一是关于路由模式。Vue Router默认是hash模式,URL里有#号,虽然不美观但部署非常简单。如果想用history模式,也就是去掉#号,Nginx必须配好try_files回退,不然后端部署方式稍有变动就白屏或404。我在部署时直接用history模式,但原则很简单:如果你不熟悉Nginx配置,先用hash模式顶上去,绝对稳。

第二个坑是CDN资源加载。前端build时如果用到了外部CDN的第三方库(比如引入了Vue的CDN版本而非本地打包),内网环境或服务器没外网时,页面会加载不出来。本地开发可能没感觉,因为开发机有外网。解决方案:不要用CDN,所有依赖走npm安装和本地打包。如果必须用CDN,要确保服务器和用户浏览器都能正常访问该CDN地址。

6. 扩展方向与二次开发建议

成套系统跑通之后,后续的扩展方向有几个很值得关注的点。

第一个方向是工作流引擎的引入。目前的请假审批还是简单的两级审批,如果公司组织架构和流程复杂,比如请假超过三天要总监审批、部门交叉审批等,再靠代码写死流程就不现实了。这种情况可以引入工作流引擎,但要注意工作流引擎的学习复杂度不低,如果不是真实需求,不要为了技术炫技而引入。

第二个方向是Excel导入导出的增强。目前员工信息支持单表导入,但如果要支持自定义字段模板、批量更新离职状态、多Sheet导入这些高级功能,可以考虑对POI或EasyExcel进行深度封装。这块的坑在于内存和性能,几万行数据的导入导出需要考虑分批处理,否则很容易内存溢出。

第三个方向是权限的精细化。目前是RBAC模型,也就是角色-菜单权限。如果业务要求更细,比如某个角色只能看员工列表的部分字段,或者某类数据需要按数据范围区分(本部门、本公司、全部),就需要增加数据权限的功能设计。这是一个看起来简单但实现起来复杂度较高的模块,建议有明确需求后再做,不要一开始就设计得太重。

第四个方向是定时任务与消息通知。比如员工生日提醒、合同到期提醒、每月考勤汇总推送。SpringBoot自带的@Scheduled注解就能实现简单的定时任务,配合邮件或者企业微信机器人推送给相关人员,这个功能的人力价值非常明显,值得优先做。

第五个方向是前端性能优化。目前前端打包后体积大约在2MB左右。如果用户访问服务器带宽有限,首次加载会偏慢。可以考虑按路由懒加载拆分Chunk、开启Gzip压缩、Nginx配置静态资源缓存。这些都是成本很低但收益明显的优化点,有空可以做。

7. 实际使用体验与最后的心得

整套系统从零到跑通,我实际用了大概两个晚上,大部分时间不是在写代码,而是花在环境配置和依赖版本对齐上,真正跑业务逻辑反而快。这套系统的设计很务实,没有堆砌花哨的技术,每一行代码都在解决实际业务问题,这对学习者和二次开发者来说体验很好。

比较触动我的一点是,这套系统的代码组织和注释习惯相当规范。类名、方法名、变量命名都遵循了常见的开发规范,读起来不费劲。后端Controller返回统一结构、Service层做事务管理、Mapper只做数据访问,每个文件的职责都很清晰。对于想学习项目架构的人来说,这种规范化的代码比任何文档都有教育意义。

部署过程中要学会看日志。后端启动失败时不要急着改代码,先看控制台输出的异常堆栈,大部分问题都是端口占用、数据库连不上、配置文件写错这三类。前端页面报错时按F12看Network面板,看请求是否发出、状态码是什么、响应内容是什么,定位速度会快很多。

最后分享一个小技巧。调试阶段我习惯在后端启动参数里加上--debug,这样MyBatis会打印SQL语句,方便确认实际执行的SQL是否符合预期。排查数据问题的时候,这个功能比看代码更快。等部署到生产环境时再去掉这个参数即可,免得SQL日志刷屏影响性能。

补充一个我最初忽略的细节:配置文件的编码。在Windows下用编辑器改过application.yml之后,部署到Linux服务器上可能出现配置读取乱码,导致数据库密码错误。解决方法是统一使用UTF-8编码保存所有配置文件,或者在Linux上直接用vim重新编辑一遍关键配置。这类琐碎但致命的问题,遇过一次之后就能变成肌肉记忆。

如果你正好需要一套能跑通的SpringBoot+Vue人事系统做参考,这套系统的价值在于它能让你快速看到一个完整项目的全貌:数据库设计、后端分层、前端组件化、权限控制、部署运维,一条链路从头到尾都是通的。照着跑一遍,再基于自己的业务需求往里加功能,比从零开始搭框架要省太多时间。

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

管程不是语法糖:并发编程中的结构化控制范式

1. 为什么“管程”这个词在并发编程里总被提起&#xff0c;却很少有人真正用对&#xff1f;“管程模型解决并发编程”——这个标题乍看像一句教科书结论&#xff0c;甚至有点过时。毕竟现在满屏都是Go的goroutine、Rust的async/await、Java的CompletableFuture&#xff0c;连面…

作者头像 李华
网站建设 2026/10/22 8:14:36

PCIe 6.0与CXL 3.0深度解析:从物理层到内存池化选型

最近一段时间&#xff0c;我已经被问了好几次“PCIe 6.0 和 CXL 3.0 到底是什么关系、能不能直接用到项目里”这类问题。说实话&#xff0c;这两个标准放在一起&#xff0c;本身就是一道信息量很大的“每日一题”&#xff1a;PCIe 6.0解决的是物理层带宽和传输效率&#xff0c;…

作者头像 李华
网站建设 2026/10/22 8:14:32

30行Keras代码实现MNIST手写数字识别:全连接神经网络入门实战

每次带新手入门深度学习&#xff0c;我几乎都会推荐从手写数字识别开始。原因很简单&#xff1a;数据集不挑机器、任务直观、反馈快&#xff0c;关键是可以把一套完整的“数据 → 模型 → 训练 → 评估 → 推理”流程在半小时内跑通。今天这篇就用 Keras 搭一个最朴素的全连接神…

作者头像 李华
网站建设 2026/10/22 8:14:32

K8s节点NotReady根源:CNI网络就绪四层验证法

1. 这个报错不是“网络没通”&#xff0c;而是K8s节点彻底失去了容器网络身份 你执行 kubectl get nodes 看到节点状态是 NotReady &#xff0c;再查日志发现 kubelet 反复报错&#xff1a; failed to setup network for pod "xxx": failed to find plugin &quo…

作者头像 李华
网站建设 2026/10/22 8:14:04

Elasticsearch容器化部署实战:从Docker环境搭建到生产就绪

1. 为什么今天还在手敲 Elasticsearch 环境&#xff1f;容器化不是“可选项”&#xff0c;而是“生存线” Elasticsearch-环境安装与容器Docker——这十个字背后&#xff0c;藏着过去五年里我帮二十多个团队踩过的全部坑。不是夸张&#xff0c;是实打实的数字&#xff1a;其中1…

作者头像 李华
网站建设 2026/10/22 8:14:00

LTE/LTE-A/LTE-R Simulink链路级仿真:从跑通到避坑

简介&#xff1a;这份资源是一个基于Simulink搭建的LTE系统仿真项目&#xff0c;面向通信工程专业学生、无线通信研究者及需要验证物理层算法的工程师&#xff0c;重点解决信道估计环节的建模与性能分析问题。压缩包内共1个文件&#xff0c;为m脚本类型&#xff0c;整体约2KB&a…

作者头像 李华