1. 项目概述
这个基于SpringBoot的网上家具商城系统是一个典型的B2C电商平台,专为课程设计和毕业设计场景打造。作为一个完整的全栈项目,它涵盖了从商品展示、购物车管理到订单处理的完整电商业务流程,非常适合计算机相关专业学生用来练手或作为毕业设计作品。
我在实际开发过程中发现,家具类电商系统相比普通电商有些特殊需求:商品需要展示多角度图片、支持3D模型预览(可选)、提供材质选择功能,以及考虑大件商品的物流计算。这些特性使得该项目比普通电商系统更具挑战性和学习价值。
2. 技术选型与架构设计
2.1 核心技术栈
- SpringBoot 2.7.x:作为基础框架,提供了快速启动和自动配置的优势
- Thymeleaf:服务端模板引擎,适合教学场景的简单前后端交互
- MyBatis-Plus:简化数据库操作,内置常用CRUD方法
- MySQL 8.0:关系型数据库存储核心业务数据
- Redis:缓存热点数据和购物车信息
- Bootstrap 5:前端UI框架,快速构建响应式界面
提示:选择2.7.x而非最新3.x版本,是因为教学环境下更稳定且兼容性更好
2.2 系统架构
采用经典的三层架构:
- 表现层:处理HTTP请求和页面渲染
- 业务逻辑层:实现核心业务规则和流程
- 数据访问层:与数据库交互,持久化数据
额外增加了:
- 公共工具层(utils)
- 配置层(config)
- 实体模型层(model)
3. 数据库设计详解
3.1 核心表结构
-- 用户表 CREATE TABLE `user` ( `id` bigint NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL, `password` varchar(100) NOT NULL, `phone` varchar(20) DEFAULT NULL, `address` text, PRIMARY KEY (`id`) ); -- 商品表(特别注意家具特有字段) CREATE TABLE `product` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `price` decimal(10,2) NOT NULL, `stock` int NOT NULL, `category_id` bigint NOT NULL, `material` varchar(50) DEFAULT NULL, -- 材质 `dimensions` varchar(50) DEFAULT NULL, -- 尺寸 `weight` decimal(10,2) DEFAULT NULL, -- 重量 PRIMARY KEY (`id`) ); -- 订单表(含家具特有字段) CREATE TABLE `order` ( `id` bigint NOT NULL AUTO_INCREMENT, `order_no` varchar(50) NOT NULL, `user_id` bigint NOT NULL, `total_price` decimal(10,2) NOT NULL, `delivery_type` tinyint DEFAULT 1, -- 1普通 2大件 `installation` tinyint DEFAULT 0, -- 是否含安装 PRIMARY KEY (`id`) );3.2 设计要点
- 商品属性扩展:除了常规字段,特别添加了材质、尺寸等家具特有属性
- 物流考量:订单表中包含配送类型和安装服务标志
- 图片存储:采用单独的商品图片表,支持多图展示
- 索引优化:在常用查询字段(如商品名称、分类)上建立索引
4. 核心功能实现
4.1 商品模块
// 商品服务实现示例 @Service public class ProductServiceImpl implements ProductService { @Autowired private ProductMapper productMapper; @Override public Page<Product> getByCategory(Long categoryId, int page, int size) { Page<Product> pageInfo = Page.of(page, size); LambdaQueryWrapper<Product> query = new LambdaQueryWrapper<>(); query.eq(Product::getCategoryId, categoryId); return productMapper.selectPage(pageInfo, query); } // 家具特有方法:按材质筛选 public List<Product> getByMaterial(String material) { LambdaQueryWrapper<Product> query = new LambdaQueryWrapper<>(); query.eq(Product::getMaterial, material); return productMapper.selectList(query); } }4.2 购物车设计
采用Redis+数据库双存储方案:
- 未登录用户:购物车数据存Redis(有效期7天)
- 已登录用户:同步到数据库持久化存储
// 购物车服务关键代码 public void addToCart(Long userId, Long productId, int quantity) { // 检查库存 Product product = productService.getById(productId); if(product.getStock() < quantity) { throw new BusinessException("库存不足"); } // 已登录用户操作数据库 if(userId != null) { Cart cart = cartMapper.selectByUserAndProduct(userId, productId); if(cart != null) { cart.setQuantity(cart.getQuantity() + quantity); cartMapper.updateById(cart); } else { cart = new Cart(userId, productId, quantity); cartMapper.insert(cart); } } // 未登录用户操作Redis else { String key = "cart:temp:" + getSessionId(); redisTemplate.opsForHash().increment(key, productId.toString(), quantity); redisTemplate.expire(key, 7, TimeUnit.DAYS); } }4.3 订单流程
- 预下单:校验库存、计算总价
- 创建订单:生成订单号、保存主订单
- 创建子订单:保存订单商品明细
- 扣减库存:使用乐观锁防止超卖
- 支付回调:处理支付结果
// 订单创建关键代码 @Transactional public String createOrder(OrderDTO orderDTO) { // 1. 校验并锁定库存 List<OrderItem> items = checkStock(orderDTO); // 2. 计算总价(含家具特有逻辑:大件商品运费) BigDecimal total = calculateTotal(items, orderDTO.getDeliveryType()); // 3. 创建订单 Order order = new Order(); order.setOrderNo(generateOrderNo()); order.setUserId(orderDTO.getUserId()); order.setTotalPrice(total); order.setDeliveryType(orderDTO.getDeliveryType()); order.setInstallation(orderDTO.getInstallation()); orderMapper.insert(order); // 4. 保存订单项 items.forEach(item -> { item.setOrderId(order.getId()); orderItemMapper.insert(item); }); // 5. 实际扣减库存 reduceStock(items); return order.getOrderNo(); }5. 特色功能实现
5.1 家具3D展示(可选)
使用Three.js实现简单的3D模型展示:
<div id="product-3dview" style="width:500px;height:400px;"></div> <script> // 初始化场景 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, 500/400, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(500, 400); document.getElementById('product-3dview').appendChild(renderer.domElement); // 加载家具模型 const loader = new THREE.GLTFLoader(); loader.load('/models/sofa.glb', function(gltf) { scene.add(gltf.scene); camera.position.z = 5; function animate() { requestAnimationFrame(animate); gltf.scene.rotation.y += 0.01; renderer.render(scene, camera); } animate(); }); </script>5.2 大件物流计算
public BigDecimal calculateDeliveryFee(BigDecimal weight, String province, int deliveryType) { // 基础运费 BigDecimal fee = BigDecimal.ZERO; // 大件商品特殊计算 if(deliveryType == 2) { fee = new BigDecimal("100"); // 基础大件运费 // 按重量加价 if(weight.compareTo(new BigDecimal("50")) > 0) { fee = fee.add(weight.subtract(new BigDecimal("50")) .multiply(new BigDecimal("2"))); } // 偏远地区附加费 if(isRemoteArea(province)) { fee = fee.add(new BigDecimal("50")); } } return fee; }6. 部署与运行
6.1 开发环境配置
- JDK 1.8+
- Maven 3.6+
- MySQL 8.0
- Redis 5.0+
# 克隆项目 git clone https://github.com/example/furniture-mall.git # 导入数据库 mysql -u root -p < db/furniture_mall.sql # 修改配置 vim src/main/resources/application.yml # 启动项目 mvn spring-boot:run6.2 关键配置项
spring: datasource: url: jdbc:mysql://localhost:3306/furniture_mall?useSSL=false username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 password: mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl7. 常见问题与解决方案
7.1 开发阶段问题
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 启动时报数据库连接错误 | 1. 数据库服务未启动 2. 配置信息错误 | 1. 检查MySQL服务状态 2. 核对application.yml配置 |
| 页面显示乱码 | 1. 未设置UTF-8编码 2. 数据库字符集问题 | 1. 在application.yml中添加spring.http.encoding.force=true2. 检查MySQL字符集是否为utf8mb4 |
| 图片上传失败 | 1. 上传目录不存在 2. 权限不足 | 1. 创建upload目录 2. 检查目录读写权限 |
7.2 业务逻辑问题
库存超卖问题
- 现象:多人同时购买时库存可能出现负数
- 解决方案:
SQL实现:@Transactional public boolean reduceStock(Long productId, int quantity) { Product product = productMapper.selectById(productId); if(product.getStock() < quantity) { return false; } // 使用乐观锁 int rows = productMapper.updateStock(productId, quantity, product.getVersion()); return rows > 0; }UPDATE product SET stock = stock - #{quantity}, version = version + 1 WHERE id = #{id} AND version = #{version}
订单超时未支付
- 使用Redis的key过期事件通知
- 配置Redis监听:
@Component public class OrderExpireListener extends KeyExpirationEventMessageListener { @Override public void onMessage(Message message, byte[] pattern) { String expiredKey = message.toString(); if(expiredKey.startsWith("order:unpaid:")) { String orderNo = expiredKey.split(":")[2]; orderService.cancelUnpaidOrder(orderNo); } } }
8. 项目扩展建议
增加推荐系统
- 基于用户浏览历史实现协同过滤推荐
- 使用Redis的Sorted Set存储用户偏好
接入第三方支付
- 集成支付宝/微信支付SDK
- 实现支付结果异步通知处理
后台管理系统
- 使用Vue+ElementUI开发独立管理端
- 增加销售统计、用户行为分析功能
物流跟踪
- 对接快递100等物流查询API
- 在订单详情页显示物流轨迹
移动端适配
- 开发微信小程序版本
- 使用uniapp跨端框架
这个项目在实际开发中,我发现最需要关注的是家具类商品特有的业务逻辑处理。比如大件商品的运费计算、是否需要安装服务等细节,这些都需要在产品设计阶段就考虑清楚。另外,商品展示方面,除了常规图片,有条件的话建议增加360°展示功能,这对家具销售非常有帮助。