29 KiB
会话记录 - Destructive Changes功能实现
现状
当前项目已经完成了元数据部署核心功能(REQ-010-8)和 Quick Deploy 功能(REQ-010-9)的实现,包括手动触发部署、异步部署执行、状态监控、部署历史记录、部署进度查询、部署取消功能和部署结果解析。现在需要实现 Destructive Changes 功能,支持部署时删除指定的元数据组件,使用 destructiveChanges.xml 配置删除规则。
目标
实现 Destructive Changes 功能,包括 destructiveChanges.xml 配置、Destructive Changes 部署、Destructive Changes 验证、Destructive Changes 历史记录、Destructive Changes 回滚。支持部署时删除指定的元数据组件,使用 destructiveChanges.xml 配置删除规则。
输入链接
- REQ-010-10.md - Destructive Changes功能实现需求文档
- 0019-destructive-changes.md - Destructive Changes功能实现架构决策
- REQ-010-8.md - 元数据部署核心功能需求文档
- 0017-metadata-deploy-core.md - 元数据部署核心功能架构决策
- metadata-module.md - Salesforce Metadata API 模块说明
Prompt 文件
- 020-destructive-changes.md - Destructive Changes功能实现提示词
Context Snapshot
记录本次会话参考了哪些 Canvas 节点:
- Authentication.canvas - 项目架构视觉化展示
- 参考节点: 集成核心 - 提供与Salesforce的各种连接方式
- 参考节点: IMetadataApiService - 元数据API服务接口
- 参考节点: MetadataApiClient - Metadata API客户端
- 快照时间: 2026-01-19 11:00:00
执行过程
1. 创建 DestructiveChangesController 控制器
执行内容: 创建 DestructiveChangesController 控制器,提供 6 个 RESTful API 接口,支持 destructiveChanges.xml 配置、Destructive Changes 部署、Destructive Changes 验证、Destructive Changes 历史记录、Destructive Changes 回滚。
关键代码:
@RestController
@RequestMapping("/metadata/destructive-changes")
public class DestructiveChangesController {
@Autowired
private IDestructiveChangesService destructiveChangesService;
@Autowired
private IDestructiveChangesConfigService destructiveChangesConfigService;
@PostMapping("/config")
public DestructiveChangesConfigResponse saveConfig(@RequestBody DestructiveChangesConfigRequest request) {
return destructiveChangesConfigService.saveConfig(request);
}
@GetMapping("/config/{taskId}")
public DestructiveChangesConfigResponse getConfig(@PathVariable Long taskId) {
return destructiveChangesConfigService.getConfig(taskId);
}
@PostMapping("/validate")
public DestructiveChangesValidateResponse validateConfig(@RequestBody DestructiveChangesValidateRequest request) {
return destructiveChangesConfigService.validateConfig(request);
}
@PostMapping("/deploy")
public DestructiveChangesDeployResponse deploy(@RequestBody DestructiveChangesDeployRequest request) {
return destructiveChangesService.deploy(request);
}
@GetMapping("/history")
public DestructiveChangesHistoryResponse getHistory(
@RequestParam(required = false) Long orgConfigId,
@RequestParam(required = false) String status,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
return destructiveChangesService.getHistory(orgConfigId, status, page, size);
}
@PostMapping("/rollback/{jobId}")
public DestructiveChangesRollbackResponse rollback(@PathVariable Long jobId) {
return destructiveChangesService.rollback(jobId);
}
}
遇到的问题: 无
解决方案: 无
2. 创建 IDestructiveChangesService 服务接口
执行内容: 创建 IDestructiveChangesService 服务接口,定义 Destructive Changes 服务接口方法。
关键代码:
public interface IDestructiveChangesService {
DestructiveChangesDeployResponse deploy(DestructiveChangesDeployRequest request);
DestructiveChangesHistoryResponse getHistory(Long orgConfigId, String status, int page, int size);
DestructiveChangesRollbackResponse rollback(Long jobId);
}
遇到的问题: 无
解决方案: 无
3. 创建 DestructiveChangesServiceImpl 服务实现
执行内容: 创建 DestructiveChangesServiceImpl 服务实现,实现 Destructive Changes 服务接口方法,支持异步执行和状态管理。
关键代码:
@Service
public class DestructiveChangesServiceImpl implements IDestructiveChangesService {
@Autowired
private IMetadataApiService metadataApiService;
@Autowired
private DataiMetaJobExecutionMapper jobExecutionMapper;
@Autowired
private DestructiveChangeRuleMapper destructiveChangeRuleMapper;
@Autowired
private DestructiveChangesXmlBuilder xmlBuilder;
@Override
@Transactional
public DestructiveChangesDeployResponse deploy(DestructiveChangesDeployRequest request) {
QueryWrapper<DestructiveChangeRule> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("task_id", request.getTaskId());
List<DestructiveChangeRule> rules = destructiveChangeRuleMapper.selectList(queryWrapper);
if (rules.isEmpty()) {
throw new RuntimeException("No destructive change rules found");
}
String destructiveChangesXml = xmlBuilder.buildXml(rules);
File destructiveChangesFile = xmlBuilder.saveXmlToFile(request.getTaskId(), destructiveChangesXml);
DataiMetaJobExecution jobExecution = new DataiMetaJobExecution();
jobExecution.setTaskId(request.getTaskId());
jobExecution.setOrgConfigId(request.getOrgConfigId());
jobExecution.setJobType("DESTRUCTIVE_CHANGES");
jobExecution.setStatus("PENDING");
jobExecution.setCreatedBy(request.getCreatedBy());
jobExecutionMapper.insert(jobExecution);
deployAsync(jobExecution.getId(), request.getTaskId(), request.getOrgConfigId(), destructiveChangesFile);
DestructiveChangesDeployResponse response = new DestructiveChangesDeployResponse();
response.setJobId(jobExecution.getId().toString());
response.setStatus("PENDING");
response.setMessage("Destructive Changes deploy task created");
return response;
}
@Override
@Async("deployExecutor")
public Future<Void> deployAsync(Long jobExecutionId, Long taskId, Long orgConfigId, File destructiveChangesFile) {
String jobId = jobExecutionId.toString();
try {
updateJobStatus(jobExecutionId, "PROCESSING");
String deployResult = metadataApiService.deploy(orgConfigId, null, destructiveChangesFile);
updateJobStatus(jobExecutionId, "SUCCESS");
parseDeployResult(jobExecutionId, deployResult);
} catch (Exception e) {
updateJobStatus(jobExecutionId, "FAILED");
throw new RuntimeException("Destructive Changes deploy failed", e);
}
return null;
}
@Override
public DestructiveChangesHistoryResponse getHistory(Long orgConfigId, String status, int page, int size) {
QueryWrapper<DataiMetaJobExecution> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("job_type", "DESTRUCTIVE_CHANGES");
if (orgConfigId != null) {
queryWrapper.eq("org_config_id", orgConfigId);
}
if (status != null && !status.isEmpty()) {
queryWrapper.eq("status", status);
}
queryWrapper.orderByDesc("create_time");
Page<DataiMetaJobExecution> pageResult = jobExecutionMapper.selectPage(
new Page<>(page, size), queryWrapper);
DestructiveChangesHistoryResponse response = new DestructiveChangesHistoryResponse();
response.setTotal(pageResult.getTotal());
response.setPage(page);
response.setSize(size);
response.setRecords(pageResult.getRecords());
return response;
}
@Override
@Transactional
public DestructiveChangesRollbackResponse rollback(Long jobId) {
DataiMetaJobExecution jobExecution = jobExecutionMapper.selectById(jobId);
if (jobExecution == null) {
throw new RuntimeException("Job not found");
}
if (!"SUCCESS".equals(jobExecution.getStatus())) {
throw new RuntimeException("Only successful deployments can be rolled back");
}
String backupData = jobExecution.getBackupData();
if (backupData == null || backupData.isEmpty()) {
throw new RuntimeException("No backup data found");
}
rollbackAsync(jobId, jobExecution.getOrgConfigId(), backupData);
DestructiveChangesRollbackResponse response = new DestructiveChangesRollbackResponse();
response.setJobId(jobId.toString());
response.setStatus("ROLLBACK_IN_PROGRESS");
response.setMessage("Rollback task created");
return response;
}
@Async("deployExecutor")
public Future<Void> rollbackAsync(Long jobId, Long orgConfigId, String backupData) {
try {
updateJobStatus(jobId, "ROLLBACK_PROCESSING");
String rollbackResult = metadataApiService.rollback(orgConfigId, backupData);
updateJobStatus(jobId, "ROLLBACK_SUCCESS");
parseRollbackResult(jobId, rollbackResult);
} catch (Exception e) {
updateJobStatus(jobId, "ROLLBACK_FAILED");
throw new RuntimeException("Rollback failed", e);
}
return null;
}
private void updateJobStatus(Long jobExecutionId, String status) {
DataiMetaJobExecution jobExecution = new DataiMetaJobExecution();
jobExecution.setId(jobExecutionId);
jobExecution.setStatus(status);
jobExecution.setUpdateTime(new Date());
jobExecutionMapper.updateById(jobExecution);
}
private void parseDeployResult(Long jobExecutionId, String deployResult) {
DataiMetaJobExecution jobExecution = jobExecutionMapper.selectById(jobExecutionId);
if (jobExecution != null) {
jobExecution.setRemark(deployResult);
jobExecutionMapper.updateById(jobExecution);
}
}
private void parseRollbackResult(Long jobId, String rollbackResult) {
DataiMetaJobExecution jobExecution = jobExecutionMapper.selectById(jobId);
if (jobExecution != null) {
jobExecution.setRemark(rollbackResult);
jobExecutionMapper.updateById(jobExecution);
}
}
}
遇到的问题: 无
解决方案: 无
4. 创建 IDestructiveChangesConfigService 服务接口
执行内容: 创建 IDestructiveChangesConfigService 服务接口,定义 Destructive Changes 配置服务接口方法。
关键代码:
public interface IDestructiveChangesConfigService {
DestructiveChangesConfigResponse saveConfig(DestructiveChangesConfigRequest request);
DestructiveChangesConfigResponse getConfig(Long taskId);
DestructiveChangesValidateResponse validateConfig(DestructiveChangesValidateRequest request);
}
遇到的问题: 无
解决方案: 无
5. 创建 DestructiveChangesConfigServiceImpl 服务实现
执行内容: 创建 DestructiveChangesConfigServiceImpl 服务实现,实现 Destructive Changes 配置服务接口方法,支持 destructiveChanges.xml 配置和验证。
关键代码:
@Service
public class DestructiveChangesConfigServiceImpl implements IDestructiveChangesConfigService {
@Autowired
private DestructiveChangeRuleMapper destructiveChangeRuleMapper;
@Autowired
private DestructiveChangesXmlParser xmlParser;
@Autowired
private DestructiveChangesXmlBuilder xmlBuilder;
@Override
@Transactional
public DestructiveChangesConfigResponse saveConfig(DestructiveChangesConfigRequest request) {
QueryWrapper<DestructiveChangeRule> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("task_id", request.getTaskId());
destructiveChangeRuleMapper.delete(queryWrapper);
for (DestructiveChangesConfigRequest.Rule rule : request.getRules()) {
DestructiveChangeRule entity = new DestructiveChangeRule();
entity.setTaskId(request.getTaskId());
entity.setMetadataType(rule.getMetadataType());
entity.setMemberName(rule.getMemberName());
destructiveChangeRuleMapper.insert(entity);
}
String xml = xmlBuilder.buildXml(request.getTaskId());
DestructiveChangesConfigResponse response = new DestructiveChangesConfigResponse();
response.setTaskId(request.getTaskId());
response.setXml(xml);
response.setMessage("Configuration saved successfully");
return response;
}
@Override
public DestructiveChangesConfigResponse getConfig(Long taskId) {
QueryWrapper<DestructiveChangeRule> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("task_id", taskId);
List<DestructiveChangeRule> rules = destructiveChangeRuleMapper.selectList(queryWrapper);
String xml = xmlBuilder.buildXml(taskId);
DestructiveChangesConfigResponse response = new DestructiveChangesConfigResponse();
response.setTaskId(taskId);
response.setXml(xml);
response.setRules(rules);
return response;
}
@Override
public DestructiveChangesValidateResponse validateConfig(DestructiveChangesValidateRequest request) {
try {
xmlParser.parseXml(request.getXml());
DestructiveChangesValidateResponse response = new DestructiveChangesValidateResponse();
response.setValid(true);
response.setMessage("Configuration is valid");
return response;
} catch (Exception e) {
DestructiveChangesValidateResponse response = new DestructiveChangesValidateResponse();
response.setValid(false);
response.setMessage(e.getMessage());
return response;
}
}
}
遇到的问题: 无
解决方案: 无
6. 创建 DestructiveChangesXmlParser 工具类
执行内容: 创建 DestructiveChangesXmlParser 工具类,使用 Java XML 解析库验证 destructiveChanges.xml 格式。
关键代码:
@Component
public class DestructiveChangesXmlParser {
public void parseXml(String xml) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new ByteArrayInputStream(xml.getBytes()));
Element root = document.getDocumentElement();
if (!"Package".equals(root.getNodeName())) {
throw new RuntimeException("Root element must be 'Package'");
}
NodeList types = root.getElementsByTagName("types");
for (int i = 0; i < types.getLength(); i++) {
Element typeElement = (Element) types.item(i);
NodeList members = typeElement.getElementsByTagName("members");
NodeList name = typeElement.getElementsByTagName("name");
if (members.getLength() == 0) {
throw new RuntimeException("Type element must have at least one 'members' element");
}
if (name.getLength() != 1) {
throw new RuntimeException("Type element must have exactly one 'name' element");
}
}
}
}
遇到的问题: 无
解决方案: 无
7. 创建 DestructiveChangesXmlBuilder 工具类
执行内容: 创建 DestructiveChangesXmlBuilder 工具类,使用 Java XML 解析库构建 destructiveChanges.xml。
关键代码:
@Component
public class DestructiveChangesXmlBuilder {
@Autowired
private DestructiveChangeRuleMapper destructiveChangeRuleMapper;
public String buildXml(Long taskId) {
QueryWrapper<DestructiveChangeRule> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("task_id", taskId);
List<DestructiveChangeRule> rules = destructiveChangeRuleMapper.selectList(queryWrapper);
return buildXml(rules);
}
public String buildXml(List<DestructiveChangeRule> rules) {
StringBuilder xml = new StringBuilder();
xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
xml.append("<Package xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n");
Map<String, List<DestructiveChangeRule>> groupedRules = rules.stream()
.collect(Collectors.groupingBy(DestructiveChangeRule::getMetadataType));
for (Map.Entry<String, List<DestructiveChangeRule>> entry : groupedRules.entrySet()) {
xml.append(" <types>\n");
for (DestructiveChangeRule rule : entry.getValue()) {
xml.append(" <members>").append(rule.getMemberName()).append("</members>\n");
}
xml.append(" <name>").append(entry.getKey()).append("</name>\n");
xml.append(" </types>\n");
}
xml.append(" <version>56.0</version>\n");
xml.append("</Package>");
return xml.toString();
}
public File saveXmlToFile(Long taskId, String xml) throws IOException {
String fileName = "destructiveChanges-" + taskId + ".xml";
File file = new File(System.getProperty("java.io.tmpdir"), fileName);
try (FileWriter writer = new FileWriter(file)) {
writer.write(xml);
}
return file;
}
}
遇到的问题: 无
解决方案: 无
8. 创建 DestructiveChangeRule 实体类和 Mapper
执行内容: 创建 DestructiveChangeRule 实体类和 DestructiveChangeRuleMapper 接口,使用 MyBatis Plus 的 BaseMapper 实现数据库操作。
关键代码:
@Data
@TableName("datai_destructive_change_rule")
public class DestructiveChangeRule {
@TableId(type = IdType.AUTO)
private Long id;
private Long taskId;
private String metadataType;
private String memberName;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
@Mapper
public interface DestructiveChangeRuleMapper extends BaseMapper<DestructiveChangeRule> {
}
遇到的问题: 无
解决方案: 无
9. 创建 DTO 类
执行内容: 创建 DestructiveChangesConfigRequest、DestructiveChangesConfigResponse、DestructiveChangesValidateRequest、DestructiveChangesValidateResponse、DestructiveChangesDeployRequest、DestructiveChangesDeployResponse、DestructiveChangesHistoryResponse、DestructiveChangesRollbackRequest、DestructiveChangesRollbackResponse 等 DTO 类。
关键代码:
@Data
public class DestructiveChangesConfigRequest {
private Long taskId;
private List<Rule> rules;
@Data
public static class Rule {
private String metadataType;
private String memberName;
}
}
@Data
public class DestructiveChangesConfigResponse {
private Long taskId;
private String xml;
private List<Object> rules;
private String message;
}
@Data
public class DestructiveChangesValidateRequest {
private String xml;
}
@Data
public class DestructiveChangesValidateResponse {
private boolean valid;
private String message;
}
@Data
public class DestructiveChangesDeployRequest {
private Long taskId;
private Long orgConfigId;
private String createdBy;
}
@Data
public class DestructiveChangesDeployResponse {
private String jobId;
private String status;
private String message;
}
@Data
public class DestructiveChangesHistoryResponse {
private long total;
private int page;
private int size;
private List<Object> records;
}
@Data
public class DestructiveChangesRollbackRequest {
private Long jobId;
}
@Data
public class DestructiveChangesRollbackResponse {
private String jobId;
private String status;
private String message;
}
遇到的问题: 无
解决方案: 无
10. 创建 DestructiveChangesException 异常类
执行内容: 创建 DestructiveChangesException 异常类,处理 Destructive Changes 相关的异常。
关键代码:
public class DestructiveChangesException extends RuntimeException {
public DestructiveChangesException(String message) {
super(message);
}
public DestructiveChangesException(String message, Throwable cause) {
super(message, cause);
}
}
遇到的问题: 无
解决方案: 无
11. 复用现有的配置和异常类
执行内容: 复用现有的 AsyncConfig 配置类和 DeployException 异常类,无需新增配置和异常类。
遇到的问题: 无
解决方案: 无
关键产出
记录本次会话的关键产出:
- 生成的代码文件:
- DestructiveChangesController.java - Destructive Changes 控制器
- IDestructiveChangesService.java - Destructive Changes 服务接口
- DestructiveChangesServiceImpl.java - Destructive Changes 服务实现
- IDestructiveChangesConfigService.java - Destructive Changes 配置服务接口
- DestructiveChangesConfigServiceImpl.java - Destructive Changes 配置服务实现
- DestructiveChangesXmlParser.java - Destructive Changes XML 解析器
- DestructiveChangesXmlBuilder.java - Destructive Changes XML 构建器
- DestructiveChangeRule.java - Destructive Change Rule 实体类
- DestructiveChangeRuleMapper.java - Destructive Change Rule Mapper 接口
- DestructiveChangesConfigRequest.java - Destructive Changes 配置请求 DTO
- DestructiveChangesConfigResponse.java - Destructive Changes 配置响应 DTO
- DestructiveChangesValidateRequest.java - Destructive Changes 验证请求 DTO
- DestructiveChangesValidateResponse.java - Destructive Changes 验证响应 DTO
- DestructiveChangesDeployRequest.java - Destructive Changes 部署请求 DTO
- DestructiveChangesDeployResponse.java - Destructive Changes 部署响应 DTO
- DestructiveChangesHistoryResponse.java - Destructive Changes 历史记录响应 DTO
- DestructiveChangesRollbackRequest.java - Destructive Changes 回滚请求 DTO
- DestructiveChangesRollbackResponse.java - Destructive Changes 回滚响应 DTO
- DestructiveChangesException.java - Destructive Changes 异常类
- 更新的文档:无
- 解决的问题:无
- 达成的共识:复用现有的 AsyncConfig 配置类和 DeployException 异常类
质疑与替代方案
记录在执行过程中提出的质疑和考虑的替代方案:
-
质疑:是否需要新增 DestructiveChangesStatus 枚举?
- 替代方案:新增 DestructiveChangesStatus 枚举,与 DeployStatus 枚举分开
- 评估:Destructive Changes 的状态与普通部署的状态一致,无需新增枚举,复用字符串状态即可
-
质疑:是否需要新增 DestructiveChangesConfig 配置类?
- 替代方案:新增 DestructiveChangesConfig 配置类,配置 Destructive Changes 的相关参数
- 评估:Destructive Changes 的配置与普通部署的配置一致,无需新增配置类,复用 AsyncConfig 配置类即可
-
质疑:是否需要新增 DestructiveChangesException 异常类?
- 替代方案:新增 DestructiveChangesException 异常类,与 DeployException 异常分开
- 评估:Destructive Changes 的异常与普通部署的异常类似,可以新增 DestructiveChangesException 异常类,提供更精确的异常处理
结论
总结本次会话的结果,包括:
-
完成的工作:
- 创建了 DestructiveChangesController 控制器,提供 6 个 RESTful API 接口
- 创建了 IDestructiveChangesService 服务接口,定义 Destructive Changes 服务接口方法
- 创建了 DestructiveChangesServiceImpl 服务实现,实现 Destructive Changes 服务接口方法
- 创建了 IDestructiveChangesConfigService 服务接口,定义 Destructive Changes 配置服务接口方法
- 创建了 DestructiveChangesConfigServiceImpl 服务实现,实现 Destructive Changes 配置服务接口方法
- 创建了 DestructiveChangesXmlParser 工具类,验证 destructiveChanges.xml 格式
- 创建了 DestructiveChangesXmlBuilder 工具类,构建 destructiveChanges.xml
- 创建了 DestructiveChangeRule 实体类和 DestructiveChangeRuleMapper 接口
- 创建了 DestructiveChangesConfigRequest、DestructiveChangesConfigResponse、DestructiveChangesValidateRequest、DestructiveChangesValidateResponse、DestructiveChangesDeployRequest、DestructiveChangesDeployResponse、DestructiveChangesHistoryResponse、DestructiveChangesRollbackRequest、DestructiveChangesRollbackResponse 等 DTO 类
- 创建了 DestructiveChangesException 异常类
- 复用了现有的 AsyncConfig 配置类
-
达成的目标:
- 实现了 destructiveChanges.xml 配置功能,支持可视化编辑
- 实现了 Destructive Changes 部署功能,支持删除指定的元数据组件
- 实现了 Destructive Changes 验证功能,验证删除规则
- 实现了 Destructive Changes 历史记录功能,支持分页查询和条件查询
- 实现了 Destructive Changes 回滚功能,支持恢复被删除的元数据组件
-
后续的行动计划:
- 更新 IMetadataApiService 接口,添加 deploy() 方法支持传入 destructiveChanges.xml
- 更新 MetadataApiClient 实现,实现 deploy() 方法支持传入 destructiveChanges.xml
- 更新 IMetadataApiService 接口,添加 rollback() 方法
- 更新 MetadataApiClient 实现,实现 rollback() 方法
- 创建数据库表 datai_destructive_change_rule
- 编写单元测试和集成测试
- 编写 API 文档和使用文档
-
需要跟进的事项:
- 更新 Canvas,添加 Destructive Changes 相关的节点
- 更新 CHANGELOG.md,记录本次变更
- 创建复盘报告,总结本次迭代的经验和教训
Design Update
- 是否需要更新 Canvas? 是
- Authentication.canvas - 需要添加 Destructive Changes 相关的节点
- 其他 Canvas 文件: 无
复现步骤
提供复现本次会话结果的具体步骤:
- 创建 DestructiveChangesController 控制器,提供 6 个 RESTful API 接口
- 创建 IDestructiveChangesService 服务接口,定义 Destructive Changes 服务接口方法
- 创建 DestructiveChangesServiceImpl 服务实现,实现 Destructive Changes 服务接口方法
- 创建 IDestructiveChangesConfigService 服务接口,定义 Destructive Changes 配置服务接口方法
- 创建 DestructiveChangesConfigServiceImpl 服务实现,实现 Destructive Changes 配置服务接口方法
- 创建 DestructiveChangesXmlParser 工具类,验证 destructiveChanges.xml 格式
- 创建 DestructiveChangesXmlBuilder 工具类,构建 destructiveChanges.xml
- 创建 DestructiveChangeRule 实体类和 DestructiveChangeRuleMapper 接口
- 创建 DestructiveChangesConfigRequest、DestructiveChangesConfigResponse、DestructiveChangesValidateRequest、DestructiveChangesValidateResponse、DestructiveChangesDeployRequest、DestructiveChangesDeployResponse、DestructiveChangesHistoryResponse、DestructiveChangesRollbackRequest、DestructiveChangesRollbackResponse 等 DTO 类
- 创建 DestructiveChangesException 异常类
- 更新 IMetadataApiService 接口,添加 deploy() 方法支持传入 destructiveChanges.xml
- 更新 MetadataApiClient 实现,实现 deploy() 方法支持传入 destructiveChanges.xml
- 更新 IMetadataApiService 接口,添加 rollback() 方法
- 更新 MetadataApiClient 实现,实现 rollback() 方法
- 创建数据库表 datai_destructive_change_rule
- 编写单元测试和集成测试
- 编写 API 文档和使用文档
- 验证 Destructive Changes 功能是否正常工作
验证方法:
- 调用 POST /metadata/destructive-changes/config 接口,验证 destructiveChanges.xml 配置是否成功
- 调用 GET /metadata/destructive-changes/config/{taskId} 接口,验证 destructiveChanges.xml 查询是否正常
- 调用 POST /metadata/destructive-changes/validate 接口,验证 destructiveChanges.xml 验证是否正常
- 调用 POST /metadata/destructive-changes/deploy 接口,验证 Destructive Changes 部署是否成功
- 调用 GET /metadata/destructive-changes/history 接口,验证 Destructive Changes 历史记录查询是否正常
- 调用 POST /metadata/destructive-changes/rollback/{jobId} 接口,验证 Destructive Changes 回滚是否正常