SpringBoot+Vue前后端分离管理平台:架构、部署与排障实战

发布时间:2026/9/28 12:18:01

SpringBoot+Vue前后端分离管理平台:架构、部署与排障实战 写这套东西的初衷很简单团队在维护一个同时面向普通用户和管理人员的平台时前后端代码全搅在一个工程里每次发版要么后端等前端要么前端等后端光联调就能耗掉大半天。后来把系统拆成了SpringBootVueMyBatisMySQL的前后端分离架构又补了一套完整的部署方案这才把开发和运维的节奏理顺。这篇内容就从我的实际落地经验出发把系统设计、后端核心实现、前端工程化、联调安全、直到部署上线整个链路掰开讲不说虚的只讲能直接抄作业的部分。做完这套东西你至少能得到三样东西一套能跑通的完整代码结构、一份不用踩坑的部署手册以及一批踩坑之后才总结出来的排障经验。1. 项目整体设计与架构拆解1.1 这套管理平台到底解决什么问题先说需求背景。一个“Web及游戏管理平台”本质上就是给运营、客服、产品甚至玩家自己用的管理后台只是业务范围覆盖了普通Web业务和游戏运营场景。你可以把它理解成一个带权限体系的控制台Web业务侧需要配置活动、管理内容、查看用户数据游戏业务侧需要维护区服、发放道具、监控日志、生成运营报表。这些操作如果全部走数据库直连或者写在散落的脚本里安全性和效率都撑不住。拆成前后端分离之后好处是立竿见影的后端只做接口职责单一数据校验、权限控制、业务逻辑全部收拢到SpringBoot服务里。前端只做界面所有页面通过Vue组件化开发调试时期的数据交互都用Mock或者后端联调环境不需要等后端页面渲染。数据库层与业务层隔离通过MyBatis做ORM映射SQL掌握在开发手里优化空间更大。我当时接到这个需求时项目已经有点“历史包袱”了原系统用FreeMarker模板渲染页面运营要新增一个字段都得改Java代码。重构前后端分离之后前端页面可以独立发版后端接口按版本迭代数据库结构变化通过Flyway或手工SQL脚本管理整个团队的配合方式彻底变了。1.2 为什么选这套技术组合而不是别的很多人问过为什么是SpringBootVueMyBatisMySQL而不是Spring Cloud全家桶也不用MyBatis-Plus更不选Vue3TypeScript我的回答很简单看团队规模和项目阶段。SpringBoot选得没什么争议生态成熟、社区大、内置Tomcat一个Jar包就能跑起来。对于管理平台这种以CRUD和权限管理为核心的系统SpringBoot的自动配置能省掉大量XML配置同时它和Spring Security、Shiro、MinIO、Redis这些周边组件都是无缝整合。前端选Vue而不是React核心原因是国内招聘市场会Vue的人更多而且Vue2/Vue3的组件化开发模式对管理后台非常友好。后台页面的交互模式高度相似表格、表单、弹窗、树形控件Vue的响应式数据绑定让这类页面的开发效率明显高于手动操作DOM。我这边使用的是Vue2.7 Vue Router Vuex的经典组合虽然Vue3已经是主流但存量系统用Vue2反而更稳升级与否取决于团队精力。MyBatis和MyBatis-Plus的取舍值得说几句。MyBatis-Plus确实提供了很多内置方法单表CRUD不用写SQL但它带来的问题是SQL对开发不透明复杂查询反而要多绕一层。我的原则是管理平台的查询条件多、动态拼接频繁直接用MyBatis写动态SQL反而更可控。而且MyBatis自带一级缓存和二级缓存机制配合PageHelper分页插件性能完全够用。MySQL更不用提开源、稳定、方案多管理平台的数据量级在百万以内时单实例MySQL合理索引完全能撑住。真到了需要分库分表的规模这套架构同样可以平滑扩展到ShardingSphere。1.3 前后端分离必须想清楚的四件事所谓前后端分离不是把项目代码分成两个文件夹就完了。真正落地时有四件事必须提前拍板否则后面全是坑。第一件是接口规范。我这边统一约定RESTful风格后端返回统一结构体{code: 0, msg: success, data: {...}}。前端所有请求都走同一套封装好的axios实例拦截器统一处理错误码和登录态过期。第二件是跨域方案。开发环境用Vue的proxyTable代理解决生产环境用Nginx反向代理或后端配置CORS。这里没有银弹根据部署环境选一个定死别混着来。第三件是权限模型。管理平台最怕权限失控。我这边用的是RBAC模型用户—角色—权限三层结构前端根据路由表动态生成菜单后端每个接口做一遍权限校验前后端双重控制。第四件是部署方式。到底是后端Jar包直跑、前后端分开部署还是前端打包后放进后端静态目录统一部署两种方式都有人用但严格意义上“前后端分离”就应该分开部署。前端打包成纯静态文件扔Nginx后端Jar包独立跑这样前端发布不影响后端后端发版不影响前端页面。2. 后端核心实现细节SpringBoot MyBatis MySQL2.1 数据库设计与MyBatis数据访问层搭建数据库是整个平台的地基。我习惯在设计表结构时把业务字段和审计字段分开。业务字段各表不同审计字段统一是create_time、update_time、create_by、update_by、deleted这几列。所有表都加上逻辑删除标记管理平台误删数据的场景太多物理删除一旦执行就找不回来了。以游戏管理平台里最典型的“区服表”为例CREATE TABLE game_server ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID, server_name varchar(64) NOT NULL COMMENT 区服名称, server_no int(11) NOT NULL DEFAULT 0 COMMENT 区服编号, game_type varchar(32) NOT NULL COMMENT 游戏类型, status tinyint(4) NOT NULL DEFAULT 1 COMMENT 状态 1-开启 0-关闭, open_time datetime DEFAULT NULL COMMENT 开服时间, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, deleted tinyint(1) NOT NULL DEFAULT 0 COMMENT 逻辑删除 0-未删除 1-已删除, PRIMARY KEY (id), KEY idx_server_no (server_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT游戏区服表;注意几个细节第一server_no设置了默认值0避免插入时漏传导致NULL入库第二open_time允许为空因为有些区服还没确定开服时间第三时间字段统一用datetime不用timestamp避免2038年问题也避免时区转换引起的麻烦。MyBatis数据访问层我建议按照Controller → Service → Mapper三层来拆。Mapper接口只做数据库读写Service层负责业务逻辑和事务控制。这里有一个关键教训Service层的事务注解Transactional不是加得越多越好只在真正需要多表写操作的方法上加否则事务粒度太大数据库连接池会被长时间占用并发一上来就出问题。MyBatis的XML文件里我习惯把动态SQL写得克制一点。where标签和if标签是日常使用频率最高的但要注意if条件里字段判空要同时判断! null和! 因为前端传参经常传空字符串。2.2 MyBatis缓存与分页插件这样配才稳MyBatis的缓存机制是面试常客也是实际项目中需要谨慎使用的部分。一级缓存是SqlSession级别的默认开启同一个SqlSession内执行相同的SQL会直接命中缓存。但SpringBoot整合MyBatis后每次Mapper方法调用都会新建SqlSession一级缓存的作用范围变得极其有限不用过多纠结。二级缓存是Mapper namespace级别的可以跨SqlSession共享。开启方式很麻烦在Mapper XML中添加cache/标签对应的实体类必须实现Serializable接口涉及多表关联查询时所有相关表的Mapper都要开启二级缓存否则会读到脏数据我实际项目的建议是管理平台原则上不开启二级缓存。原因是后台数据经常被运营和管理员实时修改二级缓存更新时机不好控制一旦缓存未刷新运营看到的报表数据就是错的。与其冒着出数据事故的风险不如把MySQL查询效率做好或者引入Redis做接口级缓存缓存粒度自己可控。分页插件用的是PageHelper用法非常固定dependency groupIdcom.github.pagehelper/groupId artifactIdpagehelper-spring-boot-starter/artifactId version1.4.7/version /dependency配置方面我习惯在application.yml里显式声明pagehelper: helper-dialect: mysql reasonable: true support-methods-arguments: true params: countcountSql代码中的用法是PageHelper.startPage(pageNum, pageSize); ListGameServerVO list gameServerMapper.selectServerList(query); PageInfoGameServerVO pageInfo new PageInfo(list);这里有三个必须记住的坑PageHelper.startPage()后面必须紧跟第一条查询语句中间不能穿插其他查询否则分页会作用到错误的SQL上。分页插件会默认执行一条count查询如果表数据量大且查询条件复杂count语句可能很慢。可以考虑用PageHelper.startPage(pageNum, pageSize, false)关闭count查询只做limit。查询结果要尽快转换成PageInfo或Page对象不要在list结果集上再做循环查询否则分页结果会丢失。2.3 SpringBoot配置项与全局过滤器的实战处理SpringBoot的配置管理其实很简单核心就一个application.yml。但管理平台需要应对不同环境我这边用的是三套配置文件application.yml公共配置只放数据源、MyBatis等不随环境变化的内容application-dev.yml开发环境数据库地址指向本地application-prod.yml生产环境数据库地址指向线上日志级别调低启动时通过spring.profiles.active指定环境比如生产环境启动命令java -jar game-admin-server.jar --spring.profiles.activeprod数据源配置我特别提醒一点SpringBoot 2.x默认用的是HikariCP连接池性能足够好但需要手动设置几个关键参数spring: datasource: hikari: minimum-idle: 5 maximum-pool-size: 20 idle-timeout: 30000 connection-timeout: 30000 max-lifetime: 1800000maximum-pool-size不能拍脑袋乱填要结合应用并发量评估。公式大致是池大小 并发请求数 × (单请求数据库操作耗时总和 / 平均请求总耗时)。管理平台并发不高20个连接完全够用太大反而浪费内存。全局过滤器这块我遇到过一个真实场景运营上传PDF文件时文件名里带了脚本片段虽然不是直接执行但存在存储型XSS风险。解决方案就是写一个全局XSS过滤器包装HttpServletRequest对所有请求参数做特殊字符转义。核心思路是重写getParameter、getParameterValues和getHeader方法对HTML敏感字符做编码处理public class XssFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { XssHttpServletRequestWrapper xssRequest new XssHttpServletRequestWrapper((HttpServletRequest) request); chain.doFilter(xssRequest, response); } }这里要注意过滤器只处理请求参数层面的XSS文件上传的二进制流不能走同样的转义逻辑否则文件内容会被破坏。我在包里判断Content-Type如果是multipart/form-data就不做参数转义文件内容单独走病毒扫描和内容校验。3. 前端工程化实现要点Vue篇3.1 Vue环境搭建与项目初始化前端部分我默认大家已经装了Node.js。注意版本Vue2.7需要Node 14以上Vue3需要Node 16以上我这边用的是Node 16.20。创建项目的方式很多我推荐用官方CLI创建Vue2项目npm install -g vue/cli vue create game-admin-web创建过程中有几个选择要提前想好包管理器选npm国内环境配好淘宝镜像装依赖速度能快不少。是否使用路由选Vue Router。状态管理管理后台建议选Vuex跨页面共享登录态最方便。CSS预处理器选Sass/SCSS写管理后台的样式嵌套会清爽很多。项目创建完成后第一件事检查package.json里的依赖版本确保vue-router和vuex版本与Vue版本匹配。Vue2配vue-router 3.x配vue-router 4会直接报错这是新手最高频的坑。开发环境的端口默认是8080后端接口跑在9090跨域问题通过Vue CLI的proxy配置解决。在vue.config.js里写module.exports { devServer: { port: 8080, proxy: { /api: { target: http://localhost:9090, changeOrigin: true, pathRewrite: { ^/api: } } } } };这样前端代码里所有的/api请求都会被代理转发到后端9090端口开发环境就没有跨域问题了。3.2 路由、接口封装和状态管理管理后台的路由结构我习惯分成两组constantRoutes是固定路由登录页、404页等asyncRoutes是权限路由根据后端返回的菜单权限动态生成。在路由配置中有一个坑就是刷新页面时动态路由会丢失。用户刷新浏览器Vue重新加载router.addRoutes的权限路由需要重新挂载。处理方式是在main入口或路由守卫里增加一个hasPermission的标志位如果为false就从后端重新拉取当前用户的权限菜单并动态添加路由。接口封装是一个容易被忽视但极其重要的环节。我在src/utils/request.js里统一封装axios实例import axios from axios import { Message } from element-ui import router from /router const service axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 15000 }) service.interceptors.request.use(config { const token sessionStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config }) service.interceptors.response.use( response { const res response.data if (res.code ! 0) { Message({ message: res.msg, type: error }) if (res.code 401) { router.push(/login) } return Promise.reject(new Error(res.msg)) } return res }, error { Message({ message: error.message, type: error }) return Promise.reject(error) } )这里401表示登录态失效由响应拦截器统一踢回登录页实现一次跳转全站生效。状态管理用Vuex保存用户名、头像、菜单权限等公共数据。有一个经验不要把接口返回的所有数据都塞进VuexVuex里的数据是响应式的大对象会造成额外的性能开销。只放全局必要的页面内部的业务状态放组件里维护即可。3.3 游戏管理场景的功能落地既然标题里写了“游戏管理平台”前端要体现出和普通后台的差异。游戏运营后台有几个典型页面区服管理页面表格展示所有区服支持开区、停服操作操作后状态列需要即时刷新。这里我用的是Element UI的el-table el-switch组件切换状态时调接口成功后再更新本地数据不做整表刷新避免页面闪烁。道具发放页面运营输入玩家ID、选择道具、填数量提交后端接口。这个页面的关键点是输入校验玩家ID必须是纯数字道具数量必须是正整数。Element UI的表单校验规则配合正则表达式就能搞定。公告管理页面支持富文本编辑、定时发布、M3U8视频公告的播放预览。M3U8播放这块游戏平台经常要嵌入视频运营素材我用的是hls.js库在Vue组件里动态加载import Hls from hls.js if (Hls.isSupported()) { const hls new Hls() hls.loadSource(videoUrl) hls.attachMedia(videoElement) }这里要特别注意hls.js只在主流浏览器中支持旧版浏览器或者部分移动端需要依赖原生播放能力要写兼容判断。我踩过坑上线后运营反馈有个别电脑看不了公告视频排查到最后就是浏览器版本不支持MSE需要引导用户升级浏览器或者走后备的mp4直链。4. 前后端联调与安全处理4.1 跨域问题的三种解决路径分离开以后跨域是绕不开的问题。我的建议是按环境分工开发环境用Vue CLI的proxyTable代理前面已经讲过。测试/预发环境后端临时开启CORS允许指定来源访问。生产环境用Nginx反向代理后端完全不关心跨域问题。生产环境的Nginx配置是最终形态server { listen 80; server_name admin.example.com; location / { root /opt/frontend/dist; index index.html; try_files $uri $uri/ /index.html; } location /prod-api/ { proxy_pass http://127.0.0.1:9090/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }注意proxy_pass末尾的斜杠是关键/prod-api/会被替换成/转发到后端这个细节容易导致接口404。开发环境偶尔也需要临时开启后端CORSSpringBoot里写一个配置类即可Configuration public class CorsConfig { Bean public CorsFilter corsFilter() { CorsConfiguration config new CorsConfiguration(); config.addAllowedOrigin(http://localhost:8080); config.addAllowedMethod(*); config.addAllowedHeader(*); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration(/**, config); return new CorsFilter(source); } }但生产环境我强烈建议关闭CORS全部交给Nginx处理。后端开CORS会让接口暴露给任意来源安全风险高。4.2 XSS攻击过滤器的完整实现思路后端过滤器我在第2.3节已经提了思路这里补充完整编码细节。XSS攻击的本质是恶意用户输入一段带标签的字符串被系统存储后在页面渲染时执行了脚本代码。防护思路叫做“输出编码”但管理平台数据流转复杂最简单的方式是在入口统一过滤。完整实现分三层第一层包装请求对象重写获取参数的方法public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { Override public String getParameter(String name) { return cleanXss(super.getParameter(name)); } Override public String[] getParameterValues(String name) { String[] values super.getParameterValues(name); if (values null) return null; String[] escapedValues new String[values.length]; for (int i 0; i values.length; i) { escapedValues[i] cleanXss(values[i]); } return escapedValues; } private String cleanXss(String value) { if (value null || .equals(value)) return value; value value.replaceAll(, lt;).replaceAll(, gt;); value value.replaceAll(, #39;).replaceAll(\, quot;); value value.replaceAll(javascript:, ); return value; } }第二层注册过滤器并设置过滤路径这里我默认只过滤/admin/**下的请求玩家端的接口不统一过滤Bean public FilterRegistrationBeanXssFilter xssFilterRegistration() { FilterRegistrationBeanXssFilter registration new FilterRegistrationBean(); registration.setFilter(new XssFilter()); registration.addUrlPatterns(/admin/*); registration.setOrder(1); return registration; }第三层处理文件上传场景。上传PDF、Word、图片等文件时文件名参数同样需要过滤但文件内容不能过滤。我在XssHttpServletRequestWrapper的getInputStream方法中不走转义逻辑让文件流原样通过。文件名在Controller层额外校验只允许中英文、数字、下划线和点号其他字符一律拦截。4.3 接口鉴权的轻量方案管理平台的接口不能裸奔。我的做法分两步走登录接口颁发token后续所有请求带token后端通过拦截器校验。方案上没有引入Spring Security这种重型框架而是直接用的是JWT 自定义拦截器。原因很简单RBAC权限模型在MySQL里几张表就能维护Spring Security的过滤器链配置复杂团队学习成本高。JWT生成代码String token Jwts.builder() .setSubject(userId.toString()) .claim(username, username) .setExpiration(new Date(System.currentTimeMillis() 24 * 3600 * 1000)) .signWith(SignatureAlgorithm.HS256, secretKey) .compact();拦截器里解析token、校验有效期、加载当前用户权限然后通过ThreadLocal把用户信息传递到业务代码。接口级别的权限注解我自定义了一个RequirePermission(game_server:add)基于AOP实现前置校验当前用户是否拥有指定权限码。这样在Controller方法上加一行注解权限控制就生效了。Token安全要注意两点密钥要独立配置不要写死在代码里token有效期不要太长管理后台一般24小时足够超过就踢下线重新登录。5. 完整部署流程实操5.1 MySQL安装与数据库准备数据库部署这一步看似简单踩坑却不少。Windows环境直接下载MySQL安装包Linux环境则更推荐用包管理器安装。以CentOS为例# 检查是否已安装 rpm -qa | grep mysql # 安装 wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm rpm -ivh mysql80-community-release-el7-3.noarch.rpm yum install mysql-server -y # 启动 systemctl start mysqld # 查找初始密码 grep temporary password /var/log/mysqld.log # 登录并修改密码 mysql -uroot -p ALTER USER rootlocalhost IDENTIFIED BY YourPassword!;我遇到过最经典的一个坑就是客户端连接报错ERROR 2002 (HY000): Cant connect to local MySQL server through socket /tmp/mysql.sock这个报错的原因99%是MySQL服务根本没启动或者是socket文件路径不对。先检查服务状态ps -ef | grep mysqld systemctl status mysqld确认服务在跑还报错的话就要检查my.cnf里的socket路径是否和客户端默认路径一致。管理平台用的连接方式是TCP/IP只要datasource.url里配了IP和端口socket路径其实不影响Java应用连接影响的是mysql命令行客户端。数据库的导入导出用Navicat或者命令行都行。我建议把建表语句和初始化数据分开管理建表语句用CREATE DATABASE加多个CREATE TABLE初始化数据单独放一份SQL文件避免每次重建库时被脏数据干扰。5.2 Tomcat部署前后端分离项目的方法这里有个概念要先理清SpringBoot项目打成Jar包后自带Tomcat根本不需要单独装Tomcat。我理解很多同学问“Tomcat部署前后端分离项目”是两种情况第一种老项目还是War包方式需要部署到独立Tomcat。做法是把打包方式改成Warpackagingwar/packaging然后在启动类继承SpringBootServletInitializer重写configure方法打成War包放进Tomcat的webapps目录即可。第二种前端静态文件想和后端一起部署在Tomcat里。注意如果走这条路那就不算严格意义的“前后端分离”了。把Vue打包生成的dist目录内容直接放在Tomcat的webapps/ROOT下访问路径就是根路径但前端请求后端的接口地址要对应上。我更推荐的标准部署方式后端mvn clean package -DskipTests打成Jar包用java -jar运行。前端npm run build生成dist静态目录放在Nginx或任意静态文件服务器里。两边通过API域名或路径区分互不干扰。这种模式下后端服务的启停用systemd管理写个service文件[Unit] DescriptionGame Admin Server Afternetwork.target [Service] Userroot ExecStart/usr/bin/java -jar /opt/game-admin/server.jar --spring.profiles.activeprod SuccessExitStatus143 Restartalways RestartSec5 [Install] WantedBymulti-user.target然后systemctl daemon-reload systemctl enable game-admin systemctl start game-admin服务即可开机自启、崩溃自动拉起。5.3 Windows下Jenkins自动化部署很多中小团队的生产服务器是WindowsJenkins在这种环境下做自动化部署也完全是可行的。我当时搭的流程是开发提交代码 → Jenkins拉取Git仓库 → Maven打包后端 → 前端构建 → 通过批处理脚本把产物拷贝到目标目录 → 重启服务。关键一步是Jenkins构建后的批处理脚本我分享一个实际用过的片段echo off set APP_NAMEgame-admin-server set SOURCE_JAR%WORKSPACE%\target\%APP_NAME%.jar set TARGET_DIRD:\deploy\ xcopy /Y %SOURCE_JAR% %TARGET_DIR% taskkill /F /IM java.exe timeout /T 3 cd /D D:\deploy start javaw -jar %APP_NAME%.jar --spring.profiles.activeprod这个脚本看起来简单坑却不少taskkill /F /IM java.exe会把服务器上所有Java进程杀掉如果同一台机器跑了多个Java服务就直接团灭。正确做法是找到具体进程PID再杀或者用脚本记录PID。start javaw是后台启动日志输出到哪了不好查。建议用start /B java -jar ... app.log 21把日志重定向到文件。前端构建在Jenkins里加一步执行npm install npm run build产物拷贝到Nginx的html目录即可。Windows下Nginx的开机自启不友好建议注册成Windows服务或用NSSM工具封装。5.4 静态资源和上传文件的处理管理平台必然涉及文件上传游戏公告的封面图、运营活动的物料包、玩家反馈的截图这些文件不能存到数据库里也不能塞进项目发布目录否则每次重启都会丢。对象存储推荐用MinIO它是开源的与SpringBoot集成非常简单。引入依赖、配置连接参数后封装一个MinIO工具类上传、下载、删除、生成临时访问链接几个方法就够用。我这边在本地环境用MinIO生产环境切到云上的对象存储服务后端的接口设计成一致的就完全平滑过渡。本地文件存储方案也可以用但有个必须解决的问题上传目录不能放在项目jar包所在目录下更不能放在tomcat的webapps里。要放在一个独立的数据盘目录比如/data/uploads然后通过Nginx映射这个目录作为静态资源访问路径。否则重新部署时文件就随老版本一起被覆盖或删除这是很多新手最容易踩的丢失文件坑。6. 常见问题与排查技巧实录6.1 MySQL连接和启动问题速查把我在这个项目里遇到的数据库问题整理成一个速查表按频率排序报错信息原因解决方法ERROR 2002 (HY000): Cant connect ... socket /tmp/mysql.sockMySQL服务未启动或socket路径不对检查systemctl status mysqld确认my.cnf的socket配置Access denied for user rootlocalhost密码错误或用户权限配置不对重置密码或用skip-grant-tables模式进入修复Public Key Retrieval is not allowed客户端工具连接MySQL 8时安全策略限制JDBC URL加allowPublicKeyRetrievaltrueConnection refused端口未开放或防火墙拦截检查netstat -tlnp看3306是否监听防火墙放行Too many connections连接数超过max_connections调大max_connections同时排查连接池是否泄漏处理数据库连接异常有一个通用排查顺序先看服务状态再看端口监听再检查账号权限最后看应用日志。不要一上来就怀疑密码错误我见过太多花半小时重置密码、最后发现是防火墙问题的案例。6.2 前端构建和路由刷新404问题Vue项目部署后刷新页面出现404是最高频的问题。原因很清晰前端路由是hash模式还好但用了history模式时刷新页面会请求http://域名/当前路径而Nginx根本没有这个物理文件自然返回404。解决办法在前端路由用history模式时的Nginx配置里加上location / { try_files $uri $uri/ /index.html; }这行配置的意思是请求的路径如果找不到就直接回退到index.html由前端路由接管。还有一个连前端构建都过不去的坑Node内存不足报JavaScript heap out of memory。这是工程项目规模大了以后webpack默认内存不够用。解决方法是构建脚本里加参数scripts: { build: node --max_old_space_size4096 node_modules/vue/cli-service/bin/vue-cli-service.js build }或者用cross-env NODE_OPTIONS--max_old_space_size4096 vue-cli-service build两种方案都行核心是给Node的堆内存扩容。6.3 MyBatis高频问题与面试避坑MyBatis这块值得单开一节说因为它的使用细节和面试高频考点高度重合。第一个高频问题MyBatis的#{}和${}有什么区别#{}是预编译占位符对应JDBC的?自动加单引号能防SQL注入${}是字符串拼接直接替换SQL片段。实际开发中表名、排序字段这类无法用占位符的地方才用${}但必须做好白名单校验。我见过有人图省事把用户输入直接拼进ORDER BY ${sortField}结果表结构被拖库这就是血的教训。第二个高频问题批量插入怎么写效率最高最标准的写法是foreach标签配合INSERT INTO ... VALUES ...多条并列insert idbatchInsert parameterTypelist INSERT INTO game_user_lottery (user_id, lottery_id, reward_id, create_time) VALUES foreach collectionlist itemitem separator, (#{item.userId}, #{item.lotteryId}, #{item.rewardId}, NOW()) /foreach /insert注意MySQL单条SQL有长度限制批量条数超过500条时建议拆成几批执行或者用MultiBatchExecutor这种ExecutorType。第三个高频问题MyBatis查询返回结果映射不上字段。根本原因是MySQL字段名是下划线风格Java实体类是驼峰风格。开启Spring Boot的配置即可解决mybatis: configuration: map-underscore-to-camel-case: true这个开关我直接在全局配置里开启省去每个Mapper XML里写resultMap的重复劳动。只在多表关联查询的复杂结果集上才手动定义resultMap。此外日常开发中建议在IDEA安装MyBatis XML高亮插件比如MyBatisX写Mapper XML时会有SQL语法提示、方法跳转、参数校验能提前抓出不少低级错误。XML里一个标签错位编译期根本发现不了运行期直接报MapperStatement找不到排查还费劲。别急着收尾再聊几句我的感受这套前后端分离的管理平台从设计到上线前前后后打磨了两个多月。后期维护里我最深的体会是架构本身不产生价值解决了业务问题的架构才有价值。SpringBoot Vue MyBatis MySQL做到今天已经是极其成熟且“平庸”的组合但正因为平庸它可靠、可预见、团队上手快。做管理平台没有太多炫技空间核心是把接口规范好、把权限控制死、把部署流程理清楚、把排查文档写完整这比任何花哨的框架选型都重要。最后分享一个小技巧在本地调试前后端联调时用Vue devtools插件查看路由和Vuex状态变化非常高效。安装方式是在Chrome应用商店搜索Vue.js devtools有些网络环境可能加载困难就可以通过离线安装的方式加载插件的crx包。调试接口请求的话直接把浏览器的Network面板打开看请求头、响应体和耗时分布大多数前后端扯皮的问题都能在十分钟内定位到是前端参数传错还是后端接口逻辑不对。这套系统后续我还在规划接入更细粒度的操作日志模块和基于WebSocket的实时运营数据看板等落地了再回来写一篇方案复盘。
延伸阅读

更多相关文章

2026/9/28 12:18:01

PCM、WAV与RIFF:语音模型输入格式检查记录

PCM、WAV与RIFF:语音模型输入格式检查记录 语音算法工程师学习路线 音频基础 01 语音推理链路出现异常时,音频格式检查应当早于模型排查。文件能够被播放器正常播放,并不能证明它满足模型的输入契约。 本文记录 PCM、WAV 和 RIFF 的关系&…

2026/9/28 12:18:01

AI辅助毕业论文全流程实战指南:从选题到定稿的实用方法

1. 为什么毕业生会把 AI 当成毕业论文的"最后一根稻草"先交代一下背景:我前后带过几十个本科生做毕业设计,自己也审过不少论文,这几年最直观的感受是——论文写作的焦虑已经从"怕写不出来"变成了"怕写不过"。选…

2026/9/28 12:18:01

前端转鸿蒙开发:ArkTS桌面卡片事件处理全链路详解与避坑指南

先分享一个观察:我身边不少前端出身的人,这两年陆续在聊“鸿蒙开发”。“前端成功转鸿蒙”这个说法听起来挺有诱惑力,但真正落地之后你会发现,TypeScript 基础能帮你省很多事,最要命的反而是“事件处理”这个环节。我自…

2026/9/28 13:18:06

混合流水车间调度HFSSPW:工人约束建模与NSGA-II启发式解码实践

HFSSPW这篇文章我断断续续做了一年多,从最初的建模陷阱到最终的Matlab代码框架,中间重写了三版解码器。最初我以为难点在进化算法,后来才意识到,真正拉开差距的是解码策略。今天把完整的求解思路、代码实现的细节和踩坑记录整理出…

2026/9/28 13:18:06

MySQL索引优化实战:从慢查询到B+树原理与设计

1. 一次线上慢查询,把我逼到重新理解索引先说个真实经历。去年年底我们有个订单列表接口,每天晚上8点到10点准时变慢,前端转圈转得用户直接在群里开喷。看了下慢查询日志,罪魁祸首就是一条按用户ID和创建时间范围分页的SQL&#x…

2026/9/28 13:18:06

JDBC实战:从连接参数到增删改查,彻底搞定MySQL数据库操作

JDBC(MySQL)这条线,第一天大家多半已经跑通了“加载驱动、拿到Connection、对着控制台证明自己能连上库”的流程。但说句实在话,那个阶段你手里的东西还撑不起一个哪怕最简单的用户管理模块。DAY02的核心任务,就是把“…

2026/9/28 13:18:06

2026电子签章软件选型指南:8款主流产品对比与落地避坑建议

电子签章软件这几年在国内企业里的普及速度,说实话比很多人预想的要快得多。前几年聊电子签章,大家问得最多的是"这东西有没有法律效力",到了今年,问法已经完全变了——"我们集团旗下七八家子公司,合同…

2026/9/28 13:18:06

Cadence培训怎么选?先分清IC设计与PCB方向再报班

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

2026/9/28 13:13:06

Flask SSTI模板注入从原理到命令执行实战解析

1. 题目分析与环境准备1.1 先看这道题在考什么BUUCTF 上的[pasecactf_2019]flask_ssti是一道非常典型的 SSTI(Server-Side Template Injection,服务端模板注入)入门题。题目名称里直接给出了两个关键信息:flask和ssti,…

2026/9/28 3:03:23

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/28 6:05:15

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/28 6:07:41

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/28 0:02:03

广州外贸网站建设推广:从零搭建全流程拆解与真实报价避坑

广州外贸网站建设推广:从零搭建全流程拆解与真实报价避坑 改个需求建站公司拖一周,后台改个文案还得再交一笔“技术维护费”。这种憋屈事儿,做外贸的朋友太熟悉了。很多老板在找广州外贸网站建设推广服务商时,光盯着首页好不好看,却忽略了从零搭建一个能…

2026/9/28 0:02:04

搞懂百度竞价推广价格,网站性能优化别掉链子

搞懂百度竞价推广价格,网站性能优化别掉链子 网站突然打不开,浏览器弹出红色警告“此网站存在安全风险”,后台一看全是乱码代码和奇怪的跳转链接。这种网站被黑挂马的绝望感,很多刚转行做网站的朋友都经历过,尤其是那些为了省几百块钱服务器费用的新手。…

2026/9/25 20:55:38

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/26 19:58:38

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/28 1:59:25

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑