简介一套基于 Java 的社区团购系统毕业设计资源面向计算机相关专业毕业生和课程设计学生提供可直接运行的完整项目源码并配套毕业论文与开题报告用于解决毕业设计选题、系统开发与论文撰写同步推进的问题。系统采用前后端分离架构前端以 Vue 组件和 JavaScript 实现页面交互后端由 Java 源码构成核心业务逻辑辅以 HTML、CSS、XML、SQL 等文件完成静态页面、权限配置与数据库脚本包内共 810 个文件压缩包整体约 15MB结构清晰便于按模块查阅。功能涵盖用户注册登录、商品浏览与详情、购物车管理、订单管理、团购查看以及管理员后台等典型模块并附带安装、启动、打包等辅助脚本可快速搭建本地环境。所有源码和论文文档统一整理既有工程实现也有文字材料已有 84 人学习适合需要一套完整案例进行参考、复用或二次开发的 Java 学习者。1. 社区团购毕设一套能直接跑的 Java 全栈源码先说个场景毕设拿到“社区团购系统”这个题目的人不少但多数人卡在同一个地方——前端套个模板后端自己写接口两边对接不上下周就中期检查了项目还没跑起来。这套 Java 毕业设计源码不一样它把选题、开题、实现、论文整条链路打包好了Spring Boot 后端、Vue 前端、MySQL 数据库配合注册登录、商品浏览、购物车、团购下单、后台管理这些完整功能外加毕业论文和开题报告。你不用再东拼西凑下载后按脚本装依赖、导入数据库、启动两个服务浏览器一开就是成品。适合三类人拿同题做课程设计的学生、想快速搞懂社区团购业务闭环的初学者、以及想要一套规范代码做二次开发的开发者。2. 技术栈与项目结构Spring Boot Vue 前后端分离的完整档案2.1 技术选型为什么毕设几乎都用这套组合这套项目的技术栈从文件列表里就能读出七七八八。后端有 mvnw.cmd说明是 Maven Wrapper 管理的 Java 项目而社区团购这种带商品、购物车、订单的系统用 Spring Boot 几乎是默认选择——它把 Tomcat 内嵌进去了java -jar 就能起服务不用像 SSH 时代那样手动装 Tomcat、配 server.xml。持久层最常见的做法是配合 MyBatis 或 MyBatis-Plus前者 SQL 可控、好讲原理后者写 CRUD 极快。答辩场景下我一般更推荐 MyBatis因为可以把 SQL 单独拎出来讲显得你对数据层有掌控力。前端部分那些 .vue.bak 文件已经暴露了用的是 Vue。Vue 2 Element UI 是这套代码里几乎必然会出现的组合Element UI 的表单、表格、弹窗组件涵盖了管理系统 90% 的需求。页面跳转用 Vue Router请求后端用 axios。用户看到的商品列表、团购详情、购物车加减全是 Vue 组件在浏览器里渲染和后端通过 JSON 交互。数据库是 MySQL。社区团购的业务模型——用户、商品、团购、购物车、订单——用关系型数据库表达非常自然外键、索引、事务都能直接派上用场这几个点也正是答辩时老师最爱问的。选这套组合的最大理由是“对口”技术栈主流、代码分层清晰、前后端分离这些在课程设计评分标准里全是加分项。你要是用 JSP Servlet 写同样功能工作量翻倍且看起来不像这个时代的产物。2.2 逐个文件拆解.classpath、.vue.bak、三个 .bat 分别是什么先把这套资源里的关键文件按作用分个类你看一眼就知道哪些要留、哪些可以无视。文件类型作用使用时注意.classpathEclipse 工程文件记录项目类路径和依赖引用用 IDEA 打开时无视即可不影响 Maven 识别mvnw.cmdMaven Wrapper 脚本自动下载指定版本 Maven 并执行构建本机没装 Maven 也能用首次运行会联网拉取1-install.bat一键安装脚本安装后端依赖和前端 npm 依赖需先装好 JDK、Node、MySQL2-run.bat一键启动脚本启动后端 jar 和前端开发服务器后端 8080前端端口看脚本配置3-build.bat打包脚本生产构建生成可部署产物用于交付或上服务器部署index.html.bak前端入口备份Vue 应用的 HTML 容器.bak 是备份实际生效的是 index.htmlupdate-password.vue.bak修改密码页面备份用户改密组件改密码要校验旧密码、确认新密码IndexAsideStatic.vue.bak侧边栏菜单备份后台管理左侧菜单新增管理页面要同步改菜单配置BreadCrumbs.vue.bak面包屑导航备份显示当前页面路径依赖路由 meta 里的 title 字段IndexHeader.vue.bak顶部导航备份用户头像、退出登录等常配合下拉菜单做退出确认这里有个值得说的细节这几个 .vue.bak 文件名是 vue-element-admin 这类后台模板里非常典型的布局组件——IndexAsideStatic 是静态侧边栏BreadCrumbs 是面包屑IndexHeader 是顶栏。改版时作者没有直接覆盖源文件而是把旧的复制成 .bak 再改这个习惯在真实项目里非常实用改组件改到一半发现思路不对把 .bak 改回来就是后悔药。.vue.bak 是纯文本文件去掉 .bak 后缀就能被 Vue 编译。如果你拿到源码后发现某个功能异常而对应位置恰好存在 .bak 文件打开对比新旧版本差异通常能快速定位改哪儿改坏的。2.3 项目目录结构前后端分离的标准骨架把 .classpath 和 .bat 放到一边项目本体应该长这样按 Maven Vue 的标准布局补全实际解压后大同小异community-group-buy ├── 1-install.bat ├── 2-run.bat ├── 3-build.bat ├── mvnw.cmd ├── backend │ ├── pom.xml │ ├── src/main/java/com/example/community │ │ ├── CommunityApplication.java # Spring Boot 启动类 │ │ ├── config │ │ │ ├── CorsConfig.java # 跨域配置 │ │ │ ├── LoginInterceptor.java # 登录拦截器 │ │ │ └── WebMvcConfig.java # 拦截器注册 │ │ ├── controller │ │ │ ├── UserController.java │ │ │ ├── GoodsController.java │ │ │ ├── GroupBuyController.java │ │ │ ├── CartController.java │ │ │ └── OrderController.java │ │ ├── service │ │ │ └── impl │ │ ├── mapper │ │ ├── entity │ │ └── common │ │ └── Result.java # 统一返回体 │ └── src/main/resources │ ├── application.yml │ ├── mapper # MyBatis XML 文件 │ └── static # 前端构建产物最终放这里 ├── frontend │ ├── package.json │ ├── vue.config.js │ └── src │ ├── main.js │ ├── router/index.js │ ├── api # axios 请求封装 │ └── views │ ├── Login.vue │ ├── Register.vue │ ├── Home.vue │ ├── GoodsDetail.vue │ ├── Cart.vue │ ├── OrderList.vue │ └── groupbuy/GroupBuyDetail.vue └── sql └── community.sql这是典型的单体前后端分离backend 单独打成 jarfrontend 单独构建成 dist。开发阶段两边分开跑前端通过代理转发请求部署阶段把 dist 里的静态文件拷进 backend 的 static 目录打成一个 fat jar实现单进程交付。论文里的“系统架构设计”章节画一张这个结构的图再配两三段文字解释基本就稳了。2.4 数据库设计社区团购的核心表长什么样社区团购和普通电商的区别在于“团购”这条业务线。用户表、商品表、购物车、订单是通用电商的标配团购表是这套系统的特色五张表串成完整业务链。核心表设计大致如下user用户表id 主键username 登录名password 加密后的密码user_type 区分普通用户和管理员phone、address 收货信息goods商品表id 主键goods_name 商品名称price 单价stock 库存img 商品图片detail 图文描述group_buy团购活动表id 主键goods_id 关联商品group_price 团购价group_size 成团人数start_time 活动开始时间end_time 活动结束时间status 活动状态cart购物车表id 主键user_id 哪个用户goods_id 哪个商品quantity 数量orders订单表id 主键order_no 订单号user_id 下单人goods_id 商品group_buy_id 走团购时关联活动quantity 数量total_price 总价status 待付款/已付款/已发货/已完成create_time 下单时间表之间的约束值得展开购物车表的 user_id goods_id 应该建唯一索引防止同一用户把同一件商品插成多条记录订单表的 order_no 必须唯一且尽量用业务号而不是自增 ID方便查询和对账订单表里加 group_buy_id 字段是为了区分普通购买和团购购买后续统计“这个团购带来了多少订单”直接查这个字段就行。这些细节写进论文的数据表设计章节属于加分项。3. 核心功能拆解一个请求从登录到加购下单的完整链路3.1 注册登录user_type 字段区分用户类型摘要里描述了注册、登录界面。在社区团购系统里登录用户分为普通用户和管理员两种登录界面会让你选登录类型。这个 user_type 字段贯穿了整个权限体系。后端登录接口的常见实现PostMapping(/login) public Result login(RequestBody LoginRequest req) { // 1. 按用户名查询用户这一步走 MyBatis 的 selectOne User user userMapper.selectByUsername(req.getUsername()); // 2. 用户不存在或密码不匹配统一返回同一句话不暴露哪个错误 if (user null) { return Result.error(用户名或密码错误); } // 实际 password 字段存的是 BCrypt 加密串这是简写演示 if (!passwordEncoder.matches(req.getPassword(), user.getPassword())) { return Result.error(用户名或密码错误); } // 3. 登录时选的类型必须和库里一致管理员不能走用户端入口 if (!req.getUserType().equals(user.getUserType())) { return Result.error(登录类型不匹配); } // 4. 登录成功把用户 id 和 user_type 放进 session request.getSession().setAttribute(userId, user.getId()); request.getSession().setAttribute(userType, user.getUserType()); return Result.success(user); }参数说明LoginRequest 是前端传来的请求体包含 username、password、userType 三个字段passwordEncoder 是 BCryptPasswordEncodermatches 方法负责比对明文和加密串绝不能把密码解密出来做字符串比较session 是登录状态的载体后续接口全部通过 LoginInterceptor 拦截未登录请求。有同学问为什么不用 JWTJWT 也行返回 token 让前端存 localStorage。但毕设场景下用 session 更符合教科书要求论文里能写“基于 Session 的登录状态保持机制”老师也容易理解。登录拦截器的注册是关键步骤public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行登录、注册接口 if (request.getRequestURI().contains(/user/login) || request.getRequestURI().contains(/user/register)) { return true; } // 校验 session 里有没有 userId Object userId request.getSession().getAttribute(userId); if (userId null) { response.setStatus(401); // 未登录返回 401前端收到后跳回登录页 return false; } return true; } }拦截器必须注册到 WebMvcConfig 里并指定排除路径。这套机制是后端保护接口的第一道防线——前端路由守卫只是 UI 层面的跳转控制真正的接口防裸调靠的是拦截器。很多毕设翻车就翻在只做了前端路由守卫后端接口不带任何校验答辩时打开开发者工具直接调接口就能绕过登录这个漏洞必须堵上。前端登录页的 Vue 代码不复杂重点在表单校验和登录后跳转script export default { data() { return { loginForm: { username: , password: , userType: user }, rules: { username: [{ required: true, message: 请输入用户名, trigger: blur }], password: [{ required: true, message: 请输入密码, trigger: blur }] } } }, methods: { handleLogin() { this.$refs.loginForm.validate(valid { if (!valid) return // userType 决定登录成功后跳前台还是跳后台 const redirect this.loginForm.userType admin ? /admin : /home this.$router.push(redirect) }) } } } /script注册页的逻辑和登录页几乎对称表单增加确认密码、手机号字段提交前做前端格式校验提交后调 /user/register成功就跳登录页。这里提醒一句注册接口后端必须做用户名重复检查否则库里出现两个同名账号后面登录时 selectOne 会直接报异常这是很容易踩的暗坑。3.2 商品详情与团购一个详情页怎么同时展示两种价格商品详情页是这套系统里信息密度最高的页面因为它要同时处理两套数据商品本身的信息名称、图片、单价、库存、描述以及当前是否有进行中的团购活动团购价、成团人数、剩余时间。后端组装详情数据的逻辑public GoodsDetailVO getGoodsDetail(Long goodsId) { // 查商品基本信息 Goods goods goodsMapper.selectById(goodsId); if (goods null) { throw new BizException(商品不存在); } // 查当前正在进行中的团购活动 GroupBuy activeGroupBuy groupBuyMapper.findActiveByGoodsId(goodsId); GoodsDetailVO vo new GoodsDetailVO(); BeanUtils.copyProperties(goods, vo); if (activeGroupBuy ! null) { vo.setGroupPrice(activeGroupBuy.getGroupPrice()); vo.setGroupSize(activeGroupBuy.getGroupSize()); vo.setGroupEndTime(activeGroupBuy.getEndTime()); } return vo; }逻辑说明findActiveByGoodsId 对应 SQL 里带 status 1 且 end_time now 的条件保证查出来的一定是当前有效的团购过期活动不会冒出来用 GoodsDetailVO 而不是直接把 Goods 实体返回给前端可以避免把库存、状态等内部字段暴露到页面上也方便后续扩展团购字段BeanUtils.copyProperties 做属性拷贝省去一大段 setter 代码。前端展示规则是有团购活动就显示团购价红色字号加大并多出一个“立即参团”按钮没有团购只显示普通价和“加入购物车”。这套逻辑写进论文可以叫“商品详情联动团购活动的动态展示策略”实际代码就一个 if 判断的事。加入购物车的接口逻辑前面提过这里补一个收藏的细节。收藏表通常单独建一张 favorite字段就 user_id goods_id create_time。点收藏前先判断是否已收藏重复点击应该是“取消收藏”而不是报错这个交互细节前端容易漏漏了会出现点第二次收藏按钮报错或者生成重复收藏记录的问题。3.3 购物车与下单事务和库存扣减的配合购物车界面按摘要描述支持修改数量、删除商品和购买。修改数量是前端组件和后端接口的配合前端用 Element UI 的数字输入框每次 change 事件调一次 /cart/updateQuantity后端更新 quantity 后重新计算小计金额返回给前端展示。关键在后端的下单接口这是整个系统最容易出 bug 的地方必须加事务Transactional(rollbackFor Exception.class) public String createOrder(OrderCreateRequest req) { // 1. 生成业务订单号前缀 CG 时间戳 随机数 String orderNo CG System.currentTimeMillis() (int)(Math.random() * 1000); BigDecimal totalPrice BigDecimal.ZERO; // 2. 遍历购物车中勾选的商品逐项校验库存 for (CartItemDTO item : req.getCheckedItems()) { Goods goods goodsMapper.selectById(item.getGoodsId()); if (goods null || goods.getStock() item.getQuantity()) { throw new BizException(商品库存不足 goods.getGoodsName()); } // 3. 扣减库存用 update 语句直接扣而不是查出来再算 int rows goodsMapper.decreaseStock(item.getGoodsId(), item.getQuantity()); if (rows 0) { throw new BizException(库存扣减失败请稍后重试); } // 4. 计算总价 BigDecimal itemPrice goods.getPrice() .multiply(BigDecimal.valueOf(item.getQuantity())); totalPrice totalPrice.add(itemPrice); // 5. 写订单主表和订单明细表 orderMapper.insertOrder(...); orderItemMapper.insert(...); } // 6. 下单成功后删除购物车中已购买的条目 cartMapper.deleteByIds(req.getCartItemIds()); return orderNo; }这段代码值得逐行看Transactional 保证整个下单过程是一个原子操作——第 3 步扣了库存第 5 步写订单失败事务回滚会把库存补回来不会出现“库存扣了订单没生成”的灵异事件decreaseStock 的 SQL 是 update goods set stock stock - #{quantity} where id #{id} and stock #{quantity}用数据库行锁保证并发安全先 select 再 update 的写法在并发场景下会超卖这是电商系统的经典坑订单号用时间戳拼随机数避免并发下单时主键冲突全部成功后再清空购物车避免用户下单失败购物车被误删。前端下单流程是购物车页勾选要买的商品点“去结算”进入确认页确认页展示商品清单和总价点“提交订单”调 createOrder 接口拿到 orderNo 后跳转订单列表页。这里有个交互细节提交按钮要做防重复点击否则手抖点两下会生成两个一模一样的订单常规做法是点击后把按钮置为 loading 状态请求结束再恢复。订单列表页按摘要描述展示个人订单信息常见实现是分页查询 orders 表关联 goods 表按 create_time 倒序订单状态用 tag 组件显示不同颜色。如果要做取消订单后端需要反向操作订单状态改成已取消同时把扣掉的库存加回来这个操作同样要放在事务里。4. 从零跑通安装依赖、导入数据库到一键启动4.1 环境准备JDK、MySQL、Node 一个都不能少先把环境清单列出来版本不需要最新稳定最重要JDK 1.8Spring Boot 2.x 用 JDK 8 最稳高版本 JDK 有时会遇到 Lombok 兼容问题MySQL 5.7 或 8.0本地装一个 Navicat或者直接用命令行导入 SQLNode.js 14 或 16Vue 2 项目对 Node 版本敏感装 Node 18 容易在 npm install 阶段翻车Maven 可以不装项目里有 mvnw.cmd 会自动下载检查命令java -version node -v npm -v mysql --version如果 java 或 node 命令找不到去官网装对应版本并配置环境变量。配置完要新开一个终端窗口才生效——这是经典坑配完了还在旧窗口敲命令当然报“不是内部或外部命令”。这里额外说一句如果你本机已经装了高版本 JDK比如 JDK 17跑 Spring Boot 2.x 大概率会遇到 java.lang.reflect.InaccessibleObjectException 这类反射报错。最省事的办法不是改代码而是把 JDK 切回 8或者升级 Spring Boot 版本。毕设项目稳定优先别折腾。4.2 初始化数据库导入 SQL 脚本解压源码后在 sql 目录下找到 community.sql或类似命名建库导入CREATE DATABASE community DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE community; SOURCE community.sql的绝对路径;核对两件事第一建库时指定 utf8mb4 字符集避免中文乱码很多翻车现场是数据库默认用了 latin1页面显示一堆问号第二导入后打开数据表确认数据条数商品表和用户表应该有初始数据管理员账号能直接在 user 表里看到。然后打开后端配置文件spring: datasource: url: jdbc:mysql://localhost:3306/community?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 你的数据库密码application.yml 里的账号密码必须改成你自己本机的。如果密码里有特殊字符在 URL 里可能需要转义这是一个很容易被忽略的细节。改完记得保存然后重启后端才生效。4.3 一键脚本1-install.bat、2-run.bat 背后做了什么来看看这三个 .bat 脚本通常做的事情。1-install.bat 核心内容echo off echo [1/2] 安装后端 Maven 依赖... call mvnw.cmd clean install -DskipTests echo [2/2] 安装前端 npm 依赖... cd frontend call npm install --registryhttps://registry.npmmirror.com cd .. echo 依赖安装完成 pause说明一下mvnw.cmd 是 Maven Wrapper它第一次运行时会通过网络下载指定版本的 Maven所以第一次会比平时慢一些那是正常的。-DskipTests 是跳过单元测试避免测试代码环境不干净导致构建失败。npm install 后面跟 registry 参数是让 npm 走国内镜像源速度会明显快不少。如果不配镜像第一次 npm install 可能要下载几百兆依赖卡十分钟以上不稀奇。2-run.bat 核心内容echo off echo 启动后端服务... start community-backend cmd /k call mvnw.cmd spring-boot:run echo 启动前端开发服务器... cd frontend start community-frontend cmd /k npm run serve echo 两个窗口启动完成 pause两个 start 会各弹一个新的命令行窗口分别跑后端和前端。后端默认监听 8080前端开发服务器默认也是 8080但被占用时会自动加 1 变成 8081。打开浏览器访问前端地址就能看到登录页。前端 8081 怎么访问后端 8080靠 vue.config.js 里的代理module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }参数说明/api 开头的请求会被代理转发到后端 8080前端代码里 axios 的 baseURL 只需写成 /api就能完美避开跨域问题changeOrigin 设为 true后端看到的请求来源就是 8080 而不是 8081。如果不配代理也可以在后端写 CORS 跨域配置但开发阶段代理更省事——改一行配置就行不用动 Java 代码。注意如果某个版本的 Vue CLI 启动端口不是 8081 而是 8082那是端口被别的进程占了代理配置不用改浏览器访问对应端口即可。4.4 3-build.bat生产构建和交付验证开发模式跑通只是第一步毕设交付和答辩环境还需要构建产物。3-build.bat 做的事情echo off cd backend call mvnw.cmd clean package -DskipTests cd ..\frontend call npm run build echo 后端 jar 包backend\target\*.jar echo 前端静态文件frontend\dist\ pause构建完成后有两个产物。常见做法是把 frontend/dist 里的文件复制到后端 src/main/resources/static 目录下再次打包后端这样最终只需要一个 jar 就能同时提供页面和接口。部署到服务器上执行java -jar community-0.0.1-SNAPSHOT.jar浏览器访问 http://服务器IP:8080 就是完整系统不需要再启动 Node。这个“前后端合并单 jar”的部署方式在论文的部署章节里写出来比“需要同时开两个服务”要显得更专业也更好演示。4.5 跑通验证三步确认系统正常后端窗口出现 Started CommunityApplication in XX seconds 说明启动成功。接下来三步验证打开浏览器访问前端地址看到登录页用普通用户账号登录能进首页看到商品列表点一个商品看详情加购物车下单订单列表里能看到新订单如果三步全通说明前后端、数据库、事务整条链路没问题论文里截这些图就够了。然后换管理员账号登录进入后台把用户管理、商品管理、团购管理逐一点一遍确认管理功能也正常。这里建议尽快用管理员账号把后台全点一遍因为后台接口如果没测过答辩现场才第一次打开容易碰到没初始化的页面报错。5. 避坑指南跑这种毕设项目最常见的五个翻车现场5.1 npm install 报 ERESOLVE 错误装到一半就挂了现象执行 1-install.bat 时npm install 跑一会儿就报 ERESOLVE unable to resolve dependency tree前端依赖装不上后面的 2-run 直接无从谈起。原因Node 版本太新。Vue 2 时代的依赖树和 Node 17 的依赖解析规则冲突尤其是 node-sass 这类原生模块在 Node 18 上几乎必挂。报错信息里通常能找到 node-sass 或 node-gyp 的字样看到这几个关键字基本就可以判定是版本问题。解决用 nvm 切回 Node 14 或 16删掉 node_modules 和 package-lock.json重新执行 npm install。如果项目里用的是 node-sass可以把它换成 sassdart-sass能省去一堆编译麻烦但要注意语法差异。排查命令node -v nvm list nvm use 14.21.3 npm install切换版本后如果 npm install 还是失败重点看报错里第一个依赖包的名字去 package.json 里搜把版本号放宽到兼容范围即可。5.2 后端启动报端口被占用现象2-run.bat 启动后端窗口里出现 Web server failed to start. Port 8080 was already in use.然后进程退出。原因之前残留了一个没关掉的 Java 进程或者你自己开了别的服务占了 8080。解决先查端口再杀进程netstat -ano | findstr 8080 taskkill /F /PID 这里填查到的PID注意杀进程要确认 PID 对得上别把别的程序杀了。如果不想杀进程也可以改后端的 server.port但前端代理 target 也要跟着改所以最简单的还是清掉占用端口的进程。提示改端口必须前后端一起改——后端 server.port 改了 8081前端 proxy target 也要改成 http://localhost:8081只改一边会出现前端页面能开、接口全挂的情况。5.3 页面全中文乱码数据库里存进去的就是问号现象页面显示的商品名称、用户昵称全是 ??打开数据库看存进去的字段本身就是问号。原因建库时字符集没指定 utf8mb4或者后端 JDBC URL 没带 characterEncodingutf8。很多本地 MySQL 默认字符集是 latin1中文根本存不进去。检查方法mysql show variables like %character%;看到 character_set_database 是 latin1基本就是它了。解决删库重建建库时用 utf8mb4同时检查 JDBC URL 是否带 characterEncodingutf8 和 serverTimezoneAsia/Shanghai。改完配置重启后端再试。乱码问题一旦数据已经写坏光改配置救不回旧数据必须重建数据库重新导入 SQL。5.4 前端页面能打开但所有接口请求报 404 或 401现象浏览器里前端页面正常渲染登录后一调接口就报错。打开 F12 看网络请求/api 开头的请求要么 404要么被拦成 401。原因404 大都是代理没生效或者后端没启动401 大都是登录拦截器生效了但请求没带上 session 的 Cookie。前端 axios 默认不开 withCredentialsCookie 不会随请求发送后端拿不到登录态。解决分两步第一步确认 vue.config.js 里 proxy 配置正确后端窗口里能看到请求日志第二步在 axios 请求封装处加一行// 请求封装文件通常是 src/api/request.js const service axios.create({ baseURL: /api, timeout: 10000, withCredentials: true // 关键跨域请求携带 Cookie })排查顺序建议是先看后端窗口有没有收到请求再检查代理最后看 Cookie。直接猜原因大概率浪费时间。用 curl 先打一下后端接口curl http://localhost:8080/api/user/login后端返回 JSON 说明服务正常问题在代理或前端连不上说明后端本身没起来。5.5 登录后刷新页面又跳回登录页现象登录成功进入首页按 F5 刷新页面跳回了登录页。原因Vue 是单页应用刷新后内存里的数据全没了。如果登录状态只存在 Vuex 里没写 sessionStorage 或 localStorage路由守卫一刷新就判断未登录。解决登录时把用户信息同步存一份 sessionStorage路由守卫里优先读 sessionStorage刷新时先取本地存储恢复登录状态再渲染。退出登录时清理本地存储。示例// 路由守卫常见于 router/index.js router.beforeEach((to, from, next) { const userInfo sessionStorage.getItem(userInfo) if (to.path /login) { next() } else if (!userInfo) { next(/login) } else { next() } })这也是答辩时老师常点的问题“为什么刷新一下就掉线”提前解决掉能避免现场尴尬。以上五个问题前四个出现在跑通阶段第五个出现在二次开发阶段都和“环境、状态、配置”相关源码本身基本不会有问题。记住排查顺序先看日志再看网络请求最后才改代码。日志是黑匣子的钥匙很多看似玄学的问题日志里一行就写明白了。6. 二次开发把固定角色改成动态权限并给团购加上预扣库存拿到这套源码第一个值得做的改造是权限部分。原系统的用户类型是写死的 user 和 admin 两个值你可以在 user 表加一个 role 字段改成标准的 RBAC 模型这样以后加“团长”“配送员”这种角色不用改表结构。具体改动分三步第一步user 表增加 role 字段保留原 user_type 用于兼容登录接口返回时带上 role前端把角色信息存到 sessionStorage。第二步后端加一个角色校验注解// 自定义角色校验注解标注在需要管理员权限的接口上 RequireRole(admin) GetMapping(/admin/user/list) public Result listUsers() { // 只有 admin 角色能访问 }前端路由守卫同步判断角色非 admin 访问后台路由跳 403 页面。第三步把 IndexAsideStatic.vue.bak 对应的侧边栏改成根据角色动态渲染普通用户登录后看不到管理菜单。第二个值得做的改造在团购模块。现在的团购下单如果是先查库存再 update并发高了会超卖。我一般会把抢购逻辑改成 Redis 预扣库存// 团购开始前把库存预加载到 Redis stringRedisTemplate.opsForValue() .set(groupbuy:stock: groupBuyId, String.valueOf(stock)); // 用户参团时用 Redis 原子递减 Long remain stringRedisTemplate.opsForValue() .decrement(groupbuy:stock: groupBuyId); if (remain null || remain 0) { // 库存不足回滚这个 key stringRedisTemplate.opsForValue() .increment(groupbuy:stock: groupBuyId); return Result.error(手慢了拼团名额已满); }然后再走数据库下单和库存扣减。用 Redis 的原子操作把判断库存和扣库存合并成一步天然避免并发超卖这个设计在论文里可以单独写一小节。改造完这两处系统就从“能跑”升级成了“能讲”权限设计用 RBAC 模型讲高并发库存用 Redis 原子操作讲。论文里每一个改造点都能对应一个小节导师问起来你也有话说。拿到这套源码后我的习惯是先花一个晚上把数据库表和接口对一遍理清楚每个页面对应哪几个接口再动手改。改之前给要动的文件复制一个 .bak 备份——这套源码的作者就是这么干的。从那以后我每次拿到新项目都会强制先梳理一遍数据表关系再改代码这个习惯帮我避开了好几次改到一半回不去的大坑。希望帮到你。本文还有配套的精品资源点击获取