
做 Java Web 方向的毕业设计这两年我接触下来的项目里出现频率最高的一个题目就是校园闲置物品交易系统。原因其实不难理解选题贴近校园生活功能边界相对清晰一套 SpringBootVue 的前后端分离结构又在企业开发里非常常见做完既不显单薄也好向评委老师和面试官交代。但同一道题交付质量的差距能拉到非常大有人拿到的所谓“完整项目源码”环境都起不来SQL 脚本跑到一半报错接口文档光有目录没有内容最后只能靠答辩现场编故事硬撑。这篇文章我就拿一套能真正跑通的校园闲置物品交易系统为例把技术选型、库表设计、后端接口、前端页面、SQL 脚本、打包部署这条完整链路逐段拆开讲顺带把项目从启动到上线会遇到的典型坑都列出来。拿到一份“完整项目”之后我自己的检查顺序通常很固定先看能不能一键启动再看 SQL 脚本能不能一次跑通最后把前端构建产物和后端静态资源那块理清楚。这三关过了项目才算真正完整。文章里讲的思路和参数配置都是我在实际调试中验证过的你可以直接拿来参考也可以照着检查自己手上的代码。1. 整体设计与技术选型1.1 为什么是 SpringBootVue而不是其他组合校园闲置物品交易系统这种业务形态核心诉求是信息展示、用户登录、商品发布与交易流程管理。它没有很高并发压力也没有复杂的实时计算但要求开发效率高、演示效果好、扩展空间足够这几条SpringBootVue的组合正好全部满足。SpringBoot 的优势不用多说它把 Spring 家族那一堆繁琐的 XML 配置降到了最低。内嵌 Tomcat 意味着不用单独安装容器再部署 war 包执行mvn spring-boot:run或者直接启动主类就能跑起来。配合 MyBatis-Plus 操作数据库CRUD 代码能缩到很短这对毕设周期的项目来说非常合适。Vue 这边按组件写页面、用路由切换视图整个前端维护起来比纯 jQuery 舒服太多而且 Vue 打包后的静态文件完全可以交给 SpringBoot 托管做到“一个 jar 包启动整个系统”的效果。有人会问为什么不直接用 JSP 做服务端渲染这就要说回现在的主流开发习惯了前后端分离的理念已经进入招聘和面试的默认语境毕设项目用 Vue 做前端至少能向评委展示你有“接口对接”“跨域处理”“静态资源部署”这方面的实战意识。纯 JSP 虽然也能实现功能但从技术展示的角度讲就吃亏了。我接手过不少同学自己写的 JSP 版校园二手交易系统功能确实有但答辩被追问“为什么不用主流框架”时回答起来会比较吃力。Vue 版本的选择上如果拿到的项目是基于 Vue 2 Element UI 的别急着说它旧。Vue 2 的生态成熟稳定Element UI 在数据管理后台场景下开箱即用很多企业的存量项目到现在还是这套组合。如果自己新建项目我也建议先从 Vue 2 起步把路由、Axios、组件复用这些基本功吃透再去看 Vue 3 的组合式 API 也不迟。这个选择能少踩非常多版本兼容的坑。1.2 用户端和管理端的功能模块怎么拆系统整体拆成两个入口普通用户端和管理员后台。不用微服务划分一个单体 SpringBoot 内部分模块即可重点是业务逻辑要分层清楚。用户端核心功能按使用流程排一下注册登录手机号或学号注册密码加密存储登录后拿到 Token 凭证。商品浏览首页展示在售闲置支持分类筛选、关键词搜索、按价格或时间排序、查看商品详情。商品发布填写标题、描述、价格、成色、实物图片提交后进入待审核状态。个人中心管理我发布的商品上下架、编辑、删除、查看收藏的商品、查看买到的和卖出的订单。留言互动在商品详情页给卖家留言询问卖家可以回复。管理员端功能对应平台运营的需要登录与主控台管理员独立入口首页显示商品总数、用户总数、订单数、待审核数量等统计信息。商品审核对新发布的商品做审核通过或驳回驳回时填写原因。分类管理增删改商品分类比如数码、书籍、衣物、生活用品等。用户管理查看用户列表、禁用违规账号、查看单个用户发布的商品。订单管理查看全部订单和订单状态流转必要时处理纠纷。很多同学做这个项目时容易把系统做成“人人都是管理员统统都能删”。这其实不是加分项反而会被评委抓住追问权限控制。上面这套拆法用户和管理员两边的操作边界是清楚的数据库里通过角色字段区分代码里通过拦截器校验答起辩来非常顺。把商品审核环节放进来是因为校园闲置交易场景下平台审核是合理需求这一设计还能把项目从“纯展示下单”提升到“带后台运营闭环”的完整度。2. 数据库设计与 SQL 脚本体检2.1 核心表结构怎么定才不乱数据库设计是评委最爱问的地方也是项目能不能支撑功能扩展的地基。这里的核心表大概有 7 张用户表、商品分类表、商品表、商品收藏表、订单表、留言表、公告表公告可选。用户表字段建议按下面这套来id 主键、username 登录账号、password 加密后的密码、nickname 昵称、avatar 头像地址、phone 手机号、student_no 学号、role 角色USER/ADMIN、status 状态1 正常/0 禁用、create_time 创建时间。注意一点密码字段一定不要用明文也不要只做简单 MD5推荐 BCrypt 或者至少加盐。MySQL 里 password 字段长度建议设成 60用于存 BCrypt 加密结果如果设成 32 存 MD5表结构设计上会被人扣分。商品分类表很简单id、name、sort 排序号、create_time。分类表不一定要做得多复杂但建议在商品表上保留 category_id 字段并且冗余存一个 category_name这样列表查询时可以少一次关联表查询性能上更干净。商品表字段略多我列一份实际验证过的结构字段类型说明idbigint主键user_idbigint发布者用户 idcategory_idbigint分类 idcategory_namevarchar(20)冗余分类名titlevarchar(50)商品标题descriptiontext商品描述pricedecimal(10,2)出售价格original_pricedecimal(10,2)原价/参考价condition_leveltinyint成色如 1到5 表示几成新到全新imagesvarchar(1000)图片地址多个逗号分隔statustinyint商品状态0 待审核 1 在售 2 已售出 3 下架 4 驳回viewsint浏览量create_timedatetime发布时间商品表的 status 字段是整个系统的业务关键。不要用简单的“0/1”表示上架下架而要做成上面这样的状态集合。理由很简单订单模块需要“已售出”这个状态来阻止商品被重复购买管理员审核需要“待审核”和“驳回”这些状态如果不提前在表里设计好后面做业务逻辑时一定到处打补丁。这是个很典型的“多花五分钟设计状态机后面省下五个小时改 Bug”的例子。订单表同样重要id、order_no 订单编号、goods_id、seller_id、buyer_id、price 成交价、status 订单状态0 已取消/1 待确认/2 交易中/3 已完成、message 备注、create_time、update_time。这里要特别提醒不要只在订单表里存 goods_id把卖家和买家 id 也冗余出来。很多同学觉得“卖家可以通过商品表查”实际上订单列表页需要频繁按用户查订单冗余这两个 id 可以省掉大量联表查询这是从性能角度出发最简单有效的一个技巧。留言表字段id、goods_id、sender_id、receiver_id、content、reply_to_id回复哪条留言、create_time。收藏表更简单id、user_id、goods_id、create_time但必须给 user_id goods_id 加唯一索引防止重复收藏也方便查询去重。2.2 表关系与字段设计的常见错误我检查过不少同学实现的校园交易系统表设计雷区集中在几个地方。第一是重复造轮子存状态。有的项目不再做订单表而是把商品表里加一个“购买者ID”这种做法的后果是同一个商品如果有历史订单数据会被覆盖交易记录完全丢失。交易系统没有订单流水业务上说不通答辩也经不起问。这一点必须用独立订单表去落地。第二是时间字段类型混乱。创建时间用 varchar 存字符串更新时间靠手工维护排序和统计时非常难受。推荐的写法是create_time 用 datetimeupdate_time 用 datetime并在插入时显示赋值或者依赖 MyBatis-Plus 的自动填充功能。日期类型明确后面的按天统计、按时间排序才不会出错。第三是图片字段设计。一个商品有多张图有人喜欢建一张子表有人用 JSON 数组字段有人用逗号分隔。毕设项目里最稳妥的是 images varchar(1000) 逗号分隔前端 split 后渲染成轮播图或缩略图。这样做的好处是表结构简单查询商品时一次取回所有图片不用额外联表性能和对开发友好度都够。如果以后要支持更复杂的图片管理再拆表也不迟。第四是删除策略。商品表不要物理删除状态字段里已经有“下架”用户删除自己的商品时把 status 改成 3 或者加一个 delete_flag 即可。这样能保留发布历史后台管理员也能追溯。用户表同理禁用账号用 status 字段控制别直接 delete 记录否则会破坏商品和订单的关联完整性。2.3 SQL 脚本里的隐藏细节字符集、索引、测试数据提供 SQL 脚本时很多人一上来就是 DROP TABLE 然后 CREATE TABLE能跑但细节上经不起推敲。一份合格的 SQL 脚本至少要包括四部分建库语句、建表语句、索引设计、初始化数据。建库语句最常见的坑是字符集。先执行CREATE DATABASE campus_trading DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;。为什么必须用 utf8mb4因为商品描述里可能输入 Emoji 表情MySQL 的老 utf8 字符集存不下 4 字节字符一旦用户输入了插入直接报错。我在实际调试中不止一次被这个坑折腾过排错到最后发现问题都指向字符集。所以第一步建库就把字符集定死后面省心。索引设计上商品表建议建这几个索引category_id 普通索引、user_id 普通索引、status 普通索引三个字段也可以做联合索引但毕设规模其实单列索引就够用。再强调一次收藏表的 user_id goods_id 唯一索引。订单表 order_no 要建唯一索引用于保证订单号绝对唯一生成订单时用日期拼接随机数极端情况下还是可能重复索引兜底是最稳的。初始化数据这件事很多源码里完全缺位。空数据库启动项目登录后首页一片白演示效果大打折扣。所以 SQL 脚本里应该预置一个管理员账号admin/123456密码是 BCrypt 密文、两三个测试用户、八个左右的分类数据、十几条覆盖不同分类的测试商品数据。测试数据不是随便编的商品标题、描述、价格要符合校园场景图片建议用项目自带静态图否则前端加载不到图片又是一堆红叉。我写测试数据时的习惯是商品名称做成“九成新《高等数学》上下册”“可折叠小台灯”“捷安特山地自行车”这种真实感很强的文案演示时评委一眼就能看出这是个能用的系统。3. 后端 SpringBoot 实战实现3.1 工程分层与关键依赖配置SpringBoot 后端项目的目录结构建议按经典的 Controller、Service、Mapper 三层来组织。不要为了显示自己能耐把所有逻辑写成一张“上帝 Service”也不要再拆出各种花里胡哨的抽象层这个规模的项目三层足够清晰答辩也好讲。分包大概是这样的config 放配置类比如跨域配置、MyBatis-Plus 分页插件、拦截器注册controller 接收前端请求调用 service返回统一结果service 处理业务逻辑像商品发布、订单流转这些核心流程mapper 配合 MyBatis-Plus 直接操作数据entity 放数据库表对应的实体类vo/dto 放前端需要的视图对象和请求参数对象common 放统一返回结果类、状态枚举、异常处理类util 放 JWT 工具类。用 Maven 作为项目构建工具这是目前 Java Web 项目的主流做法。pom.xml 里最重要的依赖我列一份常用组合spring-boot-starter-web、mybatis-plus-boot-starter、mysql-connector-java、lombok、jjwt、hutool可选方便做日期、文件、ID 生成、spring-boot-starter-validation 用于参数校验。pom 里容易出问题的有两个点。一个是 SpringBoot 2.x 和 3.x 的选择校园项目本地环境大多是 JDK8/MySQL5.7 或 8.0所以 SpringBoot 2.7.x 是非常稳的选择依赖兼容性好资料也多。如果拿到的是 SpringBoot 3.x 项目要注意 JDK 必须是 17 及以上servlet 包名从 javax 变成 jakartaMyBatis-Plus 要用对应的 3.5.3 版本这些不匹配是启动报错的重灾区。另一个是 Lombok 的版本要和 JDK 对应JDK8 配 1.18.28 左右基本没问题。application.yml 的核心配置其实就几项服务端口 server.port 默认 8080数据库连接 datasource 里要带useUnicodetruecharacterEncodingutf8和serverTimezoneAsia/ShanghaiMyBatis-Plus 开启下划线转驼峰再配一下日志输出级别。这里特别提醒数据库连接串里的时区参数不要省不然 MySQL 8 连接时会提示时区识别失败项目启动直接失败。这个报错我帮别人排过太多次了。3.2 登录鉴权与统一返回体登录这块主流方案是 JWT而不是传统 Session。因为项目是前后端分离后端接口不关心前端在哪里跑只要请求头里带一个合法的 token就能识别当前登录用户。JWT 的实现也简单登录成功时用用户信息生成 token设置两小时或稍长的有效期返回给前端前端后续每个请求在请求头 Authorization 里带上。后端写一个拦截器在进入 controller 前校验 token把用户 id 放到 ThreadLocal 里service 层直接取。拦截器里要注意白名单设计。用户登录、注册、浏览商品列表、查看商品详情这些接口不需要登录就能访问必须配置排除路径发布商品、下单、后台管理这些就必须校验权限。注册拦截器的示意代码registry.addInterceptor(jwtInterceptor) .addPathPatterns(/**) .excludePathPatterns( /api/user/login, /api/user/register, /api/goods/list, /api/goods/detail/** );这段只是示意路径要跟接口文档对齐。管理员接口最好单独再校验角色拦截器里从 token 解析出 role不是 ADMIN 的就返回 403。这个设计既是答辩加分点也是防止“普通用户调管理员接口删数据”这类低级漏洞的关键。统一返回体这个点很多新手会忽略但接口文档能不能写清楚全靠它。定义 Result 类结构是 code、message、data 三个字段code 为 200 表示成功401 表示未登录或 token 过期500 表示服务端异常。所有 controller 方法都返回 Result统一之后前端 Axios 拦截器也好统一判断。这个设计不是可选项而是减少前后端联调扯皮的核心习惯。3.3 核心业务接口的编写要领把商品发布、下单、状态流转这几个核心接口的实现思路讲清楚这基本就是整个后端项目的题眼。先说商品发布。前端提交的是一个表单包含标题、描述、价格、分类 id、几张图片地址。后端先做参数校验标题不能为空、价格必须大于 0、分类 id 必须存在。校验通过后把当前登录用户设为 user_id商品 status 默认设为 0待审核。这里有个细节前端上传图片时图片已经先通过独立的图片上传接口存到了服务器并返回 URL商品发布接口里只存这个 URL 列表不要在发布接口里同时处理二进制文件。图片上传接口单独拆出来的好处是前端可以边选边传发布表单提交时只剩 URL 拼接提交速度快失败也能定位是图片问题还是表单问题。再看下单。下单是整个系统最容易写崩的接口因为要处理并发下的重复购买。虽然毕设项目并发量不高但代码习惯要从一开始就正确。下单流程大概是根据商品 id 查商品发现 status 不是 1在售直接提示“商品已下架或已售出”结束然后生成订单号订单号用日期 用户 id 随机数组成保证唯一接着把商品状态改成 2已售出插入订单记录。关键操作是“先校验状态、再改状态、再插入订单”。为了稳妥可以在 update 时加条件 status1影响行数为 0 说明被人买走了boolean updated goodsService.update( new LambdaUpdateWrapperGoods() .eq(Goods::getId, goodsId) .eq(Goods::getStatus, 1) .set(Goods::getStatus, 2) ); if (!updated) { throw new ServiceException(商品已被购买或已下架); }这一步判断做完后面的订单插入才有意义。很多人的订单接口出 Bug都是因为先 insert order 再把商品状态改成已卖出商品状态修改失败时订单却已经生成数据就永远对不上了。状态流转这块建议做成枚举或常量类。订单状态订单创建后待确认卖家确认后交易中买家确认收货后已完成任意一方取消变成已取消。交易是校园当面交易不涉及真实线上支付这一点在项目说明里要写清楚评委不会因为没接入支付扣分反而会觉得你业务边界设计合理。如果之后想提高含金量可以接沙箱支付或者把“平台担保交易”做成可选订单状态但那是后话。4. 前端 Vue 实现与前后端联调4.1 工程初始化与路由处理Vue 项目按 Vue 2 Element UI 的组合来讲这是校园毕设项目里最常见的落地方案。环境上需要 Node.js建议 14 到 16 版本太高或太低都容易出现依赖安装问题、npm 或 yarn。初始化项目用 Vue CLI 4.x 或 5.x命令无非是vue create campus-trading-ui选择 Vue 2 预设再加 vue-router 和 axios。装依赖这件事npm install 经常因为网络问题报错常规解法是换镜像源npm config set registry https://registry.npmmirror.com。这个操作每年都能卡住一批人提前配好能省不少时间。路由层的设计最好做成“用户端 管理端分开处理再合并路由表”。router/index.js 里把页面路径列出来/login 登录页、/ 首页商品列表、/goods/:id 商品详情、/publish 发布商品、/profile 个人中心下面挂子路由、/admin 管理后台下面挂子路由。路由守卫是必须写的。在router.beforeEach里判断目标路径是否需要登录需要的话再检查 localStorage 里有没有 token没有就跳去登录页登录成功后带着 redirect 参数跳回来。这层守卫写好了用户乱敲路径也不会进入未授权页面。管理员路由再叠加角色判断权限闭环就成立了。这里也顺便解释了 vue-router 在项目里的实际用途不只是跳转页面更是权限控制的第一道门。4.2 Axios 封装、跨域与图片回显Axios 不要在每个页面里一遍遍 import 然后裸请求统一建一个 request.js 封装。核心就是三件事baseURL 统一指向后端地址请求拦截器把 token 从 localStorage 取出塞进请求头 Authorization响应拦截器统一处理后端返回的 Result 对象code 为 200 就返回 datacode 为 401 就清掉 token 并跳登录页其他 code 用 Element 的 Message 组件弹出错误提示。这套封装写完前端所有接口调用代码能缩到很短。跨域问题是前后端分离开发里最经典的坑。开发环境下前端跑在 8080后端跑在 8081两个端口不同浏览器会拦截跨源请求。解决办法有两个选一个就行。第一种是后端开启跨域支持。SpringBoot 写一个配置类实现 WebMvcConfigurer或直接在接口上加 CrossOrigin 注解。第二种更推荐前端在 vue.config.js 里配置 devServer.proxy把 /api 开头的请求代理到后端地址devServer: { port: 8080, proxy: { /api: { target: http://localhost:8081, changeOrigin: true } } }前端请求 /api/user/login开发服务器直接转发给后端的 8081 端口浏览器看到的是同源请求跨域问题自然解决。这两种方案都能用但我建议前端代理为主后端跨域配置只作兜底因为打包部署时前端静态文件和后端接口往往会在同一个站点下代理配置才是稳定可靠的方案。图片回显是另一个高频报错点。上传图片返回的是相对路径比如 /upload/goods/123.jpg前端在开发环境下访问的是 localhost:8080/upload但图片实际存在后端的 8081 端口自然显示不出来。解决办法是前端图片 src 拼上后端地址前缀或者走代理规则把 /upload 也代理到后端在 vue.config.js 的 proxy 里加一条/upload: { target: http://localhost:8081 }。打包部署后路径处理逻辑要再切回来因为 jar 包内后端已经托管静态资源了直接用相对路径访问就行。4.3 打包构建把 Vue 放进 SpringBoot这一步是整个项目能否“一个 jar 跑全部”的关键也是我检查项目时重点看的地方。先说流程Vue 项目执行npm run build生成 dist 目录里面是 index.html、CSS、JS 等静态文件然后把这个目录统一拷贝到 SpringBoot 的 resources/static 目录下。SpringBoot 默认把 static 目录当作静态资源目录所以访问 http://localhost:8080 时index.html 会直接被返回。要注意一个问题Vue 路由用了 html5 history 模式时直接访问 http://localhost:8080/goods/1 会 404因为后端没有这个路径对应的 controller静态资源服务器也找不到这个物理文件。解决办法有两个后端写一个转发 Controller把非 /api、非 /upload 的路径都转发到 index.html或者把前端路由改成 hash 模式地址变成 /#/goods/1刷新就不会 404。毕设项目里很多人图省事用 hash 模式但我更建议写一个 controller 做转发这样路由看起来干净答“为什么不用 #”时也有话说。前后端接口地址联调也要做一次统一。开发环境里前端 baseURL 可以配成空字符串或 /api依赖代理转发生产环境里前后端同源baseURL 直接写 /api 即可。这个配置必须在打包前检查好不然测试环境调通的接口部署后一打开全是 404。我见过太多项目就是在这一步翻车的。5. 接口文档与自测要点5.1 接口文档怎么写才不水接口文档是毕设项目里最容易流于形式的部分。不少人的“接口文档”就是把 controller 方法名抄一遍没有参数说明没有返回值结构这样的文档自己都看不懂更别说指导联调。一份合格的接口文档应该给每个接口标注清楚以下信息接口地址、请求方式、是否需要登录、请求参数字段名、类型、是否必填、含义、返回结果示例、错误码说明。推荐用 Apifox 或者 Postman 边测边生成接口文档比手写 markdown 效率高得多导出也方便。如果答辩用建议整理成 PDF 附在项目说明里评委想翻细节时看着舒服。下面列三个核心接口的文档示例感受一下规范程度。接口/api/user/login/api/goods/release/api/order/create方式POSTPOSTPOST是否登录否是是参数username, passwordtitle, description, price, categoryId, imagesgoodsId返回code, message, data{token, userInfo}code, message, data{goodsId}code, message, data{orderNo}失败情况用户名或密码错误参数校验失败商品已售出、未登录接口文档里的返回体格式要跟代码里 Result 类完全一致字段命名统一用驼峰别一会儿 user_name 一会儿 userName。前端对接时最讨厌的坑就是字段名不一致明明后端有数据前端读不到。5.2 接口自测的完整流程怎么走项目写完不能直接丢给答辩。建议至少按下面这条链路走一遍完整自测第一步启动 MySQL 和 SpringBoot 后端确认控制台没有任何报错数据库连接成功。第二步启动 Vue 前端开发服务器登录页面能出来输错密码有报错提示。第三步注册一个测试用户用这个用户登录拿到 token。第四步发布一个新商品带图上传去数据库查这条记录status 应该是 0。第五步用管理员账号登录后台找到这个待审核商品审核通过。第六步回到前端首页搜索到这个商品点进去看详情。第七步换另一个测试用户下单确认购买再回数据库检查商品 status 变成 2订单记录生成。第八步卖家确认订单买家确认收货订单状态变成已完成。这条链路走完系统的主要功能闭环就验证过了。我见过不少同学答辩现场翻车都是因为演示时走了一条以前没走过的路径——比如点了审核通过按钮发现接口 500或者下单时发现商品状态不对。提前按这条路走一遍能排除掉绝大多数低级问题。6. 常见问题与排查技巧实录6.1 启动阶段端口、依赖、数据库连接三座大山启动阶段遇到报错90% 集中在三个地方端口被占用、依赖版本冲突、数据库连不上。端口占用。SpringBoot 默认 8080如果本机已经跑了其他服务启动会报 “Port 8080 was already in use”。处理办法要么关掉占用端口的进程要么在 application.yml 里改成 8081。Windows 下查端口用netstat -ano | findstr 8080查到 PID 之后taskkill /PID 进程号 /F本地调试很快。前端 Vue 默认端口也是 8080一旦后端先启动占了 8080前端启动也会冲突。所以我一般习惯让后端用 8081前端保持 8080两边互不干扰代理转发也少改一处。依赖版本冲突最让人抓狂。MyBatis-Plus 的版本、SpringBoot 的版本、MySQL 驱动版本三者必须兼容。典型问题SpringBoot 3.x 项目用了低版本的 mysql-connector-java启动直接报驱动类找不到还有 SpringBoot 2.x 项目配 MySQL 8 的驱动驱动类名已经改成 com.mysql.cj.jdbc.Driver配置不更新就连不上。多看一眼 Maven 仓库里各依赖的版本号比在报错日志里猜半天有效得多。数据库连不上的常见报错是 “Access denied for user” 或 “Connection refused”。前者是账号密码或权限问题后者要么 MySQL 没启动要么连接串端口写错。MySQL 8 还经常遇到 Public Key Retrieval is not allowed 的报错解决方式是在连接串上加上allowPublicKeyRetrievaltrueuseSSLfalse。这个是 MySQL 8 安全策略导致的不加就连不上加上就通了。6.2 联调阶段跨域、接口 404、图片不显示联调阶段的坑我整理成一个速查表排查时对号入座。症状可能原因解决办法前端访问接口报 CORS error后端未开启跨域或前端代理未配置后端加 CORS 配置或前端 devServer 代理 /api前端请求 /api/user/login 返回 404请求打到了 Vue 自己的服务上检查 vue.config.js 的 proxy 配置调用后端接口返回 404 且后端无日志后端 controller 路径写错对齐接口文档和后端路径发布商品后列表页图片不显示图片 URL 是相对路径前端拼错前缀代理 /upload 到后端或拼完整地址登录后跳转页面刷新就 404Vue history 模式未做回退后端转发非接口路径到 index.html或改 hash 模式数据库写入中文变成 ??字符集未设置 utf8mb4检查数据库、表、连接串字符集自测时如果遇到接口返回 200 但 data 为 null多半不是联调问题而是后端业务逻辑抛了异常但被吞了。建议在拦截器那一层加一个全局异常处理器把异常信息返回给前端而不是让前端在页面上干瞪眼。全局异常处理这几十行代码对排查问题的价值是几何级放大的。6.3 答辩准备与进阶扩展最后说点跟毕设直接相关的准备心得。答辩时老师最常问的三个问题这个项目的难点是什么数据库为什么这样设计哪些模块是你独立完成的对应这三个问题准备的时候要理清楚三条线并发下单时防止重复购买你是怎么处理的商品状态机待审核-在售-已售出-下架为什么这样设计哪些功能是自己从零写的哪些参考了网上代码参考的部分你又改了什么。向上扩展的话这套项目能加的点很多。商品搜索从 MySQL LIKE 换成 Elasticsearch 或者引入中文分词热门商品缓存到 Redis公告和轮播图做成可配置模块下单后接一个模拟支付页面甚至可以加入卖家地址和预约时间的加锁设计。任何一个点都能在答辩时展开讲五分钟。7. 从零到一完整跑通项目的操作清单7.1 环境准备与版本对照很多项目拿到手跑不起来不是代码有问题而是环境版本跟项目要求对不上。我列一个从实践出发的推荐版本表注意并不是说只有这套版本能跑而是这套组合被验证过问题最少。组件推荐版本说明JDK1.8 或 17SpringBoot 2.7 用 JDK83.x 用 JDK17Maven3.6 以上用 IDEA 自带或单独安装都行Node.js14 到 16Vue2 项目在这个区间最稳MySQL5.7 或 8.08.0 需要在连接串加时区参数SpringBoot2.7.x校园项目首选Vue2.x配合 Element UI生态稳7.2 十分钟启动步骤把整个项目的启动流程压缩成一套最小步骤按顺序执行基本不会出问题。第一步在 IDEA 里打开后端工程确认 Maven 已经自动拉完依赖如果 pom.xml 上显示报红先执行 mvn clean install 或者刷新 Maven 项目看报错信息再处理依赖。第二步用 MySQL 客户端执行 SQL 脚本执行完确认表数量和测试数据条数都对这里有一步很重要确认数据库名和账号密码要和 application.yml 里的 datasource 配置一致。配置文件里改成本地 root 账号和密码或者新建一个专用账号取可读性强的名字。第三步启动后端主类看到 Spring Boot 启动成功日志端口 8081 或者你自己配的端口能访问说明后端已经就绪。第四步进入前端目录执行 npm install 安装依赖再执行 npm run serve。启动成功后访问 localhost:8080应该能看到首页。第五步用 SQL 脚本里的管理员账号登录后台用预置测试用户登录前台走一遍商品发布、审核、下单、完成订单的闭环。这套流程我在不同版本的源码上验证过很多次照着走下来半个小时足够把一个新环境从零跑通。如果中间有一步卡住回到上一节的问题速查表里找对应解法就行。