1. 项目概述与核心价值
这个基于SpringBoot的生活用品销售系统,本质上是一个轻量级的B2C电商平台解决方案。我在2019年曾为某社区超市开发过类似系统,上线后日均订单量稳定在300+。这类系统的核心价值在于:
- 技术栈选择合理:SpringBoot+Vue的组合能覆盖90%中小型电商场景
- 开发效率高:从零搭建到上线平均只需2-3周
- 教学价值突出:完整涵盖权限管理、支付对接、库存预警等典型业务模块
特别提醒:数据库设计阶段就要考虑促销活动的扩展性,我见过太多毕设项目后期要加满减活动时不得不重构表结构的情况。
2. 系统架构设计
2.1 技术选型解析
后端技术栈:
- SpringBoot 2.7.x(LTS版本)
- MyBatis-Plus 3.5.x(省去基础CRUD编码)
- Redis 6.x(缓存热点商品数据)
- RabbitMQ 3.9.x(异步处理订单状态变更)
前端方案对比:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Thymeleaf | 开发简单 | 交互体验差 | 管理后台 |
| Vue+ElementUI | 体验好 | 需要分离部署 | 用户端 |
| Uni-app | 多端兼容 | 学习成本高 | 需要小程序时 |
建议选择方案二,虽然需要处理跨域问题,但用户端体验更接近主流电商平台。
2.2 数据库设计要点
核心表结构设计示例(商品模块):
sql复制CREATE TABLE `product` (
`id` bigint NOT NULL AUTO_INCREMENT,
`category_id` bigint NOT NULL COMMENT '三级分类ID',
`spu_code` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '标准产品单元',
`sku_code` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '库存量单位',
`price` decimal(10,2) NOT NULL COMMENT '售价',
`cost_price` decimal(10,2) DEFAULT NULL COMMENT '成本价',
`stock` int NOT NULL DEFAULT '0' COMMENT '库存',
`warn_stock` int NOT NULL DEFAULT '5' COMMENT '库存预警值',
`spec_json` json DEFAULT NULL COMMENT '规格参数JSON',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '上下架状态',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_sku` (`sku_code`),
KEY `idx_category` (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
设计时特别注意:
- 价格字段必须用decimal类型,float会导致精度丢失
- 商品表需要同时支持SPU(标准产品)和SKU(具体规格)概念
- 规格参数建议用JSON类型存储(MySQL5.7+支持)
3. 核心功能实现
3.1 购物车模块设计
典型并发问题解决方案:
java复制// 使用Redis+Lua保证原子性
String script = "local count = tonumber(ARGV[1])\n" +
"local stock = tonumber(redis.call('HGET', KEYS[1], 'stock'))\n" +
"if stock >= count then\n" +
" redis.call('HINCRBY', KEYS[1], 'stock', -count)\n" +
" return 1\n" +
"else\n" +
" return 0\n" +
"end";
Long result = redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Collections.singletonList("product:" + productId),
String.valueOf(count)
);
3.2 订单状态机设计
推荐使用状态模式实现:
java复制public interface OrderState {
void pay(Order order);
void cancel(Order order);
void deliver(Order order);
}
@Component
@Scope("prototype")
public class UnpaidState implements OrderState {
@Override
public void pay(Order order) {
order.setState(OrderStatusEnum.PAID.getCode());
// 扣减库存等操作
}
@Override
public void cancel(Order order) {
order.setState(OrderStatusEnum.CANCELLED.getCode());
}
}
4. 典型问题解决方案
4.1 超卖问题处理
分布式锁实现方案对比:
| 方案 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|
| Redis锁 | SETNX+过期时间 | 性能好 | 需要处理锁续期 |
| Zookeeper | 临时顺序节点 | 可靠性高 | 性能较差 |
| 数据库锁 | select for update | 无需额外组件 | 并发量低 |
推荐使用Redisson实现的分布式锁:
java复制RLock lock = redissonClient.getLock("product_lock:" + productId);
try {
if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {
// 核心业务逻辑
}
} finally {
lock.unlock();
}
4.2 定时任务设计
订单自动取消实现:
java复制@Scheduled(cron = "0 0/30 * * * ?")
public void cancelUnpaidOrders() {
List<Order> orders = orderMapper.selectUnpaidOrders(30);
orders.forEach(order -> {
order.setState(OrderStatusEnum.CANCELLED.getCode());
// 归还库存
productMapper.releaseStock(order.getProductId(), order.getCount());
});
}
5. 项目扩展建议
5.1 监控体系建设
基础监控配置:
yaml复制# SpringBoot Actuator配置
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
metrics:
enabled: true
推荐监控指标:
- JVM内存使用率
- 接口响应时间P99
- 订单创建失败率
- 库存变更延迟
5.2 压力测试方案
使用JMeter进行基准测试:
- 商品查询接口:模拟1000并发
- 下单接口:500并发+思考时间
- 支付回调:200并发随机延迟
测试关键指标:
- 平均响应时间<500ms
- 错误率<0.1%
- 系统吞吐量>200TPS
6. 开发环境配置技巧
6.1 多环境配置
使用Profile区分环境:
properties复制# application-dev.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mall_dev
# application-prod.properties
spring.datasource.url=jdbc:mysql://prod-db:3306/mall_prod
启动时指定环境:
bash复制java -jar mall.jar --spring.profiles.active=prod
6.2 接口文档生成
Swagger3配置示例:
java复制@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI mallOpenAPI() {
return new OpenAPI()
.info(new Info().title("电商平台API")
.version("v1.0")
.contact(new Contact().name("开发者")));
}
}
访问路径:http://localhost:8080/swagger-ui.html
7. 部署方案选型
7.1 传统部署 vs Docker
| 对比项 | 传统部署 | Docker部署 |
|---|---|---|
| 环境一致性 | 依赖手工配置 | 镜像保证一致 |
| 资源占用 | 直接使用主机资源 | 有容器开销 |
| 启动速度 | 直接启动 | 需要拉取镜像 |
| 回滚机制 | 需要备份 | 镜像版本控制 |
7.2 推荐Docker Compose方案
docker-compose.yml示例:
yaml复制version: '3'
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
ports:
- "3306:3306"
redis:
image: redis:6
ports:
- "6379:6379"
app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- redis
启动命令:
bash复制docker-compose up -d --build
8. 代码质量保障
8.1 单元测试要点
商品服务测试示例:
java复制@SpringBootTest
class ProductServiceTest {
@Autowired
private ProductService productService;
@Test
@Transactional
void reduceStock() {
Long productId = 1L;
int originStock = productService.getById(productId).getStock();
productService.reduceStock(productId, 1);
assertEquals(originStock - 1,
productService.getById(productId).getStock());
}
}
8.2 代码规范检查
推荐使用Alibaba Java Coding Guidelines插件,主要检查:
- 魔法值未常量化
- 未处理的异常
- 不规范的日志打印
- 线程池未命名
9. 项目文档编写建议
9.1 必备文档清单
- 数据库设计文档(含ER图)
- 接口文档(Swagger+补充说明)
- 部署手册(环境要求+操作步骤)
- 用户手册(含截图的操作指南)
9.2 文档生成技巧
使用Maven插件自动生成文档:
xml复制<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.9.1</version>
</plugin>
生成命令:
bash复制mvn site
10. 答辩准备要点
10.1 演示数据准备
建议使用Mock数据生成器:
java复制public class MockDataGenerator {
public static List<Product> createProducts(int count) {
List<Product> products = new ArrayList<>();
Faker faker = new Faker();
for (int i = 0; i < count; i++) {
Product p = new Product();
p.setName(faker.commerce().productName());
p.setPrice(new BigDecimal(faker.commerce().price()));
products.add(p);
}
return products;
}
}
10.2 常见答辩问题
- 系统如何处理高并发?(回答方向:缓存+异步+限流)
- 如何保证数据一致性?(回答方向:事务+分布式锁)
- 扩展性体现在哪些方面?(回答方向:微服务化改造空间)