19 KiB
API 文档 - Apex 代码编译和执行
元数据
- 需求编号:002-02
- 需求名称:Apex 代码编译和执行
- 创建时间:2026-02-02
- 创建人:AI Assistant
- 版本:v1.0.0
- 状态:已完成
API 概述
Apex 代码编译和执行 API 提供了一套完整的接口,用于在 Salesforce 平台上编译和执行 Apex 代码。支持编译 Apex 类、编译 Apex 触发器、编译并运行测试、执行匿名 Apex 代码等功能,同时提供查询编译历史、测试结果和代码覆盖率的能力。
核心功能
- 编译 Apex 类:将 Apex 类代码编译到 Salesforce 平台
- 编译 Apex 触发器:将 Apex 触发器代码编译到 Salesforce 平台
- 编译并测试:编译代码并运行单元测试
- 执行匿名代码:执行匿名的 Apex 代码片段
- 查询功能:查询编译历史、测试结果和代码覆盖率
技术架构
- 协议: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 类代码数组,每个元素是一个完整的类定义 |
请求示例:
{
"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[] | 编译警告数组 |
成功响应示例:
{
"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": []
}
]
}
失败响应示例:
{
"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 触发器代码数组,每个元素是一个完整的触发器定义 |
请求示例:
{
"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[] | 编译警告数组 |
成功响应示例:
{
"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 | 否 | 最大失败测试数 |
请求示例:
{
"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 |
成功响应示例:
{
"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 代码 |
请求示例:
{
"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 | 错误列号(如果有) |
成功响应示例:
{
"code": 200,
"msg": "执行成功",
"data": {
"success": true,
"compiled": true,
"compileProblem": null,
"exceptionMessage": null,
"exceptionStackTrace": null,
"line": 0,
"column": 0
}
}
编译失败响应示例:
{
"code": 500,
"msg": "编译失败",
"data": {
"success": false,
"compiled": false,
"compileProblem": "Unexpected token 'System'",
"exceptionMessage": null,
"exceptionStackTrace": null,
"line": 1,
"column": 1
}
}
运行时异常响应示例:
{
"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 | 创建时间 |
成功响应示例:
{
"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 | 创建时间 |
成功响应示例:
{
"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 | 创建时间 |
成功响应示例:
{
"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. 认证失败
{
"code": 401,
"msg": "认证失败:无效的令牌"
}
原因:JWT Token 无效或已过期 解决方案:重新登录获取新的 JWT Token
2. 无权限访问
{
"code": 403,
"msg": "无权限访问:缺少 apex:compile:execute 权限"
}
原因:当前用户没有执行编译操作的权限 解决方案:联系管理员分配相应权限
3. Salesforce 连接失败
{
"code": 500,
"msg": "Salesforce 认证失败:连接超时"
}
原因:无法连接到 Salesforce 或认证信息无效 解决方案:
- 检查 Salesforce 连接配置
- 检查网络连接
- 确认认证信息(用户名、密码、安全令牌)是否正确
4. 编译错误
{
"code": 500,
"msg": "编译失败",
"data": {
"success": false,
"problem": "Unexpected token 'public'",
"line": 2,
"column": 5
}
}
原因:Apex 代码存在语法错误 解决方案:根据返回的错误信息(行号、列号、问题描述)修复代码
5. 运行时异常
{
"code": 500,
"msg": "执行失败",
"data": {
"success": false,
"exceptionMessage": "Divide by 0",
"exceptionStackTrace": "AnonymousBlock: line 1, column 1"
}
}
原因:执行的代码在运行时抛出异常 解决方案:根据异常消息和堆栈跟踪修复代码逻辑