简介:基于Spring Boot实现的电脑商城购物系统完整项目源码,面向Java初学者、毕业设计学生及需要电商项目参考的开发者,帮助快速掌握Spring Boot框架下的业务开发与项目组织方式。系统包含商品分类、商品详情、购物车、订单管理、用户管理、个人中心、收藏等功能模块,并配有MySQL数据库脚本,适合作为课程设计或毕设起点。资源共1170个文件,主要有java源码、html/css/js前端文件、xml配置、png/jpg图片及SQL脚本等,RAR压缩包约47.57MB,目录结构清晰。目前已有802人浏览学习。资源还附带pom.xml依赖管理、Maven包装器、.gitignore等工程化配置,可导入开发工具直接运行与二次开发,为理解电商类Spring Boot项目提供完整参考。
1. springboot购物系统拿到手后,先分清源码和数据库文件的关系
点开这个标题时,大部分人是刚下载了一个 springboot 电脑商城购物系统的项目压缩包,解压后看到里面有一堆 java 代码和一个数据库文件,接下来就不知道该先打开哪个了。实际上这类基于 springboot 的购物系统从结构上非常固定:数据表撑起商品、用户、购物车、订单四件事,Spring Boot 负责把表变成接口,再把接口渲染成页面或者提供给前端调用。标题里出现的“项目源码+数据库文件”是两个互补的交付物,数据库文件决定了业务边界,源码决定运行方式。
我接手或阅读这类项目时,第一步不会急着启动工程,而是先确认三件事:数据库文件是 SQL 脚本还是 mdf 实体文件;Spring Boot 版本与本地 JDK 是否匹配;前端是模板渲染还是前后端分离。顺序错了会遇到“启动时找不到数据源”“表不存在”“JDK 与 Spring Boot 版本冲突”等常见问题。这篇文章会顺着一条可落地的路径讲完:先拆数据库文件反推业务表,再配 springboot 工程的最小可运行环境,最后把商品、购物车、订单这条主链路跑通,并给出排错和验证手段。
2. 先拆 springboot 购物系统的数据库文件,再配置骨架依赖
很多 springboot 毕业设计或练习项目的数据库文件,本质上是一份建库建表脚本,偶尔附带一些初始化数据。不要一上来就在 IDE 里点 Run,先搞清楚表结构,能省掉后面 80% 的联调时间。
2.1 建表脚本和实体数据文件,springboot 项目会遇到哪两种
标题里的“数据库文件”可以指向两种格式,处理方式完全不同。常见的是.sql文本脚本,在 MySQL 或 SQL Server 里直接执行即可;另一种是 SQL Server 2016 常见的物理文件.mdf和.ldf,这类文件需要附加到数据库实例中才能变成可用的库。
区分方法很简单:用文本编辑器打开,看到CREATE DATABASE、CREATE TABLE、INSERT INTO的是 SQL 脚本;文件头是二进制乱码、扩展名是 mdf 的是物理数据库文件。对于第二种,我一般会要求对方同时提供日志文件 ldf,或者要求导出为 sql 脚本。两者选型上没有绝对的好坏,但从 springboot 开发的便捷度看,SQL 脚本更好迁移,能在不同数据库之间快速重建。
CREATE DATABASE IF NOT EXISTS shop_db DEFAULT CHARSET utf8mb4; USE shop_db;这段是导库前最常见的准备工作。先建库,再在库内建表,避免表结构散落在多个 schema 里。
2.2 从 SQL 脚本反推商城表结构:会员、商品、购物车、订单
拿到数据库文件后,不需要把全部表都读完。电商类购物系统的业务主干就那几条,重点是关注这些表之间的外键和状态值。
member(会员):id, username, password, phone, create_time product(商品):id, name, category_id, price, stock, sales, status category(分类):id, name, parent_id cart_item(购物车):id, user_id, product_id, quantity, checked orders(订单):id, order_no, user_id, total_price, status, create_time order_item(订单明细):id, order_id, product_id, product_name, price, quantity以上是商城购物系统最常见的六张核心表。订单和订单明细分离是为了让一个订单容纳多个商品,购物车表里的checked字段表示是否勾选结算,商品表里的stock和sales在后续下单时会被频繁读写,尤其需要注意并发问题。
如果脚本里还有role、permission、user_role这类表,说明权限模块是参照 RBAC 模型实现的。很多 springboot 商城的后台管理功能都挂在管理员角色上,走的是同一套校验。
2.2.1 表关系确认方法:直接看外键和索引
不要靠猜。用数据库客户端打开表结构,检查user_id、product_id、order_id这类字段是否建立了索引,索引名通常是idx_xxx。外键不一定要在物理层建立,但逻辑上一定存在。确认完表关系,再回头看 springboot 实体类,就能快速判断哪张表对应哪个 Mapper。
2.3 用 IDEA 新建一个 springboot 项目并接入数据库文件
拿到别人的项目源码,最稳妥的方式不是从零建项目,而是用 IDEA 直接打开源码目录。IDEA 会识别 pom.xml 并下载依赖。如果源码目录本身不完整,比如缺少.mvn目录或者 mvnw 脚本,仍然可以新建一个 springboot 项目,再把源码里的src目录覆盖进来。
2.3.1 pom.xml 里最少需要的依赖组合
以最常用的spring-boot-starter-web加 MyBatis、MySQL 驱动为例:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.13</version> <relativePath/> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.3.1</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>版本号不建议盲目追高。springboot 版本太高会带来 JDK 版本连锁要求,Spring Boot 3.x 强制要求 JDK 17 及以上,如果本地只有 JDK 1.8,用 2.7.x 是更稳的选择。MyBatis 官方 starter 也要跟 Spring Boot 大版本匹配,2.3.x 配 Boot 2.x 是目前兼容面最广的一组。
2.3.2 application.yml 中的关键配置参数
server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/shop_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.shop.entity configuration: map-underscore-to-camel-case: trueurl 里的serverTimezone必须设置,否则 MySQL 8.x 会报时区错误。map-underscore-to-camel-case用来把数据库里的create_time自动映射为createTime,这是减少实体类配置的重要开关。mapper-locations指向 XML 文件目录,如果你的项目全是注解 SQL,这行可以注释掉。
提示:密码不要写成 root/123456 直接上生产环境。至少换成环境变量注入,比如
${DB_PASSWORD},避免源码泄露后数据库也被撞库。
3. 把购物系统的商品、购物车、订单业务链路写进 springboot 接口
骨架搭好之后,接下来要做的是把数据库文件里的表变成可用接口。这一步是源码阅读和二次开发的重点。很多人拿到源码后不会改,核心原因是没分清 Controller、Service、Mapper 三层各自负责什么。
3.1 商品分页查询:最值得先读的一段代码
购物系统的首页一定会有商品列表。它不是一次性把全表查出来,而是走分页。MyBatis 系项目里最常见的是用 PageHelper 或 MyBatis-Plus 的分页插件。这里给一个标准的 Service 层写法:
public PageResult<ProductVO> pageProducts(int pageNum, int pageSize, String keyword) { Page<Product> page = new Page<>(pageNum, pageSize); LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<>(); wrapper.like(StringUtils.hasText(keyword), Product::getName, keyword) .eq(Product::getStatus, 1) .orderByDesc(Product::getSales); Page<Product> result = productMapper.selectPage(page, wrapper); return PageResult.of(result); }这段代码暴露了三个要点:like条件只有在 keyword 不为空时才拼接,避免空条件导致全表扫描;status = 1过滤掉下架商品,这是电商系统的通用状态约定;按销量倒序让热门商品排前面。PageResult是自定义的统一返回结构,通常包含total、pages、records三个字段,前端拿到后直接渲染分页组件。
3.2 购物车与订单的状态设计
购物车表本身没有复杂状态,真正需要设计的是订单状态。查看数据库文件里的订单表,通常只有一个status字段,我一般建议在代码里用常量或枚举管理它,而不是散落魔法数字:
- 0:待付款
- 1:待发货
- 2:已发货
- 3:已完成
- 4:已取消
下单选购物车流程通常这样配合:前端把勾选的cart_item_id发给后端,后端事务内完成三件事——查购物车明细、计算总价、写入订单和订单明细。其中,订单表生成唯一订单号order_no,用时间戳加用户 ID 加随机数组合。
@Transactional(rollbackFor = Exception.class) public Long createOrder(OrderCreateDTO dto) { // 1. 查出用户勾选的购物车项 List<CartItem> items = cartItemMapper.selectBatchIds(dto.getCartItemIds()); if (items.isEmpty()) { throw new BizException("购物车为空,无法下单"); } // 2. 创建订单主表 Order order = new Order(); order.setOrderNo(generateOrderNo(dto.getUserId())); order.setUserId(dto.getUserId()); order.setTotalPrice(calcTotalPrice(items)); order.setStatus(0); orderMapper.insert(order); // 3. 批量插入订单明细 saveOrderItems(order.getId(), items); // 4. 清空已下单的购物车项 cartItemMapper.deleteBatchIds(dto.getCartItemIds()); return order.getId(); }@Transactional保证四步操作要么全部成功,要么全部回滚,避免出现订单创建了但购物车没清空的情况。generateOrderNo是独立方法,可以复用到支付回调里。
3.3 库存扣减:springboot 商城最容易写错的地方
商品表的stock字段是典型的并发热点。如果不加控制,多个用户同时下单会出现超卖。最简单可靠的方式是使用数据库的行锁条件更新,而不是先查再改。
UPDATE product SET stock = stock - #{count} WHERE id = #{productId} AND stock >= #{count}stock >= #{count}是防超卖的关键,它让数据库在更新时做原子判断。如果影响行数为 0,说明库存不足。Java 侧通过int rows = productMapper.deductStock(productId, count); if (rows == 0) throw new BizException("库存不足");来处理失败分支。这种做法不需要引入 Redis 分布式锁,适合单体 springboot 购物系统起步阶段。
4. 把 springboot 购物系统完整跑起来:数据库导入、启动参数与高频报错
结构读完了,代码看懂了,这时候才轮到真正的运行环节。很多人卡在这一步,因为导入数据库文件时文件格式和字符集出错,或者 springboot 版本与本地 JDK 不一致。
4.1 数据库文件导入实战:sql 脚本和 mdf 都怎么处理
如果你的数据库文件是.sql,最直接的方式是命令行导入,避免图形化客户端在大文件时假死。
mysql -u root -p shop_db < /path/to/shop_db.sql前提是shop_db这个库已经存在。如果文件里已经包含CREATE DATABASE,可以先登录 MySQL 再执行source /path/to/shop_db.sql;。导入完成后,用SHOW TABLES;验证一下核心表是否齐全,重点看product、orders、cart_item是否存在。
如果拿到的是shop_db.mdf这种 SQL Server 2016 数据库文件,则需要先创建空库再附加:
CREATE DATABASE shop_db; -- 在 SSMS 中右键数据库 -> 任务 -> 附加 -> 添加 .mdf 文件附加成功后,检查sys.tables确认表列表。需要注意的是,SQL Server 里order是保留字,表名通常会写成orders或tb_order。你在 springboot 实体类上加@TableName("orders")就能对应上。
4.2 springboot 项目启动流程:先测数据源,再测接口
启动前先确认三件事:JDK 版本与 pom 里java.version一致;MySQL 服务已启动;数据库文件已成功导入。然后在 IDEA 里直接运行启动类:
@SpringBootApplication @MapperScan("com.example.shop.mapper") public class ShopApplication { public static void main(String[] args) { SpringApplication.run(ShopApplication.class, args); } }@MapperScan要指向 Mapper 接口所在包,否则 springboot 无法代理生成实现类。@SpringBootApplication内部已经包含了自动配置和组件扫描,不需要额外标注@EnableAutoConfiguration。
启动成功后,用浏览器访问http://localhost:8080/。如果项目集成了 Swagger 或 Knife4j,可以更方便地在接口文档页里测试每个接口的入参和返回。springboot 开发常用的 swagger2.9.2 版本存在未授权访问漏洞风险,不要在生产环境暴露 doc.html 路径。
4.3 常见启动报错与处理参数表
| 报错现象 | 原因 | 处理方式 |
|---|---|---|
Failed to configure a DataSource | 数据源未配置或配置错误 | 检查 application.yml 中 url、username、password |
Access denied for user 'root'@'localhost' | 数据库密码不对 | 核对密码,或临时把密码改成 root 测试 |
Unknown database 'shop_db' | 数据库文件未导入 | 重新执行 .sql 脚本,确认 CREATE DATABASE 已执行 |
java.lang.UnsupportedClassVersionError | JDK 版本过低 | 改用 JDK 17 或把 springboot 版本降到 2.7.x |
Table 'shop_db.product' doesn't exist | 表名与实体类不匹配 | 检查 @TableName 注解,或把 SQL 中表名改为实际名称 |
表格中第二项和第五项出现频率最高,八成以上的二次开发都是从改密码和改表名开始的。记住一个原则:数据库文件里的表名,和 springboot 实体类上的@TableName,必须一一对应,大小写不敏感但拼写不能错。
5. 用 MockMvc 验证购物链路,再把状态流转做成压测基线
跑通只是开始。拿到的 springboot 购物系统是否可用,要验证的是一条完整的业务流:登录 → 加购物车 → 下单 → 扣库存。这里给一个不依赖前端的验证方式,用 Spring Boot 自带的 MockMvc 完成接口级回归。
5.1 用测试类验证下单核心链路
@SpringBootTest @AutoConfigureMockMvc class OrderFlowTest { @Autowired private MockMvc mockMvc; @Test void testAddCartAndCreateOrder() throws Exception { // 1. 添加商品到购物车 mockMvc.perform(post("/cart/add") .param("userId", "1") .param("productId", "10") .param("quantity", "2")) .andExpect(status().isOk()) .andExpect(jsonPath("$.code").value(200)); // 2. 下单 mockMvc.perform(post("/order/create") .param("userId", "1") .param("cartItemIds", "5,6")) .andExpect(status().isOk()) .andExpect(jsonPath("$.code").value(200)); // 3. 校验商品库存已扣减 mockMvc.perform(get("/product/info").param("id", "10")) .andExpect(jsonPath("$.data.stock").value(8)); } }这里用jsonPath校验返回体里的状态码和库存数值,比打开浏览器反复点击要快得多。如果项目没有返回code字段,就把期望值改成实际约定的字段,核心是断言链路每一步都成功。
5.2 把订单状态流转和超时关单作为进阶方向
购物系统最常见的进阶需求是订单自动取消。在 springboot 里可以有多种实现方式,定期扫描数据库里的超时订单是最容易理解和维护的:
@Component public class OrderTimeoutJob { @Scheduled(cron = "0 */1 * * * ?") public void cancelExpiredOrders() { LocalDateTime deadline = LocalDateTime.now().minusMinutes(30); List<Order> expiredOrders = orderMapper.selectWaitingPayOrders(deadline); expiredOrders.forEach(order -> { order.setStatus(4); // 已取消 orderMapper.updateById(order); // 回补库存:将库存加回去 }); } }@Scheduled让方法每分钟执行一次,selectWaitingPayOrders(deadline)的 SQL 里用WHERE status = 0 AND create_time < #{deadline}就能圈定超时集合。库存回补需要遍历订单明细逐件加回,这一步容易遗漏,特别是订单取消后商品还被其他人买走的情况。
把这个测试类和定时任务作为每次改动后的回归基线,后续加新功能时不用再担心把原有购物链路改坏。这套从数据库文件到最后验证的路径,也完全可以套用在任何基于 springboot 的电商类毕业设计或练手项目上。
本文还有配套的精品资源,点击获取