1. 项目概述
"小饰界"线上饰品商城是一个基于SSM(Spring+Spring MVC+MyBatis)框架开发的B2C电子商务平台。作为一名长期从事Java Web开发的工程师,我认为这类项目是检验开发者全栈能力的绝佳试金石。它不仅需要扎实的后端功底,还要对前端交互、数据库设计和系统架构有深入理解。
这个项目最吸引我的地方在于它完整覆盖了电商系统的核心模块:从用户注册登录、商品展示、购物车管理,到订单处理、支付集成,再到后台的商品管理和数据分析。每个模块都涉及到不同的技术难点,比如会话管理、事务控制、性能优化等,这些都是企业级开发中必须掌握的实战技能。
2. 系统需求分析
2.1 用户需求拆解
在需求分析阶段,我们采用了用户故事(User Story)的方法来梳理功能点:
-
访客角色:
- 浏览商品分类和详情(需要支持图片懒加载和缓存)
- 商品搜索与筛选(Elasticsearch是不错的选择,但考虑到项目规模,我们先用数据库LIKE实现)
- 注册/登录(采用手机号+验证码方式,比传统邮箱更符合国内习惯)
-
会员角色:
- 购物车管理(关键难点是未登录状态的临时购物车与登录后的合并逻辑)
- 订单创建与支付(需要对接支付宝/微信支付沙箱环境)
- 个人中心(订单追踪、收藏夹、地址管理)
-
商家角色:
- 商品CRUD(特别注意SKU属性的动态管理)
- 订单处理(状态机设计是关键)
- 销售数据统计(使用ECharts实现可视化)
2.2 非功能性需求
这些隐性需求往往决定系统成败:
java复制// 性能指标示例
public class PerformanceMetrics {
private static final int MAX_RESPONSE_TIME = 500; // ms
private static final int MIN_THROUGHPUT = 100; // requests/sec
private static final int ERROR_RATE = 0.01; // 1%
}
- 并发能力:预计促销期间QPS达到200+,需要Redis缓存热点数据
- 安全性:
- SQL注入防护(MyBatis默认使用预编译)
- XSS过滤(采用Spring HtmlUtils)
- CSRF防御(Spring Security默认支持)
- 可维护性:遵循阿里巴巴Java开发规范,接口文档使用Swagger生成
3. 技术架构设计
3.1 SSM框架整合
SSM组合是Java Web开发的经典选择:
- Spring:IoC容器管理所有Bean,AOP处理事务和日志
- Spring MVC:
- 采用RESTful风格API设计
- 全局异常处理器(@ControllerAdvice)
- 参数校验(@Validated)
- MyBatis:
- 动态SQL生成
- 二级缓存配置
- 插件开发(如分页插件)
整合关键配置:
xml复制<!-- spring-mybatis.xml -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<value>
helperDialect=mysql
reasonable=true
</value>
</property>
</bean>
</array>
</property>
</bean>
3.2 数据库设计
核心表关系图:
| 表名 | 关键字段 | 关联关系 |
|---|---|---|
| user | id, phone, password_hash, salt | 一对多 orders |
| product | id, name, price, stock, sku_json | 一对多 order_items |
| order | id, user_id, total_amount, status | 一对多 order_items |
| order_item | id, order_id, product_id, count | 多对一 order, product |
| cart | user_id, product_id, count | 多对一 user, product |
特别注意:价格字段使用DECIMAL(10,2)避免浮点精度问题,SKU采用JSON格式存储可变属性
4. 核心模块实现
4.1 购物车系统实现
购物车需要解决三个关键问题:
- 数据结构设计:
java复制public class CartItem {
private Long productId;
private String productName;
private BigDecimal price;
private Integer quantity;
private Map<String, String> skuAttributes; // 如颜色、尺寸
}
-
存储策略:
- 未登录用户:使用Cookie存储(7天过期)
- 已登录用户:持久化到数据库
- 合并逻辑:用户登录时执行
-
并发控制:
java复制@Transactional
public void addToCart(Long userId, CartItem item) {
// 使用SELECT FOR UPDATE加锁
CartItem existing = cartMapper.selectForUpdate(userId, item.getProductId());
if (existing != null) {
existing.setQuantity(existing.getQuantity() + item.getQuantity());
cartMapper.update(existing);
} else {
cartMapper.insert(item);
}
}
4.2 订单创建流程
订单模块最考验事务管理能力:
- 状态机设计:
code复制待支付 -> 已支付 -> 已发货 -> 已完成
\-> 已取消
- 减库存方案对比:
| 方案 | 优点 | 缺点 |
|---|---|---|
| 下单减库存 | 避免超卖 | 可能占用无效库存 |
| 支付减库存 | 更合理 | 需要处理支付超时问题 |
| 预扣库存 | 折中方案 | 实现复杂度高 |
我们选择支付减库存,配合30分钟未支付自动取消订单:
java复制@Scheduled(fixedRate = 600000) // 每10分钟检查一次
public void cancelUnpaidOrders() {
List<Order> orders = orderMapper.selectUnpaid(LocalDateTime.now().minusMinutes(30));
orders.forEach(order -> {
order.setStatus(OrderStatus.CANCELLED);
orderMapper.update(order);
// 注意:需要返还库存
});
}
5. 性能优化实践
5.1 缓存策略
采用多级缓存架构:
- 本地缓存(Caffeine):高频访问的用户信息
java复制@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000));
return manager;
}
- 分布式缓存(Redis):
- 商品详情(设置不同的TTL)
- 秒杀库存(使用Redis原子操作)
5.2 数据库优化
-
索引设计:
- 用户表:phone(唯一索引)
- 订单表:user_id + create_time(联合索引)
- 商品表:category_id + is_on_sale
-
SQL优化示例:
sql复制-- 反例:N+1查询问题
SELECT * FROM orders WHERE user_id = 1; -- 然后循环查order_items
-- 正例:JOIN查询
SELECT o.*, oi.*
FROM orders o LEFT JOIN order_items oi ON o.id = oi.order_id
WHERE o.user_id = 1;
6. 安全防护措施
6.1 常见漏洞防护
- 密码安全:
java复制public class PasswordUtil {
public static String encrypt(String password, String salt) {
return DigestUtils.sha256Hex(password + salt);
}
public static boolean verify(String input, String salt, String storedHash) {
return encrypt(input, salt).equals(storedHash);
}
}
- XSS防护:
java复制@ControllerAdvice
public class XssAdvice implements ResponseBodyAdvice<Object> {
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType,
MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
// 使用HtmlUtils进行转义
return body instanceof String ? HtmlUtils.htmlEscape((String) body) : body;
}
}
6.2 支付安全
支付环节需要特别注意:
- 使用官方SDK(不要自己实现签名逻辑)
- 验证回调通知的真实性
- 做好对账系统(每日定时核对订单与支付记录)
java复制public boolean verifyAlipayCallback(Map<String, String> params) {
try {
return AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, "UTF-8", "RSA2");
} catch (AlipayApiException e) {
logger.error("支付宝验签失败", e);
return false;
}
}
7. 测试方案设计
7.1 测试金字塔实践
| 测试类型 | 工具 | 覆盖率目标 |
|---|---|---|
| 单元测试 | JUnit+Mockito | 70%+ |
| 集成测试 | SpringBootTest | 50%+ |
| API测试 | Postman | 100% |
| 性能测试 | JMeter | 关键接口 |
示例测试用例:
java复制@SpringBootTest
public class OrderServiceTest {
@Autowired
private OrderService orderService;
@Test
@Transactional
public void testCreateOrder() {
OrderDTO dto = new OrderDTO();
// 构造测试数据...
Order result = orderService.createOrder(dto);
assertNotNull(result.getId());
assertEquals(OrderStatus.UNPAID, result.getStatus());
// 验证库存是否扣减
}
}
7.2 压力测试结果
使用JMeter模拟100并发下单:
| 指标 | 结果 | 达标值 |
|---|---|---|
| 平均响应时间 | 238ms | <500ms |
| 错误率 | 0.5% | <1% |
| 吞吐量 | 82/sec | >50/sec |
优化建议:
- 商品查询接口添加二级缓存
- 订单创建使用异步处理非核心逻辑
- 数据库连接池调优(从默认的Hikari 10调到50)
8. 部署上线方案
8.1 服务器配置建议
最低生产环境要求:
| 组件 | 配置 | 数量 |
|---|---|---|
| 应用服务器 | 2核4G | 2 |
| 数据库 | 4核8G+SSD | 1 |
| Redis | 1核2G | 1 |
| Nginx | 1核1G(负载均衡) | 1 |
8.2 容器化部署
Docker Compose示例:
yaml复制version: '3'
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql-data:/var/lib/mysql
redis:
image: redis:alpine
ports:
- "6379:6379"
app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- redis
environment:
SPRING_PROFILES_ACTIVE: prod
9. 踩坑经验分享
-
MyBatis缓存问题:
- 现象:更新数据后查询结果未变
- 原因:未正确配置缓存刷新
- 解决:在mapper.xml中添加flushCache属性
-
事务失效场景:
- 自调用问题(this.method()不走代理)
- 异常类型不对(默认只回滚RuntimeException)
- 解决方案:
java复制@Transactional(rollbackFor = Exception.class) public void placeOrder() {...}
-
日期处理陷阱:
- MySQL时区问题
- 前端传参格式不一致
- 推荐方案:
java复制@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime;
10. 扩展方向建议
-
微服务改造:
- 按功能拆分为商品服务、订单服务、用户服务
- 使用Spring Cloud Alibaba套件
-
大数据分析:
- 用户行为埋点
- 使用Flink实时计算
-
推荐系统:
- 基于协同过滤的简单实现
- 集成阿里云推荐引擎
这个项目从技术选型到实现细节都有很多值得深入探讨的地方。我在实际开发中发现,电商系统的复杂度往往来自于业务规则而非技术本身,比如促销规则引擎、库存管理等。建议后续可以重点完善这些业务模块