1279 lines
35 KiB
Markdown
1279 lines
35 KiB
Markdown
# Prompt First - 版本回溯功能
|
||
|
||
## 输入引用
|
||
|
||
引用相关的 docs 文档链接:
|
||
|
||
- [REQ-010-13.md](../requirements/REQ-010-13.md) - 版本回溯功能需求文档
|
||
- [0022-version-rollback.md](../decisions/adr/0022-version-rollback.md) - 版本回溯功能架构决策
|
||
- [REQ-010-7.md](../requirements/REQ-010-7.md) - 文件存储和解压处理需求文档
|
||
- [REQ-010-12.md](../requirements/REQ-010-12.md) - 文件哈希对比和增量检测需求文档
|
||
- [file/index.md](../api-docs/file/index.md) - 文件模块 API 文档索引(唯一真源)
|
||
|
||
## Context Maps
|
||
|
||
强制列出本次 Prompt 依赖的 Canvas 文件:
|
||
|
||
- [Authentication.canvas](../Authentication.canvas) - 项目架构视觉化展示
|
||
- **相关节点**: [集成核心](node_integration_core) - 提供与Salesforce的各种连接方式
|
||
|
||
## 目标
|
||
|
||
实现版本回溯功能,支持查看和恢复历史版本的元数据文件。包括版本历史记录、版本对比、版本恢复、版本回滚等功能。
|
||
|
||
## 输出格式
|
||
|
||
代码示例(语言:Java)
|
||
|
||
## 约束
|
||
|
||
- **技术栈限制**: 必须基于现有的 Spring Boot 3 + MyBatis Plus 技术栈
|
||
- **架构约束**: 必须遵循 Authentication.canvas 中定义的架构和调用关系
|
||
- **模块约束**: 必须在 datai-salesforce-metadata 模块下实现
|
||
- **数据库约束**: 必须使用 MyBatis Plus 作为持久层框架
|
||
- **性能约束**: 版本对比和恢复性能必须满足要求
|
||
- **依赖约束**: 必须复用现有的 IFileStorageService、IMetadataRetrieveService、IMetadataDeployService 服务接口
|
||
|
||
## Rule Set
|
||
|
||
"请严格参考 @Authentication.canvas 中的状态机转移逻辑,不要自行发挥。"
|
||
|
||
**具体规则**:
|
||
- 必须使用 Canvas 中定义的类名和方法名
|
||
- 必须遵循 Canvas 中定义的调用关系
|
||
- 必须参考 Canvas 中的流程图逻辑
|
||
|
||
## 验收标准
|
||
|
||
- **功能完整性**: 所有版本回溯功能能够正常工作
|
||
- **性能指标**: 版本对比和恢复性能满足要求
|
||
- **安全性**: 恢复和回滚操作安全可靠,有完整的日志记录
|
||
- **代码规范性**: 代码符合项目编码规范,有清晰的注释
|
||
- **可维护性**: 代码结构清晰,易于扩展和维护
|
||
- **可测试性**: 代码易于单元测试和集成测试
|
||
|
||
## 风险
|
||
|
||
- **版本记录风险**: 版本记录不完整可能导致无法恢复
|
||
- **对比风险**: 版本对比不准确可能导致误判
|
||
- **恢复风险**: 恢复操作失败可能导致数据不一致
|
||
- **回滚风险**: 回滚操作失败可能导致无法恢复
|
||
- **存储空间风险**: 版本历史记录过多可能占用大量存储空间
|
||
|
||
## 使用记录
|
||
|
||
| 日期 | 使用场景 | 输入参数 | 输出结果 | 反馈 | 改进措施 |
|
||
|------|---------|---------|---------|------|----------|
|
||
| 2026-01-19 | 实现版本回溯功能 | REQ-010-13.md, 0022-version-rollback.md | 完整的代码实现 | 无 | 无 |
|
||
|
||
---
|
||
|
||
## 核心代码实现
|
||
|
||
### 1. MetadataVersion 实体类
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.entity;
|
||
|
||
import com.baomidou.mybatisplus.annotation.IdType;
|
||
import com.baomidou.mybatisplus.annotation.TableId;
|
||
import com.baomidou.mybatisplus.annotation.TableName;
|
||
import lombok.Data;
|
||
|
||
import java.time.LocalDateTime;
|
||
|
||
/**
|
||
* 元数据版本实体类
|
||
*/
|
||
@Data
|
||
@TableName("datai_metadata_version")
|
||
public class MetadataVersion {
|
||
|
||
/**
|
||
* 主键ID
|
||
*/
|
||
@TableId(type = IdType.AUTO)
|
||
private Long id;
|
||
|
||
/**
|
||
* 版本号
|
||
*/
|
||
private String versionNumber;
|
||
|
||
/**
|
||
* 文件路径
|
||
*/
|
||
private String filePath;
|
||
|
||
/**
|
||
* 文件哈希值
|
||
*/
|
||
private String fileHash;
|
||
|
||
/**
|
||
* 文件内容
|
||
*/
|
||
private String fileContent;
|
||
|
||
/**
|
||
* 版本类型
|
||
*/
|
||
private String versionType;
|
||
|
||
/**
|
||
* 任务ID
|
||
*/
|
||
private Long taskId;
|
||
|
||
/**
|
||
* 组织配置ID
|
||
*/
|
||
private Long orgConfigId;
|
||
|
||
/**
|
||
* 版本时间
|
||
*/
|
||
private LocalDateTime versionTime;
|
||
|
||
/**
|
||
* 部门ID
|
||
*/
|
||
private Long deptId;
|
||
|
||
/**
|
||
* 创建人
|
||
*/
|
||
private String createBy;
|
||
|
||
/**
|
||
* 创建时间
|
||
*/
|
||
private LocalDateTime createTime;
|
||
|
||
/**
|
||
* 更新人
|
||
*/
|
||
private String updateBy;
|
||
|
||
/**
|
||
* 更新时间
|
||
*/
|
||
private LocalDateTime updateTime;
|
||
|
||
/**
|
||
* 备注
|
||
*/
|
||
private String remark;
|
||
}
|
||
```
|
||
|
||
### 2. MetadataVersionMapper 接口
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.mapper;
|
||
|
||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||
import com.datai.salesforce.metadata.entity.MetadataVersion;
|
||
import org.apache.ibatis.annotations.Mapper;
|
||
import org.apache.ibatis.annotations.Param;
|
||
|
||
import java.time.LocalDateTime;
|
||
import java.util.List;
|
||
|
||
/**
|
||
* 元数据版本 Mapper 接口
|
||
*/
|
||
@Mapper
|
||
public interface MetadataVersionMapper extends BaseMapper<MetadataVersion> {
|
||
|
||
/**
|
||
* 按时间查询版本
|
||
* @param startTime 开始时间
|
||
* @param endTime 结束时间
|
||
* @return 版本列表
|
||
*/
|
||
List<MetadataVersion> selectByTimeRange(@Param("startTime") LocalDateTime startTime,
|
||
@Param("endTime") LocalDateTime endTime);
|
||
|
||
/**
|
||
* 按任务查询版本
|
||
* @param taskId 任务ID
|
||
* @return 版本列表
|
||
*/
|
||
List<MetadataVersion> selectByTaskId(@Param("taskId") Long taskId);
|
||
|
||
/**
|
||
* 按文件路径查询版本
|
||
* @param filePath 文件路径
|
||
* @return 版本列表
|
||
*/
|
||
List<MetadataVersion> selectByFilePath(@Param("filePath") String filePath);
|
||
|
||
/**
|
||
* 查询最新版本
|
||
* @param filePath 文件路径
|
||
* @return 最新版本
|
||
*/
|
||
MetadataVersion selectLatestVersion(@Param("filePath") String filePath);
|
||
|
||
/**
|
||
* 按时间查询版本(分页)
|
||
* @param page 分页参数
|
||
* @param startTime 开始时间
|
||
* @param endTime 结束时间
|
||
* @return 版本列表
|
||
*/
|
||
IPage<MetadataVersion> selectByTimeRangePage(Page<MetadataVersion> page,
|
||
@Param("startTime") LocalDateTime startTime,
|
||
@Param("endTime") LocalDateTime endTime);
|
||
}
|
||
```
|
||
|
||
### 3. IMetadataVersionService 服务接口
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.service.version;
|
||
|
||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||
import com.datai.salesforce.metadata.entity.MetadataVersion;
|
||
|
||
import java.time.LocalDateTime;
|
||
import java.util.List;
|
||
|
||
/**
|
||
* 元数据版本服务接口
|
||
*/
|
||
public interface IMetadataVersionService {
|
||
|
||
/**
|
||
* 创建版本
|
||
* @param version 版本信息
|
||
* @return 版本ID
|
||
*/
|
||
Long createVersion(MetadataVersion version);
|
||
|
||
/**
|
||
* 查询版本
|
||
* @param id 版本ID
|
||
* @return 版本信息
|
||
*/
|
||
MetadataVersion getVersion(Long id);
|
||
|
||
/**
|
||
* 按时间查询版本
|
||
* @param startTime 开始时间
|
||
* @param endTime 结束时间
|
||
* @return 版本列表
|
||
*/
|
||
List<MetadataVersion> getVersionsByTimeRange(LocalDateTime startTime, LocalDateTime endTime);
|
||
|
||
/**
|
||
* 按任务查询版本
|
||
* @param taskId 任务ID
|
||
* @return 版本列表
|
||
*/
|
||
List<MetadataVersion> getVersionsByTaskId(Long taskId);
|
||
|
||
/**
|
||
* 按文件路径查询版本
|
||
* @param filePath 文件路径
|
||
* @return 版本列表
|
||
*/
|
||
List<MetadataVersion> getVersionsByFilePath(String filePath);
|
||
|
||
/**
|
||
* 查询最新版本
|
||
* @param filePath 文件路径
|
||
* @return 最新版本
|
||
*/
|
||
MetadataVersion getLatestVersion(String filePath);
|
||
|
||
/**
|
||
* 按时间查询版本(分页)
|
||
* @param pageNum 页码
|
||
* @param pageSize 每页大小
|
||
* @param startTime 开始时间
|
||
* @param endTime 结束时间
|
||
* @return 版本列表
|
||
*/
|
||
IPage<MetadataVersion> getVersionsByTimeRangePage(int pageNum, int pageSize,
|
||
LocalDateTime startTime, LocalDateTime endTime);
|
||
|
||
/**
|
||
* 删除版本
|
||
* @param id 版本ID
|
||
* @return 删除结果
|
||
*/
|
||
boolean deleteVersion(Long id);
|
||
|
||
/**
|
||
* 批量删除版本
|
||
* @param ids 版本ID列表
|
||
* @return 删除结果
|
||
*/
|
||
boolean batchDeleteVersions(List<Long> ids);
|
||
}
|
||
```
|
||
|
||
### 4. MetadataVersionServiceImpl 服务实现
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.service.version.impl;
|
||
|
||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||
import com.datai.salesforce.metadata.entity.MetadataVersion;
|
||
import com.datai.salesforce.metadata.mapper.MetadataVersionMapper;
|
||
import com.datai.salesforce.metadata.service.version.IMetadataVersionService;
|
||
import org.springframework.stereotype.Service;
|
||
|
||
import java.time.LocalDateTime;
|
||
import java.util.List;
|
||
|
||
/**
|
||
* 元数据版本服务实现类
|
||
*/
|
||
@Service
|
||
public class MetadataVersionServiceImpl extends ServiceImpl<MetadataVersionMapper, MetadataVersion>
|
||
implements IMetadataVersionService {
|
||
|
||
@Override
|
||
public Long createVersion(MetadataVersion version) {
|
||
version.setCreateTime(LocalDateTime.now());
|
||
version.setUpdateTime(LocalDateTime.now());
|
||
save(version);
|
||
return version.getId();
|
||
}
|
||
|
||
@Override
|
||
public MetadataVersion getVersion(Long id) {
|
||
return getById(id);
|
||
}
|
||
|
||
@Override
|
||
public List<MetadataVersion> getVersionsByTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
|
||
return baseMapper.selectByTimeRange(startTime, endTime);
|
||
}
|
||
|
||
@Override
|
||
public List<MetadataVersion> getVersionsByTaskId(Long taskId) {
|
||
return baseMapper.selectByTaskId(taskId);
|
||
}
|
||
|
||
@Override
|
||
public List<MetadataVersion> getVersionsByFilePath(String filePath) {
|
||
return baseMapper.selectByFilePath(filePath);
|
||
}
|
||
|
||
@Override
|
||
public MetadataVersion getLatestVersion(String filePath) {
|
||
return baseMapper.selectLatestVersion(filePath);
|
||
}
|
||
|
||
@Override
|
||
public IPage<MetadataVersion> getVersionsByTimeRangePage(int pageNum, int pageSize,
|
||
LocalDateTime startTime, LocalDateTime endTime) {
|
||
Page<MetadataVersion> page = new Page<>(pageNum, pageSize);
|
||
return baseMapper.selectByTimeRangePage(page, startTime, endTime);
|
||
}
|
||
|
||
@Override
|
||
public boolean deleteVersion(Long id) {
|
||
return removeById(id);
|
||
}
|
||
|
||
@Override
|
||
public boolean batchDeleteVersions(List<Long> ids) {
|
||
return removeByIds(ids);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5. IVersionComparisonService 服务接口
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.service.version;
|
||
|
||
import com.datai.salesforce.metadata.entity.MetadataVersion;
|
||
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 版本对比服务接口
|
||
*/
|
||
public interface IVersionComparisonService {
|
||
|
||
/**
|
||
* 对比版本
|
||
* @param versionId1 版本ID1
|
||
* @param versionId2 版本ID2
|
||
* @return 对比结果
|
||
*/
|
||
Map<String, Object> compareVersions(Long versionId1, Long versionId2);
|
||
|
||
/**
|
||
* 对比文件内容
|
||
* @param content1 文件内容1
|
||
* @param content2 文件内容2
|
||
* @return 对比结果
|
||
*/
|
||
Map<String, Object> compareFileContent(String content1, String content2);
|
||
|
||
/**
|
||
* 对比文件哈希
|
||
* @param hash1 文件哈希1
|
||
* @param hash2 文件哈希2
|
||
* @return 对比结果
|
||
*/
|
||
Map<String, Object> compareFileHash(String hash1, String hash2);
|
||
}
|
||
```
|
||
|
||
### 6. VersionComparisonServiceImpl 服务实现
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.service.version.impl;
|
||
|
||
import com.datai.salesforce.metadata.entity.MetadataVersion;
|
||
import com.datai.salesforce.metadata.service.version.IVersionComparisonService;
|
||
import com.datai.salesforce.metadata.service.version.IMetadataVersionService;
|
||
import com.google.diffmatchpatch.DiffMatchPatch;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.stereotype.Service;
|
||
|
||
import java.util.HashMap;
|
||
import java.util.LinkedList;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 版本对比服务实现类
|
||
*/
|
||
@Service
|
||
public class VersionComparisonServiceImpl implements IVersionComparisonService {
|
||
|
||
@Autowired
|
||
private IMetadataVersionService metadataVersionService;
|
||
|
||
private final DiffMatchPatch diffMatchPatch = new DiffMatchPatch();
|
||
|
||
@Override
|
||
public Map<String, Object> compareVersions(Long versionId1, Long versionId2) {
|
||
MetadataVersion version1 = metadataVersionService.getVersion(versionId1);
|
||
MetadataVersion version2 = metadataVersionService.getVersion(versionId2);
|
||
|
||
Map<String, Object> result = new HashMap<>();
|
||
result.put("version1", version1);
|
||
result.put("version2", version2);
|
||
result.put("contentDiff", compareFileContent(version1.getFileContent(), version2.getFileContent()));
|
||
result.put("hashDiff", compareFileHash(version1.getFileHash(), version2.getFileHash()));
|
||
|
||
return result;
|
||
}
|
||
|
||
@Override
|
||
public Map<String, Object> compareFileContent(String content1, String content2) {
|
||
LinkedList<DiffMatchPatch.Diff> diffs = diffMatchPatch.diffMain(content1, content2, false);
|
||
diffMatchPatch.diffCleanupSemantic(diffs);
|
||
|
||
Map<String, Object> result = new HashMap<>();
|
||
result.put("diffs", diffs);
|
||
result.put("hasChanges", diffs.size() > 1);
|
||
|
||
return result;
|
||
}
|
||
|
||
@Override
|
||
public Map<String, Object> compareFileHash(String hash1, String hash2) {
|
||
Map<String, Object> result = new HashMap<>();
|
||
result.put("hash1", hash1);
|
||
result.put("hash2", hash2);
|
||
result.put("isEqual", hash1.equals(hash2));
|
||
|
||
return result;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 7. IVersionRecoveryService 服务接口
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.service.version;
|
||
|
||
import com.datai.salesforce.metadata.entity.MetadataVersion;
|
||
|
||
/**
|
||
* 版本恢复服务接口
|
||
*/
|
||
public interface IVersionRecoveryService {
|
||
|
||
/**
|
||
* 恢复版本
|
||
* @param versionId 版本ID
|
||
* @return 恢复结果
|
||
*/
|
||
String recoverVersion(Long versionId);
|
||
|
||
/**
|
||
* 恢复版本(异步)
|
||
* @param versionId 版本ID
|
||
* @return 恢复结果
|
||
*/
|
||
java.util.concurrent.Future<String> recoverVersionAsync(Long versionId);
|
||
}
|
||
```
|
||
|
||
### 8. VersionRecoveryServiceImpl 服务实现
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.service.version.impl;
|
||
|
||
import com.datai.salesforce.metadata.entity.MetadataVersion;
|
||
import com.datai.salesforce.metadata.service.deploy.IMetadataDeployService;
|
||
import com.datai.salesforce.metadata.service.version.IVersionRecoveryService;
|
||
import com.datai.salesforce.metadata.service.version.IMetadataVersionService;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.scheduling.annotation.Async;
|
||
import org.springframework.stereotype.Service;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
|
||
import java.util.concurrent.CompletableFuture;
|
||
import java.util.concurrent.Future;
|
||
|
||
/**
|
||
* 版本恢复服务实现类
|
||
*/
|
||
@Service
|
||
public class VersionRecoveryServiceImpl implements IVersionRecoveryService {
|
||
|
||
@Autowired
|
||
private IMetadataVersionService metadataVersionService;
|
||
|
||
@Autowired
|
||
private IMetadataDeployService metadataDeployService;
|
||
|
||
@Override
|
||
@Transactional
|
||
public String recoverVersion(Long versionId) {
|
||
MetadataVersion version = metadataVersionService.getVersion(versionId);
|
||
|
||
if (version == null) {
|
||
throw new RuntimeException("Version not found");
|
||
}
|
||
|
||
String result = metadataDeployService.deploy(version.getTaskId(),
|
||
version.getOrgConfigId(),
|
||
version.getFileContent());
|
||
|
||
return result;
|
||
}
|
||
|
||
@Override
|
||
@Async("deployExecutor")
|
||
public Future<String> recoverVersionAsync(Long versionId) {
|
||
return CompletableFuture.completedFuture(recoverVersion(versionId));
|
||
}
|
||
}
|
||
```
|
||
|
||
### 9. IVersionRollbackService 服务接口
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.service.version;
|
||
|
||
/**
|
||
* 版本回滚服务接口
|
||
*/
|
||
public interface IVersionRollbackService {
|
||
|
||
/**
|
||
* 回滚到上一个版本
|
||
* @param filePath 文件路径
|
||
* @return 回滚结果
|
||
*/
|
||
String rollbackToPreviousVersion(String filePath);
|
||
|
||
/**
|
||
* 回滚到上一个版本(异步)
|
||
* @param filePath 文件路径
|
||
* @return 回滚结果
|
||
*/
|
||
java.util.concurrent.Future<String> rollbackToPreviousVersionAsync(String filePath);
|
||
}
|
||
```
|
||
|
||
### 10. VersionRollbackServiceImpl 服务实现
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.service.version.impl;
|
||
|
||
import com.datai.salesforce.metadata.entity.MetadataVersion;
|
||
import com.datai.salesforce.metadata.service.deploy.IMetadataDeployService;
|
||
import com.datai.salesforce.metadata.service.version.IVersionRollbackService;
|
||
import com.datai.salesforce.metadata.service.version.IMetadataVersionService;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.scheduling.annotation.Async;
|
||
import org.springframework.stereotype.Service;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
|
||
import java.util.List;
|
||
import java.util.concurrent.CompletableFuture;
|
||
import java.util.concurrent.Future;
|
||
|
||
/**
|
||
* 版本回滚服务实现类
|
||
*/
|
||
@Service
|
||
public class VersionRollbackServiceImpl implements IVersionRollbackService {
|
||
|
||
@Autowired
|
||
private IMetadataVersionService metadataVersionService;
|
||
|
||
@Autowired
|
||
private IMetadataDeployService metadataDeployService;
|
||
|
||
@Override
|
||
@Transactional
|
||
public String rollbackToPreviousVersion(String filePath) {
|
||
List<MetadataVersion> versions = metadataVersionService.getVersionsByFilePath(filePath);
|
||
|
||
if (versions == null || versions.size() < 2) {
|
||
throw new RuntimeException("No previous version found");
|
||
}
|
||
|
||
MetadataVersion previousVersion = versions.get(1);
|
||
|
||
String result = metadataDeployService.deploy(previousVersion.getTaskId(),
|
||
previousVersion.getOrgConfigId(),
|
||
previousVersion.getFileContent());
|
||
|
||
return result;
|
||
}
|
||
|
||
@Override
|
||
@Async("deployExecutor")
|
||
public Future<String> rollbackToPreviousVersionAsync(String filePath) {
|
||
return CompletableFuture.completedFuture(rollbackToPreviousVersion(filePath));
|
||
}
|
||
}
|
||
```
|
||
|
||
### 11. VersionHistoryController 控制器
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.controller;
|
||
|
||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||
import com.datai.salesforce.metadata.entity.MetadataVersion;
|
||
import com.datai.salesforce.metadata.service.version.IMetadataVersionService;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.web.bind.annotation.*;
|
||
|
||
import java.time.LocalDateTime;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 版本历史控制器
|
||
*/
|
||
@RestController
|
||
@RequestMapping("/api/metadata/version-history")
|
||
public class VersionHistoryController {
|
||
|
||
@Autowired
|
||
private IMetadataVersionService metadataVersionService;
|
||
|
||
@PostMapping("/create")
|
||
public Map<String, Object> createVersion(@RequestBody MetadataVersion version) {
|
||
Long versionId = metadataVersionService.createVersion(version);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("versionId", versionId);
|
||
return response;
|
||
}
|
||
|
||
@GetMapping("/get/{id}")
|
||
public Map<String, Object> getVersion(@PathVariable Long id) {
|
||
MetadataVersion version = metadataVersionService.getVersion(id);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("version", version);
|
||
return response;
|
||
}
|
||
|
||
@GetMapping("/by-time-range")
|
||
public Map<String, Object> getVersionsByTimeRange(@RequestParam String startTime,
|
||
@RequestParam String endTime) {
|
||
LocalDateTime start = LocalDateTime.parse(startTime);
|
||
LocalDateTime end = LocalDateTime.parse(endTime);
|
||
List<MetadataVersion> versions = metadataVersionService.getVersionsByTimeRange(start, end);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("versions", versions);
|
||
return response;
|
||
}
|
||
|
||
@GetMapping("/by-task/{taskId}")
|
||
public Map<String, Object> getVersionsByTaskId(@PathVariable Long taskId) {
|
||
List<MetadataVersion> versions = metadataVersionService.getVersionsByTaskId(taskId);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("versions", versions);
|
||
return response;
|
||
}
|
||
|
||
@GetMapping("/by-file-path")
|
||
public Map<String, Object> getVersionsByFilePath(@RequestParam String filePath) {
|
||
List<MetadataVersion> versions = metadataVersionService.getVersionsByFilePath(filePath);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("versions", versions);
|
||
return response;
|
||
}
|
||
|
||
@GetMapping("/latest")
|
||
public Map<String, Object> getLatestVersion(@RequestParam String filePath) {
|
||
MetadataVersion version = metadataVersionService.getLatestVersion(filePath);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("version", version);
|
||
return response;
|
||
}
|
||
|
||
@GetMapping("/by-time-range-page")
|
||
public Map<String, Object> getVersionsByTimeRangePage(@RequestParam int pageNum,
|
||
@RequestParam int pageSize,
|
||
@RequestParam String startTime,
|
||
@RequestParam String endTime) {
|
||
LocalDateTime start = LocalDateTime.parse(startTime);
|
||
LocalDateTime end = LocalDateTime.parse(endTime);
|
||
IPage<MetadataVersion> versions = metadataVersionService.getVersionsByTimeRangePage(pageNum, pageSize, start, end);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("versions", versions);
|
||
return response;
|
||
}
|
||
|
||
@DeleteMapping("/delete/{id}")
|
||
public Map<String, Object> deleteVersion(@PathVariable Long id) {
|
||
boolean result = metadataVersionService.deleteVersion(id);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", result);
|
||
return response;
|
||
}
|
||
|
||
@DeleteMapping("/batch-delete")
|
||
public Map<String, Object> batchDeleteVersions(@RequestBody List<Long> ids) {
|
||
boolean result = metadataVersionService.batchDeleteVersions(ids);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", result);
|
||
return response;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 12. VersionComparisonController 控制器
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.controller;
|
||
|
||
import com.datai.salesforce.metadata.service.version.IVersionComparisonService;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.web.bind.annotation.*;
|
||
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 版本对比控制器
|
||
*/
|
||
@RestController
|
||
@RequestMapping("/api/metadata/version-comparison")
|
||
public class VersionComparisonController {
|
||
|
||
@Autowired
|
||
private IVersionComparisonService versionComparisonService;
|
||
|
||
@PostMapping("/compare-versions")
|
||
public Map<String, Object> compareVersions(@RequestBody Map<String, Long> request) {
|
||
Long versionId1 = request.get("versionId1");
|
||
Long versionId2 = request.get("versionId2");
|
||
Map<String, Object> result = versionComparisonService.compareVersions(versionId1, versionId2);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("result", result);
|
||
return response;
|
||
}
|
||
|
||
@PostMapping("/compare-content")
|
||
public Map<String, Object> compareFileContent(@RequestBody Map<String, String> request) {
|
||
String content1 = request.get("content1");
|
||
String content2 = request.get("content2");
|
||
Map<String, Object> result = versionComparisonService.compareFileContent(content1, content2);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("result", result);
|
||
return response;
|
||
}
|
||
|
||
@PostMapping("/compare-hash")
|
||
public Map<String, Object> compareFileHash(@RequestBody Map<String, String> request) {
|
||
String hash1 = request.get("hash1");
|
||
String hash2 = request.get("hash2");
|
||
Map<String, Object> result = versionComparisonService.compareFileHash(hash1, hash2);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("result", result);
|
||
return response;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 13. VersionRecoveryController 控制器
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.controller;
|
||
|
||
import com.datai.salesforce.metadata.service.version.IVersionRecoveryService;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.web.bind.annotation.*;
|
||
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 版本恢复控制器
|
||
*/
|
||
@RestController
|
||
@RequestMapping("/api/metadata/version-recovery")
|
||
public class VersionRecoveryController {
|
||
|
||
@Autowired
|
||
private IVersionRecoveryService versionRecoveryService;
|
||
|
||
@PostMapping("/recover")
|
||
public Map<String, Object> recoverVersion(@RequestBody Map<String, Long> request) {
|
||
Long versionId = request.get("versionId");
|
||
String result = versionRecoveryService.recoverVersion(versionId);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("result", result);
|
||
return response;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 14. VersionRollbackController 控制器
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.controller;
|
||
|
||
import com.datai.salesforce.metadata.service.version.IVersionRollbackService;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.web.bind.annotation.*;
|
||
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 版本回滚控制器
|
||
*/
|
||
@RestController
|
||
@RequestMapping("/api/metadata/version-rollback")
|
||
public class VersionRollbackController {
|
||
|
||
@Autowired
|
||
private IVersionRollbackService versionRollbackService;
|
||
|
||
@PostMapping("/rollback")
|
||
public Map<String, Object> rollbackToPreviousVersion(@RequestBody Map<String, String> request) {
|
||
String filePath = request.get("filePath");
|
||
String result = versionRollbackService.rollbackToPreviousVersion(filePath);
|
||
|
||
Map<String, Object> response = new HashMap<>();
|
||
response.put("success", true);
|
||
response.put("result", result);
|
||
return response;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 15. DTO 类
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.dto;
|
||
|
||
import com.datai.salesforce.metadata.entity.MetadataVersion;
|
||
import lombok.Data;
|
||
|
||
import java.time.LocalDateTime;
|
||
import java.util.List;
|
||
|
||
/**
|
||
* 版本历史创建请求
|
||
*/
|
||
@Data
|
||
public class VersionHistoryCreateRequest {
|
||
private String versionNumber;
|
||
private String filePath;
|
||
private String fileHash;
|
||
private String fileContent;
|
||
private String versionType;
|
||
private Long taskId;
|
||
private Long orgConfigId;
|
||
}
|
||
|
||
/**
|
||
* 版本历史创建响应
|
||
*/
|
||
@Data
|
||
public class VersionHistoryCreateResponse {
|
||
private boolean success;
|
||
private Long versionId;
|
||
}
|
||
|
||
/**
|
||
* 版本历史查询请求
|
||
*/
|
||
@Data
|
||
public class VersionHistoryQueryRequest {
|
||
private LocalDateTime startTime;
|
||
private LocalDateTime endTime;
|
||
private Long taskId;
|
||
private String filePath;
|
||
private int pageNum;
|
||
private int pageSize;
|
||
}
|
||
|
||
/**
|
||
* 版本历史查询响应
|
||
*/
|
||
@Data
|
||
public class VersionHistoryQueryResponse {
|
||
private boolean success;
|
||
private List<MetadataVersion> versions;
|
||
}
|
||
|
||
/**
|
||
* 版本对比请求
|
||
*/
|
||
@Data
|
||
public class VersionComparisonRequest {
|
||
private Long versionId1;
|
||
private Long versionId2;
|
||
}
|
||
|
||
/**
|
||
* 版本对比响应
|
||
*/
|
||
@Data
|
||
public class VersionComparisonResponse {
|
||
private boolean success;
|
||
private java.util.Map<String, Object> result;
|
||
}
|
||
|
||
/**
|
||
* 文件内容对比请求
|
||
*/
|
||
@Data
|
||
public class FileContentComparisonRequest {
|
||
private String content1;
|
||
private String content2;
|
||
}
|
||
|
||
/**
|
||
* 文件内容对比响应
|
||
*/
|
||
@Data
|
||
public class FileContentComparisonResponse {
|
||
private boolean success;
|
||
private java.util.Map<String, Object> result;
|
||
}
|
||
|
||
/**
|
||
* 文件哈希对比请求
|
||
*/
|
||
@Data
|
||
public class FileHashComparisonRequest {
|
||
private String hash1;
|
||
private String hash2;
|
||
}
|
||
|
||
/**
|
||
* 文件哈希对比响应
|
||
*/
|
||
@Data
|
||
public class FileHashComparisonResponse {
|
||
private boolean success;
|
||
private java.util.Map<String, Object> result;
|
||
}
|
||
|
||
/**
|
||
* 版本恢复请求
|
||
*/
|
||
@Data
|
||
public class VersionRecoveryRequest {
|
||
private Long versionId;
|
||
}
|
||
|
||
/**
|
||
* 版本恢复响应
|
||
*/
|
||
@Data
|
||
public class VersionRecoveryResponse {
|
||
private boolean success;
|
||
private String result;
|
||
}
|
||
|
||
/**
|
||
* 版本回滚请求
|
||
*/
|
||
@Data
|
||
public class VersionRollbackRequest {
|
||
private String filePath;
|
||
}
|
||
|
||
/**
|
||
* 版本回滚响应
|
||
*/
|
||
@Data
|
||
public class VersionRollbackResponse {
|
||
private boolean success;
|
||
private String result;
|
||
}
|
||
```
|
||
|
||
### 16. 异常类
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.exception;
|
||
|
||
/**
|
||
* 版本历史异常
|
||
*/
|
||
public class VersionHistoryException extends RuntimeException {
|
||
|
||
public VersionHistoryException(String message) {
|
||
super(message);
|
||
}
|
||
|
||
public VersionHistoryException(String message, Throwable cause) {
|
||
super(message, cause);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 版本对比异常
|
||
*/
|
||
public class VersionComparisonException extends RuntimeException {
|
||
|
||
public VersionComparisonException(String message) {
|
||
super(message);
|
||
}
|
||
|
||
public VersionComparisonException(String message, Throwable cause) {
|
||
super(message, cause);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 版本恢复异常
|
||
*/
|
||
public class VersionRecoveryException extends RuntimeException {
|
||
|
||
public VersionRecoveryException(String message) {
|
||
super(message);
|
||
}
|
||
|
||
public VersionRecoveryException(String message, Throwable cause) {
|
||
super(message, cause);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 版本回滚异常
|
||
*/
|
||
public class VersionRollbackException extends RuntimeException {
|
||
|
||
public VersionRollbackException(String message) {
|
||
super(message);
|
||
}
|
||
|
||
public VersionRollbackException(String message, Throwable cause) {
|
||
super(message, cause);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 单元测试
|
||
|
||
### MetadataVersionServiceImplTest
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.service.version.impl;
|
||
|
||
import com.datai.salesforce.metadata.entity.MetadataVersion;
|
||
import com.datai.salesforce.metadata.service.version.IMetadataVersionService;
|
||
import org.junit.jupiter.api.Test;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.boot.test.context.SpringBootTest;
|
||
|
||
import java.time.LocalDateTime;
|
||
|
||
import static org.junit.jupiter.api.Assertions.*;
|
||
|
||
@SpringBootTest
|
||
class MetadataVersionServiceImplTest {
|
||
|
||
@Autowired
|
||
private IMetadataVersionService metadataVersionService;
|
||
|
||
@Test
|
||
void testCreateVersion() {
|
||
MetadataVersion version = new MetadataVersion();
|
||
version.setVersionNumber("v1.0.0");
|
||
version.setFilePath("test.txt");
|
||
version.setFileHash("abc123");
|
||
version.setFileContent("test content");
|
||
version.setVersionType("RETRIEVE");
|
||
version.setTaskId(1L);
|
||
version.setOrgConfigId(1L);
|
||
version.setVersionTime(LocalDateTime.now());
|
||
|
||
Long versionId = metadataVersionService.createVersion(version);
|
||
assertNotNull(versionId);
|
||
assertTrue(versionId > 0);
|
||
}
|
||
|
||
@Test
|
||
void testGetVersion() {
|
||
MetadataVersion version = metadataVersionService.getVersion(1L);
|
||
assertNotNull(version);
|
||
}
|
||
}
|
||
```
|
||
|
||
### VersionComparisonServiceImplTest
|
||
|
||
```java
|
||
package com.datai.salesforce.metadata.service.version.impl;
|
||
|
||
import com.datai.salesforce.metadata.service.version.IVersionComparisonService;
|
||
import org.junit.jupiter.api.Test;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.boot.test.context.SpringBootTest;
|
||
|
||
import java.util.Map;
|
||
|
||
import static org.junit.jupiter.api.Assertions.*;
|
||
|
||
@SpringBootTest
|
||
class VersionComparisonServiceImplTest {
|
||
|
||
@Autowired
|
||
private IVersionComparisonService versionComparisonService;
|
||
|
||
@Test
|
||
void testCompareFileContent() {
|
||
String content1 = "Hello World";
|
||
String content2 = "Hello Java";
|
||
Map<String, Object> result = versionComparisonService.compareFileContent(content1, content2);
|
||
|
||
assertNotNull(result);
|
||
assertTrue((Boolean) result.get("hasChanges"));
|
||
}
|
||
|
||
@Test
|
||
void testCompareFileHash() {
|
||
String hash1 = "abc123";
|
||
String hash2 = "def456";
|
||
Map<String, Object> result = versionComparisonService.compareFileHash(hash1, hash2);
|
||
|
||
assertNotNull(result);
|
||
assertFalse((Boolean) result.get("isEqual"));
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 配置文件
|
||
|
||
### application.yml
|
||
|
||
```yaml
|
||
spring:
|
||
task:
|
||
execution:
|
||
pool:
|
||
core-size: 5
|
||
max-size: 10
|
||
queue-capacity: 100
|
||
thread-name-prefix: version-executor-
|
||
|
||
version-rollback:
|
||
max-versions: 100
|
||
retention-days: 30
|
||
```
|
||
|
||
---
|
||
|
||
## 数据库表
|
||
|
||
### datai_metadata_version
|
||
|
||
```sql
|
||
CREATE TABLE `datai_metadata_version` (
|
||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||
`version_number` varchar(50) NOT NULL COMMENT '版本号',
|
||
`file_path` varchar(500) NOT NULL COMMENT '文件路径',
|
||
`file_hash` varchar(64) DEFAULT NULL COMMENT '文件哈希值',
|
||
`file_content` text COMMENT '文件内容',
|
||
`version_type` varchar(20) NOT NULL COMMENT '版本类型',
|
||
`task_id` bigint DEFAULT NULL COMMENT '任务ID',
|
||
`org_config_id` bigint DEFAULT NULL COMMENT '组织配置ID',
|
||
`version_time` datetime NOT NULL COMMENT '版本时间',
|
||
`dept_id` bigint DEFAULT NULL COMMENT '部门ID',
|
||
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',
|
||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',
|
||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_task_id` (`task_id`),
|
||
KEY `idx_org_config_id` (`org_config_id`),
|
||
KEY `idx_file_path` (`file_path`),
|
||
KEY `idx_version_time` (`version_time`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='元数据版本表';
|
||
```
|
||
|
||
---
|
||
|
||
## 总结
|
||
|
||
本 Prompt 提供了版本回溯功能的完整实现,包括:
|
||
|
||
1. **版本历史记录** - 记录每次拉取和部署的版本
|
||
2. **版本对比** - 对比不同版本的元数据文件
|
||
3. **版本恢复** - 恢复到指定的历史版本
|
||
4. **版本回滚** - 回滚到上一个版本
|
||
|
||
所有代码都遵循 Spring Boot 3 + MyBatis Plus 技术栈,复用现有的服务接口,保持代码一致性。
|