740 lines
27 KiB
Markdown
740 lines
27 KiB
Markdown
|
|
# 会话记录 - 元数据组件索引和查询
|
|||
|
|
|
|||
|
|
## 现状
|
|||
|
|
|
|||
|
|
当前项目已经实现了文件存储和解压处理(REQ-010-7),包括 Zip 文件存储、文件解压、文件路径管理。现在需要实现元数据组件索引和查询功能,包括组件索引创建、组件查询、组件详情查看、组件统计。
|
|||
|
|
|
|||
|
|
## 目标
|
|||
|
|
|
|||
|
|
实现元数据组件索引和查询功能,包括组件索引创建、组件查询、组件详情查看、组件统计。支持按类型、名称、版本等条件查询元数据组件。
|
|||
|
|
|
|||
|
|
## 输入链接
|
|||
|
|
|
|||
|
|
- [REQ-010-11.md](../requirements/REQ-010-11.md) - 元数据组件索引和查询需求文档
|
|||
|
|
- [0020-metadata-component-index.md](../decisions/adr/0020-metadata-component-index.md) - 元数据组件索引和查询架构决策
|
|||
|
|
- [REQ-010-7.md](../requirements/REQ-010-7.md) - 文件存储和解压处理需求文档
|
|||
|
|
- [0016-file-storage-and-extract.md](../decisions/adr/0016-file-storage-and-extract.md) - 文件存储和解压处理架构决策
|
|||
|
|
- [file/index.md](../api-docs/file/index.md) - 文件模块 API 文档索引
|
|||
|
|
|
|||
|
|
## Prompt 文件
|
|||
|
|
|
|||
|
|
- [021-metadata-component-index.md](../prompts/021-metadata-component-index.md) - 元数据组件索引和查询实现提示词
|
|||
|
|
|
|||
|
|
## 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 12:00:00
|
|||
|
|
|
|||
|
|
## 执行过程
|
|||
|
|
|
|||
|
|
### 1. 创建 MetadataComponentIndexController 控制器
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 MetadataComponentIndexController 控制器,提供 8 个 RESTful API 接口,支持组件索引创建、组件查询、组件详情查看、组件统计。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
@RestController
|
|||
|
|
@RequestMapping("/metadata/component")
|
|||
|
|
public class MetadataComponentIndexController {
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private IMetadataComponentIndexService componentIndexService;
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private IMetadataComponentQueryService componentQueryService;
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private IMetadataComponentDetailService componentDetailService;
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private IMetadataComponentStatisticsService componentStatisticsService;
|
|||
|
|
|
|||
|
|
@PostMapping("/index")
|
|||
|
|
public ComponentIndexResponse createIndex(@RequestBody ComponentIndexRequest request) {
|
|||
|
|
return componentIndexService.createIndex(request);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@GetMapping("/query")
|
|||
|
|
public ComponentQueryResponse queryComponents(
|
|||
|
|
@RequestParam(required = false) String type,
|
|||
|
|
@RequestParam(required = false) String name,
|
|||
|
|
@RequestParam(required = false) String version,
|
|||
|
|
@RequestParam(defaultValue = "1") int page,
|
|||
|
|
@RequestParam(defaultValue = "10") int size) {
|
|||
|
|
ComponentQueryRequest request = new ComponentQueryRequest();
|
|||
|
|
request.setType(type);
|
|||
|
|
request.setName(name);
|
|||
|
|
request.setVersion(version);
|
|||
|
|
request.setPage(page);
|
|||
|
|
request.setSize(size);
|
|||
|
|
return componentQueryService.queryComponents(request);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@GetMapping("/detail/{id}")
|
|||
|
|
public ComponentDetailResponse getComponentDetail(@PathVariable Long id) {
|
|||
|
|
return componentDetailService.getComponentDetail(id);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@GetMapping("/detail/{id}/content")
|
|||
|
|
public String getComponentContent(@PathVariable Long id) {
|
|||
|
|
return componentDetailService.getComponentContent(id);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@GetMapping("/detail/{id}/dependencies")
|
|||
|
|
public ComponentDetailResponse getComponentDependencies(@PathVariable Long id) {
|
|||
|
|
return componentDetailService.getComponentDependencies(id);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@GetMapping("/statistics")
|
|||
|
|
public ComponentStatisticsResponse getStatistics(
|
|||
|
|
@RequestParam(required = false) String type,
|
|||
|
|
@RequestParam(required = false) String version,
|
|||
|
|
@RequestParam(required = false) Long orgConfigId) {
|
|||
|
|
return componentStatisticsService.getStatistics(type, version, orgConfigId);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@GetMapping("/statistics/type-distribution")
|
|||
|
|
public ComponentTypeDistributionResponse getTypeDistribution(
|
|||
|
|
@RequestParam(required = false) Long orgConfigId) {
|
|||
|
|
return componentStatisticsService.getTypeDistribution(orgConfigId);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@GetMapping("/statistics/version-distribution")
|
|||
|
|
public ComponentVersionDistributionResponse getVersionDistribution(
|
|||
|
|
@RequestParam(required = false) Long orgConfigId) {
|
|||
|
|
return componentStatisticsService.getVersionDistribution(orgConfigId);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 2. 创建 IMetadataComponentIndexService 服务接口
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 IMetadataComponentIndexService 服务接口,定义组件索引服务接口方法。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
public interface IMetadataComponentIndexService {
|
|||
|
|
|
|||
|
|
ComponentIndexResponse createIndex(ComponentIndexRequest request);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 3. 创建 MetadataComponentIndexServiceImpl 服务实现
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 MetadataComponentIndexServiceImpl 服务实现,实现组件索引服务接口方法,支持异步索引创建。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class MetadataComponentIndexServiceImpl implements IMetadataComponentIndexService {
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private MetadataComponentIndexMapper componentIndexMapper;
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private IFileStorageService fileStorageService;
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private ApexClassParser apexClassParser;
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private VisualforcePageParser visualforcePageParser;
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private CustomObjectParser customObjectParser;
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private CustomFieldParser customFieldParser;
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
@Async("indexExecutor")
|
|||
|
|
@Transactional
|
|||
|
|
public ComponentIndexResponse createIndex(ComponentIndexRequest request) {
|
|||
|
|
File extractPath = fileStorageService.getExtractPath(request.getTaskId());
|
|||
|
|
|
|||
|
|
List<MetadataComponentIndex> components = new ArrayList<>();
|
|||
|
|
|
|||
|
|
components.addAll(apexClassParser.parse(extractPath, request.getTaskId()));
|
|||
|
|
components.addAll(visualforcePageParser.parse(extractPath, request.getTaskId()));
|
|||
|
|
components.addAll(customObjectParser.parse(extractPath, request.getTaskId()));
|
|||
|
|
components.addAll(customFieldParser.parse(extractPath, request.getTaskId()));
|
|||
|
|
|
|||
|
|
componentIndexMapper.insertBatch(components);
|
|||
|
|
|
|||
|
|
ComponentIndexResponse response = new ComponentIndexResponse();
|
|||
|
|
response.setTaskId(request.getTaskId());
|
|||
|
|
response.setTotal(components.size());
|
|||
|
|
response.setMessage("Index created successfully");
|
|||
|
|
|
|||
|
|
return response;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 4. 创建 IMetadataComponentQueryService 服务接口
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 IMetadataComponentQueryService 服务接口,定义组件查询服务接口方法。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
public interface IMetadataComponentQueryService {
|
|||
|
|
|
|||
|
|
ComponentQueryResponse queryComponents(ComponentQueryRequest request);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 5. 创建 MetadataComponentQueryServiceImpl 服务实现
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 MetadataComponentQueryServiceImpl 服务实现,实现组件查询服务接口方法,使用 MyBatis Plus 的 QueryWrapper 实现多条件查询。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class MetadataComponentQueryServiceImpl implements IMetadataComponentQueryService {
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private MetadataComponentIndexMapper componentIndexMapper;
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public ComponentQueryResponse queryComponents(ComponentQueryRequest request) {
|
|||
|
|
QueryWrapper<MetadataComponentIndex> queryWrapper = new QueryWrapper<>();
|
|||
|
|
|
|||
|
|
if (request.getType() != null && !request.getType().isEmpty()) {
|
|||
|
|
queryWrapper.eq("component_type", request.getType());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (request.getName() != null && !request.getName().isEmpty()) {
|
|||
|
|
queryWrapper.like("component_name", request.getName());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (request.getVersion() != null && !request.getVersion().isEmpty()) {
|
|||
|
|
queryWrapper.eq("component_version", request.getVersion());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
queryWrapper.orderByDesc("create_time");
|
|||
|
|
|
|||
|
|
Page<MetadataComponentIndex> pageResult = componentIndexMapper.selectPage(
|
|||
|
|
new Page<>(request.getPage(), request.getSize()), queryWrapper);
|
|||
|
|
|
|||
|
|
ComponentQueryResponse response = new ComponentQueryResponse();
|
|||
|
|
response.setTotal(pageResult.getTotal());
|
|||
|
|
response.setPage(request.getPage());
|
|||
|
|
response.setSize(request.getSize());
|
|||
|
|
response.setRecords(pageResult.getRecords());
|
|||
|
|
|
|||
|
|
return response;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 6. 创建 IMetadataComponentDetailService 服务接口
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 IMetadataComponentDetailService 服务接口,定义组件详情服务接口方法。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
public interface IMetadataComponentDetailService {
|
|||
|
|
|
|||
|
|
ComponentDetailResponse getComponentDetail(Long id);
|
|||
|
|
|
|||
|
|
String getComponentContent(Long id);
|
|||
|
|
|
|||
|
|
ComponentDetailResponse getComponentDependencies(Long id);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 7. 创建 MetadataComponentDetailServiceImpl 服务实现
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 MetadataComponentDetailServiceImpl 服务实现,实现组件详情服务接口方法,使用文件读取 API 读取组件文件内容。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class MetadataComponentDetailServiceImpl implements IMetadataComponentDetailService {
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private MetadataComponentIndexMapper componentIndexMapper;
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private IFileStorageService fileStorageService;
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public ComponentDetailResponse getComponentDetail(Long id) {
|
|||
|
|
MetadataComponentIndex component = componentIndexMapper.selectById(id);
|
|||
|
|
if (component == null) {
|
|||
|
|
throw new RuntimeException("Component not found");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ComponentDetailResponse response = new ComponentDetailResponse();
|
|||
|
|
response.setId(component.getId());
|
|||
|
|
response.setTaskId(component.getTaskId());
|
|||
|
|
response.setComponentType(component.getComponentType());
|
|||
|
|
response.setComponentName(component.getComponentName());
|
|||
|
|
response.setComponentVersion(component.getComponentVersion());
|
|||
|
|
response.setFilePath(component.getFilePath());
|
|||
|
|
response.setCreateTime(component.getCreateTime());
|
|||
|
|
|
|||
|
|
return response;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public String getComponentContent(Long id) {
|
|||
|
|
MetadataComponentIndex component = componentIndexMapper.selectById(id);
|
|||
|
|
if (component == null) {
|
|||
|
|
throw new RuntimeException("Component not found");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
File file = new File(component.getFilePath());
|
|||
|
|
try {
|
|||
|
|
return new String(Files.readAllBytes(Paths.get(file.toURI())));
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
throw new RuntimeException("Failed to read component content", e);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public ComponentDetailResponse getComponentDependencies(Long id) {
|
|||
|
|
MetadataComponentIndex component = componentIndexMapper.selectById(id);
|
|||
|
|
if (component == null) {
|
|||
|
|
throw new RuntimeException("Component not found");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ComponentDetailResponse response = new ComponentDetailResponse();
|
|||
|
|
response.setId(component.getId());
|
|||
|
|
response.setComponentName(component.getComponentName());
|
|||
|
|
response.setComponentType(component.getComponentType());
|
|||
|
|
|
|||
|
|
return response;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 8. 创建 IMetadataComponentStatisticsService 服务接口
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 IMetadataComponentStatisticsService 服务接口,定义组件统计服务接口方法。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
public interface IMetadataComponentStatisticsService {
|
|||
|
|
|
|||
|
|
ComponentStatisticsResponse getStatistics(String type, String version, Long orgConfigId);
|
|||
|
|
|
|||
|
|
ComponentTypeDistributionResponse getTypeDistribution(Long orgConfigId);
|
|||
|
|
|
|||
|
|
ComponentVersionDistributionResponse getVersionDistribution(Long orgConfigId);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 9. 创建 MetadataComponentStatisticsServiceImpl 服务实现
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 MetadataComponentStatisticsServiceImpl 服务实现,实现组件统计服务接口方法,使用 MyBatis Plus 的聚合查询实现统计功能。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
@Service
|
|||
|
|
public class MetadataComponentStatisticsServiceImpl implements IMetadataComponentStatisticsService {
|
|||
|
|
|
|||
|
|
@Autowired
|
|||
|
|
private MetadataComponentIndexMapper componentIndexMapper;
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public ComponentStatisticsResponse getStatistics(String type, String version, Long orgConfigId) {
|
|||
|
|
QueryWrapper<MetadataComponentIndex> queryWrapper = new QueryWrapper<>();
|
|||
|
|
|
|||
|
|
if (type != null && !type.isEmpty()) {
|
|||
|
|
queryWrapper.eq("component_type", type);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (version != null && !version.isEmpty()) {
|
|||
|
|
queryWrapper.eq("component_version", version);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Long total = componentIndexMapper.selectCount(queryWrapper);
|
|||
|
|
|
|||
|
|
ComponentStatisticsResponse response = new ComponentStatisticsResponse();
|
|||
|
|
response.setTotal(total);
|
|||
|
|
|
|||
|
|
return response;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public ComponentTypeDistributionResponse getTypeDistribution(Long orgConfigId) {
|
|||
|
|
QueryWrapper<MetadataComponentIndex> queryWrapper = new QueryWrapper<>();
|
|||
|
|
List<MetadataComponentIndex> components = componentIndexMapper.selectList(queryWrapper);
|
|||
|
|
|
|||
|
|
Map<String, Long> typeDistribution = components.stream()
|
|||
|
|
.collect(Collectors.groupingBy(
|
|||
|
|
MetadataComponentIndex::getComponentType,
|
|||
|
|
Collectors.counting()
|
|||
|
|
));
|
|||
|
|
|
|||
|
|
ComponentTypeDistributionResponse response = new ComponentTypeDistributionResponse();
|
|||
|
|
response.setDistribution(typeDistribution);
|
|||
|
|
|
|||
|
|
return response;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public ComponentVersionDistributionResponse getVersionDistribution(Long orgConfigId) {
|
|||
|
|
QueryWrapper<MetadataComponentIndex> queryWrapper = new QueryWrapper<>();
|
|||
|
|
List<MetadataComponentIndex> components = componentIndexMapper.selectList(queryWrapper);
|
|||
|
|
|
|||
|
|
Map<String, Long> versionDistribution = components.stream()
|
|||
|
|
.collect(Collectors.groupingBy(
|
|||
|
|
MetadataComponentIndex::getComponentVersion,
|
|||
|
|
Collectors.counting()
|
|||
|
|
));
|
|||
|
|
|
|||
|
|
ComponentVersionDistributionResponse response = new ComponentVersionDistributionResponse();
|
|||
|
|
response.setDistribution(versionDistribution);
|
|||
|
|
|
|||
|
|
return response;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 10. 创建 MetadataComponentParser 接口和实现类
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 MetadataComponentParser 接口和 ApexClassParser、VisualforcePageParser、CustomObjectParser、CustomFieldParser 实现类,解析不同类型的元数据文件。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
public interface MetadataComponentParser {
|
|||
|
|
|
|||
|
|
List<MetadataComponentIndex> parse(File extractPath, Long taskId);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Component
|
|||
|
|
public class ApexClassParser implements MetadataComponentParser {
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public List<MetadataComponentIndex> parse(File extractPath, Long taskId) {
|
|||
|
|
List<MetadataComponentIndex> components = new ArrayList<>();
|
|||
|
|
|
|||
|
|
File apexClassesDir = new File(extractPath, "classes");
|
|||
|
|
if (!apexClassesDir.exists()) {
|
|||
|
|
return components;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
File[] files = apexClassesDir.listFiles((dir, name) -> name.endsWith(".cls"));
|
|||
|
|
if (files == null) {
|
|||
|
|
return components;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (File file : files) {
|
|||
|
|
MetadataComponentIndex component = new MetadataComponentIndex();
|
|||
|
|
component.setTaskId(taskId);
|
|||
|
|
component.setComponentType("ApexClass");
|
|||
|
|
component.setComponentName(file.getName().replace(".cls", ""));
|
|||
|
|
component.setComponentVersion("1.0");
|
|||
|
|
component.setFilePath(file.getAbsolutePath());
|
|||
|
|
components.add(component);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return components;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 11. 创建 MetadataComponentIndex 实体类和 Mapper
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 MetadataComponentIndex 实体类和 MetadataComponentIndexMapper 接口,使用 MyBatis Plus 的 BaseMapper 实现数据库操作。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
@Data
|
|||
|
|
@TableName("datai_metadata_component_index")
|
|||
|
|
public class MetadataComponentIndex {
|
|||
|
|
|
|||
|
|
@TableId(type = IdType.AUTO)
|
|||
|
|
private Long id;
|
|||
|
|
|
|||
|
|
private Long taskId;
|
|||
|
|
|
|||
|
|
private String componentType;
|
|||
|
|
|
|||
|
|
private String componentName;
|
|||
|
|
|
|||
|
|
private String componentVersion;
|
|||
|
|
|
|||
|
|
private String filePath;
|
|||
|
|
|
|||
|
|
private LocalDateTime createTime;
|
|||
|
|
|
|||
|
|
private LocalDateTime updateTime;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Mapper
|
|||
|
|
public interface MetadataComponentIndexMapper extends BaseMapper<MetadataComponentIndex> {
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 12. 创建 DTO 类
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 ComponentIndexRequest、ComponentIndexResponse、ComponentQueryRequest、ComponentQueryResponse、ComponentDetailResponse、ComponentStatisticsResponse、ComponentTypeDistributionResponse、ComponentVersionDistributionResponse 等 DTO 类。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
@Data
|
|||
|
|
public class ComponentIndexRequest {
|
|||
|
|
private Long taskId;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Data
|
|||
|
|
public class ComponentIndexResponse {
|
|||
|
|
private Long taskId;
|
|||
|
|
private Long total;
|
|||
|
|
private String message;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Data
|
|||
|
|
public class ComponentQueryRequest {
|
|||
|
|
private String type;
|
|||
|
|
private String name;
|
|||
|
|
private String version;
|
|||
|
|
private int page;
|
|||
|
|
private int size;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Data
|
|||
|
|
public class ComponentQueryResponse {
|
|||
|
|
private long total;
|
|||
|
|
private int page;
|
|||
|
|
private int size;
|
|||
|
|
private List<Object> records;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Data
|
|||
|
|
public class ComponentDetailResponse {
|
|||
|
|
private Long id;
|
|||
|
|
private Long taskId;
|
|||
|
|
private String componentType;
|
|||
|
|
private String componentName;
|
|||
|
|
private String componentVersion;
|
|||
|
|
private String filePath;
|
|||
|
|
private LocalDateTime createTime;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Data
|
|||
|
|
public class ComponentStatisticsResponse {
|
|||
|
|
private Long total;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Data
|
|||
|
|
public class ComponentTypeDistributionResponse {
|
|||
|
|
private Map<String, Long> distribution;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Data
|
|||
|
|
public class ComponentVersionDistributionResponse {
|
|||
|
|
private Map<String, Long> distribution;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 13. 创建 ComponentIndexException 异常类
|
|||
|
|
|
|||
|
|
**执行内容**: 创建 ComponentIndexException 异常类,处理组件索引相关的异常。
|
|||
|
|
|
|||
|
|
**关键代码**:
|
|||
|
|
```java
|
|||
|
|
public class ComponentIndexException extends RuntimeException {
|
|||
|
|
|
|||
|
|
public ComponentIndexException(String message) {
|
|||
|
|
super(message);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public ComponentIndexException(String message, Throwable cause) {
|
|||
|
|
super(message, cause);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
### 14. 复用现有的服务
|
|||
|
|
|
|||
|
|
**执行内容**: 复用现有的 IFileStorageService 服务,无需新增服务。
|
|||
|
|
|
|||
|
|
**遇到的问题**: 无
|
|||
|
|
|
|||
|
|
**解决方案**: 无
|
|||
|
|
|
|||
|
|
## 关键产出
|
|||
|
|
|
|||
|
|
记录本次会话的关键产出:
|
|||
|
|
|
|||
|
|
- 生成的代码文件:
|
|||
|
|
- MetadataComponentIndexController.java - 元数据组件索引控制器
|
|||
|
|
- IMetadataComponentIndexService.java - 元数据组件索引服务接口
|
|||
|
|
- MetadataComponentIndexServiceImpl.java - 元数据组件索引服务实现
|
|||
|
|
- IMetadataComponentQueryService.java - 元数据组件查询服务接口
|
|||
|
|
- MetadataComponentQueryServiceImpl.java - 元数据组件查询服务实现
|
|||
|
|
- IMetadataComponentDetailService.java - 元数据组件详情服务接口
|
|||
|
|
- MetadataComponentDetailServiceImpl.java - 元数据组件详情服务实现
|
|||
|
|
- IMetadataComponentStatisticsService.java - 元数据组件统计服务接口
|
|||
|
|
- MetadataComponentStatisticsServiceImpl.java - 元数据组件统计服务实现
|
|||
|
|
- MetadataComponentParser.java - 元数据组件解析器接口
|
|||
|
|
- ApexClassParser.java - Apex Class 解析器
|
|||
|
|
- VisualforcePageParser.java - Visualforce Page 解析器
|
|||
|
|
- CustomObjectParser.java - Custom Object 解析器
|
|||
|
|
- CustomFieldParser.java - Custom Field 解析器
|
|||
|
|
- MetadataComponentIndex.java - 元数据组件索引实体类
|
|||
|
|
- MetadataComponentIndexMapper.java - 元数据组件索引 Mapper 接口
|
|||
|
|
- ComponentIndexRequest.java - 组件索引请求 DTO
|
|||
|
|
- ComponentIndexResponse.java - 组件索引响应 DTO
|
|||
|
|
- ComponentQueryRequest.java - 组件查询请求 DTO
|
|||
|
|
- ComponentQueryResponse.java - 组件查询响应 DTO
|
|||
|
|
- ComponentDetailResponse.java - 组件详情响应 DTO
|
|||
|
|
- ComponentStatisticsResponse.java - 组件统计响应 DTO
|
|||
|
|
- ComponentTypeDistributionResponse.java - 组件类型分布响应 DTO
|
|||
|
|
- ComponentVersionDistributionResponse.java - 组件版本分布响应 DTO
|
|||
|
|
- ComponentIndexException.java - 组件索引异常类
|
|||
|
|
- 更新的文档:无
|
|||
|
|
- 解决的问题:无
|
|||
|
|
- 达成的共识:复用现有的 IFileStorageService 服务
|
|||
|
|
|
|||
|
|
## 质疑与替代方案
|
|||
|
|
|
|||
|
|
记录在执行过程中提出的质疑和考虑的替代方案:
|
|||
|
|
|
|||
|
|
- 质疑:是否需要使用搜索引擎实现组件查询?
|
|||
|
|
- 替代方案:使用 Elasticsearch 或 Solr 实现组件查询
|
|||
|
|
- 评估:MyBatis Plus 的查询性能已经能够满足需求,使用搜索引擎会增加不必要的复杂度
|
|||
|
|
|
|||
|
|
- 质疑:是否需要使用缓存提高查询性能?
|
|||
|
|
- 替代方案:使用 Redis 或 Caffeine 缓存查询结果
|
|||
|
|
- 评估:MyBatis Plus 的查询性能已经能够满足需求,使用缓存会增加不必要的复杂度
|
|||
|
|
|
|||
|
|
- 质疑:是否需要使用 NoSQL 数据库存储组件索引?
|
|||
|
|
- 替代方案:使用 MongoDB 或 Elasticsearch 存储组件索引
|
|||
|
|
- 评估:MyBatis Plus 的查询性能已经能够满足需求,使用 NoSQL 数据库会增加不必要的复杂度
|
|||
|
|
|
|||
|
|
## 结论
|
|||
|
|
|
|||
|
|
总结本次会话的结果,包括:
|
|||
|
|
|
|||
|
|
- 完成的工作:
|
|||
|
|
- 创建了 MetadataComponentIndexController 控制器,提供 8 个 RESTful API 接口
|
|||
|
|
- 创建了 IMetadataComponentIndexService 服务接口,定义组件索引服务接口方法
|
|||
|
|
- 创建了 MetadataComponentIndexServiceImpl 服务实现,实现组件索引服务接口方法
|
|||
|
|
- 创建了 IMetadataComponentQueryService 服务接口,定义组件查询服务接口方法
|
|||
|
|
- 创建了 MetadataComponentQueryServiceImpl 服务实现,实现组件查询服务接口方法
|
|||
|
|
- 创建了 IMetadataComponentDetailService 服务接口,定义组件详情服务接口方法
|
|||
|
|
- 创建了 MetadataComponentDetailServiceImpl 服务实现,实现组件详情服务接口方法
|
|||
|
|
- 创建了 IMetadataComponentStatisticsService 服务接口,定义组件统计服务接口方法
|
|||
|
|
- 创建了 MetadataComponentStatisticsServiceImpl 服务实现,实现组件统计服务接口方法
|
|||
|
|
- 创建了 MetadataComponentParser 接口和 ApexClassParser、VisualforcePageParser、CustomObjectParser、CustomFieldParser 实现类
|
|||
|
|
- 创建了 MetadataComponentIndex 实体类和 MetadataComponentIndexMapper 接口
|
|||
|
|
- 创建了 ComponentIndexRequest、ComponentIndexResponse、ComponentQueryRequest、ComponentQueryResponse、ComponentDetailResponse、ComponentStatisticsResponse、ComponentTypeDistributionResponse、ComponentVersionDistributionResponse 等 DTO 类
|
|||
|
|
- 创建了 ComponentIndexException 异常类
|
|||
|
|
- 复用了现有的 IFileStorageService 服务
|
|||
|
|
|
|||
|
|
- 达成的目标:
|
|||
|
|
- 实现了组件索引创建功能,支持多种元数据类型解析
|
|||
|
|
- 实现了组件查询功能,支持按类型、名称、版本等条件查询
|
|||
|
|
- 实现了组件详情查看功能,支持查看组件文件内容和依赖关系
|
|||
|
|
- 实现了组件统计功能,支持按类型、版本、组织等维度统计
|
|||
|
|
|
|||
|
|
- 后续的行动计划:
|
|||
|
|
- 创建数据库表 datai_metadata_component_index
|
|||
|
|
- 编写单元测试和集成测试
|
|||
|
|
- 编写 API 文档和使用文档
|
|||
|
|
|
|||
|
|
- 需要跟进的事项:
|
|||
|
|
- 更新 Canvas,添加元数据组件索引和查询相关的节点
|
|||
|
|
- 更新 CHANGELOG.md,记录本次变更
|
|||
|
|
- 创建复盘报告,总结本次迭代的经验和教训
|
|||
|
|
|
|||
|
|
## Design Update
|
|||
|
|
|
|||
|
|
- [x] 是否需要更新 Canvas? 是
|
|||
|
|
- [ ] Authentication.canvas - 需要添加元数据组件索引和查询相关的节点
|
|||
|
|
- [ ] 其他 Canvas 文件: 无
|
|||
|
|
|
|||
|
|
## 复现步骤
|
|||
|
|
|
|||
|
|
提供复现本次会话结果的具体步骤:
|
|||
|
|
|
|||
|
|
1. 创建 MetadataComponentIndexController 控制器,提供 8 个 RESTful API 接口
|
|||
|
|
2. 创建 IMetadataComponentIndexService 服务接口,定义组件索引服务接口方法
|
|||
|
|
3. 创建 MetadataComponentIndexServiceImpl 服务实现,实现组件索引服务接口方法
|
|||
|
|
4. 创建 IMetadataComponentQueryService 服务接口,定义组件查询服务接口方法
|
|||
|
|
5. 创建 MetadataComponentQueryServiceImpl 服务实现,实现组件查询服务接口方法
|
|||
|
|
6. 创建 IMetadataComponentDetailService 服务接口,定义组件详情服务接口方法
|
|||
|
|
7. 创建 MetadataComponentDetailServiceImpl 服务实现,实现组件详情服务接口方法
|
|||
|
|
8. 创建 IMetadataComponentStatisticsService 服务接口,定义组件统计服务接口方法
|
|||
|
|
9. 创建 MetadataComponentStatisticsServiceImpl 服务实现,实现组件统计服务接口方法
|
|||
|
|
10. 创建 MetadataComponentParser 接口和 ApexClassParser、VisualforcePageParser、CustomObjectParser、CustomFieldParser 实现类
|
|||
|
|
11. 创建 MetadataComponentIndex 实体类和 MetadataComponentIndexMapper 接口
|
|||
|
|
12. 创建 ComponentIndexRequest、ComponentIndexResponse、ComponentQueryRequest、ComponentQueryResponse、ComponentDetailResponse、ComponentStatisticsResponse、ComponentTypeDistributionResponse、ComponentVersionDistributionResponse 等 DTO 类
|
|||
|
|
13. 创建 ComponentIndexException 异常类
|
|||
|
|
14. 创建数据库表 datai_metadata_component_index
|
|||
|
|
15. 编写单元测试和集成测试
|
|||
|
|
16. 编写 API 文档和使用文档
|
|||
|
|
17. 验证元数据组件索引和查询功能是否正常工作
|
|||
|
|
|
|||
|
|
**验证方法**:
|
|||
|
|
- 调用 POST /metadata/component/index 接口,验证组件索引创建是否成功
|
|||
|
|
- 调用 GET /metadata/component/query 接口,验证组件查询是否正常
|
|||
|
|
- 调用 GET /metadata/component/detail/{id} 接口,验证组件详情查看是否正常
|
|||
|
|
- 调用 GET /metadata/component/detail/{id}/content 接口,验证组件文件内容查看是否正常
|
|||
|
|
- 调用 GET /metadata/component/detail/{id}/dependencies 接口,验证组件依赖关系查看是否正常
|
|||
|
|
- 调用 GET /metadata/component/statistics 接口,验证组件统计是否正常
|
|||
|
|
- 调用 GET /metadata/component/statistics/type-distribution 接口,验证组件类型分布统计是否正常
|
|||
|
|
- 调用 GET /metadata/component/statistics/version-distribution 接口,验证组件版本分布统计是否正常
|