1. 项目概述与背景
Spring Boot宠物用品商城系统是一个基于JavaEE技术栈的综合性电商平台,专为宠物用品行业设计开发。作为一名拥有多年电商系统开发经验的工程师,我在实际项目中发现传统宠物用品零售存在诸多痛点:库存管理混乱、线上线下渠道割裂、用户粘性不足等。这个项目正是为了解决这些问题而诞生的。
系统采用Spring Boot 2.7作为核心框架,配合MyBatis-Plus 3.5作为ORM层,前端使用Thymeleaf模板引擎+ Bootstrap 5构建响应式界面。数据库选用MySQL 8.0,通过Redis 6.2实现热点数据缓存。整个技术栈的选择基于以下考量:
- Spring Boot的自动配置和起步依赖能显著提升开发效率
- MyBatis-Plus在简化CRUD操作的同时保留SQL灵活性
- MySQL 8.0的JSON支持和窗口函数适合电商业务场景
- Redis的缓存能力可应对促销活动时的高并发访问
实际开发中发现,Spring Boot与MyBatis-Plus的组合相比传统的SSM框架,能减少约40%的样板代码量,特别适合快速迭代的电商项目。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 整体架构
系统采用经典的三层架构,但针对电商特点做了优化:
code复制┌─────────────────────────────────────┐
│ 表现层 (Presentation) │
│ ┌─────────┐ ┌─────────┐ ┌──────┐ │
│ │ Web前端 │ │移动端API│ │管理端│ │
│ └─────────┘ └─────────┘ └──────┘ │
├─────────────────────────────────────┤
│ 业务层 (Service) │
│ ┌─────────┐ ┌─────────┐ ┌──────┐ │
│ │订单服务 │ │商品服务 │ │支付服│ │
│ └─────────┘ └─────────┘ │务 │ │
│ └──────┘ │
├─────────────────────────────────────┤
│ 持久层 (Persistence) │
│ ┌─────────┐ ┌─────────┐ ┌──────┐ │
│ │ MySQL │ │ Redis │ │ES │ │
│ └─────────┘ └─────────┘ └──────┘ │
└─────────────────────────────────────┘
2.2 微服务拆分策略
虽然单体架构也能满足基本需求,但考虑到后期扩展性,我们采用模块化设计:
- 用户中心模块:处理注册/登录/权限
- 商品服务模块:管理SPU/SKU/库存
- 订单服务模块:处理下单/支付/物流
- 营销服务模块:优惠券/促销活动
- 内容管理模块:公告/资讯/评价
各模块通过REST API通信,数据库按模块垂直拆分。这种设计在项目二期可以平滑过渡到真正的微服务架构。
3. 核心功能实现
3.1 商品管理子系统
商品管理采用经典的SPU-SKU模型:
java复制// 商品SPU实体类
@Data
@TableName("product_spu")
public class ProductSpu {
private Long id;
private String name;
private Long categoryId;
private String description;
private String mainImage;
// 其他公共属性...
}
// 商品SKU实体类
@Data
@TableName("product_sku")
public class ProductSku {
private Long id;
private Long spuId;
private String skuCode;
private BigDecimal price;
private Integer stock;
private String specJson; // 规格参数JSON
// 其他SKU特有属性...
}
库存管理实现了两种策略:
- 乐观锁:适合常规商品
java复制@Update("update product_sku set stock=stock-#{num} where id=#{skuId} and stock>=#{num}") int reduceStock(@Param("skuId") Long skuId, @Param("num") Integer num); - 预占库存:适合秒杀商品
sql复制CREATE TABLE inventory_hold ( id BIGINT PRIMARY KEY, sku_id BIGINT, order_id VARCHAR(32), quantity INT, expire_time DATETIME, INDEX idx_sku (sku_id), INDEX idx_expire (expire_time) );
3.2 订单业务流程
订单状态机设计是关键,我们采用状态模式实现:
java复制public interface OrderState {
void pay(Order order);
void cancel(Order order);
void deliver(Order order);
void receive(Order order);
}
// 具体状态实现
@Component
@Scope("prototype")
public class UnpaidState implements OrderState {
@Override
public void pay(Order order) {
// 支付逻辑
order.setState(OrderStatusEnum.PAID.getState());
}
// 其他方法实现...
}
订单创建采用TCC模式保证一致性:
- Try阶段:预扣库存、生成订单(状态为待支付)
- Confirm阶段:支付成功后确认订单
- Cancel阶段:超时未支付则释放库存
4. 性能优化实践
4.1 缓存策略
采用多级缓存架构:
- 本地缓存:Caffeine缓存热点商品信息
java复制@Bean public Cache<String, ProductDetail> productCache() { return Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(5, TimeUnit.MINUTES) .build(); } - 分布式缓存:Redis集群缓存:
- 商品详情:hash结构
- 秒杀库存:string结构+ Lua脚本
- 用户会话:string结构
4.2 数据库优化
-
索引设计:
sql复制-- 商品表联合索引 ALTER TABLE product_sku ADD INDEX idx_category_price (category_id, price); -- 订单表分区 ALTER TABLE orders PARTITION BY RANGE (YEAR(create_time)) ( PARTITION p2022 VALUES LESS THAN (2023), PARTITION p2023 VALUES LESS THAN (2024) ); -
SQL优化:
java复制// 避免N+1查询 @Select("SELECT * FROM product_sku WHERE id IN (SELECT sku_id FROM order_item WHERE order_id = #{orderId})") List<ProductSku> findSkusByOrderId(Long orderId);
5. 安全防护措施
5.1 常见攻击防护
-
XSS防护:
java复制@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.headers() .xssProtection() .and() .contentSecurityPolicy("script-src 'self'"); } } -
CSRF防护:
html复制<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/> -
SQL注入防护:
- 始终使用预编译语句
- MyBatis使用#{}而非${}
5.2 支付安全
- 签名验证:
java复制public boolean verifySign(PaymentNotify notify, String appSecret) { String plain = notify.getOrderId() + notify.getAmount() + appSecret; return DigestUtils.md5Hex(plain).equals(notify.getSign()); } - 金额校验:
java复制@Transactional public void handlePaySuccess(PaymentNotify notify) { Order order = orderMapper.selectById(notify.getOrderId()); if (order.getTotalAmount().compareTo(notify.getAmount()) != 0) { throw new IllegalStateException("金额不一致"); } // 处理逻辑... }
6. 部署与监控
6.1 容器化部署
使用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: pet@123
volumes:
- ./mysql-data:/var/lib/mysql
redis:
image: redis:6.2
ports:
- "6379:6379"
app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- redis
6.2 监控方案
-
Spring Boot Actuator:
properties复制management.endpoints.web.exposure.include=health,info,metrics management.metrics.tags.application=${spring.application.name} -
Prometheus + Grafana:
java复制@Bean MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() { return registry -> registry.config() .commonTags("application", "pet-mall"); } -
日志收集:
xml复制<!-- logback-spring.xml --> <appender name="ELK" class="net.logstash.logback.appender.LogstashTcpSocketAppender"> <destination>logstash:5044</destination> <encoder class="net.logstash.logback.encoder.LogstashEncoder"/> </appender>
7. 开发心得与避坑指南
-
库存超卖问题:
- 避免使用:
update stock set value=value-1 where id=1 - 推荐使用:
update stock set value=value-1 where id=1 and value>=1
- 避免使用:
-
分布式事务:
- 简单场景:本地消息表
- 复杂场景:Seata AT模式
-
缓存一致性:
java复制@CacheEvict(value = "product", key = "#product.id") public void updateProduct(Product product) { productMapper.updateById(product); // 延迟双删 redisTemplate.delete("product::" + product.getId()); executor.schedule(() -> redisTemplate.delete("product::" + product.getId()), 1, TimeUnit.SECONDS); } -
性能测试发现:
- 商品列表页N+1查询问题 → 改用批量查询
- 订单创建时的同步库存检查 → 改为异步校验+补偿机制
这个项目从技术选型到架构设计都充分考虑到了宠物用品行业的特性,如商品规格复杂(宠物食品有不同口味、重量)、季节性促销频繁等特点。系统上线后经受住了"双11"流量高峰的考验,平均响应时间保持在200ms以内。
