751 lines
29 KiB
Markdown
751 lines
29 KiB
Markdown
# 会话记录 - 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](../requirements/REQ-010-10.md) - Destructive Changes功能实现需求文档
|
||
- [0019-destructive-changes.md](../decisions/adr/0019-destructive-changes.md) - Destructive Changes功能实现架构决策
|
||
- [REQ-010-8.md](../requirements/REQ-010-8.md) - 元数据部署核心功能需求文档
|
||
- [0017-metadata-deploy-core.md](../decisions/adr/0017-metadata-deploy-core.md) - 元数据部署核心功能架构决策
|
||
- [metadata-module.md](../reference-code/com/docs/metadata-module.md) - Salesforce Metadata API 模块说明
|
||
|
||
## Prompt 文件
|
||
|
||
- [020-destructive-changes.md](../prompts/020-destructive-changes.md) - Destructive Changes功能实现提示词
|
||
|
||
## Context Snapshot
|
||
|
||
记录本次会话参考了哪些 Canvas 节点:
|
||
|
||
- [Authentication.canvas](../Authentication.canvas) - 项目架构视觉化展示
|
||
- **参考节点**: [集成核心](node_integration_core) - 提供与Salesforce的各种连接方式
|
||
- **参考节点**: [IMetadataApiService](node_metadata_api_service) - 元数据API服务接口
|
||
- **参考节点**: [MetadataApiClient](node_metadata_api_client) - Metadata API客户端
|
||
- **快照时间**: 2026-01-19 11:00:00
|
||
|
||
## 执行过程
|
||
|
||
### 1. 创建 DestructiveChangesController 控制器
|
||
|
||
**执行内容**: 创建 DestructiveChangesController 控制器,提供 6 个 RESTful API 接口,支持 destructiveChanges.xml 配置、Destructive Changes 部署、Destructive Changes 验证、Destructive Changes 历史记录、Destructive Changes 回滚。
|
||
|
||
**关键代码**:
|
||
```java
|
||
@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 服务接口方法。
|
||
|
||
**关键代码**:
|
||
```java
|
||
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 服务接口方法,支持异步执行和状态管理。
|
||
|
||
**关键代码**:
|
||
```java
|
||
@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 配置服务接口方法。
|
||
|
||
**关键代码**:
|
||
```java
|
||
public interface IDestructiveChangesConfigService {
|
||
|
||
DestructiveChangesConfigResponse saveConfig(DestructiveChangesConfigRequest request);
|
||
|
||
DestructiveChangesConfigResponse getConfig(Long taskId);
|
||
|
||
DestructiveChangesValidateResponse validateConfig(DestructiveChangesValidateRequest request);
|
||
}
|
||
```
|
||
|
||
**遇到的问题**: 无
|
||
|
||
**解决方案**: 无
|
||
|
||
### 5. 创建 DestructiveChangesConfigServiceImpl 服务实现
|
||
|
||
**执行内容**: 创建 DestructiveChangesConfigServiceImpl 服务实现,实现 Destructive Changes 配置服务接口方法,支持 destructiveChanges.xml 配置和验证。
|
||
|
||
**关键代码**:
|
||
```java
|
||
@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 格式。
|
||
|
||
**关键代码**:
|
||
```java
|
||
@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。
|
||
|
||
**关键代码**:
|
||
```java
|
||
@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 实现数据库操作。
|
||
|
||
**关键代码**:
|
||
```java
|
||
@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 类。
|
||
|
||
**关键代码**:
|
||
```java
|
||
@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 相关的异常。
|
||
|
||
**关键代码**:
|
||
```java
|
||
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
|
||
|
||
- [x] 是否需要更新 Canvas? 是
|
||
- [ ] Authentication.canvas - 需要添加 Destructive Changes 相关的节点
|
||
- [ ] 其他 Canvas 文件: 无
|
||
|
||
## 复现步骤
|
||
|
||
提供复现本次会话结果的具体步骤:
|
||
|
||
1. 创建 DestructiveChangesController 控制器,提供 6 个 RESTful API 接口
|
||
2. 创建 IDestructiveChangesService 服务接口,定义 Destructive Changes 服务接口方法
|
||
3. 创建 DestructiveChangesServiceImpl 服务实现,实现 Destructive Changes 服务接口方法
|
||
4. 创建 IDestructiveChangesConfigService 服务接口,定义 Destructive Changes 配置服务接口方法
|
||
5. 创建 DestructiveChangesConfigServiceImpl 服务实现,实现 Destructive Changes 配置服务接口方法
|
||
6. 创建 DestructiveChangesXmlParser 工具类,验证 destructiveChanges.xml 格式
|
||
7. 创建 DestructiveChangesXmlBuilder 工具类,构建 destructiveChanges.xml
|
||
8. 创建 DestructiveChangeRule 实体类和 DestructiveChangeRuleMapper 接口
|
||
9. 创建 DestructiveChangesConfigRequest、DestructiveChangesConfigResponse、DestructiveChangesValidateRequest、DestructiveChangesValidateResponse、DestructiveChangesDeployRequest、DestructiveChangesDeployResponse、DestructiveChangesHistoryResponse、DestructiveChangesRollbackRequest、DestructiveChangesRollbackResponse 等 DTO 类
|
||
10. 创建 DestructiveChangesException 异常类
|
||
11. 更新 IMetadataApiService 接口,添加 deploy() 方法支持传入 destructiveChanges.xml
|
||
12. 更新 MetadataApiClient 实现,实现 deploy() 方法支持传入 destructiveChanges.xml
|
||
13. 更新 IMetadataApiService 接口,添加 rollback() 方法
|
||
14. 更新 MetadataApiClient 实现,实现 rollback() 方法
|
||
15. 创建数据库表 datai_destructive_change_rule
|
||
16. 编写单元测试和集成测试
|
||
17. 编写 API 文档和使用文档
|
||
18. 验证 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 回滚是否正常
|