1. 项目概述
最近完成了一个基于Spring Boot的网上水果销售商城项目,这是一个典型的B2C电商平台,主要面向水果零售商和消费者。项目采用前后端分离架构,后端使用Spring Boot+MyBatis+MySQL技术栈,前端使用Vue.js+Element UI实现响应式界面。整个开发周期约3个月,目前已经完成核心功能开发并通过测试。
这个项目最让我印象深刻的是如何在保证系统稳定性的同时,实现水果这类特殊商品的全流程管理。不同于普通商品,水果对新鲜度、配送时效有更高要求,这给系统设计带来了独特挑战。下面我就从技术选型、核心功能实现、性能优化等方面,分享这个项目的实战经验。
2. 技术架构设计
2.1 后端技术栈选型
选择Spring Boot作为后端框架主要基于以下几点考虑:
-
快速开发:Spring Boot的自动配置和起步依赖大大减少了样板代码。比如集成MyBatis时,只需添加
mybatis-spring-boot-starter依赖,配置数据库连接即可。 -
微服务友好:虽然当前是单体架构,但Spring Cloud基于Spring Boot,未来扩展为微服务架构成本低。
-
生态丰富:Spring生态有大量成熟解决方案,比如:
- Spring Security用于认证授权
- Spring Cache实现多级缓存
- Spring Batch处理批量任务
数据库选择MySQL 5.7,主要考虑水果商城的业务特点:
- 关系型数据模型适合电商的订单、用户等结构化数据
- 事务支持确保订单、库存等关键操作的ACID特性
- 5.7版本对JSON类型的支持便于存储商品扩展属性
2.2 前端技术选型
前端采用Vue.js 2.x + Element UI的组合,主要优势:
- 组件化开发:将商品展示、购物车等模块封装为可复用组件
- 响应式设计:Element UI的布局组件天然支持移动端适配
- 开发效率:基于Vue CLI的脚手架快速搭建项目结构
javascript复制// 典型商品组件示例
<template>
<el-card :body-style="{ padding: '0px' }">
<img :src="product.image" class="image">
<div style="padding: 14px;">
<span>{{ product.name }}</span>
<div class="bottom">
<el-button type="text" @click="addToCart">加入购物车</el-button>
</div>
</div>
</el-card>
</template>
2.3 架构设计图
系统采用经典的三层架构:
code复制表示层(Vue) → 业务逻辑层(Spring Boot) → 数据访问层(MyBatis)
↓
(Redis缓存)
关键设计决策:
- 前后端完全分离,通过RESTful API交互
- 使用JWT进行无状态认证
- 敏感数据如支付信息加密存储
- 读写分离缓解数据库压力
3. 核心功能实现
3.1 商品管理系统
水果商品管理有几个特殊需求:
- 新鲜度标识:需要显示采摘日期和保质期
- 多规格支持:如重量规格(500g/1kg)
- 动态库存:实时反映仓库实际库存
数据库表设计关键字段:
sql复制CREATE TABLE `fruit_product` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '商品名称',
`origin` varchar(50) COMMENT '产地',
`picking_date` date COMMENT '采摘日期',
`shelf_life` int COMMENT '保质期(天)',
`price` decimal(10,2) COMMENT '基准价格',
`stock` int COMMENT '总库存',
`status` tinyint COMMENT '上架状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
商品服务的核心逻辑:
java复制@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductMapper productMapper;
@Override
@Transactional
public void reduceStock(Long productId, int quantity) {
Product product = productMapper.selectById(productId);
if(product.getStock() < quantity) {
throw new BusinessException("库存不足");
}
productMapper.updateStock(productId, quantity);
}
}
3.2 订单系统设计
订单系统采用状态机模式管理订单生命周期:
code复制待支付 → 已支付 → 已发货 → 已完成
↘ 退款中 → 已退款
状态转换的代码实现:
java复制public enum OrderStatus {
PENDING_PAYMENT,
PAID,
SHIPPED,
COMPLETED,
REFUNDING,
REFUNDED;
private static final Map<OrderStatus, Set<OrderStatus>> transitions = Map.of(
PENDING_PAYMENT, Set.of(PAID, CANCELLED),
PAID, Set.of(SHIPPED, REFUNDING),
// 其他状态转换规则...
);
public boolean canTransitionTo(OrderStatus newStatus) {
return transitions.getOrDefault(this, Set.of()).contains(newStatus);
}
}
3.3 支付系统集成
对接了支付宝和微信支付双渠道,采用策略模式实现支付方式的无缝切换:
java复制public interface PaymentStrategy {
PaymentResult pay(Order order);
boolean supports(PaymentType type);
}
@Service
public class AlipayStrategy implements PaymentStrategy {
@Override
public PaymentResult pay(Order order) {
// 调用支付宝SDK
}
@Override
public boolean supports(PaymentType type) {
return type == PaymentType.ALIPAY;
}
}
@Service
public class PaymentService {
private final List<PaymentStrategy> strategies;
public PaymentResult processPayment(Order order, PaymentType type) {
return strategies.stream()
.filter(s -> s.supports(type))
.findFirst()
.orElseThrow(() -> new UnsupportedPaymentTypeException())
.pay(order);
}
}
4. 性能优化实践
4.1 缓存策略
采用多级缓存提升系统响应速度:
- 本地缓存:使用Caffeine缓存热点商品数据
java复制@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000));
return cacheManager;
}
- 分布式缓存:Redis缓存购物车、秒杀库存等数据
java复制@Cacheable(value = "product", key = "#id")
public Product getProductById(Long id) {
return productMapper.selectById(id);
}
- 前端缓存:静态资源通过CDN加速,设置HTTP缓存头
4.2 数据库优化
- 索引优化:为查询频繁的字段添加索引
sql复制ALTER TABLE `order` ADD INDEX idx_user_status (`user_id`, `status`);
- 读写分离:使用Sharding-JDBC实现
yaml复制spring:
shardingsphere:
datasource:
names: master,slave
master:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://master-host:3306/fruit_mall
username: root
password: password
slave:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://slave-host:3306/fruit_mall
username: root
password: password
masterslave:
load-balance-algorithm-type: round_robin
name: ms
master-data-source-name: master
slave-data-source-names: slave
- SQL优化:避免N+1查询问题,使用MyBatis的
<collection>标签实现关联查询
4.3 高并发处理
针对秒杀等高并发场景采取以下措施:
- 库存扣减:使用Redis原子操作+Lua脚本
lua复制local stock = tonumber(redis.call('GET', KEYS[1]))
if stock <= 0 then
return 0
end
redis.call('DECR', KEYS[1])
return 1
- 限流措施:Guava RateLimiter实现令牌桶限流
java复制@RestController
@RequestMapping("/api/seckill")
public class SeckillController {
private final RateLimiter rateLimiter = RateLimiter.create(100); // 每秒100个请求
@PostMapping
public ResponseEntity<String> seckill(@RequestBody SeckillRequest request) {
if(!rateLimiter.tryAcquire()) {
return ResponseEntity.status(429).body("请求过于频繁");
}
// 处理秒杀逻辑
}
}
- 异步处理:使用Spring Event发布领域事件
java复制public class OrderPaidEvent {
private final Order order;
public OrderPaidEvent(Order order) {
this.order = order;
}
// getter
}
@Component
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void payOrder(Long orderId) {
// 支付逻辑...
eventPublisher.publishEvent(new OrderPaidEvent(order));
}
}
@Component
public class InventoryUpdater {
@EventListener
public void handleOrderPaid(OrderPaidEvent event) {
// 异步更新库存
}
}
5. 安全防护措施
5.1 认证与授权
采用JWT实现无状态认证:
java复制public class JwtTokenProvider {
private String secretKey = "your-secret-key";
private long validityInMilliseconds = 3600000; // 1h
public String createToken(String username, List<String> roles) {
Claims claims = Jwts.claims().setSubject(username);
claims.put("roles", roles);
Date now = new Date();
Date validity = new Date(now.getTime() + validityInMilliseconds);
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(validity)
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
// 其他验证方法...
}
5.2 数据安全
- 敏感数据加密:使用Jasypt加密数据库密码等敏感信息
yaml复制spring:
datasource:
password: ENC(加密后的密码)
- SQL注入防护:MyBatis使用预编译语句
xml复制<select id="selectByName" resultType="Product">
SELECT * FROM product WHERE name LIKE CONCAT('%', #{name}, '%')
</select>
- XSS防护:前端使用DOMPurify净化用户输入
javascript复制import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(userInput);
6. 部署与监控
6.1 容器化部署
使用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:alpine
ports:
- "6379:6379"
app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- redis
volumes:
mysql_data:
6.2 监控方案
- Spring Boot Actuator:暴露健康检查端点
yaml复制management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
- Prometheus + Grafana:监控系统指标
yaml复制# Prometheus配置示例
scrape_configs:
- job_name: 'spring'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8080']
- ELK日志系统:集中管理日志
java复制@Slf4j
@Service
public class OrderService {
public void createOrder(Order order) {
log.info("创建订单:{}", order.getId());
// 业务逻辑
}
}
7. 项目总结与改进方向
这个水果商城项目让我对电商系统的核心模块有了更深入的理解。几个关键收获:
- 领域模型设计:水果这类易腐商品需要特殊的状态管理和时效控制
- 分布式事务:订单与库存的一致性保证是难点
- 性能优化:缓存策略和数据库优化对电商系统至关重要
未来改进方向:
- 引入推荐算法提升转化率
- 增加预售和团购等营销模式
- 实现更精细化的权限控制系统
- 接入第三方物流API实现智能配送
整个项目源码已经整理在GitHub上,包含完整的部署文档和数据库脚本。对于想学习Spring Boot电商系统开发的同学,这个项目提供了很好的参考实现。