一、功能概述
商品迭代记录功能用于跟踪和管理叮咚买菜平台上商品的变更历史,包括商品信息修改、上下架状态变化、价格调整等关键操作记录,确保商品管理的可追溯性和合规性。
二、系统架构设计
1. 数据库设计
```sql
-- 商品迭代记录表
CREATE TABLE product_iteration_log (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_id BIGINT NOT NULL COMMENT 商品ID,
change_type VARCHAR(50) NOT NULL COMMENT 变更类型(上架/下架/信息修改/价格调整等),
field_name VARCHAR(100) COMMENT 变更字段名,
old_value TEXT COMMENT 旧值,
new_value TEXT COMMENT 新值,
operator_id BIGINT NOT NULL COMMENT 操作人ID,
operator_name VARCHAR(50) NOT NULL COMMENT 操作人姓名,
change_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 变更时间,
ip_address VARCHAR(50) COMMENT 操作IP,
remark VARCHAR(500) COMMENT 备注,
INDEX idx_product_id (product_id),
INDEX idx_change_time (change_time)
);
```
2. 微服务架构
- 商品管理服务:处理商品核心业务逻辑
- 日志服务:专门处理商品变更记录的写入和查询
- 搜索服务:支持按条件快速检索变更记录
三、核心功能实现
1. 变更记录捕获机制
方式一:AOP切面实现
```java
@Aspect
@Component
public class ProductChangeAspect {
@Autowired
private ProductIterationLogService logService;
@AfterReturning(pointcut = "execution(* com.dingdong.product.service.ProductService.update*(..))",
returning = "result")
public void afterUpdate(JoinPoint joinPoint, Object result) {
// 获取方法参数
Object[] args = joinPoint.getArgs();
Product product = (Product) args[0]; // 假设第一个参数是Product对象
// 获取修改前数据(可通过缓存或数据库查询)
Product oldProduct = getOldProductFromCache(product.getId());
// 比较差异并记录
if (oldProduct != null) {
compareAndLogChanges(oldProduct, product, "信息修改", getCurrentOperator());
}
}
private void compareAndLogChanges(Product oldProduct, Product newProduct,
String changeType, Operator operator) {
// 实现字段比较逻辑
if (!Objects.equals(oldProduct.getName(), newProduct.getName())) {
logService.recordChange(
newProduct.getId(),
changeType,
"商品名称",
oldProduct.getName(),
newProduct.getName(),
operator
);
}
// 其他字段比较...
}
}
```
方式二:事件驱动模式
```java
@Service
public class ProductService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public Product updateProduct(ProductUpdateDTO dto) {
// 业务逻辑...
// 发布商品变更事件
ProductChangeEvent event = new ProductChangeEvent(
this,
dto.getProductId(),
"信息修改",
getCurrentOperator()
);
eventPublisher.publishEvent(event);
return product;
}
}
@Component
public class ProductChangeEventListener {
@Autowired
private ProductIterationLogService logService;
@EventListener
public void handleProductChange(ProductChangeEvent event) {
// 获取变更前数据
Product oldProduct = getOldProduct(event.getProductId());
Product newProduct = getCurrentProduct(event.getProductId());
// 比较并记录变更
// ...实现比较逻辑
}
}
```
2. 关键变更类型处理
商品上下架记录
```java
public void changeProductStatus(Long productId, Integer newStatus, Operator operator) {
// 获取当前状态
Product product = productRepository.findById(productId).orElseThrow();
Integer oldStatus = product.getStatus();
// 更新状态
product.setStatus(newStatus);
productRepository.save(product);
// 记录变更
String changeType = newStatus == 1 ? "上架" : "下架";
logService.recordChange(
productId,
changeType,
"商品状态",
oldStatus == 1 ? "已上架" : "已下架",
newStatus == 1 ? "已上架" : "已下架",
operator
);
}
```
价格变更记录
```java
public void updateProductPrice(Long productId, BigDecimal newPrice, Operator operator) {
// 获取旧价格
Product product = productRepository.findById(productId).orElseThrow();
BigDecimal oldPrice = product.getPrice();
// 更新价格
product.setPrice(newPrice);
productRepository.save(product);
// 记录变更
logService.recordChange(
productId,
"价格调整",
"商品价格",
oldPrice.toString(),
newPrice.toString(),
operator
);
}
```
3. 查询与展示功能
后台管理界面查询
```java
@RestController
@RequestMapping("/api/product-logs")
public class ProductLogController {
@Autowired
private ProductIterationLogService logService;
@GetMapping
public Page
getLogs(
@RequestParam Long productId,
@RequestParam(required = false) String changeType,
@RequestParam(required = false) Date startTime,
@RequestParam(required = false) Date endTime,
@PageableDefault Pageable pageable) {
return logService.queryLogs(productId, changeType, startTime, endTime, pageable);
}
}
```
前端展示组件
```javascript
// React示例组件
function ProductChangeHistory({ productId }) {
const [logs, setLogs] = useState([]);
useEffect(() => {
fetch(`/api/product-logs?productId=${productId}`)
.then(res => res.json())
.then(data => setLogs(data.content));
}, [productId]);
return (
商品变更记录
变更时间 |
变更类型 |
变更字段 |
旧值 |
新值 |
操作人 |
|---|
{logs.map(log => (
{formatDate(log.changeTime)} |
{log.changeType} |
{log.fieldName} |
{log.oldValue} |
{log.newValue} |
{log.operatorName} |
))}
);
}
```
四、高级功能实现
1. 变更对比视图
```java
public ProductChangeDiff getProductChangeDiff(Long productId, Date startTime, Date endTime) {
List logs = logService.getLogsBetween(productId, startTime, endTime);
ProductChangeDiff diff = new ProductChangeDiff();
diff.setProductId(productId);
// 按字段分组变更
Map> fieldChanges = new HashMap<>();
for (ProductIterationLog log : logs) {
if (log.getFieldName() != null) {
FieldChange change = new FieldChange(
log.getChangeTime(),
log.getChangeType(),
log.getOldValue(),
log.getNewValue(),
log.getOperatorName()
);
fieldChanges.computeIfAbsent(log.getFieldName(), k -> new ArrayList<>()).add(change);
}
}
diff.setFieldChanges(fieldChanges);
return diff;
}
```
2. 变更通知机制
```java
@Service
public class ChangeNotificationService {
@Autowired
private EmailService emailService;
@Autowired
private SmsService smsService;
@EventListener
public void handleCriticalChange(ProductChangeEvent event) {
if (isCriticalChange(event)) {
// 获取相关负责人
List responsibleUsers = getResponsibleUsers(event.getProductId());
// 发送通知
responsibleUsers.forEach(user -> {
emailService.sendEmail(
user.getEmail(),
"商品变更通知",
generateNotificationContent(event)
);
if (user.getPhone() != null) {
smsService.sendSms(
user.getPhone(),
"叮咚买菜商品变更提醒:" + generateShortContent(event)
);
}
});
}
}
private boolean isCriticalChange(ProductChangeEvent event) {
// 判断是否为关键变更(如价格大幅调整、下架等)
return "价格调整".equals(event.getChangeType()) ||
"下架".equals(event.getChangeType());
}
}
```
五、性能优化方案
1. 异步日志写入:使用消息队列(如RabbitMQ/Kafka)异步处理日志写入
2. 批量插入:对于高频变更,实现批量插入日志功能
3. 读写分离:日志查询走从库,写入走主库
4. 缓存热点数据:对频繁查询的商品变更记录进行缓存
5. 归档策略:对超过一定时间的日志进行归档存储
六、安全与合规考虑
1. 操作审计:记录操作IP、设备信息等辅助审计
2. 权限控制:不同角色对变更记录的查看权限不同
3. 数据加密:敏感信息(如旧价格、新价格)在传输和存储时加密
4. 合规性:符合《网络安全法》等法规对数据留存的要求
5. 防篡改:使用区块链技术或数字签名确保日志不可篡改
七、部署与监控
1. 监控指标:
- 日志写入成功率
- 查询响应时间
- 积压日志数量
2. 告警规则:
- 连续5分钟日志写入失败
- 查询平均响应时间超过500ms
- 积压日志超过1000条
3. 日志分析:
- 变更频率分析
- 高频变更字段统计
- 操作人行为分析
八、测试方案
1. 单元测试:
- 测试各种变更类型的日志记录
- 测试边界条件(如空值、超长字符串)
2. 集成测试:
- 测试与商品管理服务的集成
- 测试与消息队列的集成
3. 性能测试:
- 模拟高并发商品变更场景
- 测试大数据量下的查询性能
4. 安全测试:
- 测试权限控制是否有效
- 测试敏感数据是否泄露
九、上线计划
1. 灰度发布:
- 先在测试环境部署
- 然后对部分商品开启变更记录
- 最后全量发布
2. 数据迁移:
- 对历史商品变更数据进行补录
- 建立数据校验机制确保新旧数据一致
3. 培训文档:
- 编写操作手册
- 录制培训视频
- 开展线上培训
通过以上方案,叮咚买菜系统可以实现完善的商品迭代记录功能,提高商品管理的透明度和可追溯性,为运营决策提供有力支持。