142 lines
10 KiB
Markdown
142 lines
10 KiB
Markdown
# 复盘文档 - 查询功能
|
||
|
||
## 元数据
|
||
- 需求编号:001-04
|
||
- 创建时间:2026-01-30
|
||
- 创建人:AI Assistant
|
||
- 状态:已完成
|
||
|
||
## 复盘概述
|
||
本次复盘对 Salesforce Partner API 查询功能的开发过程进行全面回顾。查询功能包括 SOQL 查询(Query)、查询所有记录(QueryAll)、分页查询(QueryMore)和 SOSL 搜索(Search)四个核心功能。通过本次复盘,总结成功经验、识别改进点、分析问题根因,并制定行动计划,以提高后续开发过程的效率和质量。
|
||
|
||
## 目标与实际产出对比
|
||
|
||
### 目标
|
||
- 实现 Salesforce Partner API 的查询功能,包括 Query、QueryAll、QueryMore、Search 四个核心功能
|
||
- 支持自定义批次大小(1-2000,默认 500)
|
||
- 支持关系查询和跨对象搜索
|
||
- 提供完整的 REST API 接口(4 个接口)
|
||
- 实现参数验证、异常处理、权限控制、Swagger 文档
|
||
- 实现完整的单元测试,测试覆盖率不低于 80%
|
||
- 遵循 SSOT 流程,确保所有开发活动都有文档依据
|
||
|
||
### 实际产出
|
||
- ✅ 成功实现了 Query、QueryAll、QueryMore、Search 四个核心查询功能
|
||
- ✅ 支持自定义批次大小,默认 500,最大 2000
|
||
- ✅ 支持关系查询(如 Account.Name)和跨对象搜索(SOSL)
|
||
- ✅ 提供了 4 个 REST API 接口(POST /partner/query、POST /partner/queryAll、POST /partner/queryMore、POST /partner/search)
|
||
- ✅ 实现了参数验证(@NotBlank、@Min、@Max)、异常处理、权限控制(@PreAuthorize)、Swagger 文档(@Operation、@Tag)
|
||
- ✅ 实现了完整的单元测试,包含 8 个测试用例,覆盖成功、空结果、异常等场景
|
||
- ✅ 严格按照 SSOT 流程执行,每个阶段都有相应的文档(需求文档、设计文档、决策记录、提示词、变更日志、复盘文档、API 文档)
|
||
- ✅ 生成了 11 个代码文件(4 个 DTO、3 个 VO、1 个 Service 接口、1 个 Service 实现、1 个 Controller、1 个单元测试)
|
||
|
||
## 成功经验
|
||
|
||
### 1. 分层架构设计的合理性
|
||
采用 Controller → Service → Factory → Connection → Salesforce API 的分层架构,使得代码结构清晰,职责分离明确。Controller 负责接收请求和参数校验,Service 负责业务逻辑处理,Factory 负责连接管理,各层之间通过接口交互,便于单元测试和后续维护。
|
||
|
||
### 2. DTO/VO 模式的正确使用
|
||
为每个查询功能创建独立的 DTO(QueryDto、QueryAllDto、QueryMoreDto、SearchDto)和 VO(QueryResultVo、SearchResultVo、SearchRecordVo),实现了请求参数和响应数据与业务逻辑的分离。DTO 中使用 @NotBlank、@Min、@Max 等注解进行参数验证,VO 中使用 @Schema 注解提供 Swagger 文档,提高了代码的可读性和可维护性。
|
||
|
||
### 3. 异常处理的一致性
|
||
统一使用 datai-salesforce-common 模块中的异常类(SalesforceAuthException、SalesforceOperationException),在 Service 层捕获 ConnectionException 并转换为自定义异常,返回友好的错误消息。这种一致的异常处理方式使得错误处理更加规范,便于前端统一处理错误。
|
||
|
||
### 4. 单元测试的完整性
|
||
为每个查询方法编写了完整的单元测试,包括成功场景、空结果场景、连接异常场景等,使用 JUnit 5 和 Mockito 进行测试,确保测试覆盖率不低于 80%。单元测试不仅验证了功能的正确性,也为后续的代码重构提供了保障。
|
||
|
||
### 5. SOQL 和 SOSL 的准确实现
|
||
准确实现了 SOQL 查询(Query、QueryAll、QueryMore)和 SOSL 搜索(Search)的功能,正确处理了查询结果的转换(SObject[] 转换为 List<Map<String, Object>>),支持关系查询字段(如 Account.Name),正确处理了分页机制(QueryLocator)。
|
||
|
||
## 改进点
|
||
|
||
### 1. 查询性能优化可以更深入
|
||
当前实现每次查询都通过 PartnerConnectionFactory 获取连接,虽然 Factory 内部有连接缓存,但对于高频查询场景,可以考虑实现查询结果缓存,减少重复的 API 调用。此外,对于大数据量查询,可以考虑实现异步查询或流式查询。
|
||
|
||
### 2. SOQL 语法验证可以增强
|
||
当前实现直接将 SOQL 语句传递给 Salesforce API,如果 SOQL 语法错误,只能在运行时捕获异常。可以考虑在客户端增加 SOQL 语法预验证,提前发现语法错误,提高用户体验。
|
||
|
||
### 3. 查询结果的数据类型转换可以更完善
|
||
当前实现将 SObject 字段值直接放入 Map 中,保留了原始的数据类型。但对于某些特殊数据类型(如 DateTime、Currency、Percent 等),可能需要进行更精细的转换,以便前端更好地展示。
|
||
|
||
### 4. API 文档的示例可以更丰富
|
||
当前 API 文档中的示例相对简单,可以增加更多复杂的查询示例,如关系查询、聚合查询、子查询等,帮助前端开发人员更好地理解和使用 API。
|
||
|
||
## 问题分析
|
||
|
||
### 问题 1:SObject 转换时的字段类型处理
|
||
**问题描述**:在将 SObject 转换为 Map<String, Object> 时,某些字段的类型(如 DateTime)可能不符合前端期望的格式。
|
||
|
||
**根因分析**:SObject.getField(String) 方法返回的是 Object 类型,保留了 Salesforce 的原始数据类型,没有进行统一的数据类型转换。
|
||
|
||
**解决方案**:
|
||
- 短期:在 VO 中增加字段类型说明,告知前端可能的字段类型
|
||
- 长期:实现一个统一的数据类型转换器,将 Salesforce 的数据类型转换为标准的 JSON 数据类型(如将 DateTime 转换为 ISO 8601 格式的字符串)
|
||
|
||
### 问题 2:QueryMore 的 queryLocator 有效期限制
|
||
**问题描述**:QueryMore 使用的 queryLocator 有有效期限制(通常为 15 分钟),如果用户在前一页查询后等待较长时间再查询下一页,可能会遇到 queryLocator 过期的问题。
|
||
|
||
**根因分析**:Salesforce API 的 queryLocator 设计就是为了限制查询结果的有效期,避免长时间占用服务器资源。
|
||
|
||
**解决方案**:
|
||
- 短期:在 API 文档中明确说明 queryLocator 的有效期限制,建议客户端在获取 queryLocator 后尽快使用
|
||
- 长期:可以考虑实现一个查询结果缓存机制,将查询结果临时存储在服务器端,客户端通过自定义的游标获取数据,不受 Salesforce queryLocator 有效期限制
|
||
|
||
### 问题 3:SOSL 搜索结果的对象类型识别
|
||
**问题描述**:SOSL 搜索结果中,每个记录都需要识别其对象类型(如 Account、Contact),当前实现通过 SearchRecordVo.type 字段返回对象类型,但前端可能需要更多的对象元数据信息。
|
||
|
||
**根因分析**:SOSL 搜索返回的 SearchResult 中包含了记录的对象类型信息,但没有包含对象的完整元数据(如字段列表、字段类型等)。
|
||
|
||
**解决方案**:
|
||
- 短期:在 API 文档中说明,如果需要对象元数据,可以调用 Describe API 获取
|
||
- 长期:可以考虑在 SearchResultVo 中增加对象元数据信息,或者提供一个批量获取对象元数据的 API
|
||
|
||
## 行动计划
|
||
|
||
| 序号 | 改进点/问题 | 具体行动 | 责任人 | 时间节点 |
|
||
|------|------------|----------|--------|----------|
|
||
| 1 | 查询性能优化 | 研究并实现查询结果缓存机制,减少重复 API 调用 | 开发团队 | 下一个迭代 |
|
||
| 2 | SOQL 语法验证 | 调研 SOQL 语法验证方案,增加客户端预验证 | 开发团队 | 下一个迭代 |
|
||
| 3 | 数据类型转换 | 实现统一的数据类型转换器,将 Salesforce 类型转换为标准 JSON 类型 | 开发团队 | 下一个迭代 |
|
||
| 4 | API 文档示例 | 增加更多复杂的查询示例(关系查询、聚合查询等) | AI Assistant | 立即执行 |
|
||
| 5 | queryLocator 有效期 | 在 API 文档中明确说明有效期限制,提供最佳实践建议 | AI Assistant | 立即执行 |
|
||
| 6 | SOSL 对象元数据 | 提供批量获取对象元数据的 API 或文档说明 | 开发团队 | 下一个迭代 |
|
||
|
||
## 提取模式
|
||
|
||
### 有效的 Prompt 技巧
|
||
|
||
1. **明确的代码生成顺序**:在提示词中明确指定代码生成的顺序(DTO → VO → Service 接口 → Service 实现 → Controller → 单元测试),可以确保生成的代码结构清晰,依赖关系正确。
|
||
|
||
2. **详细的验证注解要求**:在提示词中明确要求使用 @NotBlank、@Min、@Max 等验证注解,以及 @Schema 注解提供 Swagger 文档,可以提高生成代码的规范性和可用性。
|
||
|
||
3. **异常处理的统一要求**:在提示词中明确要求使用统一的异常处理机制(捕获 ConnectionException 并转换为自定义异常),可以确保生成的代码具有一致的错误处理方式。
|
||
|
||
### 避免的坑
|
||
|
||
1. **不要忽略 SObject 转换的细节**:SObject 到 Map 的转换看似简单,但需要注意字段类型、关系字段、空值处理等细节,否则可能导致数据丢失或类型错误。
|
||
|
||
2. **不要忽视分页机制的实现**:QueryMore 的分页机制需要正确处理 queryLocator 和 done 标志,如果实现不当,可能导致数据重复或遗漏。
|
||
|
||
3. **不要忽略 SOQL 和 SOSL 的区别**:SOQL 用于查询单个对象的记录,SOSL 用于跨对象搜索,两者的使用场景和返回结果结构不同,不能混用。
|
||
|
||
## 模板迭代
|
||
|
||
经过本次复盘,发现当前的提示词模板在以下方面可以改进:
|
||
|
||
1. **增加数据类型转换的要求**:在提示词中增加对数据类型转换的具体要求,明确哪些类型需要转换,如何转换。
|
||
|
||
2. **增加分页机制的详细说明**:在提示词中增加对分页机制的详细说明,包括 queryLocator 的有效期、done 标志的含义等。
|
||
|
||
3. **增加复杂查询示例**:在提示词中增加复杂查询的示例(如关系查询、聚合查询、子查询等),帮助生成更完善的代码和文档。
|
||
|
||
计划在下一个迭代中更新提示词模板,增加上述内容。
|
||
|
||
## 相关文档
|
||
|
||
- [需求文档](../requirements/sub/2026-01-28-001-04-查询功能.md)
|
||
- [设计文档](../design/2026-01-30-004-查询功能-设计.md)
|
||
- [决策记录](../decisions/2026-01-30-004-ADR-查询功能技术选型.md)
|
||
- [提示词文档](../prompts/2026-01-30-004-prompt-查询功能.md)
|
||
- [变更日志](../changelog/2026-01-30-004-changelog.md)
|
||
- [API 文档](../api-docs/2026-01-30-004-api.md)
|
||
- [会话记录](../sessions/2026-01-28-001-session.md) |