ARTICLE DETAIL

资讯详情

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

SpringBoot+Vue+MySQL前后端分离论坛系统实战指南

SpringBoot+Vue+MySQL前后端分离论坛系统实战指南 做论坛类的信息管理系统SpringBoot Vue MySQL 这套组合基本是绕不开的经典搭配。最近正好在整理一套可以直接跑起来的论坛网站源码后端用 SpringBoot前端用 Vue数据库走 MySQL整个项目拆成前后端分离的结构本地配置好环境之后导入 SQL、改两行配置就能启动。这套代码拿来当毕业设计、课程设计或者刚接触全栈开发的人拿来当练手项目都很合适。我先把这套系统的定位讲清楚它是一个带用户注册登录、版块分类、发帖回帖、评论互动、个人中心、后台管理的基础论坛系统。跟前几年流行的 JSP Servlet 单体论坛不一样这套是标准的 RESTful 前后端分离架构前端只管页面渲染和交互后端只提供 JSON 数据接口数据库层面由 MySQL 统一存储。这也意味着前端可以单独部署到 Nginx后端可以单独打成 jar 包跑在服务器上以后要扩展功能、换页面皮肤都不用动后端代码。下面我会把项目从技术选型、数据库设计到部署运行、常见问题排查再到二次开发思路一条线讲清楚。这不是那种只贴代码不解释的“源码包”我会把每个模块为什么要这么设计、运行中会遇到什么坑都说透你照着操作基本能一次跑通。1. 项目定位与整体技术方案1.1 这套论坛源码到底能做什么从使用者的角度来看论坛系统最核心的价值是“内容发布 用户互动”。这套系统包含两套端用户端注册、登录、退出登录之后才能发帖回帖按版块分类浏览帖子列表支持关键词搜索发帖时选择分类填写标题和正文支持 Markdown 或富文本查看帖子详情可以在帖子下发表评论也可以对评论进行回复个人中心查看自己发过的帖子、收到的评论、修改个人资料管理端管理员登录后进入后台管理用户禁用/启用账号、重置密码管理帖子置顶、加精、删除违规内容管理分类新增板块、调整排序数据统计用户数、帖子数、评论数等基础指标功能不算特别复杂但一个论坛该有的骨架都在。如果你是拿它做毕业设计在这个基础上加“关注”“私信”“积分系统”就足够撑起一篇论文的核心章节了。1.2 技术选型为什么是 SpringBoot Vue MySQL先回答一个很多人纠结的问题这套技术栈到底哪里好SpringBoot相比传统的 SSMSpring SpringMVC MyBatis配置方式最大的优势是“约定大于配置”。它内置了 Tomcat不需要再额外去装一个外置容器打成一个 jar 包就能跑。对于课程设计和毕业设计来说光这一条就能省掉大量部署上的折腾。SpringBoot 还自带 starter 机制比如你想操作数据库引入 spring-boot-starter-web 和 mybatis-plus-boot-starter 就能直接开写不用像老项目里那样去维护一堆 XML 配置文件。Vue是目前国内前端圈普及率最高的框架。跟前端三大框架里的另外两个React、Angular相比Vue 的学习曲线更平缓模板语法跟传统 HTML 更接近一个后端出身的开发者看两天官方文档就能上手写页面。它在组件化开发和数据双向绑定这块做得非常顺手——页面上用户输入的内容直接绑定到 data 里的变量不用像 jQuery 时代那样自己手动操作 DOM 去取值赋值。MySQL更不用多说开源数据库里它就是默认答案。免费、稳定、资料多、云厂商基本都提供托管版。论坛这种读多写少、表结构相对固定的场景MySQL 的关系型建模能力完全够用。配合 InnoDB 引擎事务支持也有保障发帖和加积分数这种需要原子性的操作可以放心。为什么不是 Python 的 Django Vue也不是 Node.js 的 Express Vue不是说别的不行而是从“项目可维护性”和“你自己将来找工作”这两个角度看Java SpringBoot 在国内企业级应用里的存量太大。你随便打开一个招聘网站搜后端开发Java 的岗位数量依然占大头。做毕设也好、写进简历也好SpringBoot 的认可度比小众框架高一个量级。1.3 前后端分离架构与目录规划所谓的“前后端分离”核心是把两个端彻底拆开。传统 JSP 项目是后端把 HTML 页面渲染好再返回给浏览器前后端代码混在一起而前后端分离项目是后端只提供 JSON 数据接口前端通过 Ajaxaxios去请求这些接口拿到 JSON 之后自己在浏览器里渲染出页面。这套项目的标准目录结构长这样forum-system ├── frontend/ # 前端工程Vue │ ├── src/ │ │ ├── api/ # 封装 axios 请求的 JS 模块 │ │ ├── router/ # Vue Router 路由配置文件 │ │ ├── views/ # 页面组件 │ │ ├── components/ # 公共组件 │ │ ├── store/ # Vuex / Pinia 状态管理 │ │ └── main.js │ ├── vite.config.js # 前端构建配置 代理配置 │ └── package.json └── backend/ # 后端工程SpringBoot ├── src/main/java/ │ ├── controller/ # 接口层 │ ├── service/ # 业务逻辑层 │ ├── mapper/ # MyBatis 数据访问层 │ ├── entity/ # 实体类 │ ├── config/ # 配置类跨域、拦截器、JWT等 │ └── ForumApplication.java ├── src/main/resources/ │ ├── application.yml # 核心配置文件 │ └── mapper/ # MyBatis XML 映射文件 └── pom.xml分开之后有个很明显的好处开发期前端可以起自己的开发服务器比如 Vite 默认的 5173 端口后端跑在 8080 端口前端请求 /api 的前缀时通过代理转发到后端 8080从而实现跨域访问。部署时前端打包成静态文件丢进 Nginx后端打成 jar 包跑在服务器上两边各自伸缩互不干扰。后端接口统一使用 RESTful 风格比如POST /api/user/register 注册POST /api/user/login 登录GET /api/post/list 帖子列表GET /api/post/detail/{id} 帖子详情POST /api/post/create 发帖POST /api/comment/create 评论每个接口返回统一的 JSON 结构一般长这样{ code: 200, message: 操作成功, data: { id: 1, title: SpringBoot入门经验分享 } }code 表示业务状态码200 是成功401 是未登录500 是服务端异常。前端 axios 的响应拦截器里统一判断 code不是 200 直接弹出错误提示。这样做的好处是接口返回结构稳定前端处理逻辑统一调新接口时不用每个都单独写错误处理。2. 核心功能模块与数据库设计2.1 用户体系与登录态管理论坛系统首先要有用户所以 user 表是整个数据库的核心表之一。我建议至少包含这些字段字段名类型说明idbigint主键自增usernamevarchar(50)用户名唯一索引passwordvarchar(100)密码BCrypt加密后存储nicknamevarchar(50)昵称avatarvarchar(255)头像URLemailvarchar(100)邮箱roletinyint角色0-普通用户 1-管理员statustinyint状态0-正常 1-禁用create_timedatetime注册时间update_timedatetime更新时间关于密码存储这里必须提醒一句永远不要用明文存密码。早期很多教学项目直接把密码以明文形式存进数据库这是非常严重的错误。一旦数据库泄露所有用户的密码直接暴露。正确做法是用 BCrypt 哈希加密每次用户注册时生成一个随机的 salt 混进密码里做哈希登录时再把用户输入的密码哈希后和库里存的比对。推荐用 Spring Security 的 BCryptPasswordEncoder或者 SpringBoot 集成的 spring-security-crypto 依赖。用法很简单// 注册时加密 String encodedPwd new BCryptPasswordEncoder().encode(rawPassword); // 登录时校验 boolean matches new BCryptPasswordEncoder().matches(rawPassword, encodedPwd);登录态管理这块传统方案是 Session但前后端分离项目我更推荐用 JWTJSON Web Token。原因是 Session 依赖服务器保存状态如果前端和后端分开部署在不同域名处理跨域 Cookie 会很麻烦。而 JWT 是无状态的用户登录成功后后端生成一个 token 返回给前端前端每次请求在 HTTP Header 里带上Authorization: Bearer token后端拦截器解析 token 就能知道当前是哪个用户。JWT 的生成和解析可以用 jjwt 库核心代码大约是这样String token Jwts.builder() .setSubject(userId.toString()) .setExpiration(new Date(System.currentTimeMillis() 24*60*60*1000)) .signWith(SignatureAlgorithm.HS256, secretKey) .compact();这个 token 的有效期视项目需求而定论坛一般设置 24 小时到 7 天。过期之后前端收到 401 就跳回登录页让用户重新登录。虽然 JWT 无法主动失效服务器不保存状态但对论坛这种低敏业务场景这个缺点可以接受实现成本比引入 Redis 做 Session 共享低得多。2.2 论坛业务表怎么设计才不踩坑论坛的核心业务是发帖和评论所以有三张表必不可少category分类表、post帖子表、comment评论表。我挨个拆一下关键字段和设计理由。category 表CREATE TABLE category ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, sort INT DEFAULT 0, status TINYINT DEFAULT 1 );很简单就是存“技术交流”“生活闲聊”“二手交易”这些版块。sort 字段控制前台显示顺序后台管理里可以调整。为什么不直接把分类写死在前端因为分类是可变的做成数据表之后管理员可以随时增删不用改代码重新打包。post 表CREATE TABLE post ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL COMMENT 发帖人ID, category_id BIGINT NOT NULL COMMENT 所属分类ID, title VARCHAR(100) NOT NULL, content TEXT NOT NULL, view_count INT DEFAULT 0 COMMENT 浏览量, comment_count INT DEFAULT 0 COMMENT 评论数, top_flag TINYINT DEFAULT 0 COMMENT 是否置顶, status TINYINT DEFAULT 1 COMMENT 1-正常 0-删除, create_time DATETIME, update_time DATETIME, INDEX idx_category_time (category_id, create_time), INDEX idx_user_time (user_id, create_time) );这里有两个设计细节值得讲。第一个是comment_count字段。它属于典型的“冗余字段”目的是避免每次展示帖子列表时都要去 comment 表 COUNT 一次。帖子列表页有分页每页查 10 条帖子如果不冗余这个字段那这 10 条帖子每条都要额外跑一条 COUNT 查询列表接口会变慢。正确的做法是每次用户发表/删除评论时顺手把对应 post 表的 comment_count 加一或减一保证这个字段始终近似准确。注意我用的是“近似”——并发场景下 COUNT 可能会偶发不准但对论坛展示来说差个一两条完全不影响使用。第二个是索引设计。论坛帖子的查询场景往往是“按分类看帖子最新发的在前面”所以建了(category_id, create_time)联合索引。一个常见的误区是给 title 加上全文索引做搜索。依赖 MySQL 全文索引去做论坛搜索一旦数据量大起来性能会很差而且相关性排序也不好做。这套代码里搜索用的是LIKE %关键词%走全表扫描数据量几千条时没压力但如果将来帖子过十万建议接入 Elasticsearch 或者至少用 MySQL 的全文索引做一层过滤。comment 表CREATE TABLE comment ( id BIGINT PRIMARY KEY AUTO_INCREMENT, post_id BIGINT NOT NULL, user_id BIGINT NOT NULL, parent_id BIGINT DEFAULT 0 COMMENT 父评论ID0表示一级评论, content VARCHAR(500) NOT NULL, create_time DATETIME, INDEX idx_post_id (post_id) );为什么不需要单独的“楼中楼”表因为评论的层级关系用 parent_id 一个字段就能表达parent_id 为 0 的是对帖子的直接评论非 0 的是对某条评论的回复。查询时会稍微麻烦一点——先查出一级评论再根据一级评论的 id 集合查它的子评论——但论坛评论的层级通常不会超过两层评论区、回复区这个查询开销完全可以接受还能少维护一张表。2.3 后台管理模块与核心接口一览后台管理如果从零开发量会很大。这套源码的做法是复用用户端的接口结构在 controller 层做权限控制。管理员接口都要求请求头里携带的 JWT 里的 role 字段为 1否则直接返回 403。核心管理接口模块接口说明用户管理GET /api/admin/user/list分页查询用户列表用户管理PUT /api/admin/user/status/{id}启用/禁用用户帖子管理GET /api/admin/post/list分页查询帖子帖子管理PUT /api/admin/post/top/{id}置顶/取消置顶帖子管理DELETE /api/admin/post/{id}删除帖子分类管理POST /api/admin/category新增分类分类管理PUT /api/admin/category/{id}修改分类统计GET /api/admin/stats用户数、帖子数、今日发帖等后台统计模块里还有一个细节统计“今日发帖”时不能只查 create_time 大于等于今天零点因为在分布式部署或者数据库服务器时区不一致的情况下前端传的时间和数据库时间可能不同步。稳妥做法是后端代码里统一取当前服务器时间计算零点不要依赖前端传时间范围。后台界面的数据表格用的前端组件一般是 Element Plus 里的 el-table配合分页组件 el-pagination。后端接口返回分页数据格式为{ total: 156, records: [ { id: 1, title: xxx, author: 张三, createTime: 2025-01-01 } ] }前端拿到之后直接用 records 渲染表格、用 total 计算分页总数交互逻辑非常清晰。3. 从零到一部署运行全流程3.1 环境准备与版本兼容问题先说环境这部分看似简单但翻车的人最多。我在本地实操多次后建议你按这个清单准备软件推荐版本备注JDK1.8 或 11SpringBoot 2.x 用 JDK8 完全够Maven3.6管理后端依赖Node.js16/18 LTSVue2/Vue3 项目要求不同MySQL5.7 或 8.08.0 需要注意 SSL 和时区配置IDEA2022后端开发 IDEVSCode任意前端开发用版本兼容是个老生常谈但永远有人踩坑的问题。SpringBoot 2.x 对应 JDK8-11SpringBoot 3.x 必须配 JDK17。如果源码是基于 SpringBoot 2.7 写的你本地装了个 JDK17 还配了 SpringBoot3很容易出现依赖冲突启动报错。拿到源码先看 pom.xml 里的 spring-boot-starter-parent 版本号再决定装哪个 JDK。这一步能帮你省掉至少半小时的折腾。前端方面Vue 2 和 Vue 3 的生态差别很大。Vue 2 用的是 vue-cliwebpackVue 3 现在主流是 Vite。如果你拿到的是 Vue 3 Vite 项目Node 版本必须大于 16。老项目 vue-cli 在 Node 18 上偶尔会有 OpenSSL 错误需要加NODE_OPTIONS--openssl-legacy-provider。3.2 数据库初始化与连接配置数据库初始化很简单但步骤别乱。我推荐用命令行或 Navicat 执行顺序如下第一步创建数据库CREATE DATABASE forum CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;数据库字符集一定要选 utf8mb4。这个可能从 MySQL 5.5 开始就说烂了但还是有人漏掉——不选 utf8mb4用户发帖内容里一旦出现 emoji 表情插入数据库就会报错甚至直接导致该字段数据截断。第二步导入源码配套的forum.sql脚本。不管是命令行还是可视化工具导入前先确认当前选择了 forum 库。我遇到过不止一次有人把 SQL 文件往别的库里一导表建了但后端连的库名对不上启动后全是一堆“table not exist”报错。第三步修改后端配置文件application.ymlspring: datasource: url: jdbc:mysql://localhost:3306/forum?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver这一段配置里面隐藏了好几个高频问题来源我单独讲一下useSSLfalseMySQL 8.0 默认开启 SSL 检查本地开发环境没有证书配置很容易报 “SSL connection error”直接关掉省事。serverTimezoneAsia/Shanghai不指定时区会报 “The server time zone value ‘й’ is unrecognized” 这样的乱码错误本质是 MySQL 系统时区跟 JDBC 驱动解析不一致。allowPublicKeyRetrievaltrueMySQL 8.0 使用 caching_sha2_password 认证插件时第一次连接需要获取 RSA 公钥不配这个参数会报 “Public Key Retrieval is not allowed”。characterEncodingutf8保证中文正常存储不乱码。很多“源码跑不起来”的问题80% 出在这一步的数据库连接配置上。有些源码用的是老版com.mysql.jdbc.Driver但 MySQL 8.0 里面这个类已经被移除了必须换成com.mysql.cj.jdbc.Driver。看报错信息里如果是ClassNotFoundException基本就是驱动类没写对。3.3 后端启动步骤与关键配置后端启动有两种方式开发环境我推荐直接在 IDEA 里运行主类。在 IDEA 里打开后端根目录等 Maven 把依赖下载完第一次下载会很久建议用国内镜像在~/.m2/settings.xml里配置阿里云镜像仓库运行ForumApplication.java的 main 方法。看到控制台输出Tomcat started on port(s): 8080就算启动成功。这里有几个小细节注意一下端口冲突。8080 被占用是最常见的情况尤其是本机装过其他服务的时候。如果启动报Port 8080 was already in use关掉占用进程或者直接在application.yml里改server.port8081。改完端口之后前端代理配置也要同步改否则前端还是请求 8080一样不通。配置文件激活。很多源码里会有application-dev.yml、application-prod.yml两个环境配置主配置文件里通过spring.profiles.activedev来激活。如果启动后数据库和 Redis 连接配置不生效先检查一下这个 active 配的是不是当前要用的环境。Maven 依赖下载不动。国内网络环境从中央仓库拉依赖经常卡死。在pom.xml所在项目目录下新建一个.mvn文件夹或者直接改用户级 settings.xml把镜像换成阿里云mirror idaliyunmaven/id mirrorOfcentral/mirrorOf urlhttps://maven.aliyun.com/repository/public/url /mirror后端启动成功后可以先用浏览器直接访问一个 GET 接口GET http://localhost:8080/api/category/list如果返回了 JSON 数据说明数据库连接没问题后端接口正常工作。3.4 前端安装与联调前端部分相对更省事因为 Vite/Webpack 会自动把依赖装的整整齐齐。打开前端目录执行npm install如果太慢同样换成淘宝镜像npm install --registryhttps://registry.npmmirror.com装完之后看package.json里的 scripts 配置scripts: { dev: vite --port 5173, build: vite build }执行npm run serve或npm run devVite 默认会起在 5173 端口。此时直接访问前端页面页面能打开但登录和列表数据大概率是空的——因为前端 5173 端口直接向后端 8080 发跨域请求会被浏览器拦截。解决方案是在vite.config.js里配置 proxy 代理把/api开头的请求都转发到后端export default defineConfig({ server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })加上这个配置之后前端在开发环境下请求/api/post/listVite 开发服务器会自动转发到http://localhost:8080/api/post/list。这是一个非常关键的小技巧很多新手不知道这个代理配置以为跨域必须去后端加 CORS结果两边都配了还是不生效。后端那边的 CORS 配置当然也要有因为如果将来前端部署在 Nginx、后端部署在另一台服务器就是真正的跨域场景了。SpringBoot 里一般通过配置类实现Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(Registry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE) .allowedHeaders(*) .allowCredentials(true); } }联调通过后如果要把前端打包发给后端一起部署执行npm run build产物是一个dist目录。把 dist 目录里的文件丢到后端src/main/resources/static/下SpringBoot 就能直接托管前端页面这样出现了“前后端不再分离”的部署形态但代码结构依然是分离的。这一步适合演示、答辩的时候懒得起两个服务的情况一个 jar 包就能把前后端全带起来。4. 常见问题与排查技巧实录4.1 登录状态丢失、请求返回 401这套系统的用户操作基本都是登录态驱动的前端每次请求都要带 token。最典型的现象是登录成功跳转回首页刷新一下页面再点发帖就弹“未登录”。排查顺序从三个地方着手第一看浏览器 localStorage / sessionStorage 里 token 是不是保存了。前端登录接口返回 token 后有没有正确存进本地存储这步最容易被遗漏。用 Vue 写登录逻辑时常见做法是const res await login(form); localStorage.setItem(token, res.data.token);刷新页面后axios 请求拦截器里再从这个 storage 里取出来加进 Header。如果拦截器里读 token 的名字写错了或者压根没写拦截器刷新之后所有请求都会 401。第二看 axios 拦截器是否在请求头里加了 Authorizationaxios.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers.Authorization Bearer token; } return config; });注意部分源码里对 header 名称做了自定义比如token或者X-Token需要和后端拦截器读的字段保持一致。不一致就出现“前端发了 token后端说没收到”的情况。第三看后端拦截器怎么解析 token。有些项目在拦截器里解析失败会直接抛出异常返回 JSON{ code: 401, message: token无效或已过期 }。如果 token 密钥或者过期时间配置和后端不一样也会出现这种问题。这里分享一个我常用的排查技巧打开浏览器 DevTools 的 Network 面板点击一个返回 401 的请求在 Request Headers 里检查 Authorization 字段是否存在。如果存在且看起来正常问题大概率在后端拦截器如果不存在问题就在前端 axios 封装上。4.2 MySQL 连接报错与中文乱码这类问题出现的频率仅次于登录问题而且报错信息五花八门。我整理几个高频画面第 1 种java.sql.SQLException: The server time zone value Öйú±ê׼ʱ¼ä is unrecognized这个乱码报错其实就是 MySQL 服务器的时区不是标准时区导致的。解决方案是在 JDBC URL 里加serverTimezoneAsia/Shanghai或者在 MySQL 里执行SET GLOBAL time_zone 8:00。第 2 种Public Key Retrieval is not allowedMySQL 8.0 默认加密插件是caching_sha2_password客户端需要公钥才能进行 RSA 加密传输密码。JDBC URL 加上allowPublicKeyRetrievaltrue即可。第 3 种中文内容变成了 ??? 问号建库的时候库、表、字段的字符集不是 utf8mb4或者 JDBC URL 里没带characterEncodingutf8。最省事的解决办法是重新建库字符集统一 utf8mb4DROP DATABASE IF EXISTS forum; CREATE DATABASE forum CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;我之前写过一篇排坑文章里专门提过MySQL 5.7 的默认排序规则是utf8mb4_general_ci8.0 的默认是utf8mb4_0900_ai_ci。跨版本导数据时如果 SQL 文件里有 COLLATE 指定容易出现排序规则冲突报错直接删掉 COLLATE 子句再用默认值就行。第 4 种Unknown database forum库不存在。源码里配置的库名和实际建立的库名不一样尤其是有时候建立了库但名字笔画多、大小写不一致。Linux 下 MySQL 的表名默认区分大小写表名大小写对不上也会报错。4.3 Vue 打包部署后刷新 404 与静态资源路径问题这块是“本地跑得欢部署就翻车”的重灾区。本地开发用 Vite 起服务前端路由用的是 History 模式URL 里没有 # 号打包丢进 Nginx 后点页面没事但一按 F5 刷新就 404。原因很简单Nginx 里没有配置 fallback 规则。浏览器请求/post/123这个路径Nginx 先去磁盘上找有没有这个文件的路径找不到就直接返回 404它可不知道这个路径应该交给前端路由处理。处理方案有两种第一种简单路由模式从createWebHistory改成createWebHashHistoryURL 变成/#/post/123。Hash 模式不会向服务器发请求刷新不会 404。缺点是 URL 丑一点SEO 基本无望。第二种正式Nginx 加 try_files 配置location / { try_files $uri $uri/ /index.html; }含义是找不到文件就全部丢给index.html处理由前端路由接管。静态资源 404 是另一个典型问题。打包出的 CSS/JS 文件默认路径是/assets/xxx.js如果部署在子目录比如http://ip/forum/资源路径就找不到了。处理方式是改构建配置里的base参数// vite.config.js export default defineConfig({ base: ./ })base改成相对路径后打包出来的资源引用就变成./assets/xxx.js部署到子目录也能正常加载。4.4 快速排查清单速查表把上面所有问题浓缩成一张速查表方便你遇到问题时直接对号入座现象大概率原因解决动作后端启动报 Port 8080 占用本机端口被其他进程占用改 server.port 或关闭占用进程mvn/npm 安装依赖超时网络源过慢配置阿里云/淘宝镜像启动时报 SQL 连接异常JDBC URL 缺时区或 SSL 参数补齐 serverTimezone、useSSLfalse注册中文用户名变 ???数据库字符集不对库表统一 utf8mb4登录后接口全 401前端没有传 token检查 axios 拦截器和 localStorage 存储退出登录后仍能访问接口后端没校验 token 或 token 不失效检查拦截器配置前端页面能看但调不到数据代理没配或代理 target 写错检查 vite proxy target 端口打包后刷新 404路由 mode 是 history 但服务器没配 fallbackNginx 加 try_files 或改 hash 路由打包后图片/资源加载不了base 路径问题vite 配置 base: ./接口返回 data 是 null后端查询条件为空或实体类字段与列名不符检查 MyBatis resultMap 映射5. 二次开发与扩展方向5.1 如何把项目改造成能答辩的毕业设计拿源码跑通只是第一步要用来做毕业设计或者写简历项目肯定得在这个基础上做二次开发。我给几个性价比最高的扩展点按“投入少、效果明显”排序加一个 Redis 缓存层。把帖子列表和分类列表缓存到 Redis设置过期时间比如 10 分钟。答辩时可以讲热点数据走缓存、缓存穿透如何解决、缓存和数据库一致性怎么做。这一块讲清楚论文就能多出一个章节面试官也会觉得你懂高并发的基础。加文件上传功能。用户头像、帖子图片上传本地存磁盘或者接入阿里云 OSS。前端用 Element Plus 的 el-upload 组件后端接收 MultipartFile 后保存并返回访问 URL。这个小功能能延伸出很多技术点文件格式校验、大小限制、存储目录规划、访问鉴权。加消息通知模块。别人回复了你的帖子系统生成一条站内消息。这个功能涉及事件触发、未读消息数、已读未读状态维护业务逻辑比单纯 CRUD 复杂不少但技术难度适中。加积分/等级体系。发帖 2 分回帖 1 分帖子被点赞 5 分积分达到一定值升级。这个能体现数据库事务发帖和加积分要同时成功用 Transactional 控制也会涉及重复发放的问题可以引出幂等性设计。做毕设论文时需求分析章节别再写“本系统用户登录后可以进行登录操作”这种废话。围绕你新加的功能把业务流程画清楚、数据库设计字段列出、核心接口给出测试结果论文自然就充实了。5.2 性能与生产环境部署优化建议如果你不满足于本地运行想部署到服务器或者给别人演示有几点值得做Nginx 反向代理 静态资源缓存。前端打包后放到 Nginx 的 html 目录下配置proxy_pass把/api请求反向代理到后端 jar 包端口。静态资源js/css/img配置expires 7d缓存头浏览器第二次访问秒开。开启 MySQL 慢查询日志。论坛系统做起来不难但以后帖子多了列表查询慢是必然的。先在 MySQL 里执行SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 1;然后再跑一遍核心接口看日志里哪些 SQL 执行超过 1 秒针对性建索引或者优化 SQL。后端日志分级。生产环境别全打 INFO改成只输出 WARN 和 ERROR避免日志文件膨胀太快。logback 配置文件里按天滚动切分保留最近 7 天日志。用 Docker 一键部署。把 MySQL、后端、前端分别写进 docker-compose以后换机器部署就是一条命令的事。这个对答辩加分非常明显——评委问你“部署怎么搞”你直接演示docker compose up -d整套环境就起来了。最后再分享一个小技巧这套论坛项目虽然结构简单但它是学习 Java 全栈的一个很标准的路标。我把这种项目定位成“第二遍做更重要”的类型——第一遍照着源码跑通是熟悉流程第二遍从头自己写一遍才是真正内化。你可以先把源码里的后端 controller 层遮住只看 mapper 和实体类自己试着把接口写出来再反过来看前端页面尝试自己接一两个功能模块。我实际测过很多次能不看源码独立把登录注册 发帖这两个模块实现出来的人再去拆别的开源项目效率会快很多。遇到问题记得先看日志后端看控制台堆栈前端看 Network 面板日志会告诉你 80% 的答案。剩下的 20%跑通一遍这个项目之后你基本就具备自己排查的能力了。
返回列表