背景痛点毕设开发的三座“隐形大山”做毕设时很多同学把“能跑起来”当成唯一目标结果在答辩前一周集体踩坑前后端混写JSP 里嵌 VueVue 里写 SQL代码一耦合改需求就“牵一发动全身”。接口随意URL 叫/login2、/getData状态码清一色 200前端拿到 500 只能alert(报错)老师一问“幂等性怎么保证”就集体沉默。部署黑洞Windows 上跑得好好的上云就 404静态资源 404、跨域 502最后把 jar 包和 node_modules 一起塞进 FTP服务器 1G 内存直接 OOM。这些痛点的本质是“缺一套教学友好、又能平滑过渡到生产的脚手架”。下面这套 SpringBoot Vue 的“最小可用骨架”就是为此而生。技术选型为什么不是 SSM 与 React维度SpringBoot vs SSMVue vs React冷启动内嵌 Tomcat一键启动CLI 开箱即用模板语法近似 HTML配置量零 XMLyml 即可单文件组件样式作用域天然隔离学习曲线注解驱动无需整合 Struts双向绑定 选项式 API学生可“猜”语法生态对齐MyBatis-Plus、Knife4j 一键集成Element-Plus 与 Boot 配套脚手架最多结论SpringBoot 让“跑起来”成本最低Vue 让“写出来”心智负担最小两者组合是“教学—生产”梯度最平滑的栈。核心实现细节1. 项目骨架back └─ src ├─ main │ ├─ java │ │ └─ com.example.demo │ │ ├─ config │ │ ├─ controller │ │ ├─ entity │ │ ├─ mapper │ │ ├─ service │ │ └─ DemoApplication.java │ └─ resources │ ├─ application.yml │ └─ mapper/*.xml front └─ src ├─ api ├─ router ├─ store └─ views前后端彻底解耦端口级联通过.env文件注入方便 CI 时替换。2. 统一响应封装Data public class RT { private int code; private String msg; private T data; public static T RT ok(T data){ return new R(200,ok,data); } public static RVoid fail(int code,String msg){ return new R(code,msg,null); } }所有 Controller 返回R前端拦截器只需判断code ! 200即可集中弹窗降低心智负担。3. JWT 鉴权 幂等性保证登录接口PostMapping(/login) public RString login(RequestBody LoginDTO dto){ User user service.lambdaQuery() .eq(User::getUsername,dto.getUsername()) .one(); if(usernull || !BCrypt.checkpw(dto.getPassword(),user.getPassword())){ return R.fail(401,账号或密码错误); } String token Jwts.builder() .setSubject(user.getId().toString()) .setExpiration(new Date(System.currentTimeMillis()EXPIRE)) .signWith(SignatureAlgorithm.HS512,SECRET) .compact(); return R.ok(token); }Token 存入 VuexAxios 拦截器统一挂载service.interceptors.request.use(config{ config.headers[Authorization] Bearer store.getters.token return config })为防止重复提交在 JWT payload 加入jti字段后端用 RedisSETNX做幂等性校验30 s 过期既防重复又避免长期占用内存。4. MyBatis-Plus 通用 CRUDRestController RequestMapping(/api/student) PreAuthorize(hasRole(ADMIN)) public class StudentController { Resource private StudentService service; GetMapping(/page) public RIPageStudent page(PageDTO dto){ LambdaQueryWrapperStudent qw Wrappers.lambdaQuery(); qw.like(StringUtils.isNotBlank(dto.getName()),Student::getName,dto.getName()); return R.ok(service.page(dto.toPage(),qw)); } }前端直接传current size后端返回records total列表分页零 SQL。5. 跨域与 OPTIONS 缓存spring: mvc: cors: allowed-origins: * allowed-methods: * allowed-headers: * allow-credentials: true max-age: 3600CORS 预检缓存 1 h减少 50% 以上无效 OPTIONS 请求。精简代码片段后端登录 密码加密// UserService.java public void addUser(UserDTO dto){ User user new User(); user.setUsername(dto.getUsername()); user.setPassword(BCrypt.hashpw(dto.getPassword(),BCrypt.gensalt())); save(user); }前端Vue3 组合式登录调用// api/user.js export function login(data){ return request.post(/login,data) } // views/Login.vue const form reactive({username:,password:}) async function handleLogin(){ const {data} await login(form) store.commit(SET_TOKEN,data) router.push(/dashboard) }Nginx 静态资源映射location / { root /usr/share/nginx/html/dist; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/; }安全性 性能XSSVue 默认转义后端富文本用 Jsoup 白名单过滤onerror、javascript:等危险属性。SQL 注入MyBatis-Plus 内置#{}预编译拒绝${}拼接。密码加密BCrypt 10 轮盐值彩虹表成本指数级上升。接口缓存对热点字典加Cacheable(key#root.methodName)配合 Spring Cache CaffeineQPS 提升 3 倍。懒加载Vue Router 动态import(())首屏 chunk 减少 40%3G 网络 2 s 内可交互。生产环境避坑指南数据库连接池默认 HikariCPmax10在 1C2G 学生机足够云服务器 4C8G 可提到 30并打开leakDetectionThreshold60000揪出慢 SQL。静态资源 404SpringBoot 打包后jar里无webapp前端必须走 Nginx禁止spring.resources.static-locations指到file:绝对路径否则重启即失效。文件上传Linux 默认/tmp7 天清理上传目录改到/data/upload并在application.yml显式声明spring.servlet.multipart.location。时区容器镜像用openjdk:8-jre-alpine记得加-Duser.timezoneGMT08否则定时任务差 8 小时。日志使用logback-spring.xml按天归档保留 30 天学生机磁盘小关闭console输出只留file。可扩展方向加 Redis把幂等 token、热点榜单缓存 5 min压测 QPS 再翻一倍。上 WebSocket通知模块用 STOMP毕业答辩实时弹幕老师印象分 10。多模块拆分将user、file、order拆成独立 SpringBoot 微服务用 Nacos 注册提前体验分布式。代码生成器基于mybatis-plus-generator自定义模板一键生成 DTO、VO、ConverterCURD 页面 5 分钟搞定。模板已开源在 GitHub欢迎提 PR 补充单元测试、Docker Compose 脚本或者把 Element-Plus 换成 Ant Design Vue给后来者多一条可选路径。毕设不是终点把代码写成“别人愿意继续维护”的样子才算真正毕业。