# 订单商品验证功能指南

## 概述

本文档介绍了订单创建时商品信息后台验证的实现方案。该方案确保了订单数据的安全性和一致性，防止前端数据被篡改。

## 主要特性

### 1. 商品信息后台验证
- ✅ 商品存在性验证
- ✅ 商品状态验证（上架/下架）
- ✅ 商品价格验证
- ✅ 库存数量验证
- ✅ 购买数量限制验证
- ✅ 订单总金额重新计算

### 2. 数据安全保障
- ✅ 防止前端价格篡改
- ✅ 使用后台查询的真实商品信息
- ✅ 订单金额一致性检查
- ✅ 详细的错误提示信息

## 实现细节

### 核心方法

#### 1. validateOrderRequest()
```java
private void validateOrderRequest(OrderCreateRequest request, User loginUser) {
    // 1. 用户登录验证
    if (loginUser == null) {
        throw new BusinessException("用户未登录");
    }

    // 2. 验证商品信息并计算总金额
    BigDecimal calculatedTotal = validateAndCalculateTotal(request);
    
    // 3. 检查金额一致性
    if (request.getTotalPrice() != null && 
        request.getTotalPrice().subtract(calculatedTotal).abs().compareTo(new BigDecimal("0.01")) > 0) {
        throw new BusinessException("订单金额计算错误，请刷新重试");
    }

    // 4. 使用后台计算的金额
    request.setTotalPrice(calculatedTotal);

    // 5. 检查租户特殊规则
    // ...
}
```

#### 2. validateAndCalculateTotal()
```java
private BigDecimal validateAndCalculateTotal(OrderCreateRequest request) {
    BigDecimal total = BigDecimal.ZERO;
    
    for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) {
        // 获取商品信息
        ShopGoods goods = shopGoodsService.getById(item.getGoodsId());
        
        // 验证商品存在性
        if (goods == null) {
            throw new BusinessException("商品不存在，商品ID：" + item.getGoodsId());
        }
        
        // 验证商品状态
        if (goods.getStatus() != 0) {
            throw new BusinessException("商品已下架：" + goods.getName());
        }
        
        // 验证库存
        if (goods.getStock() != null && goods.getStock() < item.getQuantity()) {
            throw new BusinessException("商品库存不足：" + goods.getName());
        }
        
        // 验证购买数量限制
        if (goods.getCanBuyNumber() != null && item.getQuantity() > goods.getCanBuyNumber()) {
            throw new BusinessException("商品购买数量超过限制：" + goods.getName());
        }
        
        // 计算小计
        BigDecimal itemTotal = goods.getPrice().multiply(new BigDecimal(item.getQuantity()));
        total = total.add(itemTotal);
    }
    
    return total;
}
```

### 订单商品保存优化

```java
private void saveOrderGoods(OrderCreateRequest request, ShopOrder shopOrder) {
    for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) {
        // 重新获取商品信息（确保数据一致性）
        ShopGoods goods = shopGoodsService.getById(item.getGoodsId());
        
        // 再次验证商品状态（防止并发问题）
        if (goods.getStatus() != 0) {
            throw new BusinessException("商品已下架：" + goods.getName());
        }

        ShopOrderGoods orderGoods = new ShopOrderGoods();
        
        // 使用后台查询的真实数据
        orderGoods.setGoodsId(item.getGoodsId());
        orderGoods.setGoodsName(goods.getName());
        orderGoods.setPrice(goods.getPrice()); // 使用后台价格
        orderGoods.setTotalNum(item.getQuantity());
        
        // 设置其他信息...
    }
}
```

## 验证流程

```mermaid
graph TD
    A[前端提交订单] --> B[validateOrderRequest]
    B --> C[validateAndCalculateTotal]
    C --> D[验证商品存在性]
    D --> E[验证商品状态]
    E --> F[验证库存数量]
    F --> G[验证购买限制]
    G --> H[计算总金额]
    H --> I[检查金额一致性]
    I --> J[保存订单]
    J --> K[saveOrderGoods]
    K --> L[再次验证商品状态]
    L --> M[使用后台数据保存]
```

## 错误处理

### 常见错误信息

| 错误码 | 错误信息 | 说明 |
|--------|----------|------|
| 1 | 用户未登录 | 用户身份验证失败 |
| 1 | 商品不存在，商品ID：xxx | 商品ID无效或已删除 |
| 1 | 商品已下架：xxx | 商品状态不是上架状态 |
| 1 | 商品价格异常：xxx | 商品价格为空或小于等于0 |
| 1 | 商品库存不足：xxx，当前库存：xxx | 购买数量超过可用库存 |
| 1 | 商品购买数量超过限制：xxx，最大购买数量：xxx | 超过单次购买限制 |
| 1 | 订单金额计算错误，请刷新重试 | 前端金额与后台计算不一致 |
| 1 | 商品金额不能为0 | 计算后的总金额为0或负数 |

## 测试用例

项目包含完整的单元测试，覆盖以下场景：

1. ✅ 正常订单创建
2. ✅ 商品不存在
3. ✅ 商品已下架
4. ✅ 库存不足
5. ✅ 超过购买限制
6. ✅ 多商品金额计算
7. ✅ 金额不一致检测

运行测试：
```bash
mvn test -Dtest=OrderValidationTest
```

## 最佳实践

### 1. 安全性
- 始终使用后台查询的商品信息
- 不信任前端传入的价格数据
- 在保存前再次验证商品状态

### 2. 性能优化
- 批量查询商品信息（如果需要）
- 缓存商品基础信息（可选）
- 合理的错误提示，避免过多数据库查询

### 3. 用户体验
- 提供清晰的错误提示信息
- 支持金额小误差容忍（0.01元）
- 及时更新前端商品状态

## 总结

通过后台验证商品信息的方案，我们实现了：

1. **数据安全性**：防止价格篡改，确保订单金额准确
2. **业务完整性**：完整的商品状态、库存、限制验证
3. **系统稳定性**：详细的错误处理和日志记录
4. **可维护性**：清晰的代码结构和完整的测试覆盖

这种方案比前端传递商品信息更安全可靠，是电商系统的最佳实践。
