一、系统目标
实现美团买菜系统中商品信息的版本控制和迭代记录功能,支持:
- 商品信息的全生命周期管理
- 商品变更历史追溯
- 商品版本对比
- 回滚到历史版本
- 变更审批流程
二、核心功能设计
1. 商品模型设计
```
商品(Product) {
- 商品ID (product_id): 主键
- 当前版本ID (current_version_id): 外键
- 基础信息: 名称、分类、单位等
- 状态: 上架/下架/待审核
- 创建时间、更新时间
}
商品版本(ProductVersion) {
- 版本ID (version_id): 主键
- 商品ID (product_id): 外键
- 版本号 (version_number): 格式如1.0.0
- 变更类型: 新增/修改/删除
- 变更内容 (change_content): JSON格式存储变更字段
- 变更人 (operator_id)
- 变更时间 (change_time)
- 变更说明 (change_description)
- 状态: 草稿/已发布/已回滚
- 前置版本ID (previous_version_id): 外键
}
商品版本详情(ProductVersionDetail) {
- 详情ID (detail_id): 主键
- 版本ID (version_id): 外键
- 字段名 (field_name)
- 旧值 (old_value)
- 新值 (new_value)
}
```
2. 核心功能实现
2.1 商品创建流程
```java
public VersionedProduct createProduct(ProductDTO productDTO, String operator) {
// 1. 生成新版本号
String version = generateVersionNumber(null); // 初始版本1.0.0
// 2. 创建商品基础信息
Product product = new Product();
product.setName(productDTO.getName());
// 设置其他基础字段...
productRepository.save(product);
// 3. 创建初始版本
ProductVersion versionRecord = new ProductVersion();
versionRecord.setProductId(product.getId());
versionRecord.setVersionNumber(version);
versionRecord.setChangeType(ChangeType.CREATE);
versionRecord.setOperator(operator);
versionRecord.setStatus(VersionStatus.PUBLISHED);
// 4. 记录变更详情
List
details = mapFieldsToDetails(null, productDTO);
versionDetailRepository.saveAll(details);
// 5. 关联当前版本
product.setCurrentVersionId(versionRecord.getId());
productRepository.save(product);
return new VersionedProduct(product, versionRecord);
}
```
2.2 商品更新流程
```java
public VersionedProduct updateProduct(Long productId, ProductDTO productDTO, String operator) {
// 1. 获取当前商品和版本
Product product = productRepository.findById(productId).orElseThrow();
ProductVersion currentVersion = versionRepository.findById(product.getCurrentVersionId()).orElseThrow();
// 2. 生成新版本号
String newVersion = incrementVersion(currentVersion.getVersionNumber());
// 3. 创建新版本记录
ProductVersion newVersionRecord = new ProductVersion();
newVersionRecord.setProductId(productId);
newVersionRecord.setVersionNumber(newVersion);
newVersionRecord.setChangeType(ChangeType.UPDATE);
newVersionRecord.setOperator(operator);
newVersionRecord.setStatus(VersionStatus.DRAFT);
newVersionRecord.setPreviousVersionId(currentVersion.getId());
// 4. 记录变更详情
List details = compareAndGenerateDetails(currentVersion, productDTO);
versionDetailRepository.saveAll(details);
// 5. 保存新版本(草稿状态)
versionRepository.save(newVersionRecord);
// 6. 审批流程(简化版)
if (requiresApproval(details)) {
// 触发审批工作流
return new VersionedProduct(product, newVersionRecord, VersionStatus.PENDING_APPROVAL);
} else {
// 自动发布
newVersionRecord.setStatus(VersionStatus.PUBLISHED);
versionRepository.save(newVersionRecord);
product.setCurrentVersionId(newVersionRecord.getId());
productRepository.save(product);
return new VersionedProduct(product, newVersionRecord);
}
}
```
2.3 版本对比功能
```java
public List compareVersions(Long productId, String version1, String version2) {
// 获取两个版本的详情
List details1 = versionDetailRepository.findByProductIdAndVersionNumber(productId, version1);
List details2 = versionDetailRepository.findByProductIdAndVersionNumber(productId, version2);
// 转换为Map便于比较
Map values1 = details1.stream()
.collect(Collectors.toMap(ProductVersionDetail::getFieldName, ProductVersionDetail::getNewValue));
Map values2 = details2.stream()
.collect(Collectors.toMap(ProductVersionDetail::getFieldName, ProductVersionDetail::getNewValue));
// 找出差异字段
List changes = new ArrayList<>();
Set allFields = new HashSet<>(values1.keySet());
allFields.addAll(values2.keySet());
for (String field : allFields) {
String val1 = values1.getOrDefault(field, "");
String val2 = values2.getOrDefault(field, "");
if (!val1.equals(val2)) {
changes.add(new FieldChange(field, val1, val2));
}
}
return changes;
}
```
2.4 版本回滚功能
```java
public VersionedProduct rollbackToVersion(Long productId, String targetVersion, String operator) {
// 1. 验证目标版本存在且可回滚
ProductVersion targetVersionRecord = versionRepository.findByProductIdAndVersionNumber(productId, targetVersion)
.orElseThrow(() -> new RuntimeException("目标版本不存在"));
if (targetVersionRecord.getStatus() != VersionStatus.PUBLISHED) {
throw new RuntimeException("只能回滚到已发布版本");
}
// 2. 获取当前版本
Product product = productRepository.findById(productId).orElseThrow();
ProductVersion currentVersion = versionRepository.findById(product.getCurrentVersionId()).orElseThrow();
// 3. 创建回滚版本记录
String newVersion = generateVersionNumber(currentVersion.getVersionNumber()); // 如1.0.1回滚到1.0.0会生成1.0.2
ProductVersion rollbackVersion = new ProductVersion();
rollbackVersion.setProductId(productId);
rollbackVersion.setVersionNumber(newVersion);
rollbackVersion.setChangeType(ChangeType.ROLLBACK);
rollbackVersion.setOperator(operator);
rollbackVersion.setStatus(VersionStatus.PUBLISHED);
rollbackVersion.setPreviousVersionId(currentVersion.getId());
rollbackVersion.setChangeDescription("回滚到版本 " + targetVersion);
// 4. 复制目标版本的所有字段作为新版本内容
// (实际实现中需要从targetVersionRecord获取所有字段值)
List rollbackDetails = generateRollbackDetails(targetVersionRecord);
versionDetailRepository.saveAll(rollbackDetails);
// 5. 更新商品当前版本
versionRepository.save(rollbackVersion);
product.setCurrentVersionId(rollbackVersion.getId());
productRepository.save(product);
return new VersionedProduct(product, rollbackVersion);
}
```
三、技术实现要点
1. 版本号生成策略:
- 初始版本:1.0.0
- 小变更(修正):第三位递增(1.0.1)
- 中等变更(功能):第二位递增(1.1.0)
- 大变更(重构):第一位递增(2.0.0)
2. 变更检测:
- 使用反射或DTO比较工具自动检测字段变更
- 关键字段变更触发审批流程
3. 存储优化:
- 完整快照存储:每个版本保存完整商品数据(适合小商品)
- 差异存储:只保存变更字段(适合大商品)
4. 索引优化:
- 为product_id和version_number建立复合索引
- 为change_time建立索引以便按时间查询
四、扩展功能
1. 变更审批工作流:
- 集成公司现有OA审批系统
- 关键字段变更自动触发审批
- 多级审批支持
2. 变更通知:
- 商品变更实时通知相关系统(库存、促销等)
- 变更邮件/站内信通知负责人
3. 数据分析:
- 变更频率统计
- 变更原因分析
- 高频变更字段识别
4. AB测试支持:
- 版本灰度发布
- 多版本并行测试
五、部署与监控
1. 灰度发布策略:
- 先在测试环境验证版本
- 小流量用户逐步放开新版本
2. 监控指标:
- 版本发布成功率
- 回滚率
- 变更审批时效
3. 回滚演练:
- 定期进行回滚演练
- 确保回滚流程在5分钟内完成
六、实施路线图
1. 第一阶段(1个月):
- 实现基础版本控制功能
- 商品创建/更新/删除的版本记录
2. 第二阶段(1个月):
- 版本对比与回滚功能
- 基础审批流程
3. 第三阶段(1个月):
- 与周边系统集成
- 高级分析功能
- 灰度发布支持
该方案实现了美团买菜系统商品信息的全生命周期管理,支持高效的版本控制和变更追溯,同时保持了对业务最小化的影响。