电商系统实战
使用 LCGYL Framework 构建一个完整的电商系统。
系统架构
微服务划分
- 用户服务:用户注册、登录、个人信息
- 商品服务:商品管理、分类、库存
- 订单服务:订单创建、支付、物流
- 购物车服务:购物车管理
- 支付服务:支付处理、退款
商品服务
商品实体
java
public class Product {
private Long id;
private String name;
private String description;
private BigDecimal price;
private Integer stock;
private String categoryId;
private List<String> images;
private ProductStatus status;
private LocalDateTime createdAt;
}
public enum ProductStatus {
ON_SALE, // 在售
OFF_SALE, // 下架
OUT_OF_STOCK // 缺货
}商品服务实现
java
@Component
public class ProductService {
private final ProductRepository productRepository;
private final Cache<Long, Product> productCache;
public Product getProductById(Long id) {
return productCache.get(id, () ->
productRepository.findById(id)
.orElseThrow(() -> new NotFoundException("商品不存在"))
);
}
public Page<Product> searchProducts(String keyword, int page, int size) {
return productRepository.search(keyword, page, size);
}
@Transactional
public boolean decreaseStock(Long productId, Integer quantity) {
Product product = getProductById(productId);
if (product.getStock() < quantity) {
throw new BusinessException("库存不足");
}
product.setStock(product.getStock() - quantity);
productRepository.save(product);
// 清除缓存
productCache.invalidate(productId);
return true;
}
}订单服务
订单实体
java
public class Order {
private Long id;
private Long userId;
private String orderNo;
private BigDecimal totalAmount;
private OrderStatus status;
private String shippingAddress;
private List<OrderItem> items;
private LocalDateTime createdAt;
}
public class OrderItem {
private Long productId;
private String productName;
private BigDecimal price;
private Integer quantity;
private BigDecimal subtotal;
}
public enum OrderStatus {
PENDING_PAYMENT, // 待支付
PAID, // 已支付
SHIPPED, // 已发货
COMPLETED, // 已完成
CANCELLED // 已取消
}订单服务实现
java
@Component
public class OrderService {
private final OrderRepository orderRepository;
private final ProductServiceClient productServiceClient;
private final PaymentServiceClient paymentServiceClient;
private final EventBus eventBus;
@Transactional
public Order createOrder(Long userId, CreateOrderRequest request) {
// 1. 验证商品库存
for (OrderItemRequest item : request.getItems()) {
Product product = productServiceClient.getProduct(item.getProductId());
if (product.getStock() < item.getQuantity()) {
throw new BusinessException("商品库存不足:" + product.getName());
}
}
// 2. 创建订单
Order order = new Order();
order.setUserId(userId);
order.setOrderNo(generateOrderNo());
order.setStatus(OrderStatus.PENDING_PAYMENT);
order.setShippingAddress(request.getShippingAddress());
// 3. 添加订单项
List<OrderItem> items = new ArrayList<>();
BigDecimal totalAmount = BigDecimal.ZERO;
for (OrderItemRequest itemReq : request.getItems()) {
Product product = productServiceClient.getProduct(itemReq.getProductId());
OrderItem item = new OrderItem();
item.setProductId(product.getId());
item.setProductName(product.getName());
item.setPrice(product.getPrice());
item.setQuantity(itemReq.getQuantity());
item.setSubtotal(product.getPrice().multiply(
BigDecimal.valueOf(itemReq.getQuantity())
));
items.add(item);
totalAmount = totalAmount.add(item.getSubtotal());
}
order.setItems(items);
order.setTotalAmount(totalAmount);
// 4. 保存订单
order = orderRepository.save(order);
// 5. 扣减库存
for (OrderItem item : items) {
productServiceClient.decreaseStock(
item.getProductId(),
item.getQuantity()
);
}
// 6. 发布订单创建事件
eventBus.publish(new OrderCreatedEvent(order));
return order;
}
@Transactional
public Order payOrder(Long orderId, String paymentMethod) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new NotFoundException("订单不存在"));
if (order.getStatus() != OrderStatus.PENDING_PAYMENT) {
throw new BusinessException("订单状态不正确");
}
// 调用支付服务
PaymentResult result = paymentServiceClient.pay(
order.getOrderNo(),
order.getTotalAmount(),
paymentMethod
);
if (result.isSuccess()) {
order.setStatus(OrderStatus.PAID);
orderRepository.save(order);
// 发布订单支付成功事件
eventBus.publish(new OrderPaidEvent(order));
}
return order;
}
private String generateOrderNo() {
return "ORD" + System.currentTimeMillis() +
ThreadLocalRandom.current().nextInt(1000, 9999);
}
}购物车服务
购物车实现
java
@Component
public class CartService {
private final RedisTemplate redisTemplate;
private final ProductServiceClient productServiceClient;
public Cart getCart(Long userId) {
String key = "cart:" + userId;
Cart cart = redisTemplate.get(key, Cart.class);
if (cart == null) {
cart = new Cart(userId);
}
return cart;
}
public Cart addItem(Long userId, Long productId, Integer quantity) {
Cart cart = getCart(userId);
// 获取商品信息
Product product = productServiceClient.getProduct(productId);
// 添加到购物车
CartItem item = new CartItem();
item.setProductId(productId);
item.setProductName(product.getName());
item.setPrice(product.getPrice());
item.setQuantity(quantity);
cart.addItem(item);
// 保存到 Redis
String key = "cart:" + userId;
redisTemplate.set(key, cart, Duration.ofDays(7));
return cart;
}
public Cart removeItem(Long userId, Long productId) {
Cart cart = getCart(userId);
cart.removeItem(productId);
String key = "cart:" + userId;
redisTemplate.set(key, cart, Duration.ofDays(7));
return cart;
}
public void clearCart(Long userId) {
String key = "cart:" + userId;
redisTemplate.delete(key);
}
}分布式事务
Saga 模式实现
java
@Component
public class OrderSaga {
private final OrderService orderService;
private final ProductServiceClient productServiceClient;
private final PaymentServiceClient paymentServiceClient;
public Order createOrderWithSaga(Long userId, CreateOrderRequest request) {
SagaContext context = new SagaContext();
try {
// 步骤1:创建订单
Order order = orderService.createOrder(userId, request);
context.addCompensation(() -> orderService.cancelOrder(order.getId()));
// 步骤2:扣减库存
for (OrderItem item : order.getItems()) {
productServiceClient.decreaseStock(
item.getProductId(),
item.getQuantity()
);
context.addCompensation(() ->
productServiceClient.increaseStock(
item.getProductId(),
item.getQuantity()
)
);
}
// 步骤3:创建支付订单
paymentServiceClient.createPayment(order);
context.addCompensation(() ->
paymentServiceClient.cancelPayment(order.getOrderNo())
);
return order;
} catch (Exception e) {
// 执行补偿操作
context.compensate();
throw e;
}
}
}
class SagaContext {
private final List<Runnable> compensations = new ArrayList<>();
public void addCompensation(Runnable compensation) {
compensations.add(compensation);
}
public void compensate() {
// 逆序执行补偿操作
for (int i = compensations.size() - 1; i >= 0; i--) {
try {
compensations.get(i).run();
} catch (Exception e) {
// 记录补偿失败
logger.error("补偿操作失败", e);
}
}
}
}秒杀功能
秒杀服务
java
@Component
public class SeckillService {
private final RedisTemplate redisTemplate;
private final OrderService orderService;
private final MessageProducer messageProducer;
public boolean seckill(Long userId, Long productId) {
String key = "seckill:stock:" + productId;
// 使用 Lua 脚本保证原子性
String script =
"local stock = redis.call('get', KEYS[1]) " +
"if tonumber(stock) > 0 then " +
" redis.call('decr', KEYS[1]) " +
" return 1 " +
"else " +
" return 0 " +
"end";
Long result = redisTemplate.execute(script,
Collections.singletonList(key));
if (result == 1) {
// 发送消息异步创建订单
SeckillOrderMessage message = new SeckillOrderMessage(
userId, productId
);
messageProducer.send("seckill.order", message);
return true;
}
return false;
}
}
@MessageListener(topic = "seckill.order")
public class SeckillOrderListener {
private final OrderService orderService;
public void onMessage(SeckillOrderMessage message) {
// 创建订单
CreateOrderRequest request = new CreateOrderRequest();
request.addItem(message.getProductId(), 1);
orderService.createOrder(message.getUserId(), request);
}
}