ARTICLE DETAIL

资讯详情

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

SpringBoot 2.7 + Vue 3.2 全栈联调实战指南

SpringBoot 2.7 + Vue 3.2 全栈联调实战指南 简介这是一套基于SpringBoot与Vue全栈开发的轻量级书评系统源码面向计算机、电子信息、数学等专业本科生适用于课程设计、期末大作业及毕业设计参考。系统采用前后端分离架构后端以SpringBoot构建RESTful API前端使用Vue3Vite实现交互界面涵盖用户管理、图书录入、评论发布与展示等核心功能模块。资源包共91个文件含53个Java业务逻辑与控制器类、17个Vue组件页面、6个JS工具脚本以及SQL建表语句、配置文件yaml/env和项目说明文档md整体仅75KB结构清晰、开箱即用。目前已有64人学习下载读者可直接导入IDE与Node环境运行调试快速掌握前后端协同开发流程、接口联调方法及常见排错思路特别适合初学SpringBoot与Vue整合开发的学习者夯实工程实践能力。1. 为什么一个「书评系统」值得用 SpringBoot Vue 重做一遍你手头可能正压着一份叫书评系统源码项目说明.zip的压缩包解压后看到backend/和frontend/两个文件夹pom.xml里写着spring-boot.version2.7.18/spring-boot.versionpackage.json中vue版本是3.2.47README.md第一行写着「支持用户注册、图书检索、多级评分、评论点赞、热门榜单」——但跑起来卡在登录页白屏控制台报Failed to resolve component: router-view或者后端启动后http://localhost:8080/api/books返回 404。这不是代码写错了而是典型的新手组合陷阱SpringBoot 和 Vue 各自能跑但联调时连通性、跨域、静态资源路径、构建产物部署方式全没对齐。这个标题不是在卖源码它是一份「可落地的全栈协作契约」后端提供 RESTful 接口契约JSON Schema Swagger 文档前端按约定消费双方通过application.yml和vue.config.js显式声明边界。我带过 12 个校企合作项目80% 的翻车点不在业务逻辑而在Vue 打包后 dist 目录怎么被 SpringBoot 正确 serve、JWT Token 怎么从 Vue 路由守卫透传到 Spring Security、图书封面图上传时 multipart/form-data 的 boundary 处理差异这三处。如果你正卡在这类问题里这篇笔记就是为你写的——不讲原理只拆解从解压到上线的每一步真实操作、每个参数含义、每个报错背后的底层机制。2. 搭建前先搞清为什么选 SpringBoot 2.7.x Vue 3.x 而不是最新版2.1 版本选型不是越新越好兼容性比特性更重要SpringBoot 3.x 要求 JDK 17、移除了javax.*包、强制使用 Jakarta EE 9而绝大多数高校教学环境、企业老旧服务器仍运行 JDK 8 或 11Vue 3.4 引入defineOptions语法糖但vue/cli5.0.8对应 Vue 3.2.x才是当前vue-router4.2.xpinia2.0.33组合最稳定的基线。我们拿到的.zip中pom.xml指定spring-boot-starter-parent:2.7.18package.json锁定vue:3.2.47这不是作者偷懒而是经过生产验证的「最小可行兼容矩阵」SpringBoot 2.7.x 对应spring-security:5.7.x支持PreAuthorize注解与 JWT 集成零配置Vue 3.2.x 的Composition API已成熟script setup语法可读性高且axios与vue-router的 Promise 链异常捕获机制稳定关键中间件如mybatis-spring-boot-starter:2.2.2、vue-axios:3.2.5均在此版本区间有完整文档和 issue 闭环。提示不要手动升级spring-boot.version到 3.0 或vue到 3.4。曾有团队将 Vue 升级到 3.3.8 后useRoute()在onBeforeRouteUpdate中返回undefined根源是vue-router的NavigationGuard生命周期变更未同步适配——这种坑要花 3 天查源码才能定位。2.2 环境检查清单5 分钟确认本地能否跑通在解压书评系统源码项目说明.zip后先执行以下命令验证基础环境顺序不能错# 1. 检查 Java 版本必须为 8 或 11 java -version # 输出应类似openjdk version 11.0.20 2023-07-18 # 2. 检查 Node.js 版本必须为 16.x非 18.x 或 20.x node -v # 输出应类似v16.20.2 # 3. 检查 npm 镜像源避免下载 vue-template-compiler 失败 npm config get registry # 应为 https://registry.npmjs.org/ 或国内镜像如 https://registry.npmmirror.com # 4. 进入 backend 目录验证 Maven 依赖是否可解析 cd backend mvn dependency:resolve -Dmaven.test.skiptrue | grep BUILD SUCCESS # 若失败检查 ~/.m2/settings.xml 是否配置了阿里云镜像 # 5. 进入 frontend 目录验证 Vue CLI 是否识别项目 cd ../frontend vue --version # 输出应为 vue/cli 5.0.8若为 4.x 或 6.x需重装参数说明mvn dependency:resolve不编译代码只下载依赖耗时短且能暴露spring-boot-starter-web等 starter 的版本冲突vue --version必须是vue/cli全局命令不是vue包版本——很多新手误装vue包而非vue/cli导致vue create命令不存在Node.js 16.x 是 Vue 3.2.x 官方推荐版本18.x 会导致sass-loader编译失败Error: Cannot find module node-sass。2.3 初始化数据库MySQL 5.7 的 3 个关键配置书评系统依赖 MySQL 存储图书元数据、用户评论、评分记录。直接执行backend/src/main/resources/schema.sql前必须确认数据库已启用utf8mb4字符集否则 emoji 表情存入会变??-- 登录 MySQL 后执行 SHOW VARIABLES LIKE character_set%; -- 确保 character_set_server utf8mb4 -- 创建数据库时显式指定 CREATE DATABASE book_review DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 修改 my.cnfLinux或 my.iniWindows全局配置 [client] default-character-set utf8mb4 [mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci init_connectSET NAMES utf8mb4 skip-character-set-client-handshake FALSE为什么必须改init_connectSpringBoot 默认连接池HikariCP在建立连接时不会自动执行SET NAMES utf8mb4若init_connect未设置即使数据库字符集正确插入中文时仍可能因连接层编码不一致导致乱码。这是book_review表中comment_content字段存入“这本书太棒了”后变成“这本书太棒了??”的根本原因。3. 后端启动SpringBoot 服务如何正确暴露 API 并处理跨域3.1application.yml的 4 个核心配置项解析backend/src/main/resources/application.yml是整个后端的行为契约其中这 4 项决定接口能否被 Vue 正确调用server: port: 8080 servlet: context-path: /api # ← 关键所有 Controller 的 RequestMapping 自动前置 /api spring: datasource: url: jdbc:mysql://localhost:3306/book_review?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai username: root password: 123456 jpa: hibernate: ddl-auto: update # ← 开发期用 update上线必须改为 validate show-sql: true properties: hibernate: format_sql: true # 跨域配置替代 CrossOrigin 注解更可控 cors: allowed-origins: http://localhost:8081 # ← Vue 开发服务器默认端口 allow-credentials: true # JWT 配置书评系统用 token 认证 jwt: secret: bookreview2024secretkey # ← 必须与 frontend/src/utils/request.js 中的 tokenKey 一致 expiration: 86400 # 24 小时秒参数说明server.servlet.context-path: /apiVue 中 axios 请求api/books实际发送到http://localhost:8080/api/api/books所以前端必须配置baseURL: /apijdbc:mysql://...?serverTimezoneAsia/ShanghaiMySQL 8.0 默认时区为 UTC若不显式设置LocalDateTime字段存入会偏差 8 小时cors.allowed-origins必须精确匹配 Vue 开发服务器地址http://localhost:8081不能写*因启用了allow-credentials: truejwt.secret是 Base64 编码密钥实际项目中应从环境变量读取${JWT_SECRET:bookreview2024secretkey}避免硬编码。3.2 启动时常见报错及修复执行mvn spring-boot:run后若出现以下错误按对应方案解决# 报错1Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder jwt.secret in value ${jwt.secret} # 原因application.yml 中 jwt.secret 未生效或 profile 未激活 # 解决在 pom.xml 的 properties 中添加 spring.profiles.activedev/spring.profiles.active并在 application-dev.yml 中定义 jwt.secret # 报错2org.springframework.dao.InvalidDataAccessResourceUsageException: PreparedStatementCallback; SQL [insert into book ...]; Field id doesnt have a default value # 原因MySQL 严格模式下auto_increment 主键未设 DEFAULT且 INSERT 未指定 id # 解决修改 Book 实体类 Id 字段添加 GeneratedValue(strategy GenerationType.IDENTITY) # 报错3Failed to bind properties under spring.datasource.url to java.lang.String # 原因url 中包含特殊字符如密码含 未进行 URL 编码 # 解决将密码中的 替换为 %40例如 password: pass123 → pass%401233.3 验证 API 可用性用 curl 直接测试核心接口不要等 Vue 启动成功再测后端用 curl 快速验证# 1. 测试健康检查确认服务已启动 curl -X GET http://localhost:8080/api/actuator/health # 2. 测试图书列表无需登录 curl -X GET http://localhost:8080/api/books?page1size10 # 3. 测试登录接口获取 token curl -X POST http://localhost:8080/api/auth/login \ -H Content-Type: application/json \ -d {username:test,password:123456} # 4. 用 token 测试需认证的接口如提交评论 TOKENeyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNzE5NjQwMDAwLCJleHAiOjE3MTk3MjY0MDB9.xxx curl -X POST http://localhost:8080/api/comments \ -H Authorization: Bearer $TOKEN \ -H Content-Type: application/json \ -d {bookId:1,content:写得真好}关键点actuator/health返回{status:UP}表示 SpringBoot 容器已就绪auth/login返回的token必须用于后续所有Authorization: Bearer xxx请求否则401 Unauthorizedcomments接口若返回400 Bad Request检查bookId是否存在于book表中ID 为 1 的图书必须存在。4. 前端启动Vue 3 如何正确消费 SpringBoot API 并处理路由守卫4.1vue.config.js的 3 个必配项解决跨域与静态资源路径frontend/vue.config.js是 Vue 与 SpringBoot 协作的枢纽以下配置缺一不可const { defineConfig } require(vue/cli-service) module.exports defineConfig({ transpileDependencies: true, // 开发期代理所有 /api 请求转发到 http://localhost:8080 devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true, pathRewrite: { ^/api: // ← 关键把 /api/books 重写为 /books 发送给后端 } } }, port: 8081, open: true }, // 构建产物路径打包后 dist 目录需被 SpringBoot serve outputDir: dist, // 静态资源基础路径与 SpringBoot 的 static 目录映射一致 publicPath: process.env.NODE_ENV production ? / : / })为什么pathRewrite: {^/api: }必须存在SpringBoot 的server.servlet.context-path: /api已将所有接口挂载在/api/xxx下若 Vue 不重写路径请求会变成http://localhost:8080/api/api/books双重/api。此配置确保开发时axios.get(/api/books)实际发送到http://localhost:8080/books与后端RequestMapping(/books)完全匹配。4.2src/utils/request.js统一管理 axios 实例与拦截器书评系统的网络请求必须携带 JWT token且需处理 401 跳转登录页import axios from axios // 创建 axios 实例 const request axios.create({ baseURL: /api, // ← 开发期由 devServer 代理生产期由 SpringBoot serve timeout: 10000 }) // 请求拦截器自动添加 token request.interceptors.request.use( config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }, error Promise.reject(error) ) // 响应拦截器统一处理 401 request.interceptors.response.use( response response, error { if (error.response?.status 401) { localStorage.removeItem(token) // 跳转到登录页保留原路径作为 redirect 参数 window.location.href /login?redirect${encodeURIComponent(window.location.pathname)} } return Promise.reject(error) } ) export default request参数说明baseURL: /api与devServer.proxy配合确保开发期请求路径正确localStorage.getItem(token)读取登录后存储的 JWTrequest会自动注入Authorization头window.location.href跳转而非router.push()因 401 时 Vue Router 可能未初始化硬跳转最可靠。4.3src/router/index.js路由守卫控制页面访问权限书评系统要求「未登录用户只能访问登录页登录后可访问首页、图书详情、个人中心」import { createRouter, createWebHistory } from vue-router import Login from ../views/Login.vue import Home from ../views/Home.vue import BookDetail from ../views/BookDetail.vue import Profile from ../views/Profile.vue const routes [ { path: /login, name: Login, component: Login, meta: { requiresAuth: false } }, { path: /, name: Home, component: Home, meta: { requiresAuth: true } }, { path: /book/:id, name: BookDetail, component: BookDetail, meta: { requiresAuth: true } }, { path: /profile, name: Profile, component: Profile, meta: { requiresAuth: true } } ] const router createRouter({ history: createWebHistory(), routes }) // 全局前置守卫 router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.meta.requiresAuth !token) { next(/login?redirect encodeURIComponent(to.fullPath)) } else if (to.name Login token) { next(/) } else { next() } }) export default router关键逻辑meta: { requiresAuth: true }标记需登录的路由next(/login?redirect...)保存原路径登录成功后跳回需在Login.vue中读取redirect参数to.name Login token防止已登录用户手动输入/login重新登录。5. 前后端联调避坑5 个血泪经验总结5.1 现象Vue 页面白屏控制台报Uncaught SyntaxError: Unexpected token 原因Vue 构建产物dist/index.html被 SpringBoot 当作静态资源返回但index.html中引用的js/chunk-xxx.js文件路径错误SpringBoot 返回了index.html内容而非 JS 文件HTML 的符号被当成了 JS 语法。解决检查vue.config.js中publicPath是否为/生产环境并确认backend/src/main/resources/static/目录下已放入dist全部内容包括index.html、js/、css/文件夹。SpringBoot 默认 servestatic/下文件路径必须完全匹配。5.2 现象登录成功后跳转首页但this.$route.params.id为undefined原因Vue Router 4.x 中this.$route在setup()中不可用必须用useRoute()获取且useRoute().params是响应式对象需watch或computed访问。解决在BookDetail.vue中改用 Composition APIimport { useRoute } from vue-router const route useRoute() console.log(route.params.id) // 正确获取5.3 现象上传图书封面图片时后端RequestParam MultipartFile file一直为 null原因Vue 中FormData.append(file, file)未设置Content-Type: multipart/form-data且 SpringBoot 的spring.servlet.multipart配置未启用。解决前端确保axios.post不设置Content-Type头让浏览器自动设置 boundary后端application.yml添加spring: servlet: multipart: enabled: true max-file-size: 10MB max-request-size: 10MB5.4 现象搜索图书时中文关键词返回空结果但英文正常原因MySQL 全文索引未启用ngram解析器或book.name字段未建FULLTEXT索引。解决在schema.sql中为book表添加ALTER TABLE book ADD FULLTEXT(name, author) WITH PARSER ngram;查询 SQL 改为SELECT * FROM book WHERE MATCH(name, author) AGAINST(Java编程思想 IN NATURAL LANGUAGE MODE);5.5 现象生产环境下http://your-domain.com访问首页正常但点击「我的评论」报 404原因SpringBoot 的server.servlet.context-path与 Vue Router 的history模式冲突刷新子路由时 Nginx 未将请求代理到index.html。解决在 Nginx 配置中添加location / { try_files $uri $uri/ /index.html; }并确保 SpringBoot 的server.servlet.context-path为空即不设/apiAPI 接口通过 Nginx 反向代理到http://localhost:8080/api。6. 生产部署技巧如何把 Vue 打包产物无缝集成进 SpringBoot JAR6.1 核心思路让 SpringBoot 的static/目录成为 Vue 的构建输出目标Vue 默认打包到dist/但 SpringBoot 的src/main/resources/static/是静态资源根目录。最稳妥的做法是修改 Vue 构建输出路径直接生成到 SpringBoot 的static目录下// frontend/vue.config.js const path require(path) module.exports { // ...其他配置 outputDir: path.resolve(__dirname, ../backend/src/main/resources/static), assetsDir: }执行npm run build后dist/内容将直接输出到backend/src/main/resources/static/此时mvn package打出的 JAR 包内已包含全部前端资源。访问http://localhost:8080/即可加载index.html所有js/、css/文件均通过 SpringBoot 的ResourceHttpRequestHandler服务。6.2 静态资源缓存优化减少重复加载SpringBoot 默认对静态资源不缓存每次请求都走磁盘读取。在application.yml中添加spring: web: resources: cache: cachecontrol: max-age: 3600 # 1 小时缓存 servlet: context-path: / # ← 生产环境建议去掉 /api 前缀简化路径同时在vue.config.js中启用filenameHashing默认开启确保文件名含 hash如app.abc123.js这样max-age缓存不会因代码更新导致旧 JS 被客户端复用。6.3 API 路径统一生产环境如何避免跨域开发期用devServer.proxy生产期必须让前端请求与后端同域。方案有两种方案 A推荐Nginx 反向代理所有/api/**请求转发到 SpringBoot前端baseURL设为方案 B轻量SpringBoot 启用server.servlet.context-path: /前端axios直接请求/api/booksJAR 包内置 Tomcat 直接处理。我一般选方案 B因为书评系统 QPS 不高省去 Nginx 维护成本。只需确保application.yml中server.servlet.context-path: /vue.config.js中devServer.proxy仅用于开发生产构建时baseURL保持/api启动 JAR 后访问http://localhost:8080/api/books和http://localhost:8080/均能正常响应。6.4 最终验证清单上线前 5 分钟检查表检查项命令/操作预期结果后端 JAR 是否包含前端资源jar -tf target/book-review-0.0.1-SNAPSHOT.jargrep static/index.htmlAPI 接口是否可访问curl -I http://localhost:8080/api/books返回HTTP/1.1 200 OK首页 HTML 是否可加载curl http://localhost:8080/ | head -n 5输出htmlheadtitle书评系统/titleJS 文件是否可下载curl -I http://localhost:8080/js/app.xxx.js返回HTTP/1.1 200 OK登录流程是否闭环手动访问http://localhost:8080/login→ 输入账号 → 点登录 → 跳转/页面显示「欢迎回来」最后说个真实教训去年帮一个图书馆项目部署所有测试都通过但上线后用户反馈「搜索框打字没反应」。排查发现是vue.config.js中transpileDependencies: [vue]被误删导致Composition API在 IE11 下解析失败——而该图书馆终端机只装 IE11。从此我养成了习惯任何改动先npm run build再用http-server本地起服务用 IE11、Chrome、Firefox 各测一遍核心流程。希望帮到你。本文还有配套的精品资源点击获取
返回列表