ARTICLE DETAIL

资讯详情

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

SpringBoot+Vue考研互助平台全栈系统源码解析与部署实践

SpringBoot+Vue考研互助平台全栈系统源码解析与部署实践 1. 这类全栈项目为什么值得拆开看考研互助平台的核心价值收到一套“考研互助交流平台信息管理系统”源码的时候我的第一反应不是急着启动而是先把技术栈梳理清楚SpringBoot后端、Vue前端、MySQL数据库标准的前后端分离结构号称可以直接运行。说实话这种项目在毕业设计、课程作业、个人练手场景里出现频率非常高但是能真正做到目录清晰、配置完整、跑起来不报一堆环境错误的反而不多。所以我打算把这套系统的设计思路和运行过程完整拆一遍既分享我用到的关键代码逻辑也把最容易卡住大家的启动步骤和坑位讲清楚。这套系统解决的并不是一个假需求。考研群体最大的痛点就是信息分散经验贴散落在各个群、资料网盘链接容易失效、想找个研友搭伴复习很难、专业课真题不知道上哪找。考研互助交流平台要做的就是一个相对轻量的信息管理系统把用户、帖子、评论、资料、公告这些内容统一管起来让考生能发帖提问、分享经验、上传资料、回复讨论同时让管理员能在后台审核内容、管理用户。我当时花了一个下午把源码完整过了一遍发现它特别适合这三类人参考一是准备做毕业设计的计算机专业学生二是刚学完SpringBoot和Vue、想找个完整项目练手的前后端初学者三是想把类似系统改造成校园社区、兴趣社群的同学。下面我按“业务功能—技术选型—数据库—后端代码—前端工程—实际运行—踩坑记录”这条线把整个项目讲明白保证你拿到源码后能看懂、能跑起来、还能自己动手改。1.1 平台的业务边界与角色权限先说清楚这套系统管什么、不管什么。它的核心是信息内容管理不是电商系统也不是在线课程平台所以不需要复杂的订单流程、支付流程和视频流服务。系统里最重要的对象就是内容用户发的互助帖子、帖子的评论回复、上传的考研资料、管理员发布的公告通知。从角色上划分系统通常有三种身份普通用户注册登录后可以发帖、回帖、评论、上传资料、修改个人资料。管理员登录后台后可以审核帖子、隐藏非法评论、禁用违规用户、管理分类、发布公告。游客一般只看公开内容不能发帖和评论。权限模型不复杂但很典型。后端用一个用户角色字段区分普通用户和管理员接口层通过拦截器校验登录状态管理员接口再单独校验角色字段。很多同类毕设项目还会引入Spring Security或者Sa-Token来做精细化权限控制但这套系统如果用的是JWT加拦截器方案反而更适合学习因为你能更清楚地看到“登录态”和“权限判断”是怎么一步步实现的。1.2 功能模块全景与页面对应我在跑通代码后画了一个功能对应表方便你把后端接口、数据库表和前端页面三者对应起来看。拿到源码后建议先照着这个表理一遍比直接读代码效率高得多。模块核心功能数据库表前端页面用户模块注册、登录、个人信息修改、头像上传user登录页、注册页、个人中心帖子模块发布互助帖、查看列表、关键字搜索、帖子详情post、category首页、帖子列表页、详情页评论模块发表评论、回复评论、删除自己的评论comment帖子详情页内的评论区资料模块上传考研资料、预览下载、审核管理resource资料库页面、后台资料管理公告模块管理员发布公告、前台滚动展示announcement首页公告栏、公告详情后台管理用户管理、内容审核、数据统计、分类管理对应业务表后台管理端页面这样看下来你会发现系统虽然叫“信息管理系统”本质就是一个社区内容管理项目。它把最经典的增删改查、分页搜索、登录鉴权、文件上传都涵盖了而这些恰恰是后端面试和毕设答辩里最常被问到的点。2. 技术选型的逻辑SpringBoot、Vue、MySQL这套组合为什么这么顺很多初学者会问为什么这类项目偏偏选SpringBoot加Vue加MySQL而不是Servlet加JSP也不是Python Flask加MongoDB答案就在“效率”和“生态”这两个词上。这套组合不是性能最强的却是开发速度最快、参考资料最多、遇到问题最好搜到解决方案的。2.1 后端为什么是SpringBoot如果是五年以前写Java后端还得自己配置SpringMVC的XML文件、配置数据源、配置事务管理器项目还没开始写业务光环境就能折腾一两天。SpringBoot最大的贡献是让“能跑”的成本降到最低内嵌Tomcat不再需要单独部署Web服务器starter依赖引入什么就自动配置什么开发阶段一个main方法直接启动应用。这套系统里你大概率会在pom.xml里看到这些核心依赖parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency /dependencies这里有个关键点要注意如果parent版本是2.7.x对应JDK 8就能跑如果parent版本跳到3.2.x甚至更高那一般强制要求JDK 17。很多人拿到源码后第一件事不问版本直接用自己电脑上的JDK 8去编译SpringBoot 3.x项目结果报出一堆“无法解析符号”和“无效的目标发行版”错误。这个我在后面踩坑部分会专门讲。2.2 前端为什么是Vue而不是JQuery管理系统的前端本质上是表格、表单、弹窗、导航这些高度重复的界面。用原生JavaScript或者JQuery写这些界面最痛苦的是数据和DOM的同步数据一变你得手动操作DOM去更新页面代码多且容易乱。Vue用响应式数据加上组件化把这件事简化了数据变化页面自动更新公用模块抽成组件改一处全站生效。拿到这种源码先看前端目录下的package.json搞清楚用的是Vue 2还是Vue 3Vue 2搭配Element UI比较经典老项目居多。Vue 3搭配Element Plus功能更新生态更贴近现在的主流。路由基本都是Vue RouterHTTP请求基本都是Axios。无论哪个版本核心套路一样首页、列表页、详情页、后台管理页通过Vue Router切来切去每个页面里用import引入组件和接口方法用Axios发请求拿后端数据渲染成表格和卡片。2.3 数据库为什么选MySQLMySQL在这个项目里承担的是持久化和关系查询的任务用户和帖子是一对多的关系帖子下有多条评论评论还能回复评论这种结构天然适合关系型数据库。MySQL免费、跨平台、SQL语法通用网上的安装教程和配置说明最多教学资源和生产环境复用度都高所以它成为这类系统的默认选择几乎没有任何争议。我在导入SQL脚本时一直坚持一个习惯把数据库字符集明确设为utf8mb4。因为帖子和评论里经常出现表情符号、特殊字符直接用默认的latin1或者utf8会导致插入异常或乱码。建库语句通常是这种形式CREATE DATABASE IF NOT EXISTS kaoyan_help DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;3. 数据库设计一张表一张表地把互助交流的骨架搭起来看代码之前我建议先看SQL脚本。数据结构理解透了后面看后端Mapper和前端页面的思路都会很顺。这套系统中最核心的是用户表、帖子表、评论表。我下面把这三张表拆开讲再把分类、资料、公告这些辅助表带一下。3.1 用户表用角色字段区分管理员和普通用户用户表是所有业务表的外联基础。我简化后的建表语句大致长这样CREATE TABLE user ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL COMMENT 登录名, password VARCHAR(100) NOT NULL COMMENT 加密后的密码, nickname VARCHAR(50) DEFAULT NULL COMMENT 昵称, avatar VARCHAR(255) DEFAULT NULL COMMENT 头像地址, role TINYINT DEFAULT 0 COMMENT 0-普通用户 1-管理员, status TINYINT DEFAULT 1 COMMENT 0-禁用 1-正常, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;这里有两个细节值得学习。第一password不存明文而是存加密串系统里通常用MD5加盐、BCrypt或者Spring Security的PasswordEncoder做加密。第二status字段用于逻辑禁用管理员封号时不是把用户记录删掉而是把status改成0保留用户的历史发言和操作记录。这种做法在真实项目里非常常见能避免误删、方便审计。3.2 帖子表状态字段撑起审核流程帖子表是互助交流平台的核心内容表CREATE TABLE post ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL COMMENT 发布人, category_id BIGINT NOT NULL COMMENT 分类ID, title VARCHAR(100) NOT NULL, content TEXT COMMENT 正文内容, view_count INT DEFAULT 0 COMMENT 浏览量, like_count INT DEFAULT 0 COMMENT 点赞量, comment_count INT DEFAULT 0 COMMENT 评论量, status TINYINT DEFAULT 0 COMMENT 0-待审核 1-已发布 2-已删除, top TINYINT DEFAULT 0 COMMENT 0-未置顶 1-置顶, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_user_id (user_id), KEY idx_category_id (category_id), KEY idx_create_time (create_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT互助帖子表;说几个容易被新手忽略的点。第一status字段不是0和1两种状态而是三种待审核、已发布、已删除。用户发帖默认是待审核管理员审核后改成已发布遇到违规内容改成已删除。这样设计的价值是前台永远只查status1的帖子后台却能看到完整的帖子流并进行审核。第二view_count、like_count、comment_count这些数字字段是“冗余统计字段”。严格的关系设计会把点赞行为专门存一张like表需要时count一下。但实际项目为了列表页性能会在帖子表里直接把统计数据冗余保存每次点赞或评论时顺便更新数字查列表时就不用做聚合运算了。第三create_time建索引很关键。互助平台首页最常见的行为就是按发布时间倒序看新帖没有索引时帖子量一大排序查询会明显变慢。3.3 评论表用parent_id实现楼中楼回复评论是这类社区系统里最能体现设计功底的地方。如果只是简单的“帖子下有一堆评论”那表结构可以很直接一个post_id就够。但考研互助平台里的用户可以互相回复形成类似“楼中楼”的效果这时候就需要parent_id字段CREATE TABLE comment ( id BIGINT PRIMARY KEY AUTO_INCREMENT, post_id BIGINT NOT NULL COMMENT 所属帖子, user_id BIGINT NOT NULL COMMENT 评论人, parent_id BIGINT DEFAULT 0 COMMENT 0-顶级评论否则为被回复评论ID, content VARCHAR(500) NOT NULL, status TINYINT DEFAULT 1 COMMENT 0-隐藏 1-正常, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_post_id (post_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT评论表;当用户A发了一条顶层评论parent_id是0用户B回复用户A这条评论时B的记录里parent_id就是A评论的id。前端展示时先查出parent_id等于0的顶层评论再根据parent_id把回复找出来挂在对应评论下面。这种设计比无限级递归更简单也够覆盖大多数互助平台的交流场景。剩余的辅助表也值得扫一眼分类表category用来管理“公共课、专业课、复试调剂、备考经验”这些栏目资源表resource记录资料名称、文件路径和上传人公告表announcement存管理员的通知内容操作日志表记录关键管理行为。读完这些表结构你就理解了这个系统的数据流用户产生内容内容挂在分类下评论挂在内容下管理员控制内容可见性。4. 后端核心代码拆解从登录鉴权到帖子发布的完整链路数据库是骨架后端就是负责加工数据的引擎。我会挑几个最有代表性的代码片段来讲这些片段几乎就是同类项目的通用答案。4.1 统一返回结构前端才好写逻辑跑这类前后端分离项目最怕的是每个接口返回格式都不一样有的直接返回对象有的返String有的报错连状态码都没有。好的做法是在后端定义一个统一结果类所有Controller都返回这个统一结构前端拦截器只需要解析一种格式。package com.kaoyan.common; public class ResultT { private Integer code; private String msg; private T data; public static T ResultT success(T data) { ResultT r new Result(); r.code 200; r.msg 操作成功; r.data data; return r; } public static T ResultT error(String msg) { ResultT r new Result(); r.code 500; r.msg msg; return r; } public static T ResultT error(Integer code, String msg) { ResultT r new Result(); r.code code; r.msg msg; return r; } // getter/setter 省略 }前端Axios层只要判断code是不是200不是就直接弹错误提示不需要每个页面单独处理异常格式。这样写的好处一是省事二是风格统一三是后续加全局异常处理器时不用改前端代码。4.2 JWT登录鉴权拦截器里做判断如果源码里用的是JWT方案那核心逻辑通常包括两部分登录接口生成Token拦截器校验Token。登录成功后后端返回一串加密字符串前端存到localStorage后续请求都在请求头里带上它。生成Token的工具类核心代码如下Component public class JwtUtil { private static final String SECRET kaoyan-secret-key; private static final long EXPIRE 7 * 24 * 60 * 60 * 1000L; public String createToken(Long userId, Integer role) { return Jwts.builder() .setSubject(String.valueOf(userId)) .claim(role, role) .setExpiration(new Date(System.currentTimeMillis() EXPIRE)) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); } public Long getUserId(String token) { return Long.parseLong(Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token) .getBody() .getSubject()); } }校验逻辑一般在拦截器HandlerInterceptor的preHandle方法里完成public class AuthInterceptor implements HandlerInterceptor { Autowired private JwtUtil jwtUtil; Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String auth request.getHeader(Authorization); if (auth null || !auth.startsWith(Bearer )) { response.setStatus(401); return false; } try { Long userId jwtUtil.getUserId(auth.substring(7)); request.setAttribute(userId, userId); return true; } catch (Exception e) { response.setStatus(401); return false; } } }这里有一个我自己踩过的坑很多新手会把JWT密文SECRET写死在代码里这其实没关系学习项目可以接受但生产项目一定要放到配置文件中并定期更换密钥。拦截器只做了登录校验管理员接口还需要再判断一次用户角色通常查询当前用户role字段是否为1。4.3 帖子发布与分页查询的业务逻辑帖子Controller一般长这样RestController RequestMapping(/api/post) public class PostController { Autowired private PostService postService; PostMapping(/publish) public Result? publish(RequestBody Post post, HttpServletRequest request) { Long userId (Long) request.getAttribute(userId); post.setUserId(userId); post.setStatus(0); // 先进入待审核状态 postService.save(post); return Result.success(发布成功等待管理员审核); } GetMapping(/list) public ResultIPagePostVO list(RequestParam(defaultValue 1) long current, RequestParam(defaultValue 10) long limit, RequestParam(required false) String keyword) { return Result.success(postService.pageByCondition(current, limit, keyword)); } }关键逻辑在分页查询里。使用MyBatis-Plus时典型的实现是public IPagePostVO pageByCondition(long current, long limit, String keyword) { PagePost page new Page(current, limit); LambdaQueryWrapperPost wrapper new LambdaQueryWrapper(); wrapper.eq(Post::getStatus, 1) // 前台只展示审核通过的帖子 .and(StringUtils.hasText(keyword), w - w .like(Post::getTitle, keyword) .or() .like(Post::getContent, keyword)) .orderByDesc(Post::getTop) .orderByDesc(Post::getCreateTime); IPagePost postPage postMapper.selectPage(page, wrapper); // 组装userName和categoryName后返回PostVO return convertToVO(postPage); }这段代码里有几个值得留意的“为什么”前台查帖子必须带status1条件否则用户提交的待审核帖子直接出现在首页审核流程就失去了意义。搜索时标题和正文用like模糊匹配这是学习项目里最常见、最简单的搜索实现。数据量大了以后可以换成全文索引或者Elasticsearch但现阶段意义不大。排序时置顶字段优先再按发布时间倒序这是内容社区通用的排序规则。4.4 后台审核与统计功能怎么实现后台管理本质上就是对同一批数据的另一种视角。管理员看帖子时不能只看已发布内容要看到全部状态然后在审核通过、下架、删除之间切换状态。后台接口和前台接口共用同一张post表不同之处在于查询条件不强制status1以及调用者必须具有管理员角色。统计报表则是用SQL聚合来实现的比如统计每天的帖子发布量SELECT DATE(create_time) AS day, COUNT(*) AS cnt FROM post GROUP BY DATE(create_time) ORDER BY day DESC;接口返回这个结果后前端用ECharts或Chart.js渲染成折线图这就是后台首页“近七天发布趋势”的常见实现。很多源码里看起来很高端的大屏图表追根溯源都是这种简单的聚合查询。5. 前端工程Vue路由、Axios封装与页面联调的关键细节后端写得再好前端跑不通也白搭。很多初学者拿到这种项目先卡在npm install再卡在接口跨域最后卡在登录状态丢失。这一节我把前端工程怎么组织、路由怎么配、Axios怎么封装讲清楚。5.1 前端目录结构与开发模式典型的前端目录结构是src/ ├── api/ # 按模块封装的后端接口方法 ├── assets/ # 静态资源 ├── components/ # 通用组件比如分页、评论框、上传组件 ├── router/ # Vue Router路由配置 ├── store/ # Vuex/Pinia状态管理 ├── utils/ # 工具类比如request.js是Axios封装 ├── views/ # 页面组件一个文件夹对应一个页面 ├── App.vue └── main.js看一眼目录结构基本就能判断代码质量。好的项目一定把api单独抽一层页面里不直接写axios方法而是import api/index.js里定义好的函数。这样后端接口改了地址你只需改一个地方不用满页面找。前端开发时和后端联调最省事的方式是配置Vue CLI的devServer代理把请求转发到SpringBoot端口。在vue.config.js里常见写法是module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }这样前端在localhost:8081访问/api/post/list时请求会被代理到后端的8080端口开发阶段不需要处理跨域。5.2 路由拆分和登录守卫Vue Router做页面跳转的同时也负责判断某些页面要不要登录才能看。前端路由配置里可以给页面加meta信息const routes [ { path: /, name: Home, component: Home }, { path: /login, name: Login, component: Login }, { path: /post/:id, name: PostDetail, component: PostDetail }, { path: /admin, name: Admin, component: AdminLayout, meta: { requiresAuth: true, requiresAdmin: true } } ]路由守卫在每次跳转前执行检查登录和权限router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.meta.requiresAuth !token) { next(/login) return } const role localStorage.getItem(role) if (to.meta.requiresAdmin role ! 1) { next(/) return } next() })这里有个容易忽略的细节前端路由守卫只是体验层面的拦截真正安全的后端接口鉴权不能少。因为用户完全可以绕开前端页面直接用Postman发请求如果后端不校验权限管理接口照样裸奔。5.3 Axios拦截器的正确封装方式前端请求层最常见的封装方式是这样的import axios from axios import { Message } from element-ui import router from /router const request axios.create({ baseURL: /api, timeout: 10000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }) request.interceptors.response.use( res { const { code, msg, data } res.data if (code ! 200) { Message.error(msg) if (code 401) { localStorage.removeItem(token) router.push(/login) } return Promise.reject(new Error(msg)) } return data }, err { Message.error(err.message || 网络错误) return Promise.reject(err) } ) export default request这样一个封装解决三个问题所有请求自动携带Token、所有响应统一处理后端返回结构、登录过期自动跳转到登录页。页面组件里用起来就很干净比如import { getPostList } from /api/post export default { data() { return { list: [], loading: false } }, async created() { this.loading true this.list await getPostList({ current: 1, limit: 10 }) this.loading false } }5.4 列表页和详情页的数据交互套路列表页的套路是用分页组件触发接口请求每页切换时带着关键词和分类ID重新查询后端返回当前页数据和总条数。详情页的套路是从路由参数里拿帖子ID调一次详情接口获取帖子内容然后调评论接口获取评论列表。发布和回复成功后就刷新一遍详情页数据。这些交互逻辑没有难点但特别能培养“前后端协作”的意识。前端看到的是一个一个的页面组件和数据对象后端看到的是一段一段的接口逻辑。你在调试时要能准确判断问题出在哪一层是请求没发出去还是后端报错还是数据返回了但渲染格式不对。判断方法很简单打开浏览器开发者工具看Network面板接口返回红字就说明后端或者网络有问题返回正常但页面没变化就去看前端的数据绑定和生命周期。6. 把源码真正跑起来环境准备、数据库初始化和双端启动“可直接运行”四个字是这套源码最大的卖点但可运行绝不等于打开文件夹就能跑而是说环境对了之后按顺序执行几步就能看到完整页面。下面我按实际操作顺序列一个完整的启动清单你照着做就行。6.1 环境版本清单在动手之前先把环境对齐。我实测下来最稳的版本组合是这样软件推荐版本说明JDK1.8或17取决于pom.xmlSpringBoot 2.x用JDK83.x用JDK17Maven3.6.3及以上管理后端依赖MySQL5.7或8.08.0的驱动类和5.7略有差异Node.js14/16/18Vue2项目用16最稳Vue3项目建议18前端包管理器npm或yarn也可配置国内镜像加速不确定自己该用哪个版本时记住一条原则先看源码里的配置文件再看代码里用了哪些语法。比如pom.xml里如果显示spring-boot-starter-parent版本是2.6或者2.7那就直接用JDK 8不要犹豫如果版本号是3.0以上立刻切到JDK 17。前端同理package.json里vue版本是2.x就用Node 16是3.x就用Node 18基本不会出大问题。6.2 初始化MySQL数据库拿到源码后先在数据库目录下找到SQL脚本文件名通常叫kaoyan.sql、init.sql或者db.sql。启动数据库后执行导入命令mysql -uroot -p kaoyan.sql如果不想敲命令行也可以用Navicat或者DataGrip直接运行脚本。导入完成后检查一下有没有这三样数据库里出现了预期的数据表默认管理员账号已经存在分类数据已经初始化。如果SQL脚本里有管理员账号密码字段一般存的是加密后的串不是明文这个别疑惑。6.3 修改配置并启动后端打开后端项目的application.yml把数据源改成你自己的数据库账号密码server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/kaoyan_help?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: 你的数据库密码 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl启动后端有三种方式直接用IDEA运行启动类、命令行执行mvn spring-boot:run、或者先打包再执行java -jar。开发阶段建议直接在IDEA里运行方便看日志。控制台出现“Started Application in x seconds”并监听8080端口说明后端启动成功。如果连接数据库时报SSL相关错误关键就在url参数里useSSLfalse和allowPublicKeyRetrievaltrue这两个参数MySQL 8.0的驱动默认行为会触发公钥检索校验不加第二个参数经常报“Public Key Retrieval is not allowed”。6.4 启动前端开发服务器打开前端项目目录先执行npm install网络慢的情况下可以换成淘宝镜像npm install --registryhttps://registry.npmmirror.com安装完成后启动开发服务器npm run serve看到类似“App running at Local: http://localhost:8081”的输出浏览器打开这个地址就能进入系统。开发模式下前端页面和SpringBoot后端通过代理联调页面里所有请求都走/api前缀。6.5 生产环境打包把Vue构建产物放进SpringBoot开发调试用两个端口没问题但部署上线时最好只开一个端口。做法是在Vue项目里先执行构建npm run build构建完成后dist目录里会出现静态文件。把这整个dist目录里的内容复制到SpringBoot的src/main/resources/static目录下重新打包后端mvn clean package -DskipTests执行java -jar target/kaoyan-0.0.1-SNAPSHOT.jar浏览器访问http://localhost:8080就能看到完整系统。这样做的好处是不需要额外部署Nginx不需要配置跨域前端静态资源由SpringBoot统一托管一个应用容器解决所有问题。这也是网络热词“vue打包放进springboot中”这个操作的具体落地流程。7. 运行过程中最容易踩的坑版本、连接、路由和跨域源码能一次跑通是理想状态实际上十个新手里面至少有六个会卡在下面几个报错上。我把每个坑的原因和解决方案写清楚你遇到直接对照处理能省下大量查资料时间。7.1 MySQL连接时报错集中在SSL和驱动上我遇到过最典型的报错有两种。第一种是“Communications link failure”第二种是“Public Key Retrieval is not allowed”。前者多半是数据库没启动、端口不对、账号密码写错后者基本是MySQL 8.0的驱动对连接参数要求更严格。解决方案就是按第6.3节里的url来配把useSSL、serverTimezone、allowPublicKeyRetrieval、characterEncoding这些参数补齐。另外检查一下pom.xml里的驱动版本如果用的是com.mysql.jdbc.Driver这种旧驱动类而数据库是MySQL 8.0以上版本要改成com.mysql.cj.jdbc.Driver。7.2 SpringBoot版本太高导致的JDK不匹配“SpringBoot版本太高”这个问题我在不同项目里遇到好几次。表现是Maven编译时直接报错[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:... Invalid target release: 17这是因为SpringBoot 3.x的底层要求JDK 17而你的环境变量指向的是JDK 8。解决思路有两个要么降SpringBoot版本到2.7.x适配JDK 8要么装JDK 17然后在IDEA里把Project SDK和Maven的JRE设置统一改成17。个人建议学习阶段没必要追求新版本用2.7.18加JDK 8是兼容性最好的组合除非源码里明显使用了SpringBoot 3.x的语法比如jakarta命名空间。7.3 Vue Router history模式在SpringBoot里刷新404前端打包进SpringBoot后如果路由用的history模式直接点击页面内链接没问题但点浏览器刷新键或者手动输入二级路径比如直接访问http://localhost:8080/post/1很可能报404。原因是SpringBoot对未知路径返回404前端路由的路径并没有对应的后端Controller。解决方案有两种。第一种最简单把Vue Router的模式改成hash模式url里会出现#符号刷新不会404。第二种保留history模式在后端加一个WebMvcConfigurer配置把没有匹配到的路径转发到index.htmlConfiguration public class WebConfig implements WebMvcConfigurer { Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController(/{spring:[a-zA-Z0-9-_]}) .setViewName(forward:/index.html); } }前端部署时这种问题特别常见建议一次配好。7.4 开发模式下的跨域与代理配置如果开发时没配代理而是直接让前端发http://localhost:8080的请求浏览器就会报跨域。跨域的本质是浏览器的同源策略限制前端和后端端口不一致就属于跨域。开发阶段最优雅的解决办法是配第5.1节里的devServer.proxy生产阶段把前端产物塞进SpringBoot里彻底避免跨域。临时想解决也可以用后端加CrossOrigin注解或者配置CorsFilter但这不是长久之计。7.5 依赖安装失败和前端启动报错执行npm install时报错很多时候是网络源的问题或者依赖版本冲突。先换成国内镜像源再清掉缓存重新安装npm cache clean --force rm -rf node_modules package-lock.json npm install --registryhttps://registry.npmmirror.com如果项目里依赖node-sass在Node高版本下经常编译失败建议把node-sass换成sass或者把Node降到对应的老版本。这类问题的排查思路是看报错堆栈里提到哪个包再去调整那个包的版本。最后说句实在话运行这类源码最忌讳的是一上来就双击运行或者跳过环境检查。我每次接手新项目都会先看README、pom.xml、package.json、application.yml和SQL脚本这五个文件花五分钟理清版本和配置后面就顺畅很多。考研互助交流平台这类SpringBoot加Vue加MySQL的项目代码难度不高但麻雀虽小五脏俱全把它的登录鉴权、内容管理、前后端部署链路完整跑通再自己动手加上一个搜索功能或者数据统计图表你对全栈开发的理解会上一个台阶。
返回列表