资讯动态

Spring Boot 商城课设实战:从建库到下单的完整闭环

发布时间:2026/10/23 8:10:54 来源:尧图企业网站定制
简介这份资源是面向计算机及相关专业本科生、研究生的课程设计文档围绕基于Spring Boot的网上购物商城系统展开帮助读者理解Java技术、MySQL数据库与B/S结构在实际电商项目中的落地方式。文档完整覆盖需求分析、系统设计、功能实现与系统测试全过程包含用户、商家、管理员三大模块的注册登录、商品浏览购买、商品信息管理及用户商家管理等内容并给出E-R图与数据库表结构设计测试部分从功能、性能、安全三方面展开可作为课程设计选题、项目开发参考与后续维护扩展的资料。资源包共1个docx文件约3.8MB结构清晰便于查阅。目前已有76人学习适合需要完整电商系统案例与规范文档范式的读者参考。1. 从一份课设文档到能跑起来的商城这套 Spring Boot 资源到底值不值得拆很多同学拿到「基于 Spring Boot 的网上购物商城系统」这类课程设计资源时第一反应是打开文档翻目录看到需求分析、E-R 图、用例图、测试方案一应俱全就觉得稳了。真正动手才发现文档里写的是「用户下单后跳转支付」代码里可能连订单状态机都没建文档说「管理员管理商品分类」数据库里分类表和外键约束对不上。这套资源的真实价值不在于文档写得多完整而在于它给了一套能跑通的最小闭环Java Spring Boot MySQL B/S 结构用户、商家、管理员三个角色注册登录、商品浏览、购物车、订单管理这几条核心链路都有对应的实现思路和表结构设计。适合正在做课设、需要快速搭出一个可演示系统的本科生也适合想拿一个完整案例练手 Spring Boot 增删改查和事务处理的初级开发者。下面我按「先跑通再优化」的顺序把这份资源拆成能直接抄作业的步骤。2. 环境搭建与数据库落地从建表到连上 MySQL2.1 技术选型为什么是 Spring Boot MySQL 而不是别的这套资源选 Spring Boot 不是跟风。课设场景下时间紧、要演示、老师要看「技术栈是否主流」Spring Boot 的内嵌 Tomcat 和自动配置能让你少写一堆 XML把精力放在业务逻辑上。MySQL 作为关系型数据库表结构清晰E-R 图能直接映射成建表语句适合购物车、订单这种强关联场景。B/S 结构意味着你只需要一个浏览器就能演示不用给老师装客户端。如果你换成 NoSQL 或者前后端分离课设的复杂度会翻倍答辩时反而不好解释「为什么用这个」。所以我的建议是先按资源里的技术栈把系统跑起来再考虑加 Redis 缓存或者消息队列做优化。2.2 建库建表把 E-R 图翻译成可执行的 SQL资源里的 E-R 图给了商品分类、商家、订单、管理员、商品五个核心实体。我一般会先把它们落成建表语句注意字段类型和索引。下面这段 SQL 可以直接在 MySQL 里执行建一个shopping_mall库和几张核心表-- 创建数据库字符集用 utf8mb4 支持 emoji CREATE DATABASE shopping_mall DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE shopping_mall; -- 商品分类表分类名唯一避免重复添加 CREATE TABLE category ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(64) NOT NULL UNIQUE COMMENT 分类名称, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; -- 商家表账号唯一余额用 DECIMAL 避免浮点误差 CREATE TABLE merchant ( id BIGINT PRIMARY KEY AUTO_INCREMENT, account VARCHAR(64) NOT NULL UNIQUE COMMENT 登录账号, password VARCHAR(128) NOT NULL COMMENT 加密后的密码, name VARCHAR(64) NOT NULL COMMENT 商家名称, phone VARCHAR(20), email VARCHAR(128), balance DECIMAL(12,2) DEFAULT 0.00 COMMENT 账户余额, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; -- 商品表外键关联分类和商家价格用 DECIMAL CREATE TABLE product ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(128) NOT NULL, category_id BIGINT NOT NULL, merchant_id BIGINT NOT NULL, price DECIMAL(10,2) NOT NULL, stock INT DEFAULT 0 COMMENT 库存, image_url VARCHAR(255), detail TEXT, status TINYINT DEFAULT 1 COMMENT 1上架 0下架, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (category_id) REFERENCES category(id), FOREIGN KEY (merchant_id) REFERENCES merchant(id) ) ENGINEInnoDB; -- 订单表状态字段用 TINYINT 表示待支付/已支付/已发货/已完成 CREATE TABLE orders ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(64) NOT NULL UNIQUE COMMENT 订单编号, user_id BIGINT NOT NULL, total_amount DECIMAL(12,2) NOT NULL, status TINYINT DEFAULT 0 COMMENT 0待支付 1已支付 2已发货 3已完成, address VARCHAR(255) NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB;建表时有两个参数要特别注意utf8mb4是为了支持商品名里的特殊字符DECIMAL是为了金额计算不丢精度。外键约束在课设阶段建议加上能帮你提前发现数据不一致的问题。如果后面插入数据报foreign key constraint fails先检查分类和商家是否已经存在。2.3 Spring Boot 项目初始化与数据库连接配置用 IDEA 的 Spring Initializr 建项目勾选 Spring Web、Spring Data JPA、MySQL Driver、Thymeleaf如果做服务端渲染。pom.xml里关键依赖如下dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependencyapplication.yml里配置数据源注意时区和编码spring: datasource: url: jdbc:mysql://localhost:3306/shopping_mall?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: update # 开发阶段自动建表生产环境改成 none show-sql: true # 控制台打印 SQL方便调试ddl-auto: update在课设阶段很好用实体类改了字段它会自动同步表结构。但要注意它不会删除字段只会新增。如果你把某个字段改名旧字段会留在表里新字段会加上去容易造成数据混乱。我一般会在开发初期用create每次重启清空重建数据稳定后再改成update。3. 用户、商家、管理员三端核心功能实现3.1 注册登录密码加密与角色区分资源里注册流程写了「判断用户名是否存在」登录流程写了「判断用户名和密码是否正确」。实现时最容易翻车的地方是密码明文存储。我一般用 BCrypt 做哈希Spring Security 的BCryptPasswordEncoder可以直接用不引入 Security 的话也可以单独加spring-security-crypto依赖。import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; public class PasswordUtil { private static final BCryptPasswordEncoder encoder new BCryptPasswordEncoder(); // 注册时调用返回加密后的密码存库 public static String encode(String rawPassword) { return encoder.encode(rawPassword); } // 登录时调用比对明文和数据库里的哈希 public static boolean matches(String rawPassword, String encodedPassword) { return encoder.matches(rawPassword, encodedPassword); } }角色区分用一张user表加role字段或者三张独立表。资源里是用户、商家、管理员分开的我建议保持这个设计因为三者的字段差异较大商家有余额、身份证用户有收货地址。登录时根据账号去对应表查询返回不同的角色标识前端根据角色跳转到不同首页。这里有个坑如果三张表都有account字段登录接口要明确告诉前端「当前登录的是哪个角色」否则前端不知道跳哪里。3.2 商品浏览与购物车分页查询和 Session 存储商品列表要分页Spring Data JPA 的Pageable可以直接用GetMapping(/products) public PageProduct listProducts( RequestParam(defaultValue 0) int page, RequestParam(defaultValue 10) int size, RequestParam(required false) Long categoryId) { Pageable pageable PageRequest.of(page, size, Sort.by(createTime).descending()); if (categoryId ! null) { return productRepository.findByCategoryId(categoryId, pageable); } return productRepository.findAll(pageable); }购物车在课设阶段不建议存数据库用 Session 或 Redis 更简单。Session 方案HttpSession里放一个MapLong, Integerkey 是商品 IDvalue 是数量。加入购物车时判断商品是否下架、库存是否足够。这里有个血泪经验如果用户没登录就加购Session 里的购物车在登录后会丢失。常见做法是登录成功后把匿名 Session 的购物车合并到用户购物车或者干脆要求登录后才能加购课设演示时后者更省事。3.3 订单创建与状态流转事务和库存扣减下单是最容易出问题的地方。用户点击「提交订单」时要做三件事扣库存、生成订单、清空购物车。这三步必须在一个事务里否则扣了库存没生成订单或者订单生成了库存没扣都会导致数据不一致。Service public class OrderService { Autowired private ProductRepository productRepository; Autowired private OrderRepository orderRepository; Transactional(rollbackFor Exception.class) public Order createOrder(Long userId, ListOrderItem items, String address) { BigDecimal total BigDecimal.ZERO; for (OrderItem item : items) { // 悲观锁防止并发下单超卖 Product product productRepository.findByIdForUpdate(item.getProductId()); if (product.getStock() item.getQuantity()) { throw new RuntimeException(库存不足 product.getName()); } product.setStock(product.getStock() - item.getQuantity()); productRepository.save(product); total total.add(product.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))); } Order order new Order(); order.setOrderNo(generateOrderNo()); order.setUserId(userId); order.setTotalAmount(total); order.setAddress(address); order.setStatus(0); // 待支付 return orderRepository.save(order); } }Transactional(rollbackFor Exception.class)里的rollbackFor很关键默认只回滚RuntimeException如果你抛的是受检异常事务不会回滚。findByIdForUpdate需要在 Repository 里用Lock(LockModeType.PESSIMISTIC_WRITE)注解这样并发下单时第二个请求会等第一个完成避免超卖。课设演示时并发量不大但加上这个能让你在答辩时多一个亮点。4. 避坑与排查课设系统最容易翻车的五个地方4.1 中文乱码从数据库到页面的全链路排查现象商品名或地址里的中文在页面上显示成问号或乱码。原因通常是数据库字符集不是utf8mb4或者 JDBC URL 没加characterEncodingutf8。解决先执行SHOW VARIABLES LIKE character%;确认character_set_database是utf8mb4不是的话用ALTER DATABASE shopping_mall CHARACTER SET utf8mb4;修改。然后检查application.yml里的 URL 参数确保有useUnicodetruecharacterEncodingutf8。最后检查 Thymeleaf 模板的meta charsetUTF-8。4.2 外键约束导致删不掉数据现象删除商品分类时报Cannot delete or update a parent row: a foreign key constraint fails。原因是有商品关联了这个分类。解决要么先删除关联商品要么在删除分类时把商品的category_id置空或移到默认分类。课设阶段我一般会在 Service 层做检查如果分类下有商品直接返回「该分类下还有商品不能删除」而不是让数据库抛异常。4.3 订单状态和支付状态混在一起现象用户支付后订单状态没变或者管理员看到的状态和用户看到的不一致。原因是把「订单状态」和「支付状态」塞进了一个字段。解决拆成两个字段order_status表示待支付/已支付/已发货/已完成pay_status表示未支付/已支付/已退款。这样支付回调只改pay_status发货只改order_status逻辑清晰。资源里的订单实体图只画了一个状态字段实际实现时建议拆开。4.4 Session 丢失导致购物车清空现象用户登录后购物车里的商品没了或者刷新页面后购物车空了。原因是 Session 超时或者服务重启。解决开发阶段把server.servlet.session.timeout设长一点比如3600s。如果用了 Nginx 做负载均衡还要考虑 Session 共享课设阶段一般不会涉及但如果你在本地起了多个实例记得用 Redis 存 Session。4.5 测试用例只测了正常流程现象答辩时老师问「如果用户没登录直接访问订单页面会怎样」你发现系统报 500 错误。原因是只写了正常流程的测试没测边界。解决至少补三类测试——未登录访问受保护页面、库存为 0 时下单、订单金额和商品总价不一致。Spring Boot 里可以用MockMvc写集成测试也可以手动在浏览器里开无痕窗口模拟未登录状态。5. 从能跑到能答辩三个进阶技巧和验证方法5.1 用统一返回体包装接口前端处理更省心课设系统里 Controller 返回的数据格式五花八门有的返回String有的返回Map前端处理起来很乱。我一般会定义一个ResultT类public class ResultT { private int code; // 200成功500失败 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 fail(String msg) { ResultT r new Result(); r.code 500; r.msg msg; return r; } }Controller 里统一返回Result.success(...)或Result.fail(...)前端只需要判断code是否为 200。这样异常处理也统一了用ControllerAdvice捕获全局异常返回Result.fail(e.getMessage())避免把堆栈信息暴露给用户。5.2 用 Postman 或 curl 做接口冒烟测试答辩前我会把核心接口用 curl 跑一遍确认没有 500 错误。比如测试商品列表分页# 测试商品列表第一页每页5条 curl -X GET http://localhost:8080/products?page0size5 -H Accept: application/json # 测试登录接口注意密码要传明文后端会做哈希比对 curl -X POST http://localhost:8080/login \ -H Content-Type: application/json \ -d {account:testuser,password:123456,role:user}如果返回{code:200,msg:操作成功,data:{...}}就说明接口通了。如果返回 500去看控制台日志通常是数据库连接失败或者实体映射错误。这个习惯能帮你在答辩前发现 80% 的低级问题。5.3 数据库备份和初始化脚本课设演示前一定要把数据库导出成 SQL 文件万一演示时数据被改乱了可以快速恢复。用mysqldump命令mysqldump -u root -p shopping_mall shopping_mall_backup.sql恢复时用source命令mysql -u root -p shopping_mall shopping_mall_backup.sql我还会在项目里放一个init.sql包含建库建表和几条测试数据这样换一台电脑也能快速把环境搭起来。测试数据至少要有两个分类、两个商家、每个商家三个商品、一个测试用户、一条已完成订单。这样演示时每个页面都有数据不会出现空白页。从那以后我每次拿到课设资源都强制自己先跑一遍「建库 → 启动 → 注册 → 下单 → 查订单」这条最小闭环确认能跑通再去看文档里的细节。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑