# API 文档 - Apex 代码编译和执行 ## 元数据 - 需求编号:002-02 - 需求名称:Apex 代码编译和执行 - 创建时间:2026-02-02 - 创建人:AI Assistant - 版本:v1.0.0 - 状态:已完成 ## API 概述 Apex 代码编译和执行 API 提供了一套完整的接口,用于在 Salesforce 平台上编译和执行 Apex 代码。支持编译 Apex 类、编译 Apex 触发器、编译并运行测试、执行匿名 Apex 代码等功能,同时提供查询编译历史、测试结果和代码覆盖率的能力。 ### 核心功能 1. **编译 Apex 类**:将 Apex 类代码编译到 Salesforce 平台 2. **编译 Apex 触发器**:将 Apex 触发器代码编译到 Salesforce 平台 3. **编译并测试**:编译代码并运行单元测试 4. **执行匿名代码**:执行匿名的 Apex 代码片段 5. **查询功能**:查询编译历史、测试结果和代码覆盖率 ### 技术架构 - **协议**:HTTP/HTTPS - **数据格式**:JSON - **认证方式**:JWT Token(通过请求头 Authorization: Bearer {token}) - **权限控制**:Spring Security @PreAuthorize - **基础路径**:`/api/apex` ## 接口列表 ### 1. 编译 Apex 类 **功能描述**:编译一个或多个 Apex 类到 Salesforce 平台 **请求方式**:POST **请求路径**:`/api/apex/compile/classes` **权限要求**:`@PreAuthorize("@ss.hasPermi('apex:compile:execute')")` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | classes | String[] | 是 | Apex 类代码数组,每个元素是一个完整的类定义 | **请求示例**: ```json { "classes": [ "public class MyClass {\n public String name;\n public Integer count;\n}", "public class AnotherClass {\n public static void doSomething() {\n System.debug('Hello');\n }\n}" ] } ``` **响应参数**: | 参数名 | 类型 | 说明 | |--------|------|------| | code | Integer | 状态码(200 成功,其他失败) | | msg | String | 提示信息 | | data | CompileClassResultVo[] | 编译结果数组 | **CompileClassResultVo 字段说明**: | 字段名 | 类型 | 说明 | |--------|------|------| | success | Boolean | 是否编译成功 | | id | String | 编译后的类 ID | | name | String | 类名 | | problem | String | 编译问题描述(如果有) | | line | Integer | 错误行号(如果有) | | column | Integer | 错误列号(如果有) | | bodyCrc | Long | 代码体 CRC 校验值 | | problems | CompileIssueVo[] | 编译问题数组 | | warnings | CompileIssueVo[] | 编译警告数组 | **成功响应示例**: ```json { "code": 200, "msg": "编译成功", "data": [ { "success": true, "id": "01pxx0000003DHb2AAG", "name": "MyClass", "problem": null, "line": 0, "column": 0, "bodyCrc": 123456789, "problems": [], "warnings": [] }, { "success": true, "id": "01pxx0000003DHc2AAG", "name": "AnotherClass", "problem": null, "line": 0, "column": 0, "bodyCrc": 987654321, "problems": [], "warnings": [] } ] } ``` **失败响应示例**: ```json { "code": 500, "msg": "编译失败: 类 MyClass 编译错误", "data": [ { "success": false, "id": null, "name": "MyClass", "problem": "Unexpected token 'public'", "line": 2, "column": 5, "bodyCrc": 0, "problems": [ { "message": "Unexpected token 'public'", "line": 2, "column": 5 } ], "warnings": [] } ] } ``` --- ### 2. 编译 Apex 触发器 **功能描述**:编译一个或多个 Apex 触发器到 Salesforce 平台 **请求方式**:POST **请求路径**:`/api/apex/compile/triggers` **权限要求**:`@PreAuthorize("@ss.hasPermi('apex:compile:execute')")` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | triggers | String[] | 是 | Apex 触发器代码数组,每个元素是一个完整的触发器定义 | **请求示例**: ```json { "triggers": [ "trigger MyTrigger on Account (before insert) {\n for (Account acc : Trigger.new) {\n acc.Name = acc.Name.toUpperCase();\n }\n}" ] } ``` **响应参数**: | 参数名 | 类型 | 说明 | |--------|------|------| | code | Integer | 状态码(200 成功,其他失败) | | msg | String | 提示信息 | | data | CompileTriggerResultVo[] | 编译结果数组 | **CompileTriggerResultVo 字段说明**: | 字段名 | 类型 | 说明 | |--------|------|------| | success | Boolean | 是否编译成功 | | id | String | 编译后的触发器 ID | | name | String | 触发器名称 | | problem | String | 编译问题描述(如果有) | | line | Integer | 错误行号(如果有) | | column | Integer | 错误列号(如果有) | | bodyCrc | Long | 代码体 CRC 校验值 | | problems | CompileIssueVo[] | 编译问题数组 | | warnings | CompileIssueVo[] | 编译警告数组 | **成功响应示例**: ```json { "code": 200, "msg": "编译成功", "data": [ { "success": true, "id": "01qxx0000003DHb2AAG", "name": "MyTrigger", "problem": null, "line": 0, "column": 0, "bodyCrc": 123456789, "problems": [], "warnings": [] } ] } ``` --- ### 3. 编译并测试 **功能描述**:编译 Apex 代码并运行单元测试 **请求方式**:POST **请求路径**:`/api/apex/compile/compile-and-test` **权限要求**:`@PreAuthorize("@ss.hasPermi('apex:compile:execute')")` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | checkOnly | Boolean | 否 | 是否仅检查而不实际部署,默认 false | | classes | String[] | 否 | Apex 类代码数组 | | triggers | String[] | 否 | Apex 触发器代码数组 | | deleteClasses | String[] | 否 | 要删除的类名称数组 | | deleteTriggers | String[] | 否 | 要删除的触发器名称数组 | | runTestsRequest | RunTestsRequestDto | 否 | 测试运行请求 | **RunTestsRequestDto 字段说明**: | 字段名 | 类型 | 必填 | 说明 | |--------|------|------|------| | allTests | Boolean | 否 | 是否运行所有测试,默认 false | | classes | String[] | 否 | 要测试的类名称数组 | | namespace | String | 否 | 命名空间 | | maxFailedTests | Integer | 否 | 最大失败测试数 | **请求示例**: ```json { "checkOnly": false, "classes": [ "public class TestClass {\n @isTest\n static void testMethod() {\n System.assertEquals(1, 1);\n }\n}" ], "runTestsRequest": { "allTests": false, "classes": ["TestClass"] } } ``` **响应参数**: | 参数名 | 类型 | 说明 | |--------|------|------| | code | Integer | 状态码(200 成功,其他失败) | | msg | String | 提示信息 | | data | CompileAndTestResultVo | 编译并测试结果 | **CompileAndTestResultVo 字段说明**: | 字段名 | 类型 | 说明 | |--------|------|------| | compileSuccess | Boolean | 编译是否成功 | | testSuccess | Boolean | 测试是否全部通过 | | compileResults | CompileClassResultVo[] | 类编译结果 | | triggerResults | CompileTriggerResultVo[] | 触发器编译结果 | | testResults | RunTestsResultVo | 测试结果 | **RunTestsResultVo 字段说明**: | 字段名 | 类型 | 说明 | |--------|------|------| | numTestsRun | Integer | 运行的测试数量 | | numFailures | Integer | 失败的测试数量 | | totalTime | Double | 总执行时间(毫秒) | | successes | TestSuccessVo[] | 成功的测试 | | failures | TestFailureVo[] | 失败的测试 | | codeCoverage | CodeCoverageResultVo[] | 代码覆盖率结果 | | apexLogId | String | Apex 日志 ID | **成功响应示例**: ```json { "code": 200, "msg": "编译并测试成功", "data": { "compileSuccess": true, "testSuccess": true, "compileResults": [ { "success": true, "id": "01pxx0000003DHb2AAG", "name": "TestClass", "problem": null, "line": 0, "column": 0, "bodyCrc": 123456789, "problems": [], "warnings": [] } ], "triggerResults": [], "testResults": { "numTestsRun": 1, "numFailures": 0, "totalTime": 150.5, "successes": [ { "className": "TestClass", "methodName": "testMethod", "time": 150.5 } ], "failures": [], "codeCoverage": [ { "id": "01pxx0000003DHb2AAG", "name": "TestClass", "type": "Class", "namespace": null, "numLocations": 10, "numLocationsNotCovered": 2, "coveragePercent": 80.0 } ], "apexLogId": "07Lxx0000003DHb2AAG" } } } ``` --- ### 4. 执行匿名 Apex 代码 **功能描述**:执行匿名的 Apex 代码片段 **请求方式**:POST **请求路径**:`/api/apex/execute/anonymous` **权限要求**:`@PreAuthorize("@ss.hasPermi('apex:execute:anonymous')")` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | code | String | 是 | 要执行的 Apex 代码 | **请求示例**: ```json { "code": "System.debug('Hello, Salesforce!');\nInteger sum = 1 + 2;\nSystem.debug('Sum: ' + sum);" } ``` **响应参数**: | 参数名 | 类型 | 说明 | |--------|------|------| | code | Integer | 状态码(200 成功,其他失败) | | msg | String | 提示信息 | | data | ExecuteAnonymousResultVo | 执行结果 | **ExecuteAnonymousResultVo 字段说明**: | 字段名 | 类型 | 说明 | |--------|------|------| | success | Boolean | 是否执行成功 | | compiled | Boolean | 是否编译成功 | | compileProblem | String | 编译问题描述(如果有) | | exceptionMessage | String | 异常消息(如果有) | | exceptionStackTrace | String | 异常堆栈(如果有) | | line | Integer | 错误行号(如果有) | | column | Integer | 错误列号(如果有) | **成功响应示例**: ```json { "code": 200, "msg": "执行成功", "data": { "success": true, "compiled": true, "compileProblem": null, "exceptionMessage": null, "exceptionStackTrace": null, "line": 0, "column": 0 } } ``` **编译失败响应示例**: ```json { "code": 500, "msg": "编译失败", "data": { "success": false, "compiled": false, "compileProblem": "Unexpected token 'System'", "exceptionMessage": null, "exceptionStackTrace": null, "line": 1, "column": 1 } } ``` **运行时异常响应示例**: ```json { "code": 500, "msg": "执行失败", "data": { "success": false, "compiled": true, "compileProblem": null, "exceptionMessage": "Divide by 0", "exceptionStackTrace": "AnonymousBlock: line 1, column 1", "line": 1, "column": 1 } } ``` --- ### 5. 查询编译历史 **功能描述**:查询 Apex 代码编译历史记录 **请求方式**:GET **请求路径**:`/api/apex/compile/history` **权限要求**:`@PreAuthorize("@ss.hasPermi('apex:compile:query')")` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | compileType | String | 否 | 编译类型(class/trigger/compile_and_test) | | startTime | String | 否 | 开始时间(格式:yyyy-MM-dd HH:mm:ss) | | endTime | String | 否 | 结束时间(格式:yyyy-MM-dd HH:mm:ss) | | pageNum | Integer | 否 | 页码,默认 1 | | pageSize | Integer | 否 | 每页大小,默认 10 | **响应参数**: | 参数名 | 类型 | 说明 | |--------|------|------| | code | Integer | 状态码(200 成功,其他失败) | | msg | String | 提示信息 | | data | PageResult | 分页结果 | **DataiApexCompileHistory 字段说明**: | 字段名 | 类型 | 说明 | |--------|------|------| | id | Long | 主键 ID | | compileType | String | 编译类型 | | codeContent | String | 代码内容 | | compileSuccess | Boolean | 编译是否成功 | | compileProblem | String | 编译问题描述 | | compileTime | Date | 编译时间 | | createBy | String | 创建人 | | createTime | Date | 创建时间 | **成功响应示例**: ```json { "code": 200, "msg": "查询成功", "data": { "total": 100, "rows": [ { "id": 1, "compileType": "class", "codeContent": "public class MyClass { ... }", "compileSuccess": true, "compileProblem": null, "compileTime": "2026-02-02T10:30:00", "createBy": "admin", "createTime": "2026-02-02T10:30:00" } ] } } ``` --- ### 6. 查询测试结果 **功能描述**:查询 Apex 测试结果记录 **请求方式**:GET **请求路径**:`/api/apex/test/results` **权限要求**:`@PreAuthorize("@ss.hasPermi('apex:test:query')")` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | testRunId | String | 否 | 测试运行 ID | | startTime | String | 否 | 开始时间(格式:yyyy-MM-dd HH:mm:ss) | | endTime | String | 否 | 结束时间(格式:yyyy-MM-dd HH:mm:ss) | | pageNum | Integer | 否 | 页码,默认 1 | | pageSize | Integer | 否 | 每页大小,默认 10 | **响应参数**: | 参数名 | 类型 | 说明 | |--------|------|------| | code | Integer | 状态码(200 成功,其他失败) | | msg | String | 提示信息 | | data | PageResult | 分页结果 | **DataiApexTestResult 字段说明**: | 字段名 | 类型 | 说明 | |--------|------|------| | id | Long | 主键 ID | | testRunId | String | 测试运行 ID | | numTestsRun | Integer | 运行的测试数量 | | numFailures | Integer | 失败的测试数量 | | totalTime | Double | 总执行时间(毫秒) | | apexLogId | String | Apex 日志 ID | | testTime | Date | 测试时间 | | allPassed | Boolean | 是否全部通过 | | totalCoverage | Double | 总体覆盖率 | | createBy | String | 创建人 | | createTime | Date | 创建时间 | **成功响应示例**: ```json { "code": 200, "msg": "查询成功", "data": { "total": 50, "rows": [ { "id": 1, "testRunId": "707xx0000003DHb2AAG", "numTestsRun": 10, "numFailures": 0, "totalTime": 1500.5, "apexLogId": "07Lxx0000003DHb2AAG", "testTime": "2026-02-02T10:30:00", "allPassed": true, "totalCoverage": 85.5, "createBy": "admin", "createTime": "2026-02-02T10:30:00" } ] } } ``` --- ### 7. 查询代码覆盖率 **功能描述**:查询 Apex 代码覆盖率记录 **请求方式**:GET **请求路径**:`/api/apex/test/coverage` **权限要求**:`@PreAuthorize("@ss.hasPermi('apex:test:query')")` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | testResultId | Long | 否 | 测试结果 ID | | name | String | 否 | 类/触发器名称 | | type | String | 否 | 类型(Class/Trigger) | | pageNum | Integer | 否 | 页码,默认 1 | | pageSize | Integer | 否 | 每页大小,默认 10 | **响应参数**: | 参数名 | 类型 | 说明 | |--------|------|------| | code | Integer | 状态码(200 成功,其他失败) | | msg | String | 提示信息 | | data | PageResult | 分页结果 | **DataiApexCodeCoverage 字段说明**: | 字段名 | 类型 | 说明 | |--------|------|------| | id | Long | 主键 ID | | testResultId | Long | 测试结果 ID | | name | String | 类/触发器名称 | | type | String | 类型(Class/Trigger) | | namespace | String | 命名空间 | | numLocations | Integer | 总位置数 | | numLocationsNotCovered | Integer | 未覆盖的位置数 | | coveragePercent | Double | 覆盖率百分比 | | createTime | Date | 创建时间 | **成功响应示例**: ```json { "code": 200, "msg": "查询成功", "data": { "total": 30, "rows": [ { "id": 1, "testResultId": 1, "name": "MyClass", "type": "Class", "namespace": null, "numLocations": 100, "numLocationsNotCovered": 20, "coveragePercent": 80.0, "createTime": "2026-02-02T10:30:00" } ] } } ``` --- ## 错误码 ### 系统错误码 | 错误码 | 说明 | 处理建议 | |--------|------|----------| | 200 | 操作成功 | 无需处理 | | 401 | 未授权 | 检查 JWT Token 是否有效 | | 403 | 无权限 | 检查用户是否有相应权限 | | 404 | 资源不存在 | 检查请求路径是否正确 | | 500 | 服务器内部错误 | 查看服务器日志,联系管理员 | ### 业务错误码 | 错误码 | 说明 | 处理建议 | |--------|------|----------| | 1001 | Salesforce 认证失败 | 检查 Salesforce 连接配置 | | 1002 | Salesforce 会话过期 | 重新登录获取新会话 | | 1003 | 编译失败 | 检查代码语法是否正确 | | 1004 | 测试执行失败 | 检查测试代码是否正确 | | 1005 | 执行匿名代码失败 | 检查代码语法和逻辑 | | 1006 | 查询参数错误 | 检查请求参数是否符合要求 | ### 常见错误场景 #### 1. 认证失败 ```json { "code": 401, "msg": "认证失败:无效的令牌" } ``` **原因**:JWT Token 无效或已过期 **解决方案**:重新登录获取新的 JWT Token #### 2. 无权限访问 ```json { "code": 403, "msg": "无权限访问:缺少 apex:compile:execute 权限" } ``` **原因**:当前用户没有执行编译操作的权限 **解决方案**:联系管理员分配相应权限 #### 3. Salesforce 连接失败 ```json { "code": 500, "msg": "Salesforce 认证失败:连接超时" } ``` **原因**:无法连接到 Salesforce 或认证信息无效 **解决方案**: - 检查 Salesforce 连接配置 - 检查网络连接 - 确认认证信息(用户名、密码、安全令牌)是否正确 #### 4. 编译错误 ```json { "code": 500, "msg": "编译失败", "data": { "success": false, "problem": "Unexpected token 'public'", "line": 2, "column": 5 } } ``` **原因**:Apex 代码存在语法错误 **解决方案**:根据返回的错误信息(行号、列号、问题描述)修复代码 #### 5. 运行时异常 ```json { "code": 500, "msg": "执行失败", "data": { "success": false, "exceptionMessage": "Divide by 0", "exceptionStackTrace": "AnonymousBlock: line 1, column 1" } } ``` **原因**:执行的代码在运行时抛出异常 **解决方案**:根据异常消息和堆栈跟踪修复代码逻辑 ## 相关文档 - [需求文档](../requirements/sub/2026-01-28-002-02-Apex代码编译和执行.md) - [设计文档](../design/2026-02-02-002-02-Apex代码编译和执行-设计.md) - [决策记录](../decisions/2026-02-02-002-02-ADR-Apex代码编译和执行技术选型.md) - [变更日志](../changelog/2026-02-02-002-02-changelog.md) - [复盘文档](../retros/2026-02-02-002-02-retro.md)