934 lines
32 KiB
Markdown
934 lines
32 KiB
Markdown
# datai-salesforce-common 模块详细文档
|
||
|
||
## 模块概述
|
||
|
||
### 基本信息
|
||
- **模块名称**: datai-salesforce-common
|
||
- **模块类型**: 通用工具模块
|
||
- **版本**: 1.0.0
|
||
- **Java 版本**: 22
|
||
- **编码**: UTF-8
|
||
|
||
### 功能描述
|
||
datai-salesforce-common 模块是 Salesforce 集成体系的通用工具模块,提供常量定义、工具类、数据转换、异常处理等基础功能。该模块被其他所有 Salesforce 相关模块依赖,是整个体系的基础设施层。
|
||
|
||
### 核心特性
|
||
1. **常量管理**:统一的 Salesforce 相关常量定义
|
||
2. **SOQL 构建**:强大的 SOQL 查询构建器
|
||
3. **数据转换**:Salesforce 数据类型转换工具
|
||
4. **异常处理**:完善的异常体系
|
||
5. **参数封装**:统一的参数封装类
|
||
6. **工具方法**:丰富的工具方法集合
|
||
|
||
## 模块架构
|
||
|
||
### 整体架构图
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ datai-salesforce-common │
|
||
│ │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ 常量层(Constants) │ │
|
||
│ │ SalesforceConstants | ConfigConstants | Connection │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
│ │ │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ 工具层(Utils) │ │
|
||
│ │ SoqlBuilder | SoqlUtil | ApiListUtils | FileValidation│ │
|
||
│ │ IdUtils | ValidationUtils | BooleanConverter │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
│ │ │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ 转换层(Converters) │ │
|
||
│ │ SalesforceDataTypeConverter │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
│ │ │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ 参数层(Params) │ │
|
||
│ │ SalesforceParam | SalesforceStockParam │ │
|
||
│ │ SalesforceIncrementParam │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
│ │ │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ 异常层(Exceptions) │ │
|
||
│ │ SalesforceAuthException | SalesforceLoginException │ │
|
||
│ │ SalesforceOAuthException | FileUploadException │ │
|
||
│ │ ... (30+ 异常类) │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
│ │ │
|
||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||
│ │ 枚举层(Enums) │ │
|
||
│ │ FileObjectType │ │
|
||
│ └─────────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 分层说明
|
||
|
||
#### 1. 常量层
|
||
负责统一管理 Salesforce 相关常量,包括 API 版本、连接端点、HTTP 方法、日期格式等。
|
||
|
||
#### 2. 工具层
|
||
提供各种工具方法,包括 SOQL 查询构建、文件验证、ID 处理、数据验证等。
|
||
|
||
#### 3. 转换层
|
||
负责数据类型转换,特别是 Salesforce 特有的数据类型转换。
|
||
|
||
#### 4. 参数层
|
||
封装各种业务参数,提供统一的参数传递方式。
|
||
|
||
#### 5. 异常层
|
||
定义完善的异常体系,覆盖各种业务场景。
|
||
|
||
#### 6. 枚举层
|
||
定义业务枚举,提供类型安全的常量定义。
|
||
|
||
## 核心组件详解
|
||
|
||
### 1. SalesforceConstants(常量类)
|
||
|
||
**类路径**: `com.datai.common.constant.SalesforceConstants`
|
||
|
||
**功能描述**:
|
||
统一管理 Salesforce 相关常量,按照功能模块分类,便于维护和使用。
|
||
|
||
**主要常量分类**:
|
||
|
||
#### API 版本常量
|
||
```java
|
||
// REST API 版本
|
||
public static final String REST_API_VERSION = "v59.0";
|
||
|
||
// Bulk API v1 版本
|
||
public static final String BULK_V1_API_VERSION = "47.0";
|
||
|
||
// Bulk API v2 版本
|
||
public static final String BULK_V2_API_VERSION = "v59.0";
|
||
```
|
||
|
||
#### 连接端点常量
|
||
```java
|
||
// REST API 端点后缀
|
||
public static final String REST_ENDPOINT_SUFFIX = "/services/data/";
|
||
|
||
// Bulk API v1 端点后缀
|
||
public static final String BULK_V1_ENDPOINT_SUFFIX = "/services/async/";
|
||
|
||
// Bulk API v2 端点后缀
|
||
public static final String BULK_V2_ENDPOINT_SUFFIX = "/services/data/v59.0/jobs/";
|
||
|
||
// SOAP API 端点后缀
|
||
public static final String SOAP_ENDPOINT_SUFFIX = "/services/Soap/u/59.0/";
|
||
```
|
||
|
||
#### 连接类型常量
|
||
```java
|
||
// 连接类型 - SOAP
|
||
public static final String CONNECTION_TYPE_SOAP = "SOAP";
|
||
|
||
// 连接类型 - REST
|
||
public static final String CONNECTION_TYPE_REST = "REST";
|
||
|
||
// 连接类型 - Bulk API v1
|
||
public static final String CONNECTION_TYPE_BULK_V1 = "BULK_V1";
|
||
|
||
// 连接类型 - Bulk API v2
|
||
public static final String CONNECTION_TYPE_BULK_V2 = "BULK_V2";
|
||
```
|
||
|
||
#### HTTP 相关常量
|
||
```java
|
||
// HTTP 方法
|
||
public static final String HTTP_METHOD_GET = "GET";
|
||
public static final String HTTP_METHOD_POST = "POST";
|
||
public static final String HTTP_METHOD_PUT = "PUT";
|
||
public static final String HTTP_METHOD_PATCH = "PATCH";
|
||
public static final String HTTP_METHOD_DELETE = "DELETE";
|
||
|
||
// 内容类型
|
||
public static final String CONTENT_TYPE_JSON = "application/json";
|
||
public static final String CONTENT_TYPE_CSV = "text/csv";
|
||
public static final String CONTENT_TYPE_XML = "application/xml";
|
||
|
||
// 授权头
|
||
public static final String AUTH_HEADER_NAME = "Authorization";
|
||
public static final String AUTH_HEADER_PREFIX = "Bearer ";
|
||
```
|
||
|
||
#### 日期格式常量
|
||
```java
|
||
// Salesforce 日期时间格式
|
||
public static final String SF_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
|
||
|
||
// Salesforce 日期格式
|
||
public static final String SF_DATE_ONLY_FORMAT = "yyyy-MM-dd";
|
||
|
||
// Salesforce 时间格式
|
||
public static final String SF_TIME_FORMAT = "HH:mm:ss.SSS'Z'";
|
||
```
|
||
|
||
#### 批次处理常量
|
||
```java
|
||
// 大批次大小(外层批次)
|
||
public static final int LARGE_BATCH_SIZE = 10000;
|
||
|
||
// 小批次大小(API 调用批次)
|
||
public static final int SMALL_BATCH_SIZE = 200;
|
||
|
||
// 批次间休眠时间(毫秒)
|
||
public static final long BATCH_SLEEP_MS = 1L;
|
||
|
||
// 日志输出间隔
|
||
public static final int LOG_OUTPUT_INTERVAL = 10;
|
||
```
|
||
|
||
#### 重试相关常量
|
||
```java
|
||
// 最大重试次数
|
||
public static final int MAX_RETRY_COUNT = 3;
|
||
|
||
// 重试延迟时间(毫秒)
|
||
public static final long RETRY_DELAY_MS = 1000L;
|
||
```
|
||
|
||
### 2. SoqlBuilder(SOQL 查询构建器)
|
||
|
||
**类路径**: `com.datai.common.utils.SoqlBuilder`
|
||
|
||
**功能描述**:
|
||
强大的 SOQL 查询构建器,支持复杂查询条件,采用链式调用方式,提供类型安全的查询构建。
|
||
|
||
**SOQL 语法限制**:
|
||
1. 不支持 SELECT *,必须明确指定字段或使用 FIELDS()
|
||
2. 不支持 BETWEEN 运算符,请使用 >= 和 <= 组合代替
|
||
3. 不支持 JOIN,使用关系查询(Relationship Queries)如 Account.Name
|
||
4. 不支持 UNION,无法合并两个不相关的结果集
|
||
5. 查询最多返回 50000 条记录
|
||
6. OFFSET 上限为 2000,且必须与 LIMIT 一起使用
|
||
7. 支持的运算符:=, !=, >, >=, <, <=, LIKE, IN, NOT IN, = NULL, != NULL
|
||
8. 支持的子句:WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, OFFSET
|
||
|
||
**核心方法**:
|
||
|
||
#### SELECT 子句
|
||
```java
|
||
// 设置 SELECT 子句
|
||
public SoqlBuilder select(String... fields)
|
||
|
||
// 示例
|
||
SoqlBuilder builder = new SoqlBuilder()
|
||
.select("Id", "Name", "Account.Name", "CreatedDate");
|
||
```
|
||
|
||
#### FROM 子句
|
||
```java
|
||
// 设置 FROM 子句
|
||
public SoqlBuilder from(String object)
|
||
|
||
// 示例
|
||
SoqlBuilder builder = new SoqlBuilder()
|
||
.from("Contact");
|
||
```
|
||
|
||
#### WHERE 子句
|
||
```java
|
||
// 添加 WHERE 子句
|
||
public SoqlBuilder where(String clause)
|
||
|
||
// 添加等于条件
|
||
public SoqlBuilder whereEq(String field, Object value)
|
||
|
||
// 添加不等于条件
|
||
public SoqlBuilder whereNe(String field, Object value)
|
||
|
||
// 添加大于条件
|
||
public SoqlBuilder whereGt(String field, Object value)
|
||
|
||
// 添加大于等于条件
|
||
public SoqlBuilder whereGe(String field, Object value)
|
||
|
||
// 添加小于条件
|
||
public SoqlBuilder whereLt(String field, Object value)
|
||
|
||
// 添加小于等于条件
|
||
public SoqlBuilder whereLe(String field, Object value)
|
||
|
||
// 添加 IN 条件
|
||
public SoqlBuilder whereIn(String field, List<Object> values)
|
||
|
||
// 添加 NOT IN 条件
|
||
public SoqlBuilder whereNotIn(String field, List<Object> values)
|
||
|
||
// 添加 LIKE 条件
|
||
public SoqlBuilder whereLike(String field, String value)
|
||
|
||
// 添加 NOT LIKE 条件
|
||
public SoqlBuilder whereNotLike(String field, String value)
|
||
|
||
// 添加 = NULL 条件
|
||
public SoqlBuilder whereIsNull(String field)
|
||
|
||
// 添加 != NULL 条件
|
||
public SoqlBuilder whereIsNotNull(String field)
|
||
|
||
// 示例
|
||
SoqlBuilder builder = new SoqlBuilder()
|
||
.whereEq("Status", "Active")
|
||
.whereGt("Amount", 1000)
|
||
.whereIn("Type", Arrays.asList("Customer", "Partner"))
|
||
.whereLike("Name", "John%");
|
||
```
|
||
|
||
#### ORDER BY 子句
|
||
```java
|
||
// 添加 ORDER BY 子句
|
||
public SoqlBuilder orderBy(String field, SortOrder direction)
|
||
|
||
// 示例
|
||
SoqlBuilder builder = new SoqlBuilder()
|
||
.orderBy("CreatedDate", SortOrder.DESC)
|
||
.orderBy("Name", SortOrder.ASC);
|
||
```
|
||
|
||
#### GROUP BY 子句
|
||
```java
|
||
// 添加 GROUP BY 子句
|
||
public SoqlBuilder groupBy(String... fields)
|
||
|
||
// 示例
|
||
SoqlBuilder builder = new SoqlBuilder()
|
||
.groupBy("Account.Name", "Status");
|
||
```
|
||
|
||
#### HAVING 子句
|
||
```java
|
||
// 添加 HAVING 子句
|
||
public SoqlBuilder having(String clause)
|
||
|
||
// 示例
|
||
SoqlBuilder builder = new SoqlBuilder()
|
||
.having("COUNT(Id) > 10");
|
||
```
|
||
|
||
#### LIMIT 和 OFFSET 子句
|
||
```java
|
||
// 设置 LIMIT 子句
|
||
public SoqlBuilder limit(int limit)
|
||
|
||
// 设置 OFFSET 子句
|
||
public SoqlBuilder offset(int offset)
|
||
|
||
// 示例
|
||
SoqlBuilder builder = new SoqlBuilder()
|
||
.limit(100)
|
||
.offset(50);
|
||
```
|
||
|
||
#### 构建查询
|
||
```java
|
||
// 构建 SOQL 查询语句
|
||
public String build()
|
||
|
||
// 构建 COUNT 查询语句
|
||
public String buildCountQuery()
|
||
|
||
// 示例
|
||
String soql = new SoqlBuilder()
|
||
.select("Id", "Name", "Account.Name", "CreatedDate")
|
||
.from("Contact")
|
||
.whereEq("Status", "Active")
|
||
.whereGt("Amount", 1000)
|
||
.orderBy("CreatedDate", SortOrder.DESC)
|
||
.limit(100)
|
||
.build();
|
||
```
|
||
|
||
**完整示例**:
|
||
```java
|
||
// 简单查询
|
||
String soql1 = new SoqlBuilder()
|
||
.select("Id", "Name")
|
||
.from("Account")
|
||
.whereEq("Status", "Active")
|
||
.orderBy("Name", SortOrder.ASC)
|
||
.limit(10)
|
||
.build();
|
||
// 生成: SELECT Id, Name FROM Account WHERE Status = 'Active' ORDER BY Name ASC LIMIT 10
|
||
|
||
// 复杂查询
|
||
String soql2 = new SoqlBuilder()
|
||
.select("Id", "Name", "Account.Name", "TotalAmount", "CreatedDate")
|
||
.from("Opportunity")
|
||
.whereEq("StageName", "Closed Won")
|
||
.whereGe("CloseDate", "2024-01-01")
|
||
.whereIn("Type", Arrays.asList("New Customer", "Existing Customer"))
|
||
.orderBy("TotalAmount", SortOrder.DESC)
|
||
.limit(50)
|
||
.build();
|
||
// 生成: SELECT Id, Name, Account.Name, TotalAmount, CreatedDate
|
||
// FROM Opportunity
|
||
// WHERE StageName = 'Closed Won'
|
||
// AND CloseDate >= '2024-01-01'
|
||
// AND Type IN ('New Customer', 'Existing Customer')
|
||
// ORDER BY TotalAmount DESC
|
||
// LIMIT 50
|
||
|
||
// COUNT 查询
|
||
String countSoql = new SoqlBuilder()
|
||
.select("Id", "Name")
|
||
.from("Account")
|
||
.whereEq("Status", "Active")
|
||
.buildCountQuery();
|
||
// 生成: SELECT count(Id) FROM Account WHERE Status = 'Active'
|
||
```
|
||
|
||
### 3. SalesforceDataTypeConverter(数据类型转换器)
|
||
|
||
**类路径**: `com.datai.common.converter.SalesforceDataTypeConverter`
|
||
|
||
**功能描述**:
|
||
Salesforce 特定数据类型转换工具,处理日期时间转换、ID 格式转换等。
|
||
|
||
**核心方法**:
|
||
|
||
#### 日期时间转换
|
||
```java
|
||
// 将 Salesforce 日期时间字符串转换为 Date 对象
|
||
public Date convertToDate(String dateTimeString)
|
||
|
||
// 将 Date 对象转换为 Salesforce 日期时间字符串
|
||
public String convertToString(Date date)
|
||
|
||
// 将 Date 对象转换为 Salesforce 日期字符串
|
||
public String convertToDateString(Date date)
|
||
|
||
// 示例
|
||
SalesforceDataTypeConverter converter = new SalesforceDataTypeConverter();
|
||
|
||
// 转换为 Date
|
||
Date date = converter.convertToDate("2024-01-15T10:30:00.000Z");
|
||
|
||
// 转换为字符串
|
||
String dateTimeStr = converter.convertToString(new Date());
|
||
String dateStr = converter.convertToDateString(new Date());
|
||
```
|
||
|
||
#### ID 格式转换
|
||
```java
|
||
// 将 Salesforce ID 转换为 15 位格式
|
||
public String to15CharId(String salesforceId)
|
||
|
||
// 将 Salesforce ID 转换为 18 位格式
|
||
public String to18CharId(String salesforceId)
|
||
|
||
// 示例
|
||
String id18 = converter.to18CharId("001xx000003DHb2AAG");
|
||
String id15 = converter.to15CharId("001xx000003DHb2AAG");
|
||
```
|
||
|
||
**时区支持**:
|
||
```java
|
||
// 使用默认时区(UTC)
|
||
SalesforceDataTypeConverter converter1 = new SalesforceDataTypeConverter();
|
||
|
||
// 使用自定义时区
|
||
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
|
||
SalesforceDataTypeConverter converter2 = new SalesforceDataTypeConverter(zoneId);
|
||
```
|
||
|
||
### 4. SalesforceParam(参数封装类)
|
||
|
||
**类路径**: `com.datai.common.param.SalesforceParam`
|
||
|
||
**功能描述**:
|
||
封装 Salesforce 查询参数,提供统一的参数传递方式。
|
||
|
||
**主要字段**:
|
||
|
||
| 字段名 | 类型 | 说明 |
|
||
|--------|------|------|
|
||
| api | String | 查询对象 API 名称 |
|
||
| select | String | 查询字段 |
|
||
| beginDate | Date | 开始日期 |
|
||
| endDate | Date | 结束日期 |
|
||
| beginCreateDate | Date | 开始创建日期 |
|
||
| endCreateDate | Date | 结束创建日期 |
|
||
| beginModifyDate | Date | 开始修改日期 |
|
||
| endModifyDate | Date | 结束修改日期 |
|
||
| maxId | String | 最大 ID |
|
||
| idField | String | ID 字段名(默认为 "Id") |
|
||
| dateField | String | 日期字段名(默认为 "CreatedDate") |
|
||
| sql | String | 自定义 SQL |
|
||
| batchId | Integer | 批次 ID |
|
||
| isDeleted | Boolean | 是否逻辑删除 |
|
||
| limit | Integer | 查询限制数量 |
|
||
| isSingleThread | Boolean | 是否单线程(默认为 false) |
|
||
|
||
**使用示例**:
|
||
```java
|
||
SalesforceParam param = new SalesforceParam();
|
||
param.setApi("Account");
|
||
param.setSelect("Id, Name, CreatedDate");
|
||
param.setBeginCreateDate(startDate);
|
||
param.setEndCreateDate(endDate);
|
||
param.setLimit(100);
|
||
```
|
||
|
||
### 5. FileObjectType(文件对象类型枚举)
|
||
|
||
**类路径**: `com.datai.common.enums.FileObjectType`
|
||
|
||
**功能描述**:
|
||
定义 Salesforce 文件对象类型,提供文件上传相关的元数据。
|
||
|
||
**枚举值**:
|
||
|
||
| 枚举值 | API 名称 | 描述 | 最大大小 | 推荐 | 上传方法 | 必需字段 |
|
||
|--------|----------|------|----------|------|----------|----------|
|
||
| ATTACHMENT | Attachment | 传统附件对象(已弃用) | 50 MB | 仅兼容旧系统 | REST API (JSON + Base64) | ParentId, Name, Body |
|
||
| CONTENT_DOCUMENT | ContentDocument | 现代文件对象 | 2048 MB | 强烈推荐 | REST API (Multipart/form-data) | Title, PathOnClient, VersionData |
|
||
| DOCUMENT | Document | 文档对象 | 25 MB | 仅用于特定遗留功能 | Partner API (SOAP) | FolderId, Name, Body |
|
||
|
||
**使用示例**:
|
||
```java
|
||
// 获取枚举
|
||
FileObjectType type = FileObjectType.fromApiName("ContentDocument");
|
||
|
||
// 获取属性
|
||
String apiName = type.getApiName(); // "ContentDocument"
|
||
int maxSizeMB = type.getMaxSizeMB(); // 2048
|
||
long maxSizeBytes = type.getMaxSizeBytes(); // 2147483648
|
||
String recommendation = type.getRecommendation(); // "强烈推荐"
|
||
```
|
||
|
||
### 6. 异常体系
|
||
|
||
**异常层次结构**:
|
||
|
||
```
|
||
SalesforceAuthException(认证异常基类)
|
||
├── SalesforceLoginException(登录异常)
|
||
├── SalesforceLegacyCredentialLoginException(传统凭证登录异常)
|
||
├── SalesforceOAuthException(OAuth 异常)
|
||
├── SalesforceSessionIdLoginException(Session ID 登录异常)
|
||
└── SalesforceCliLoginException(CLI 登录异常)
|
||
|
||
SalesforceLoginException(登录异常)
|
||
├── PasswordExpiredException(密码过期异常)
|
||
└── NotLoggedInException(未登录异常)
|
||
|
||
FileUploadException(文件上传异常)
|
||
├── FileSizeExceededException(文件大小超出限制异常)
|
||
├── FileTypeNotSupportedException(文件类型不支持异常)
|
||
├── FileObjectNotFoundException(文件对象未找到异常)
|
||
└── FileValidationException(文件验证异常)
|
||
|
||
SalesforceOperationException(操作异常)
|
||
├── ExtractException(提取异常)
|
||
├── LoadException(加载异常)
|
||
└── ...
|
||
|
||
DataAccessException(数据访问异常)
|
||
├── DataAccessObjectException(数据访问对象异常)
|
||
├── DataAccessRowException(数据访问行异常)
|
||
└── ...
|
||
|
||
ConfigException(配置异常)
|
||
├── ConfigInitializationException(配置初始化异常)
|
||
├── OrgConfigNotFoundException(组织配置未找到异常)
|
||
└── ...
|
||
```
|
||
|
||
**主要异常类**:
|
||
|
||
#### SalesforceAuthException
|
||
```java
|
||
// Salesforce 认证异常基类
|
||
public class SalesforceAuthException extends RuntimeException {
|
||
private String errorCode;
|
||
|
||
public SalesforceAuthException(String errorCode, String message) {
|
||
super(message);
|
||
this.errorCode = errorCode;
|
||
}
|
||
|
||
public String getErrorCode() {
|
||
return errorCode;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### SalesforceLoginException
|
||
```java
|
||
// Salesforce 登录异常
|
||
public class SalesforceLoginException extends SalesforceAuthException {
|
||
public SalesforceLoginException(String message) {
|
||
super(message);
|
||
}
|
||
|
||
public SalesforceLoginException(String errorCode, String message) {
|
||
super(errorCode, message);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### FileUploadException
|
||
```java
|
||
// 文件上传异常
|
||
public class FileUploadException extends RuntimeException {
|
||
private FileErrorCode errorCode;
|
||
|
||
public FileUploadException(FileErrorCode errorCode, String message) {
|
||
super(message);
|
||
this.errorCode = errorCode;
|
||
}
|
||
|
||
public FileErrorCode getErrorCode() {
|
||
return errorCode;
|
||
}
|
||
}
|
||
```
|
||
|
||
**使用示例**:
|
||
```java
|
||
// 抛出登录异常
|
||
throw new SalesforceLoginException("LOGIN_FAILED", "登录失败,请检查用户名和密码");
|
||
|
||
// 抛出文件上传异常
|
||
throw new FileUploadException(FileErrorCode.FILE_SIZE_EXCEEDED, "文件大小超出限制");
|
||
|
||
// 捕获异常
|
||
try {
|
||
// 执行登录
|
||
} catch (SalesforceLoginException e) {
|
||
String errorCode = e.getErrorCode();
|
||
String message = e.getMessage();
|
||
// 处理异常
|
||
}
|
||
```
|
||
|
||
## 依赖关系
|
||
|
||
### Maven 依赖
|
||
|
||
```xml
|
||
<dependencies>
|
||
<!-- datai-common:通用工具模块 -->
|
||
<dependency>
|
||
<groupId>com.datai</groupId>
|
||
<artifactId>datai-common</artifactId>
|
||
</dependency>
|
||
|
||
<!-- commons-beanutils:Bean 工具 -->
|
||
<dependency>
|
||
<groupId>commons-beanutils</groupId>
|
||
<artifactId>commons-beanutils</artifactId>
|
||
<version>1.9.4</version>
|
||
</dependency>
|
||
|
||
<!-- force-wsc:Force Web Service Connector -->
|
||
<dependency>
|
||
<groupId>com.force.api</groupId>
|
||
<artifactId>force-wsc</artifactId>
|
||
<version>61.0.0</version>
|
||
</dependency>
|
||
|
||
<!-- hutool-all:Hutool 工具包 -->
|
||
<dependency>
|
||
<groupId>cn.hutool</groupId>
|
||
<artifactId>hutool-all</artifactId>
|
||
<version>5.8.22</version>
|
||
</dependency>
|
||
|
||
<!-- fastjson2:JSON 处理 -->
|
||
<dependency>
|
||
<groupId>com.alibaba.fastjson2</groupId>
|
||
<artifactId>fastjson2</artifactId>
|
||
<version>2.0.60</version>
|
||
</dependency>
|
||
</dependencies>
|
||
```
|
||
|
||
### 模块依赖
|
||
|
||
**被依赖的模块**:
|
||
- datai-salesforce-auth:使用常量、异常、工具类
|
||
- datai-salesforce-partner:使用常量、参数、工具类
|
||
- datai-salesforce-apex:使用常量、参数、工具类
|
||
- datai-salesforce-metadata:使用常量、参数、工具类
|
||
- datai-salesforce-tooling:使用常量、参数、工具类
|
||
|
||
**依赖的模块**:
|
||
- datai-common:通用工具模块
|
||
|
||
## 使用示例
|
||
|
||
### 示例 1:使用 SoqlBuilder 构建查询
|
||
|
||
```java
|
||
// 简单查询
|
||
String soql1 = new SoqlBuilder()
|
||
.select("Id", "Name", "CreatedDate")
|
||
.from("Account")
|
||
.whereEq("Status", "Active")
|
||
.orderBy("CreatedDate", SortOrder.DESC)
|
||
.limit(10)
|
||
.build();
|
||
|
||
// 复杂查询
|
||
String soql2 = new SoqlBuilder()
|
||
.select("Id", "Name", "Account.Name", "TotalAmount", "StageName")
|
||
.from("Opportunity")
|
||
.whereEq("StageName", "Closed Won")
|
||
.whereGe("CloseDate", "2024-01-01")
|
||
.whereIn("Type", Arrays.asList("New Customer", "Existing Customer"))
|
||
.whereLike("Name", "Project%")
|
||
.orderBy("TotalAmount", SortOrder.DESC)
|
||
.limit(50)
|
||
.build();
|
||
|
||
// COUNT 查询
|
||
String countSoql = new SoqlBuilder()
|
||
.select("Id")
|
||
.from("Account")
|
||
.whereEq("Status", "Active")
|
||
.buildCountQuery();
|
||
```
|
||
|
||
### 示例 2:使用 SalesforceDataTypeConverter
|
||
|
||
```java
|
||
// 创建转换器(使用默认时区)
|
||
SalesforceDataTypeConverter converter = new SalesforceDataTypeConverter();
|
||
|
||
// 日期时间转换
|
||
Date date = converter.convertToDate("2024-01-15T10:30:00.000Z");
|
||
String dateTimeStr = converter.convertToString(date);
|
||
String dateStr = converter.convertToDateString(date);
|
||
|
||
// ID 格式转换
|
||
String id18 = converter.to18CharId("001xx000003DHb2AAG");
|
||
String id15 = converter.to15CharId("001xx000003DHb2AAG");
|
||
|
||
// 使用自定义时区
|
||
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
|
||
SalesforceDataTypeConverter converter2 = new SalesforceDataTypeConverter(zoneId);
|
||
```
|
||
|
||
### 示例 3:使用 SalesforceParam
|
||
|
||
```java
|
||
// 创建参数对象
|
||
SalesforceParam param = new SalesforceParam();
|
||
param.setApi("Account");
|
||
param.setSelect("Id, Name, CreatedDate, LastModifiedDate");
|
||
param.setBeginCreateDate(startDate);
|
||
param.setEndCreateDate(endDate);
|
||
param.setLimit(100);
|
||
param.setIsDeleted(false);
|
||
|
||
// 使用参数构建查询
|
||
String soql = new SoqlBuilder()
|
||
.select(param.getSelect().split(",\\s*"))
|
||
.from(param.getApi())
|
||
.whereGe(param.getDateField(), param.getBeginCreateDate())
|
||
.whereLe(param.getDateField(), param.getEndCreateDate())
|
||
.whereEq("IsDeleted", param.getIsDeleted())
|
||
.limit(param.getLimit())
|
||
.build();
|
||
```
|
||
|
||
### 示例 4:使用 FileObjectType
|
||
|
||
```java
|
||
// 获取文件对象类型
|
||
FileObjectType type = FileObjectType.fromApiName("ContentDocument");
|
||
|
||
// 获取文件对象属性
|
||
String apiName = type.getApiName(); // "ContentDocument"
|
||
String description = type.getDescription(); // "现代文件对象"
|
||
int maxSizeMB = type.getMaxSizeMB(); // 2048
|
||
long maxSizeBytes = type.getMaxSizeBytes(); // 2147483648
|
||
String recommendation = type.getRecommendation(); // "强烈推荐"
|
||
String uploadMethod = type.getUploadMethod(); // "REST API (Multipart/form-data)"
|
||
String requiredFields = type.getRequiredFields(); // "Title, PathOnClient, VersionData"
|
||
|
||
// 验证文件大小
|
||
long fileSize = 1024 * 1024 * 500; // 500 MB
|
||
if (fileSize > type.getMaxSizeBytes()) {
|
||
throw new FileUploadException(FileErrorCode.FILE_SIZE_EXCEEDED,
|
||
"文件大小超出限制,最大允许 " + type.getMaxSizeMB() + " MB");
|
||
}
|
||
```
|
||
|
||
### 示例 5:使用异常类
|
||
|
||
```java
|
||
// 抛出登录异常
|
||
try {
|
||
// 执行登录
|
||
if (loginResult == null || !loginResult.isSuccess()) {
|
||
throw new SalesforceLoginException("LOGIN_FAILED", "登录失败,请检查用户名和密码");
|
||
}
|
||
} catch (SalesforceLoginException e) {
|
||
String errorCode = e.getErrorCode();
|
||
String message = e.getMessage();
|
||
// 处理异常
|
||
logger.error("登录失败: errorCode={}, message={}", errorCode, message);
|
||
}
|
||
|
||
// 抛出文件上传异常
|
||
try {
|
||
// 上传文件
|
||
if (fileSize > maxSize) {
|
||
throw new FileUploadException(FileErrorCode.FILE_SIZE_EXCEEDED,
|
||
"文件大小超出限制,最大允许 " + maxSize + " MB");
|
||
}
|
||
} catch (FileUploadException e) {
|
||
FileErrorCode errorCode = e.getErrorCode();
|
||
String message = e.getMessage();
|
||
// 处理异常
|
||
logger.error("文件上传失败: errorCode={}, message={}", errorCode, message);
|
||
}
|
||
|
||
// 抛出操作异常
|
||
try {
|
||
// 执行操作
|
||
if (operationResult == null) {
|
||
throw new SalesforceOperationException("OPERATION_FAILED", "操作失败");
|
||
}
|
||
} catch (SalesforceOperationException e) {
|
||
String errorCode = e.getErrorCode();
|
||
String message = e.getMessage();
|
||
// 处理异常
|
||
logger.error("操作失败: errorCode={}, message={}", errorCode, message);
|
||
}
|
||
```
|
||
|
||
### 示例 6:使用常量
|
||
|
||
```java
|
||
// 使用 API 版本常量
|
||
String restApiVersion = SalesforceConstants.REST_API_VERSION; // "v59.0"
|
||
String bulkV1ApiVersion = SalesforceConstants.BULK_V1_API_VERSION; // "47.0"
|
||
String bulkV2ApiVersion = SalesforceConstants.BULK_V2_API_VERSION; // "v59.0"
|
||
|
||
// 使用端点常量
|
||
String restEndpointSuffix = SalesforceConstants.REST_ENDPOINT_SUFFIX; // "/services/data/"
|
||
String bulkV1EndpointSuffix = SalesforceConstants.BULK_V1_ENDPOINT_SUFFIX; // "/services/async/"
|
||
String bulkV2EndpointSuffix = SalesforceConstants.BULK_V2_ENDPOINT_SUFFIX; // "/services/data/v59.0/jobs/"
|
||
|
||
// 使用连接类型常量
|
||
String soapConnectionType = SalesforceConstants.CONNECTION_TYPE_SOAP; // "SOAP"
|
||
String restConnectionType = SalesforceConstants.CONNECTION_TYPE_REST; // "REST"
|
||
String bulkV1ConnectionType = SalesforceConstants.CONNECTION_TYPE_BULK_V1; // "BULK_V1"
|
||
String bulkV2ConnectionType = SalesforceConstants.CONNECTION_TYPE_BULK_V2; // "BULK_V2"
|
||
|
||
// 使用 HTTP 方法常量
|
||
String httpGet = SalesforceConstants.HTTP_METHOD_GET; // "GET"
|
||
String httpPost = SalesforceConstants.HTTP_METHOD_POST; // "POST"
|
||
|
||
// 使用内容类型常量
|
||
String contentTypeJson = SalesforceConstants.CONTENT_TYPE_JSON; // "application/json"
|
||
String contentTypeCsv = SalesforceConstants.CONTENT_TYPE_CSV; // "text/csv"
|
||
|
||
// 使用日期格式常量
|
||
String sfDateFormat = SalesforceConstants.SF_DATE_FORMAT; // "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
|
||
String sfDateOnlyFormat = SalesforceConstants.SF_DATE_ONLY_FORMAT; // "yyyy-MM-dd"
|
||
|
||
// 使用批次处理常量
|
||
int largeBatchSize = SalesforceConstants.LARGE_BATCH_SIZE; // 10000
|
||
int smallBatchSize = SalesforceConstants.SMALL_BATCH_SIZE; // 200
|
||
long batchSleepMs = SalesforceConstants.BATCH_SLEEP_MS; // 1L
|
||
|
||
// 使用重试常量
|
||
int maxRetryCount = SalesforceConstants.MAX_RETRY_COUNT; // 3
|
||
long retryDelayMs = SalesforceConstants.RETRY_DELAY_MS; // 1000L
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
### 1. 使用 SoqlBuilder 构建查询
|
||
- 始终使用 SoqlBuilder 构建 SOQL 查询,不要手动拼接字符串
|
||
- 利用链式调用提高代码可读性
|
||
- 使用类型安全的方法(如 whereEq、whereGt)而不是手动拼接条件
|
||
- 注意 SOQL 的限制(如最多返回 50000 条记录,OFFSET 上限为 2000)
|
||
|
||
### 2. 使用 SalesforceDataTypeConverter 进行数据转换
|
||
- 始终使用 SalesforceDataTypeConverter 进行日期时间转换
|
||
- 注意时区问题,根据需要设置正确的时区
|
||
- 使用 to18CharId 和 to15CharId 进行 ID 格式转换
|
||
|
||
### 3. 使用 SalesforceParam 封装参数
|
||
- 使用 SalesforceParam 封装查询参数,提高代码可维护性
|
||
- 设置合理的默认值(如 idField、dateField)
|
||
- 注意参数验证,防止无效参数
|
||
|
||
### 4. 使用 FileObjectType 处理文件上传
|
||
- 优先使用 ContentDocument(现代文件对象)
|
||
- 注意文件大小限制,上传前验证文件大小
|
||
- 使用枚举获取文件对象的元数据
|
||
|
||
### 5. 使用异常类处理错误
|
||
- 使用合适的异常类,不要使用通用的 RuntimeException
|
||
- 提供清晰的错误码和错误消息
|
||
- 在合适的层级捕获和处理异常
|
||
|
||
### 6. 使用常量避免魔法值
|
||
- 使用 SalesforceConstants 中的常量,不要硬编码字符串
|
||
- 保持常量的可读性和可维护性
|
||
- 按功能模块分类组织常量
|
||
|
||
## 常见问题
|
||
|
||
### Q1:SoqlBuilder 支持 SELECT * 吗?
|
||
A:不支持。SOQL 不支持 SELECT *,必须明确指定查询字段或使用 FIELDS()。
|
||
|
||
### Q2:SoqlBuilder 支持 BETWEEN 运算符吗?
|
||
A:不支持。请使用 >= 和 <= 组合代替 BETWEEN。
|
||
|
||
### Q3:SoqlBuilder 支持 JOIN 吗?
|
||
A:不支持。请使用关系查询(Relationship Queries)如 Account.Name。
|
||
|
||
### Q4:SoqlBuilder 支持 UNION 吗?
|
||
A:不支持。SOQL 无法合并两个不相关的结果集。
|
||
|
||
### Q5:SoqlBuilder 查询最多返回多少条记录?
|
||
A:最多返回 50000 条记录。
|
||
|
||
### Q6:SoqlBuilder 的 OFFSET 上限是多少?
|
||
A:OFFSET 上限为 2000,且必须与 LIMIT 一起使用。
|
||
|
||
### Q7:SalesforceDataTypeConverter 支持哪些时区?
|
||
A:支持所有 Java 时区。默认使用 UTC 时区,可以通过构造函数指定自定义时区。
|
||
|
||
### Q8:Salesforce ID 的 15 位和 18 位有什么区别?
|
||
A:15 位 ID 是不区分大小写的,18 位 ID 包含校验位,可以区分大小写。建议使用 18 位 ID。
|
||
|
||
### Q9:FileObjectType 推荐使用哪种文件对象?
|
||
A:强烈推荐使用 ContentDocument(现代文件对象),它支持更大的文件大小(2048 MB)和更好的功能。
|
||
|
||
### Q10:如何选择合适的异常类?
|
||
A:根据业务场景选择合适的异常类。例如,登录失败使用 SalesforceLoginException,文件上传失败使用 FileUploadException,操作失败使用 SalesforceOperationException。
|
||
|
||
## 总结
|
||
|
||
datai-salesforce-common 模块是整个 Salesforce 集成体系的基础设施层,提供了丰富的工具类、常量定义、数据转换和异常处理功能。该模块被其他所有 Salesforce 相关模块依赖,是整个体系的基础。
|
||
|
||
**核心优势**:
|
||
1. 统一的常量管理
|
||
2. 强大的 SOQL 查询构建器
|
||
3. 完善的数据类型转换
|
||
4. 丰富的异常体系
|
||
5. 统一的参数封装
|
||
6. 类型安全的枚举定义
|
||
|
||
**适用场景**:
|
||
- 所有与 Salesforce 集成的应用
|
||
- 需要 SOQL 查询构建的场景
|
||
- 需要数据类型转换的场景
|
||
- 需要统一异常处理的场景
|
||
- 需要参数封装的场景
|
||
- 需要文件上传的场景
|