每年到毕设季,后台私信里总挤满了"有没有现成的Java项目可以参考"这种话。我做过的 Spring Boot 毕业设计项目不止一个,飘香水果购物网站算是我做得比较满意的一版。这不是那种几十行代码糊弄事的半成品,而是一个业务闭环完整的 B2C 电商系统,从用户注册、商品浏览、购物车、下单支付,到后台的商品管理和订单处理,整条链路都是通的。源码和 SQL 脚本我已经整理好了,免费分享出来,需要的同学可以直接拿去参考、二次开发。
这篇内容我会讲清楚几个维度:项目选了哪些技术,为什么这么选;数据库表是怎么设计的;核心业务代码——尤其是下单和库存扣减——到底该怎么写;前端页面怎么跟后端对接;最后是我实际运行过程中踩过的坑,以及论文、答辩准备的一些建议。内容偏实操,按顺序看完,基本能自己把项目从零搭出来。
1. 这个选题到底香在哪里
1.1 为什么选水果购物网站而不是千篇一律的管理系统
毕设选题最怕什么?不是题目难,而是做完之后连自己都讲不清"这个项目到底解决了什么问题"。很多同学选各种"管理系统"——学生管理系统、图书馆管理系统、员工考勤系统,代码写完之后,天天就是对几张表做增删改查,答辩时老师问一句"业务难点在哪",全场安静。
购物网站项目就不太一样。电商天然是一个有商品、有用户、有流程、有状态的业务场景,系统里有明显的数据流转:用户浏览商品、加购物车、下单、支付、后台发货、用户确认收货。这一条链路串下来,可讲的东西一下子就有了层次,从需求分析到数据库设计,从接口调试到事务处理,每一步都有实实在在的业务逻辑在里头。
再说选水果这个品类,其实也是个小心机。水果有分类(热带、时令、进口),有时效性和库存概念,可以做折扣、做限时抢购、做销量排行,甚至还能写一个简单的"根据销量推荐热卖水果"的小功能。这些业务细节会让系统看起来更完整,答辩时讲故事也能讲得更生动。见过太多人做"手机商城""服装商城",水果购物网站反而让人眼前一亮。
1.2 技术选型背后的逻辑:为什么 Spring Boot 是毕设首选
Spring Boot 能成为 Java 毕设的事实标准,不是没有原因的。传统 SSM 项目要写一大堆 XML 配置,光是 Spring、SpringMVC、MyBatis 之间的整合就够折腾几天,一不小心还配置冲突。Spring Boot 最大的价值,是把框架整合的痛苦降到最低,内嵌 Tomcat 服务器,一个java -jar就能起服务。你做毕设遇到什么情况最多?答辩演示时环境出问题。Spring Boot 的一键启动特性,直接帮你把翻车概率降下来一大截。
但版本选择上有个很现实的坑:Spring Boot 3.x 必须配合 JDK 17 使用,而且很多第三方依赖在新版框架下要做兼容适配;Spring Boot 2.7.x 则比较仁慈,JDK 8 就能跑。我实际见过太多同学,电脑上装的 JDK 8,却用骨架生成了 Spring Boot 3.x 的项目,最后连编译都过不去,还一脸懵。
注意:先确认 JDK 版本,再选 Spring Boot 版本。如果学校机房统一是 JDK 8,老老实实选 Spring Boot 2.7.x;如果自己电脑装的是 JDK 17 或更高,再考虑上 3.x。别小瞧这个选择,它决定了你后面几天是顺利还是踩坑。
除了 Spring Boot,项目里还用了这些核心组件:
- MyBatis-Plus:负责数据库操作,手写 SQL 可控性更好,答辩时聊 SQL 也接得住;
- MySQL 8.0:主数据库;
- Redis:做登录会话缓存和热点数据缓存;
- Vue3 + Element Plus:搭前台页面和后台管理页面;
- MinIO(可选):做商品图片文件存储。
1.3 整体功能地图:用户端和管理端各做什么
项目按角色分为两端,我习惯叫"用户端"和"管理端",也可以用"前台/后台"来理解。
用户端(前台)核心模块:
- 注册登录:手机号或用户名加密码,登录后用 token 维持会话;
- 首页展示:轮播图、热卖水果、新品推荐、分类导航;
- 商品模块:按分类浏览、关键字搜索、商品详情页展示价格、库存、销量、详情介绍;
- 购物车:加购、修改数量、删除商品、勾选结算;
- 订单模块:确认订单、模拟支付、订单列表、订单详情、取消订单;
- 个人中心:收货地址管理、头像上传、个人信息修改。
管理端(后台)核心模块:
- 仪表盘:简单统计今日订单数、销售额、商品总数等;
- 商品管理:商品添加、编辑、删除、上下架状态切换、库存调整;
- 分类管理:商品分类的增删改,支持一级分类;
- 订单管理:订单列表、查看订单明细、订单发货操作;
- 用户管理:查看注册用户列表、禁用或启用用户。
两端共用同一套后端接口,只是权限不同。用户和管理员各自登录到不同角色,后台接口通过拦截器校验权限。
2. 从零搭起:环境准备与项目初始化
2.1 开发环境版本搭配建议
先说版本,因为毕设项目七八成的坑都出在环境上。我推荐的方案是这些:
| 组件 | 版本建议 | 关键说明 |
|---|---|---|
| JDK | 8 或 17 | JDK8 配 Boot 2.7.x,JDK17 配 Boot 3.x,别混搭 |
| Maven | 3.8 及以上 | 配置阿里云镜像,下载依赖速度会明显提升 |
| MySQL | 8.0 | 连接串里要加时区参数,否则会报错 |
| Redis | 5.0 及以上 | Windows 下可以直接启动官方提供的压缩包 |
| Node.js | 16 及以上 | 前端构建需要,Vue3 + Vite 依赖这个版本 |
| IDEA | 2022 或更高 | 社区版免费完全够用 |
这里有个容易忽略的点:Maven 一定要配置国内镜像。默认中央仓库在国内下载依赖极慢,一个项目拉几百个 jar 包,卡到怀疑人生。配置方法很简单,在~/.m2/settings.xml里加入阿里云镜像地址即可,具体写法网上随手就能搜到,这里不贴了。
2.2 创建 Spring Boot 项目骨架
建项目用两种方式任选:一是 IDEA 内置的 Spring Initializr,打开 File -> New -> Project -> Spring Initializr;二是直接用浏览器打开 start.spring.io 在线生成,然后解压导入 IDEA。
依赖勾选建议:
- Spring Web:提供 MVC 能力,Controller 层靠它;
- MySQL Driver:连接数据库的驱动;
- MyBatis-Plus:如果用的 Boot 3.x,记得引入
mybatis-plus-spring-boot3-starter版本; - Lombok:简化实体类代码;
- Validation:参数校验;
- Spring Data Redis:接入 Redis。
骨架拉下来以后,用 IDEA 打开,先把 Maven 仓库刷完。第一次导入项目会慢,但只要镜像配置没问题,基本上几分钟就能完成。刷完依赖之后不要急着写业务代码,先把工程分层建好。我的分包结构是这样的:
com.fruitshop ├── controller // 接口层 ├── service // 业务逻辑层 ├── mapper // 数据访问层(MyBatis-Plus) ├── entity // 数据库实体类 ├── dto // 请求/响应对象 ├── config // 配置类(拦截器、跨域、静态资源映射) ├── common // 统一返回结果、业务异常、常量 └── utils // 工具类(订单号生成、JWT等)这种分包方式主流、清晰,老师看代码印象也会更好。
2.3 application.yml 核心配置
项目跑起来以后,第一件事就是把配置文件写好。下面是我实际用到的一套核心配置,以 Spring Boot 2.7.x + MySQL 8.0 为例:
server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/fruit_shop?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true username: root password: 你自己的密码 driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 password: database: 0 servlet: multipart: max-file-size: 10MB max-request-size: 20MB mybatis-plus: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl很多人在连接串这里踩坑,我提醒三点:
serverTimezone=Asia/Shanghai不写,MySQL 8.0 会报时区错误;useSSL=false建议加上,本地开发时减少不必要的握手干扰;allowPublicKeyRetrieval=true不写,MySQL 8.0 会报一个非常经典的错误,具体名称下面踩坑环节再讲。
MyBatis-Plus 的map-underscore-to-camel-case开启后,数据库的user_name能自动映射到实体的userName,省掉一大堆手写映射。log-impl设置成 StdOutImpl,控制台会直接打印 SQL,调试时非常有用,答辩现场也能给老师展示你的 SQL 日志。
3. 数据库设计与核心代码实现
3.1 核心表设计
数据库设计是整个项目的地基。我第一次做这个项目的时候,一开始只设计了六张表,后来发现少了一张地址表,又从订单表里拆出来,反复改了好几次代码。每次改表的教训都是:初期必须把表结构设计完整再动手写代码。
这个项目最终用的是八张表:
| 表名 | 说明 | 核心字段 |
|---|---|---|
| user | 用户表 | id, username, password, nickname, phone, avatar, role, status |
| category | 商品分类表 | id, name, sort, create_time |
| product | 商品表 | id, category_id, name, image, price, stock, sales, status, detail |
| cart | 购物车表 | id, user_id, product_id, quantity, checked |
| orders | 订单表 | id, order_no, user_id, total_price, status, receiver_name, receiver_phone, receiver_address, create_time, pay_time |
| order_item | 订单明细表 | id, order_id, product_id, product_name, product_image, price, quantity |
| address | 收货地址表 | id, user_id, name, phone, province, city, district, detail, is_default |
| banner | 轮播图表 | id, image, link, sort, status |
这里面最关键的是 orders 表和 order_item 表。一张订单对应多条订单明细,通过 order_id 关联,这是电商系统最标准的"主从表"结构。为什么订单明细里要冗余商品名称和图片?因为商品表里的信息可能会变,但订单是历史数据,应该保留下单那一刻的商品快照。这个细节在答辩时特别加分,能体现业务理解。
order_no 订单号要唯一,我用的生成规则是:时间戳加用户ID后四位加随机三位数,拼接完存进数据库,并加唯一索引,防止并发场景下重复。
3.2 统一返回结果与异常处理
接口设计上,强烈建议项目一开始就定好统一的返回格式。前端的 axios 请求封装也要依赖它。我的返回体设计如下:
{ "code": 200, "message": "操作成功", "data": {} }对应的 Java 类:
@Data public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> success(T data) { Result<T> r = new Result<>(); r.setCode(200); r.setMessage("操作成功"); r.setData(data); return r; } public static <T> Result<T> error(Integer code, String message) { Result<T> r = new Result<>(); r.setCode(code); r.setMessage(message); return r; } }再配一个全局异常处理器,用@RestControllerAdvice捕获业务异常和参数校验异常,Controller 里就不用到处写 try-catch 了。全局异常处理的好处是,不管哪里报错,返回给前端的格式都一致,前端统一弹出错误提示。
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(BusinessException.class) public Result<Void> handleBusinessException(BusinessException e) { return Result.error(e.getCode(), e.getMessage()); } @ExceptionHandler(MethodArgumentNotValidException.class) public Result<Void> handleValidException(MethodArgumentNotValidException e) { return Result.error(400, e.getBindingResult().getAllErrors().get(0).getDefaultMessage()); } }这个阶段别忘了用 Lombok,实体类上都加@Data,自动生成 getter/setter,代码量会少很多。
3.3 下单流程怎么保证数据一致性
购物网站最核心的业务,也是答辩时最高频被问的一个点,就是下单。先描述场景:用户从购物车勾选商品,点击结算,后端需要做四件事——生成订单、生成订单明细、扣减库存、清空购物车。这四件事必须在一个事务里完成,任何一步失败,都不能留下脏数据。
我写的核心下单逻辑大概是这样的:
@Transactional(rollbackFor = Exception.class) public Order createOrder(OrderCreateRequest request) { // 1. 校验用户地址 Address address = addressMapper.selectById(request.getAddressId()); // 2. 生成订单号 String orderNo = generateOrderNo(userId); // 3. 保存订单主表 Order order = new Order(); order.setOrderNo(orderNo); order.setUserId(userId); order.setStatus(OrderStatus.PENDING_PAYMENT); order.setReceiverName(address.getName()); // ... 设置商品总价、支付时间等 orderMapper.insert(order); // 4. 遍历购物车勾选项,写入订单明细并扣库存 for (CartItem item : cartItems) { Product product = productMapper.selectById(item.getProductId()); // 条件更新库存,防止并发超卖 int rows = productMapper.deductStock(product.getId(), item.getQuantity()); if (rows == 0) { throw new BusinessException(500, "商品【" + product.getName() + "】库存不足"); } OrderItem orderItem = new OrderItem(); orderItem.setOrderId(order.getId()); orderItem.setProductId(product.getId()); orderItem.setProductName(product.getName()); orderItem.setProductImage(product.getImage()); orderItem.setPrice(product.getPrice()); orderItem.setQuantity(item.getQuantity()); orderItemMapper.insert(orderItem); } // 5. 清空购物车对应商品 cartMapper.deleteByUserIdAndProductIds(userId, productIds); return order; }这里重点说一下库存扣减的 SQL。如果只是简单写UPDATE product SET stock = stock - #{count} WHERE id = #{id},并发下单时会出现超卖问题——两个请求同时读到同一个库存余量,各自都扣了一次,库存直接扣成负数。我用的写法是加一个stock >= #{count}条件:
UPDATE product SET stock = stock - #{count} WHERE id = #{id} AND stock >= #{count}通过 UPDATE 影响行数判断:返回 0 说明库存不足,抛业务异常让整个事务回滚。这样实现简单,压力测试下也不会超卖,对新手很友好,不需要引入复杂的锁机制,但能在答辩时清楚讲出"为什么这样设计"——这就是加分项。
3.4 登录鉴权:拦截器加 Redis 会话
登录这块,我采用的是比较主流的 token 方案:用户登录成功后,服务端生成一个随机 token,以token为 key、userId为 value 存进 Redis,并设置过期时间,比如 30 分钟。之后前端每次请求都带上这个 token,后端用一个拦截器统一校验。
为什么用 Redis 不用 session?主要原因两个:一是前后端分离模式下,session 跨域处理比较麻烦;二是 Redis 天然支持过期时间,token 过期管理简单,以后项目要扩容部署多台服务器,Redis 里的会话状态也能共享。
拦截器示例:
public class LoginInterceptor implements HandlerInterceptor { private final StringRedisTemplate redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("Authorization"); if (StringUtils.hasText(token)) { String userId = redisTemplate.opsForValue().get("token:" + token); if (userId != null) { request.setAttribute("userId", userId); return true; } } response.setStatus(401); return false; } }再把拦截器注册到 WebMvcConfig 里,排除掉登录注册、商品列表、商品详情等公开接口,其他接口统一走拦截器。这里要注意:管理员接口路径建议统一以/admin开头,再单独写一个管理员权限拦截器,专门校验登录用户是不是管理员角色。两个拦截器分开写,职责更清晰,扩展性也好很多。
4. 前端页面与文件上传:让项目"能看"比"能跑"更重要
4.1 前端技术选型与页面结构
毕设项目如果只把后端接口做齐,是撑不住分数的。老师打开浏览器,看到页面还是上个年代的风格,第一印象就大打折扣。我的建议是用 Vue3 + Element Plus。Element Plus 组件颜值在线,表单、表格、弹窗、分页都有现成组件,后台管理页面写起来效率极高,前台页面也可以拿它做基础风格。
前端工程分两个入口:
- 用户端页面:首页、商品列表、商品详情、购物车、结算页、订单列表、个人中心;
- 管理端页面:登录页、仪表盘、商品管理、分类管理、订单管理、用户管理。
路由结构简单说一下:用户端走/下的公共路由,管理端走/admin下的路由。管理端路由统一挂一个requiresAdmin的路由守卫,登录后没有管理员标识的跳回用户端首页。这个小设计在答辩演示时很加分,因为可以现场演示"普通用户访问不到后台接口"这个权限控制效果。
4.2 前端如何和后端无缝对接
前端发请求我用 axios,统一封装一个 request 工具,配置baseURL和拦截器:请求拦截器里带上 token,响应拦截器里统一处理 401(未登录)、500(业务异常)、200(正常返回 data)。这样每个页面调用接口的时候,代码可以写得很干净,不用每个接口都重复一遍错误处理。
有一点必须提醒:开发阶段会遇到跨域问题。解决方式有三种,任选其一:
- 后端配置
@CrossOrigin或全局 CORS 配置; - 前端在 Vite 里配置代理;
- 直接把前端打包产物放进 Spring Boot 的静态资源目录,同源访问,彻底避开跨域。
我自己最终采用的是第三种,因为省心,部署也方便。
4.3 前端打包放进 Spring Boot
之前不少人问过"vue 打包放进 springboot 中"这个问题,看起来基础,实际坑不少。我再把踩过的坑讲一遍。
前端工程执行npm run build之后,dist目录里会生成index.html和assets等文件夹。把这个目录下所有内容复制到 Spring Boot 的src/main/resources/static目录下,然后重新打包启动 Spring Boot,访问http://localhost:8080/index.html就是前端页面,接口同源,CORS 问题直接消失。
注意打包前确认 Vite 配置里的base是相对路径./,否则部署后静态资源会找不到。前端路由建议用 hash 模式,也就是createWebHashHistory,这样部署到静态目录后刷新页面不会出现 404。
4.4 商品图片上传与 MinIO 整合
商品要有图片,图片就得有存储方案。最简单的方式是本地存储:Spring Boot 配置一个静态资源映射目录,上传的文件写入磁盘,通过http://localhost:8080/upload/xxx.jpg访问,毕设演示场景下完全够用。
如果想在项目里体现更强的工程能力,可以整合 MinIO。用 Docker 一条命令就能起一个 MinIO 服务:
docker run -p 9000:9000 -p 9001:9001 minio/minio server /data --console-address ":9001"然后在 Spring Boot 里加入依赖io.minio:minio,配置好 endpoint、accessKey、secretKey、bucketName,写一个简单的FileStorageService,上传文件时生成唯一文件名,返回可访问的 URL。MinIO 的好处是文件不占应用服务器磁盘,服务重启不丢数据,结构也更接近生产环境。时间充裕的同学建议加上,答辩时老师问"图片存哪里",你讲一套对象存储方案,层次一下子就上去了。
5. 踩坑实录:我跑这个项目时遇到的高频问题
5.1 环境与版本类问题
这类问题占了所有问题的六成,我把高频问题整理成速查表:
| 问题现象 | 原因 | 解决方案 |
|---|---|---|
| MySQL 连接报错,提示 Public Key Retrieval is not allowed | MySQL 8.0 默认认证插件需要公钥 | 连接串加allowPublicKeyRetrieval=true |
| 启动报时区错误 | 数据库时区与本地不一致 | 连接串加serverTimezone=Asia/Shanghai,或执行set global time_zone='+8:00' |
| 项目启动后端口被占用 | 上一个进程没退出 | 改server.port,或找到对应进程并结束 |
| 依赖下载超慢 | Maven 没配国内镜像 | 在 settings.xml 配置阿里云 mirror |
| 导入项目后一堆红叉 | Maven 仓库损坏或版本冲突 | 执行mvn clean install并刷新 Maven 仓库 |
5.2 代码与配置类问题
除环境外,代码层面的坑也不少。
第一个是 MyBatis-Plus 的自动填充时间字段。很多人新建商品时发现create_time是 null,原因是没有配置 MetaObjectHandler,或者数据库里的默认值没设置好。我的建议是双保险:数据库所有时间字段都设置默认值CURRENT_TIMESTAMP,实体里用@TableField(fill = FieldFill.INSERT)配合自动填充处理器。
第二个是前台上传图片后,刷新页面图片 404。这通常是 Spring Boot 静态资源映射没配好。上传目录在磁盘上时,需要在配置里加资源映射:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/upload/**") .addResourceLocations("file:/绝对路径/upload/"); } }第三个是 JSON 序列化报错,比如 LocalDateTime 字段返回给前端变成一段很丑的数字。解决方法是配置 Jackson 时间格式:
spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai5.3 部署与演示前的最后检查清单
答辩演示当天最容易翻车的,是演示前才发现某些功能没法用了。我整理了一份每次演示前必过的检查清单,照着走一遍,基本不会出意外:
- 启动 MySQL 和 Redis,确认端口正常;
- 用初始化 SQL 重建数据库,保证数据是最新状态;
- 启动 Spring Boot 后,检查控制台没有异常日志;
- 用两个浏览器分别测试用户端和管理端的登录;
- 走一遍核心流程:注册,浏览商品,加购物车,下单,模拟支付,后台发货;
- 提前准备几个演示账号和若干条商品数据,最好包含一个库存极低的商品,现场演示"库存不足"的异常提示,反而更有看点;
- 如果学校机房网络不稳定,提前确认前端已经打进后端,离线也能完整演示;
- 准备一张项目目录结构截图和数据库 ER 图放 PPT 里,避免现场打开 IDEA 找文件时干等。
6. 论文与答辩:把代码变成分数
6.1 毕业论文结构怎么搭
很多代码能力强的人,论文反而是短板。其实毕设论文有很成熟的结构模板,按照学校要求套就行,我建议的框架是这样:
| 章节 | 内容 | 大致篇幅 |
|---|---|---|
| 第一章 绪论 | 背景与意义、国内外研究现状、主要工作 | 4000字左右 |
| 第二章 相关技术介绍 | Spring Boot、Vue、MySQL、Redis 等 | 3000字左右 |
| 第三章 需求分析 | 可行性分析、业务流程、功能需求、非功能需求、用例图 | 4000字左右 |
| 第四章 系统设计 | 架构设计、功能模块图、数据库设计(ER 图和表结构) | 5000字左右 |
| 第五章 系统实现 | 每个核心模块的实现截图加关键代码片段 | 5000字左右 |
| 第六章 系统测试 | 测试环境、功能测试用例、测试结果 | 3000字左右 |
| 总结与展望 | 总结项目亮点和不足 | 1000字左右 |
数据库设计这一章,别只贴建表 SQL,一定要画 ER 图,用 PowerDesigner 或 draw.io 都可以,画清楚主从表关系。系统实现这一章,不要整段贴大段代码,挑核心逻辑——下单事务、拦截器、库存扣减——贴小段关键代码加解释就够了。论文查重时,代码块一般不计重复,但文字描述一定要用自己的话组织,别直接抄开源项目的 README。
6.2 答辩演示的黄金十分钟
答辩一般就十分钟左右,节奏很关键。我自己的演示顺序是固定的,分享给各位参考:
第一步,用一分钟讲清楚项目做什么:飘香水果购物网站,一个基于 Spring Boot 的 B2C 电商系统,用户能购买水果,管理员能管理商品和订单。
第二步,用两分钟讲技术亮点:前后端分离、Redis 做会话与缓存、MyBatis-Plus 手写 SQL 扣库存、事务保证订单数据一致性、MinIO 做对象存储。
第三步,用四分钟现场演示:重点走一条主线,在前台注册一个新账号,浏览水果,加购,下单,模拟支付,然后切到后台管理端发货,同时穿插演示商品搜索、购物车数量修改、订单状态变化这些细节。
第四步,用两分钟展示数据库设计和代码:打开 ER 图和核心表,再打开订单 Service 的@Transactional代码,讲清楚为什么这么写。
剩下的时间留给老师提问。平时最常被问的问题,我顺手整理了一遍:
- 为什么订单表要单独存商品快照?——商品信息可能变化,订单必须保留历史数据;
- 库存扣减怎么防超卖?——条件更新加事务回滚;
- Redis 里存了什么?——登录 token 和首页热卖商品的缓存;
- 项目有哪些不足?——支付是模拟的、缺少更精细的权限校验、前端没有做单元测试。承认不足但要强调"我知道如何改进",可以说"下一步可以接入真实支付沙箱、引入 Spring Security 做更细粒度授权"。
写在最后:一点真实的项目心得
这个项目我做完花了大约两周的正常课余时间,算上写论文的话四周左右。回头复盘,最值得分享的经验是:先画表再写代码,先把接口定好再对接页面。我前期因为贪快,表设计改过两次,导致后面 Service 层代码也连带重写。这个教训后来每次带队做项目都会提。如果你准备拿这个项目做毕设,建议不要直接全部照抄,可以把品类换成别的、加上一个评论功能,或者设计一个优惠券模块,改动之后系统就是你的了,答辩的时候你能讲得更有底气。
需要完整源码和初始化 SQL 的同学,可以按这篇步骤自己搭一份,也可以留言给我。我再补一句:做毕设的过程本身比分数更重要,等你把下单事务、库存扣减、权限拦截这几个点真正讲明白,你能明显感觉到自己确实入门了 Java 企业级开发。祝顺利。