Skip to content

电商系统实战

使用 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);
    }
}

下一步

Released under the Apache License 2.0