
做了几年的 Java 后端也带过不少做毕设的学弟学妹SpringBoot Vue 这种前后端分离的组合几乎快成了选题区的“标准答案”。这不后台又有人问我能不能用一套网上超市项目做参考把全栈开发的流程捋一遍。网上超市这个题目确实经久不衰功能边界清晰既有 C 端用户的下单购物流程又有 B 端管理的商品、订单、用户维护流程技术点覆盖全做起来也不会像“图书管理系统”那样显得单薄。这篇文章我不打算只丢给你一份源码链接那样没什么意义。我直接把整个网上超市平台的项目结构、数据库设计、后端接口逻辑、前端页面交互以及部署时容易踩的坑全部拆开讲。你看完就算不直接用这套代码也能清楚自己动手写的时候每一步该怎么走。别担心前端基础弱Vue 部分我会从环境搭起讲后端如果你只学过 SSM 或刚接触 SpringBoot也能跟得上。如果是准备拿它当毕设或者课设那更要仔细看第三节和第六节一个是数据库设计一个是答辩前必查的部署细节都是拿分关键。1. 项目整体定位与功能拆解网上超市本质上就是一个垂直电商系统只不过售卖的商品以日用百货、零食生鲜这类超市品类为主。它和淘宝京东这类平台型电商最大的区别在于业务边界更收敛不会涉及商家入驻、多店铺、复杂的营销中台等重逻辑但一个电商系统该有的核心链路——用户浏览商品、加购物车、生成订单、模拟支付、后台管理——全都要有这就是它适合做毕设课设的根本原因。1.1 这套系统解决的是什么问题从学习者的角度看这套系统解决的是“如何用一套主流技术栈把一个真实业务场景落地”的问题。你在学校里的课程作业大多是单机的、单一页面的比如写一个 Java 控制台版本的图书管理或者用 JSP Servlet 做一个简单的 CRUD。但到了毕设阶段要求明显会上一档要有完整的前端页面、要有 RESTful 接口、要有数据库设计文档、要有部署说明。网上超市这个题目正好处在“课程作业”和“企业级项目”之间的合理位置。它的功能足够多可以拆出十几个 REST 接口但每个功能的业务规则又不算复杂不会出现高并发秒杀、分布式事务这类短期很难掌握的深水区。换句话说在有限的时间内完整跑通这套项目你的收获是最成体系的。1.2 我建议你按四个模块来理解这个项目整个平台建议分成四个大模块去看这四个模块也基本对应了源码包的目录结构用户端商城模块商品分类浏览、商品搜索、商品详情、购物车管理、订单确认与提交、个人中心收货地址、订单记录、修改密码。后台管理模块管理员登录、商品上架下架、商品分类维护、库存管理、订单状态管理发货、完成、用户管理禁用/启用。公共支撑模块统一登录认证、文件上传商品图片、分页查询、全局异常处理、接口返回结果的统一封装。报表统计模块可选加分项用户数、订单量、销售额的简单统计图表展示。如果你打算把分数往上拉一拉这个模块是性价比最高的增强点后端只需要多写几个 count 和 sum 的聚合 SQL前端用 ECharts 画几个图就行。注意不管你有没有拿到现成源码动手第一步一定是先把模块边界切出来再往里面填功能。很多人拿到手就直接跑起来然后从首页开始一行行看代码很容易绕晕。正确姿势应该是先跑通项目然后用“用户下单”这条主线把前后端代码串着走一遍剩下的再单独看。1.3 技术栈版本选择说明先说版本这是我被问得最多的问题因为网上很多老项目的版本太旧导入 IDEA 之后各种依赖冲突。建议的版本组合如下Windows/Mac 都能用JDK 1.8 或 17注意如果用的是 SpringBoot 2.7.x请务必用 JDK 8SpringBoot 3.x 必须配 JDK 17我自己测试用的是 JDK 8 SpringBoot 2.7.18最稳定网上查资料也好查。Maven 3.6.3 以上用来管理后端依赖。MySQL 5.7 或 8.0这里建议直接装 8.0编码问题上更省心。Vue 2 Element UI 搭配最成熟因为网上的组件案例和搜到的错误解决方案大部分都是 Vue 2 的Vue 3 Element Plus 也可以但遇到宝藏级报错的时候能搜到的内容相对少。前端构建工具Vue CLI 4.x 或 5.x不建议新手上来就用 Vite配置上容易多出一些麻烦。这套组合的好处在于SpringBoot 2.7.x 对 JDK 8 的兼容性极好而 Vue 2 的生态资料量几乎是碾压级的多。你如果是为了毕设答辩用最成熟的方案永远是最优解不要在这个时候追求技术要新。2. 核心流程设计与前后端交互逻辑很多同学拿到项目之后先急着看代码我建议先对着我下面这张交互逻辑描述体会一遍对整个系统的数据流转心里有数了后面看代码就是“看一个熟悉的故事”而不是“读一本天书”。2.1 一条订单的完整生命周期一个网上超市系统最核心的流程就是用户从登录到下订单再到管理员发货的完整链路。这条链路你务必要搞明白因为答辩的时候老师最喜欢让你画的就是业务流程图。第一步用户在前端登录输入账号密码后端收到请求后先做校验密码正确就生成一个 Token 返回给前端。前端拿到 Token 存入本地存储后续每一次请求都在请求头里带着它。第二步用户在商品列表页找到想买的商品点击“加入购物车”前端把商品 ID 和数量发给后端后端的购物车服务会在数据库的购物车表里写入一条记录或者更新已有记录的数量。第三步用户在购物车页面勾选商品并点击“去结算”跳转到订单确认页选择收货地址点击“提交订单”。这时候后端会做两件事一是把订单主表和订单明细表的数据插入数据库二是把购物车里被勾选的对应商品记录删除。第四步用户点击“模拟支付”后端把订单状态从“待付款”改为“待发货”。这里不需要真的接支付宝微信用一个接口模拟状态流转即可这是毕设常见的合法简化方式答辩时如实说明就行。第五步管理员在后台看到新订单点击“发货”订单状态变成“待收货”。用户在前端点“确认收货”状态变成“已完成”。如果用户申请退款管理员可以审核退完之后订单变成“已退款”。这个过程中订单状态是整个系统的“神经中枢”。我见过太多人把订单状态管理得乱七八糟前后端各存一套状态码导致对不上。建议在前后端都定义一套常量枚举统一约定0 待付款1 待发货2 待收货3 已完成4 已退款5 已取消。2.2 前后端分离下的接口约定前端和后端跑在不同的端口上比如前端 8080后端 9090它们之间靠 HTTP JSON 接口通信。这里有个关键要点跨域问题。如果不处理浏览器会拦截前端的请求这是新手第一次跑前后端分离项目的必修课。后端的处理方式是在 SpringBoot 里写一个 WebMvcConfigurer 配置类重写 addCorsMappings 方法允许前端地址跨域访问Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }同时在前后端之间约定一个统一的返回结果类 Result 所有的接口都返回这个结构前端才能用同一套逻辑处理成功和失败。定义一个 Result 类很简单包含 code、msg、data 三个字段public class ResultT { private Integer code; private String msg; private T data; // 省略getter/setter和构造方法 }前端 axios 封装里统一判断 code 是否为 200不是就直接弹出错误提示。这样写的好处我多说一句不仅是对毕设实际工作中前后端联调也是这么约定的提前养成习惯没有坏处。2.3 为什么要用 JWT 做登录认证网上超市有两种角色普通用户和管理员。如果每次请求都要告诉后端“我是谁”最粗暴的办法是把用户 ID 传过去但这样任何人都可以伪造身份。这里用的是 JWTJSON Web Token方案用户登录成功后后端生成一个 Token 字符串里面用密钥签名前端保存。后续的请求带上这个 Token后端解析验证通过后就知道是谁了。JWT 不太好理解的话你可以把它想象成一张“游乐场手环”。买票的时候工作人员给你戴上之后玩每个项目只需要亮一下手环工作人员一眼就能看出来你有没有资格、是哪种票不需要再去查数据库确认。它的好处是无状态、易于扩展后端不用在服务器保存会话信息非常适合前后端分离架构。有的项目也会用 Spring Security JWT 的综合方案功能更强大但学习成本高一点。如果你是为了毕设可以只用 JWT 拦截器做一个轻量级的认证效果足够代码还更好解释。这是我在实际教学里验证过很多次的取舍。3. 数据库设计网上超市的“地基”数据库设计是整个项目的灵魂甚至可以说评审老师拿到项目第一眼看什么通常不是你的页面漂不漂亮而是你的数据库表设计合不合理。下面我把这套系统的核心数据表全部列出来字段我都按实际落库规格标注了你可以把它当作一份可直接参考的建表模板也可以对照自己手里的源码去理解。3.1 核心数据表清单与字段解析用户表 user字段包括 user_id主键、username用户名、password密码加密后保存、nickname昵称、avatar头像、phone手机号、status状态0正常 1禁用、create_time创建时间。商品分类表 categorycategory_id主键、name分类名如生鲜果蔬、休闲零食、sort排序权重、icon分类图标地址。商品表 productproduct_id主键、category_id归属分类、name商品名、subtitle副标题、main_image主图、detail详情描述富文本、price价格用 Decimal 类型、stock库存、sales销量、status上下架状态0下架 1上架、create_time。购物车表 cartcart_id主键、user_id用户、product_id商品、quantity数量、checked是否勾选用于结算时只处理勾选项、create_time、update_time。这里建议加一个 UNIQUE 约束user_id, product_id保证同一个用户对同一商品只会有一条购物车记录重复添加时做数量累加。订单主表 ordersorder_id主键、order_no订单编号建议用时间戳随机数生成展示给用户看、user_id下单人、total_amount订单总金额、pay_amount实付金额如果做了优惠则区分、status订单状态、address_snapshot收货地址快照、create_time、pay_time、deliver_time、finish_time。这里我特别说一下 address_snapshot 这个字段订单提交的时候把用户的收货地址原样保存一份到订单里而不是通过 address_id 去关联地址表。因为地址信息未来可能被用户修改如果订单只存 ID用户改完地址之后历史的订单发货信息也会跟着变这在电商业务里是低级错误。地址快照是电商系统设计的常识写进项目里绝对是加分项。订单明细表 order_itemitem_id主键、order_id所属订单、product_id、product_name、product_image、price下单时的单价、quantity数量、total_price小计。明细表里冗余了商品名称和图片同样是为了避免商品信息变更后历史订单数据错乱。收货地址表 shipping_addressaddress_id主键、user_id、receiver_name收货人、receiver_phone、province、city、district、detail_address、is_default是否默认地址。管理员表 adminadmin_id主键、username、password、nickname、role角色。轮播图表 banner可选商城首页的广告图banner_id、image_url、link_url、sort。这些表之间的关联关系一句话概括用户下订单订单包含多条明细每一条明细对应一个商品用户维护多个收货地址下单时把选中地址快照进订单管理员维护商品和分类商品归属于一个分类。建好这些表整个后台管理的数据模型就完整了。3.2 外键该不该加很多教材里教你要加外键约束但实际企业开发里绝大部分项目会主动去掉物理外键只在应用中维护逻辑关联。原因是物理外键会导致插入和更新时的性能开销在数据量大和并发场景下还会造成锁竞争。毕设项目数据量小加与不加在性能上没区别但如果你在数据库设计说明里写上“采用逻辑外键而非物理外键提升系统可扩展性”答辩老师会觉得你有工程意识。同时公共字段不要漏掉几乎每张业务表都建议带 create_time 和 update_time用 datetime 类型update_time 可以在应用层更新也可以用数据库的 ON UPDATE CURRENT_TIMESTAMP 自动维护。展示数据的时候按 create_time 倒序排列——这是很多毕设项目里常见的排序规则别弄反了。3.3 初始化数据的重要性我见过不少同学项目代码写得没问题但运行起来首页空荡荡的因为数据库里没数据。你拿这套项目去跑一定要确认 SQL 脚本里包含了基础的分类数据和商品数据。如果源码里没有你也可以自己写一个数据初始化脚本插入 10 个分类、每个分类 5~10 条商品、1 个管理员账号和 1 个测试用户账号。别小看这一步答辩演示的时候数据库有数据和没数据给人留下的印象差了不止一个档次。还需要注意 MySQL 8.0 和 5.7 的差异如果你安装的是 MySQL 8.0数据库驱动要引入 mysql-connector-java 8.x 以上并且连接 URL 要写成 jdbc:mysql://localhost:3306/supermarket?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8mb4。serverTimezone 这个参数特别关键不写的话经常会报时区相关的错误。4. 后端实现重点SpringBoot 接口与业务逻辑后端是整个项目的“大脑”。我带你走一遍几个重点模块的实现逻辑你可以一边看一边对照自己的代码看看有没有思路上的差异、有没有可以优化的地方。4.1 项目分层与典型代码组织SpringBoot 后端项目的代码分包建议按技术职责分而不是按功能模块分这样代码结构最清晰。一个经典的包结构如下com.example.supermarket ├── common // 公共类Result返回封装、全局异常、常量、JWT工具类 ├── config // 配置类CORS配置、拦截器注册 ├── controller // 控制层接收前端请求 ├── service // 业务层业务逻辑接口 │ └── impl // 业务实现类 ├── mapper // 数据访问层MyBatis的Mapper接口 ├── entity // 实体类对应数据库表 └── dto / vo // 参数接收对象与视图返回对象Controller 只做参数接收和结果返回不写具体业务逻辑业务判断放在 Service 层数据操作放在 Mapper 层。这是最基础也是最重要的规范如果源码里有人把 SQL 写在 Controller 里那一定是反例你要花力气去改掉。4.2 商品搜索接口的实现思路商品列表页是用户端的第一个核心页面。它要支持分类筛选、关键字模糊搜索、分页加载。对应的接口是 GET /api/product/list参数包括 categoryId、keyword、pageNum、pageSize。后端实现用 MyBatis 动态 SQL 拼接查询条件select idselectProductList resultTypecom.example.supermarket.entity.Product SELECT * FROM product where if testcategoryId ! null AND category_id #{categoryId} /if if testkeyword ! null and keyword ! AND (name LIKE CONCAT(%, #{keyword}, %) OR subtitle LIKE CONCAT(%, #{keyword}, %)) /if AND status 1 /where ORDER BY sales DESC, create_time DESC LIMIT #{offset}, #{pageSize} /select这里最关键的是排序规则按销量排序在超市场景下是“默认好货优先”的体验同时按创建时间倒序可以保证新上的商品能被看到。分页用 LIMIT 偏移量即可数据量不大不需要引入 PageHelper 这类插件保持代码简单。4.3 购物车与订单的并发问题购物车和订单是后端业务里逻辑最重的部分也最容易出问题。先说购物车。核心是“原子性”问题如果用户快速点击两次“加入购物车”数据库里不应该出现两条相同的商品记录而应该变成一条记录数量加 2。解决方案就是前面提到的唯一约束加上数据库层面的 INSERT ... ON DUPLICATE KEY UPDATE或者先查后更新用事务保证。MyBatis 的写法长这样insert idinsertOrUpdateCart INSERT INTO cart(user_id, product_id, quantity, checked, create_time, update_time) VALUES(#{userId}, #{productId}, #{quantity}, 1, NOW(), NOW()) ON DUPLICATE KEY UPDATE quantity quantity #{quantity}, update_time NOW() /insert再往后就是提交订单。真正复杂的是事务用户提交订单时需要同时操作订单主表、订单明细表、商品库存表、购物车表任何一个步骤失败整条链路都应该回滚。在 SpringBoot 里直接在 Service 方法上标注 Transactional 注解即可Transactional(rollbackFor Exception.class) public OrderVO submitOrder(OrderSubmitDTO dto) { // 1. 生成订单主记录状态置为待付款 // 2. 批量插入订单明细 // 3. 扣减商品库存库存不足要抛异常触发回滚 // 4. 删除购物车中已勾选的记录 // 5. 返回订单号 }这里有个细节新手很容易漏扣减库存之前要判断库存是否充足并且库存字段不能减成负数最简单的办法是 SQL 里带上 stock #{quantity} 条件受影响行数为 0 就说明库存不足直接抛出异常。这样才能保证在高并发场景下虽然在毕设里你不一定能测到并发但面试一定会问不会超卖。4.4 管理端统计与文件上传管理端首页需要一个数据概览通常包含“用户总数、商品总数、今日订单数、今日销售额”这几个数字。实现起来不难写四个聚合查询 SQL 就好。Response 返回一个 Map 或单独的 VO。我建议你把销售额的统计时间范围做成可配置的入参传一个 startTime 和 endTime前端默认传今天 0 点到当前时刻这样答辩的时候可以直接在页面上演示“某时间段内订单分布图表”。文件上传是一个看起来很“低端”但人人都要做的功能商品图片上传。后端接口通常是 POST /api/admin/upload接收 MultipartFile 参数保存到项目本地的 upload 目录然后返回一个可访问的 URL。这里有两个关键点第一你需要配置一个资源映射让 SpringBoot 能把本地的图片目录映射成静态资源 URL否则你保存了图片但浏览器访问不到Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceLocations(file: System.getProperty(user.dir) /upload/); } }第二保存文件名不要用原始文件名用 UUID 重新生成避免中文文件名乱码和同名文件覆盖。5. 前端实现要点Vue 页面与工程化配置如果你之前主要写后端Vue 部分可能是你心里最没底的一块。实际上毕设级别的前端没有想象中那么难掌握了页面组件划分和几个常用操作你完全可以自己调通。下面我挑几个“卡脖子”的地方详细讲。5.1 前端工程创建与依赖安装前端项目用 Vue CLI 创建在命令行执行 vue create supermarket-web选择 Vue 2 预设。依赖方面除了 Vue 本体一般还需要安装axiosHTTP 请求库用来调后端接口。element-ui桌面端组件库表格、表单、弹窗都能直接用它。vue-router前端路由管理页面跳转。vuex状态管理用来存储用户登录信息和购物车数量如果项目够简单用 localStorage 也能替代。这里我强烈提醒一句安装依赖时建议使用 npm并且把镜像源切换为国内镜像源虽然不能提具体的工具但建议搜索“npm 国内镜像配置”会有很多教程否则依赖下载速度会让你怀疑人生。安装完成后用 npm run serve 启动 Vue 开发服务器。5.2 路由设计与页面组件划分前端页面分为用户端和管理端两套布局。用户端路由如下/首页展示轮播图、分类导航、热卖商品。/product-list商品列表页支持左侧分类 顶部搜索。/product-detail/:id商品详情页展示图片、价格、库存、加入购物车按钮。/cart购物车页面。/checkout订单确认页从购物车跳转过来。/orders订单列表页。/login、/register登录与注册页。管理端单独挂在 /admin 路径下包含 /admin/dashboard数据概览、/admin/product商品管理、/admin/category分类管理、/admin/order订单管理、/admin/user用户管理等页面。组件的划分原则很简单一个完整的页面就是一个 Vue 文件页面里的公共部分比如商品卡片、分页器、搜索框抽成单独组件。不要为了抽组件而抽组件页面少就直接放在页面里反而更直观。5.3 axios 封装与路由守卫所有请求都通过一个统一的 request 工具发出去这是工程化最基本的习惯。核心逻辑是import axios from axios const request axios.create({ baseURL: http://localhost:9090/api, // 后端接口前缀 timeout: 10000 }) // 请求拦截器自动带 token request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[token] token } return config }) // 响应拦截器统一处理业务错误 request.interceptors.response.use( response { const res response.data if (res.code ! 200) { this.$message.error(res.msg) } return res }, error { this.$message.error(网络异常请确认后端服务是否启动) return Promise.reject(error) } )路由守卫主要解决“未登录不能访问个人中心或后台”这个问题。在 vue-router 里注册全局前置守卫判断 localStorage 中是否有 token没有就跳转登录页router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.path.startsWith(/admin) !token) { next(/login) } else { next() } })5.4 购物车数量与状态联动前端最容易出现“bug”的地方是购物车和订单确认页之间的状态联动。举个例子用户在购物车页面全选点击“去结算”订单确认页显示的是勾选商品的总额而不是购物车全部商品的总额。这个数据传递方式建议用 Vuex 管理在全局状态里维护一个 cartList 和 checkedList购物车页面修改状态时同步更新 Vuex订单确认页从 Vuex 里读取。对于毕设项目来说这个设计已经足够清晰了不要搞一堆本地事件总线来传递数据调试起来会非常痛苦。6. 本地部署与常见问题排查项目写完了或者拿到源码了怎么把它跑起来这是另一个高频问题很多人的项目本身没问题是栽在环境配置上。下面我把标准步骤和踩坑记录写全。6.1 部署运行的标准步骤后端部分安装 JDK 8 并配置 JAVA_HOME 环境变量。安装 Maven 并配置本地仓库地址。在 MySQL 里创建数据库 supermarket执行源码提供的 init.sql 脚本。导入后端项目到 IDEA等待 Maven 自动下载依赖修改 application.yml 里的数据库账号密码。运行主类执行 SpringBoot 启动看到“Started Application”即成功。前端部分安装 Node.js建议 14.x 或 16.x 版本Vue 2 项目不要用太新的 Node容易出兼容问题。在项目目录下执行 npm install 安装依赖。检查 src/api 目录下封装的 baseURL 是否指向后端地址。执行 npm run serve浏览器访问 http://localhost:8080。6.2 高频问题排查速查表问题现象可能原因解决办法后端启动报 java.sql.SQLException: Access denied数据库密码错误或账号不存在核对 application.yml 中 username 和 password后端启动报 Unknown database supermarket还没有创建数据库先在 MySQL 中执行 CREATE DATABASE supermarket前端请求接口报 404后端接口路径或 baseURL 不匹配在浏览器控制台 Network 面板里比对实际请求路径与后端 RequestMapping前端请求接口报 Network Error后端没启动、跨域未配置或端口不一致确认后端已启动且前端 baseURL 端口与后端 server.port 一致页面能登录但发不了请求token 相关报错后端没有配置拦截器放行登录接口在拦截器排除 /api/user/login 和 /api/user/register 路径商品图片显示不出来图片未上传或资源映射缺失确认图片文件存在后检查 addResourceHandlers 配置npm install 报 ERESOLVE 错误Node 版本过高依赖冲突降低 Node 版本或使用 npm install --legacy-peer-deps6.3 答辩演示前必须检查的五个细节第一个提前准备好演示数据。后台登录之后尽量保留一些真实的商品、订单或用户数据不要只留几条空白记录。答辩的时候打开展示数据越饱满说服力越强。第二个理清“启动顺序”。先把 MySQL 启动再启动后端最后启动前端。如果后端启动失败页面空转没法演示。你自己心里要有这个顺序以免答辩现场手忙脚乱。第三个改一个“标识性细节”。建议把系统名称换成你自己的项目名称页面上的 Logo、浏览器标题、数据库名都统一改掉。很多答辩老师会问“这个项目是你自己做的吗”如果你的页面标题还是源码里默认的旧名字会给你带来很不好的第一印象。第四个准备一份“亮点清单”。我随便列几个你看自己的项目里有没有没有的话赶紧补JWT 登录、事务处理提交订单、全局异常处理器、Excel 导出订单列表可选加分项。答辩时主动说“我用了 JWT 做无状态登录在数据库层面加了唯一约束来保证购物车幂等”效果会比你被动回答问题好太多。第五个验证“演示链路完整顺畅”。从管理员登录开始到商品上架再到用户登录、下单、模拟支付然后切到管理员后台看订单消息、点发货再回到用户端确定收货。全流程走一遍确认每一步顺滑无报错这是答辩前最值得花时间做的演练。7. 项目扩展与避坑心得最后聊几个我自己带人过程中反复强调的扩展方向和容易踩的坑这可能比前面的技术细节更值钱。7.1 三个高性价比的扩展方向如果基础功能都做完了想加点让项目“看起来不普通”的内容我比较推荐下面三个方向。它们实现的难度都不高但都是写进论文和答辩展示的亮点。第一个是购物车幂等性设计。结合前面提到的数据库唯一约束与 INSERT ... ON DUPLICATE KEY UPDATE写一段“如何防止购物车重复提交”的设计说明。这个点涵盖了对数据库特性、并发控制、接口幂等的理解面试时也是加分项。第二个是前端数据可视化。在后台管理的数据概览页用 ECharts 画一个近七天订单趋势图或商品销量 Top10 柱状图。数据来源很简单后端写一个“按日期分组统计订单数”的接口前端拿到数据直接渲染。这个功能视觉冲击力很强很多老师看了会有眼前一亮的感觉。第三个是小程序端的适配选做。如果你时间充裕可以尝试把一个商品展示页做成 uni-app 版的同一个前端代码能同时跑小程序和 H5。不过我不建议作为毕设必做项因为会引入不少额外的前端编译问题影响你完成核心目标的时间。7.2 那些没人提醒你容易踩的坑时序问题当你第一次启动后端如果提示端口被占用默认是 9090直接找到占用进程关掉或者在 application.yml 里改 server.port。但要注意改完端口后前端 axios 的 baseURL 也要同步改这个遗忘率极高。数据库时区问题数据库连接串里一定要加 serverTimezoneAsia/Shanghai不然差 8 个小时订单创建时间会错乱。不要问我为什么强调这个我至少帮别人排查过十次以上类似问题。依赖版本问题SpringBoot 2.7.x 对应 MyBatis 的 starter 应该用 mybatis-spring-boot-starter 2.x 系列不要配成 3.x 的否则会启动报错。这个细节我记得特别清楚因为很多新手在网上随意复制坐标很容易就翻车。MySQL 驱动也同理5.x 和 8.x 对应不同的驱动类名。自己从零配置项目时统一用下面这组坐标就不会出太大问题。dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.2/version /dependency7.3 最后的进阶建议网上超市这个题目看似简单但如果你想通过它学到“面向真实开发的思维”可以试着给自己加一个约束严格按照 RESTful 规范来定义接口把 Controller、Service、Mapper 三层彻底分离尽量在代码里加上统一异常处理和参数校验。学校里很多时候只要求“能跑就行”但这点思维方式的转变往往比技术本身更能帮你从学生过渡到开发者。这套项目的意义不在于“交差”而在于让你完整地经历一次思考、设计、实现、排错的全过程。把数据库表设计多花点时间想清楚把一条订单主链路彻底跑通再配合上面的扩展点和避坑清单我相信不管你用它做毕设还是拿来练手都能收获实实在在的工程能力。我个人见过太多人拿到了源码也只是跑通就跑非常可惜。建议你拿到手之后先把数据库表结构和主链路代码读一遍然后自己动手改几个功能、加几个新需求这样它在答辩以及后续找实习的面试里才会真正变成拿得出手的项目经历。