1. 项目概述与核心需求解析
鲜花电商系统作为典型的B2C垂直领域应用,其技术架构需要同时满足高并发交易、复杂业务逻辑和良好的用户体验三大核心诉求。基于SSM(Spring+SpringMVC+MyBatis)框架的解决方案,在Java Web开发领域经过多年验证,能够有效平衡开发效率与系统性能。
这个鲜花商城系统需要实现的核心模块包括:
- 用户认证与权限管理(多角色:顾客/商家/管理员)
- 商品管理与分类体系(鲜花品类/花语标签/节日专题)
- 购物车与订单处理流程(含库存实时校验)
- 支付系统对接(第三方支付+虚拟账户)
- 物流跟踪接口(快递API集成)
- 评价与售后服务体系
特别提示:鲜花类商品具有时效性强、库存波动大的特点,系统设计时需要重点考虑秒杀场景下的库存一致性问题,以及配送时效的精确计算。
2. 技术栈选型与框架整合
2.1 SSM框架版本选择
- Spring 5.3.x:提供完整的IoC容器和声明式事务管理
- SpringMVC 5.3.x:RESTful风格API支持+文件上传处理
- MyBatis 3.5.x:注解+XML混合配置模式
- Tomcat 9.0.x:Servlet 4.0规范支持
2.2 框架整合关键配置
- Spring与MyBatis整合:
xml复制<!-- 数据源配置 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- SqlSessionFactory配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
<!-- Mapper扫描配置 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.flower.mapper"/>
</bean>
- Spring与SpringMVC整合:
- 通过ContextLoaderListener加载Spring根容器
- DispatcherServlet加载SpringMVC子容器
- 使用
<context:component-scan>时注意排除重复扫描
2.3 辅助技术选型
| 功能模块 | 技术方案 | 选型理由 |
|---|---|---|
| 缓存 | Redis 6.x | 高并发商品详情页缓存 |
| 搜索 | Elasticsearch 7.x | 鲜花多维度检索(颜色/花语) |
| 消息队列 | RabbitMQ 3.9 | 订单异步处理与削峰填谷 |
| 安全框架 | Spring Security 5.5 | OAuth2.0+JWT实现安全认证 |
3. 核心业务逻辑实现
3.1 商品库存管理
鲜花商品需要处理特殊库存逻辑:
java复制// 使用乐观锁解决超卖问题
@Update("UPDATE flower_stock SET quantity = quantity - #{num}, version = version + 1
WHERE flower_id = #{flowerId} AND version = #{version} AND quantity >= #{num}")
int reduceStock(@Param("flowerId") Long flowerId,
@Param("num") Integer num,
@Param("version") Integer version);
3.2 订单状态机设计
mermaid复制stateDiagram-v2
[*] --> PENDING_PAYMENT
PENDING_PAYMENT --> PAID: 支付成功
PENDING_PAYMENT --> CANCELLED: 用户取消
PAID --> SHIPPED: 商家发货
SHIPPED --> RECEIVED: 用户收货
RECEIVED --> COMPLETED: 确认完成
RECEIVED --> RETURNING: 发起退货
RETURNING --> RETURNED: 退货完成
3.3 支付系统对接
采用策略模式实现多支付渠道:
java复制public interface PaymentStrategy {
PaymentResult pay(Order order);
}
@Service
public class AlipayStrategy implements PaymentStrategy {
// 支付宝具体实现
}
@Service
public class WechatPayStrategy implements PaymentStrategy {
// 微信支付具体实现
}
@Service
public class PaymentContext {
@Autowired
private Map<String, PaymentStrategy> strategyMap;
public PaymentResult executePay(String channel, Order order) {
return strategyMap.get(channel + "Strategy").pay(order);
}
}
4. 性能优化实践
4.1 MyBatis二级缓存配置
xml复制<cache eviction="LRU"
flushInterval="60000"
size="512"
readOnly="true"/>
4.2 Spring声明式事务优化
java复制@Transactional(propagation=Propagation.REQUIRED,
isolation=Isolation.READ_COMMITTED,
timeout=30,
rollbackFor=Exception.class)
public void createOrder(OrderDTO orderDTO) {
// 订单创建逻辑
}
4.3 高并发场景解决方案
- 库存预热:活动开始前将热门商品库存加载到Redis
- 令牌桶限流:使用Guava RateLimiter控制接口访问
- 分布式锁:Redisson实现跨JVM操作互斥
5. 典型问题排查实录
5.1 MyBatis关联查询N+1问题
现象:查询订单列表时产生大量SQL
解决方案:
xml复制<resultMap id="orderWithItems" type="Order">
<collection property="items" ofType="OrderItem"
select="selectItemsByOrderId" column="id"/>
</resultMap>
<!-- 使用JOIN一次性查询 -->
<select id="selectOrderWithItems" resultMap="orderWithItems">
SELECT o.*, i.*
FROM orders o LEFT JOIN order_items i ON o.id = i.order_id
WHERE o.user_id = #{userId}
</select>
5.2 Spring事务失效场景
- 自调用问题(同类方法调用)
- 异常类型不匹配(默认只回滚RuntimeException)
- 方法修饰符非public
5.3 文件上传大小限制
在spring-mvc.xml中配置:
xml复制<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5242880"/> <!-- 5MB -->
<property name="defaultEncoding" value="UTF-8"/>
</bean>
6. 项目部署与监控
6.1 Tomcat优化参数
properties复制# conf/server.xml
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="500"
minSpareThreads="30"
acceptCount="1000"
compression="on"
URIEncoding="UTF-8"/>
6.2 健康检查端点配置
java复制@RestController
@RequestMapping("/health")
public class HealthController {
@Autowired
private DataSource dataSource;
@GetMapping
public ResponseEntity<String> check() {
try (Connection conn = dataSource.getConnection()) {
return ResponseEntity.ok("UP");
} catch (Exception e) {
return ResponseEntity.status(503).body("DB DOWN");
}
}
}
在实际项目开发中,我们发现鲜花类商品的时效性要求催生了一些特殊需求。比如母亲节前一周的康乃馨订单量会是平时的50倍,这时需要:
- 提前进行压力测试(使用JMeter模拟5000TPS)
- 准备自动扩容方案(基于Kubernetes的HPA)
- 建立降级预案(当库存服务不可用时启用本地缓存)
对于MyBatis的复杂查询,我们总结出一个实用技巧:在XML映射文件中使用<sql>片段重用公共SQL部分,例如:
xml复制<sql id="flowerBaseColumn">
id, name, price, main_img, stock, category_id, status
</sql>
<select id="selectById" resultType="Flower">
SELECT <include refid="flowerBaseColumn"/>
FROM flower
WHERE id = #{id}
</select>
这种写法不仅减少重复代码,当需要添加通用字段(如create_time)时只需修改一处。
