# integration 集成模块

基于 Spring MVC 5 + Kingdee EAS/BOS 平台的第三方系统集成框架，提供统一的 OpenAPI 认证、调用日志、接口自动注册等通用能力，支持钉钉单点登录、北森考勤同步、风控数据同步等业务场景。

## 目录结构

```
com.kingdee.eas.custom.integration
├── base/           # 公共基础模块（注解、拦截器、过滤器、异常、工具类、配置）
├── apimgt/         # API 管理与网关（认证拦截、接口注册同步、调用日志）
├── dingtalk/       # 钉钉单点登录模块
├── beisen/         # 北森考勤数据同步模块
├── riskcontrol/    # 风控平台数据同步模块
├── feishu.zip      # 飞书模块（待迁移）
└── scrm/           # SCRM 模块（待开发）
```

## 基础模块 (base)

提供所有业务模块共享的通用组件。

| 包 | 说明 | 关键类 |
|---|---|---|
| `controller/` | Controller 基类 | `AbstractAuthController`（OAuth认证）、`AbstractIntegrationController`（业务通用） |
| `advice/` | 全局异常处理 | `GlobalExceptionHandler`（IntegrationException → JSON） |
| `filter/` | Servlet Filter | `ContentCachingFilter`（请求/响应体缓存） |
| `annotation/` | 通用注解 | `@SkipAuth`、`@SkipCallLog`、`@ApiDoc` |
| `dto/` | 统一响应体 | `ApiResult<T>`（code/message/data/timestamp） |
| `exception/` | 异常体系 | `IntegrationException`、`ErrorCode`、`CommonErrorCodes` |
| `service/` | 通用服务 | `IntegrationConfigService`（配置热加载）、`OAuthService`（OAuth策略） |
| `util/` | 工具类 | `JsonUtils`、`AppSecretDecryptor`（AES-GCM）、`SpringContextHolder` |
| `config/` | 配置定义 | `AppConfig`、`OAuthConfig`、`OpenApiConfig` |

### Controller 基类层级

```
AbstractAuthController              AbstractIntegrationController
(认证流程：doAuth/doCallback)        (通用能力：响应封装/参数校验/分页)
        |                                   |
DingtalkAuthController          BeisenAttendanceController
                                RiskControlSyncController
```

## API 管理与网关 (apimgt)

### 认证流程

`OpenApiAuthInterceptor` 拦截所有 integration 包下的请求，基于 appSecret 进行身份认证：

1. 跳过非 integration 包的 Controller
2. 检查 `@SkipAuth` → 跳过认证，标记 anonymous
3. 检查 `@SkipCallLog` → 跳过调用日志
4. 查询 `ApiRegistryBill` 匹配接口
5. 接口 `isAuthRequired = false` → 免授权放行
6. 读取 `X-Api-Secret` 请求头 → 校验密钥有效性
7. 认证通过 → 写入 `OpenApiRequestContext`

### 接口自动注册

`ApiRegistrySyncRunner` 在 Spring 容器启动时扫描所有 Controller 方法，同步写入 `ApiRegistryBill` 表：

- 扫描路径：`com.kingdee.eas.custom.integration`
- 已存在接口（按 number 字段）跳过，仅新增
- 支持 `ApiRegistryBillListHandler.rescanApiAction` 手动重新扫描
- 注解映射：
  - `@SkipAuth` → isAuthRequired
  - `@SkipCallLog` → isSkipCallLog
  - `@ApiDoc.name` → name
  - `@ApiDoc.desc` → apiDesc

### 调用日志

每次 OpenAPI 调用自动记录到 `ApiCallLog` 实体：

- **请求入参**：`ContentCachingRequestWrapper` 缓存 POST body，GET 用 queryString
- **响应体**：`ContentCachingResponseWrapper` 缓存，鉴权失败兜底错误 JSON
- **调用方**：认证通过为平台编码，免授权为 public，匿名/跳过认证为 anonymous
- **跳过日志**：非 integration 包 或 `@SkipCallLog` 标记的接口不记录

## 业务模块

### dingtalk — 钉钉单点登录

| 组件 | 说明 |
|---|---|
| `DingtalkAuthController` | 继承 `AbstractAuthController`，`@SkipAuth` + `@SkipCallLog` |
| 认证入口 | `GET /auth/dingtalk?state=xxx` |
| 回调地址 | `GET /auth/callback/dingtalk/{appType}` |

### beisen — 北森考勤同步

| 组件 | 说明 |
|---|---|
| `BeisenAttendanceController` | 继承 `AbstractIntegrationController` |
| `POST /beisen/attendance/daily` | 日报批量写入 |
| `POST /beisen/attendance/monthly` | 月报批量写入 |
| `AttendanceService` | 考勤写入服务 |
| `AttendanceValidator` | 参数校验器（批量场景单条失败不影响其他） |
| `BeisenException` | 继承 IntegrationException 的模块专用异常 |

### riskcontrol — 风控数据同步

| 组件 | 说明 |
|---|---|
| `RiskControlSyncController` | 继承 `AbstractIntegrationController` |
| `POST /risk-control/complaint-donation-deduct/sync` | 投诉捐赠扣除数据同步 |

## 注解一览

| 注解 | 作用域 | 说明 |
|---|---|---|
| `@SkipAuth` | 类/方法 | 跳过密钥认证（OAuth 单点接口） |
| `@SkipCallLog` | 类/方法 | 跳过调用日志记录（浏览器跳转类接口） |
| `@ApiDoc` | 方法 | 接口中文名称 + 描述，同步到 ApiRegistryBill |

## 统一响应格式

所有业务接口使用 `ApiResult<T>` 或继承 `AbstractIntegrationController` 的 `success()`/`fail()` 方法：

```json
{
  "code": 200,
  "message": "success",
  "data": {},
  "timestamp": 1783565457512
}
```

状态码常量：`CODE_SUCCESS`(200)、`CODE_BAD_REQUEST`(400)、`CODE_UNAUTHORIZED`(401)、`CODE_FORBIDDEN`(403)、`CODE_ERROR`(500)。

## 配置

- 开发版 Spring 配置：`web/webRoot/WEB-INF/properties/applicationContext.xml`
- 部署版 Spring 配置：`runtime/server/deploy/easweb.ear/qy.war/WEB-INF/properties/applicationContext.xml`
- 业务配置：`integration-config.json`（支持热加载）
- 敏感信息加密：`AppSecretDecryptor`（AES-256-GCM），密钥通过环境变量 `OAUTH_ENCRYPT_KEY` 传入

## 新增模块开发指引

1. 在 `com.kingdee.eas.custom.integration` 下创建新包
2. Controller 继承 `AbstractIntegrationController`
3. 方法上添加 `@ApiDoc(name = "...", desc = "...")` 提供文档
4. 需要密钥验证的接口注册 appSecret（`OpenPlatformAuthBill`）
5. OAuth 单点接口标记 `@SkipAuth` + `@SkipCallLog`
6. 异常统一使用 `IntegrationException` 或其子类
7. 启动后接口自动注册到 `ApiRegistryBill`
