Files
zt-dsc/docs/iWork用印流程集成开发文档.md
wuzongyong 42c01dc0a4 docs(iwork): 添加用印流程集成开发文档
- 新增完整的 iWork 用印流程集成开发文档
- 包含整体架构图和完整流程时序图
- 详细说明数据库设计和状态流转机制
- 提供 API 接口说明和请求参数定义
- 描述 MQ 消息机制和消息格式定义
- 编写业务模块接入指南和消费者实现示例
- 说明重试机制配置和手工重试接口
- 提供本地开发调试和常见问题解决方案
- 列出相关代码位置便于查阅和维护
2026-01-30 10:12:45 +08:00

515 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# iWork 用印流程集成开发文档
## 1. 概述
本文档描述了 ZT Cloud 平台与 iWork 系统的用印流程集成方案,包括流程发起、回调处理、消息通知及重试机制。
### 1.1 功能特性
- **流程发起**:支持用印专用流程和通用流程两种创建方式
- **回调处理**:接收 iWork 回调,自动通知业务模块
- **消息队列**:基于 RocketMQ 的异步消息通知机制
- **自动重试**:失败回调自动重试,支持配置重试次数和间隔
- **日志追踪**:完整记录流程创建和回调处理全生命周期
### 1.2 整体架构
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 业务系统 │────▶│ System 模块 │────▶│ iWork 系统 │
│ (调用方) │ │ (集成层) │ │ (OA 流程) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
▲ ▲ │
│ │ │
│ └───────────────────────┘
│ iWork 流程完成后回调
│ ┌─────────────────┐
│ │ RocketMQ │
│ │ (消息队列) │
└───────────────┴─────────────────┘
```
### 1.3 完整流程时序图
```
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│ 业务系统 │ │ System │ │ iWork │ │RocketMQ│ │业务消费者│
└───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘
│ │ │ │ │
│ 1.发起用印流程 │ │ │ │
│──────────────▶│ │ │ │
│ │ 2.创建流程 │ │ │
│ │──────────────▶│ │ │
│ │ 返回requestId│ │ │
│ │◀──────────────│ │ │
│ 返回结果 │ │ │ │
│◀──────────────│ │ │ │
│ │ │ │ │
│ │ │ 3.OA流程审批 │ │
│ │ │ (异步进行) │ │
│ │ │ │ │
│ │ 4.流程完成回调 │ │ │
│ │◀──────────────│ │ │
│ │ │ │ │
│ │ 5.发送MQ消息 │ │ │
│ │──────────────────────────────▶│ │
│ │ │ │ 6.投递消息 │
│ │ │ │──────────────▶│
│ │ │ │ │
│ │ │ │ 7.返回处理结果 │
│ │ │ │◀──────────────│
│ │ 8.接收结果 │ │ │
│ │◀──────────────────────────────│ │
│ │ │ │ │
│ │ 9.更新日志状态 │ │ │
│ │ (成功/重试) │ │ │
└───────────────┴───────────────┴───────────────┴───────────────┘
```
**流程说明**
1. **发起流程**:业务系统调用 System 模块的流程创建接口
2. **创建流程**System 模块调用 iWork API 创建 OA 流程,获取 `requestId`
3. **OA 审批**:流程在 iWork 系统中流转(审批、签章等),此过程异步进行
4. **iWork 回调**流程完成后iWork 系统主动回调 System 模块的回调接口
5. **MQ 通知**System 模块将回调数据通过 RocketMQ 发送给业务消费者
6. **业务处理**:业务消费者接收消息并处理(如保存签章文件、更新业务状态)
7. **返回结果**:业务消费者处理完成后,发送处理结果消息
8. **接收结果**System 模块接收处理结果
9. **状态更新**:根据结果更新日志状态,失败则触发重试机制
## 2. 数据库设计
### 2.1 流程日志表 (system_iwork_workflow_log)
| 字段名 | 类型 | 说明 |
|--------|------|------|
| id | BIGINT | 主键 |
| request_id | VARCHAR(128) | iWork 请求编号(唯一) |
| workflow_id | BIGINT | 流程模板 ID |
| business_code | VARCHAR(128) | 业务编码 |
| biz_callback_key | VARCHAR(255) | 业务回调标识MQ tag |
| raw_request | VARCHAR(2000) | 创建请求原文 |
| status | VARCHAR(32) | 流程状态 |
| callback_status | INTEGER | 回调处理状态 |
| retry_count | INTEGER | 已重试次数 |
| max_retry | INTEGER | 最大重试次数 |
| last_error_message | VARCHAR(512) | 最后错误信息 |
| raw_callback | VARCHAR(2000) | 回调原文 |
| last_callback_time | TIMESTAMP | 最近回调时间 |
| tenant_id | BIGINT | 租户编号 |
### 2.2 回调状态枚举 (callback_status)
| 值 | 状态 | 说明 |
|----|------|------|
| 0 | CREATE_PENDING | 创建中 |
| 1 | CREATE_SUCCESS | 创建成功 |
| 2 | CREATE_FAILED | 创建失败 |
| 3 | CALLBACK_PENDING | 回调待处理 |
| 4 | CALLBACK_SUCCESS | 回调处理成功 |
| 5 | CALLBACK_FAILED | 回调处理失败 |
| 6 | CALLBACK_RETRYING | 回调重试中 |
| 7 | CALLBACK_RETRY_FAILED | 回调重试失败 |
### 2.3 状态流转图
```
┌─────────────────────────────────────────────────────┐
│ 流程创建阶段 │
│ ┌──────────┐ 成功 ┌──────────┐ │
│ │ PENDING │ ─────────▶ │ SUCCESS │ │
│ │ (0) │ │ (1) │ │
│ └──────────┘ └──────────┘ │
│ │ │
│ │ 失败 │
│ ▼ │
│ ┌──────────┐ │
│ │ FAILED │ │
│ │ (2) │ │
│ └──────────┘ │
└─────────────────────────────────────────────────────┘
│ iWork 回调
┌─────────────────────────────────────────────────────┐
│ 回调处理阶段 │
│ ┌──────────┐ 成功 ┌──────────┐ │
│ │ CALLBACK │ ─────────▶ │ CALLBACK │ │
│ │ PENDING │ │ SUCCESS │ │
│ │ (3) │ │ (4) │ │
│ └──────────┘ └──────────┘ │
│ │ │
│ │ 失败 │
│ ▼ │
│ ┌──────────┐ 重试中 ┌──────────┐ │
│ │ CALLBACK │ ◀───────▶ │ CALLBACK │ │
│ │ FAILED │ │ RETRYING │ │
│ │ (5) │ │ (6) │ │
│ └──────────┘ └──────────┘ │
│ │ │
│ │ 重试次数耗尽 │
│ ▼ │
│ ┌──────────┐ │
│ │ RETRY │ │
│ │ FAILED(7)│ │
│ └──────────┘ │
└─────────────────────────────────────────────────────┘
```
## 3. API 接口说明
### 3.1 用印流程创建
**接口地址**`POST /admin-api/system/integration/iwork/workflow/create`
**请求参数**
```json
{
"operatorUserId": "1001",
"jbr": "1001",
"yybm": "2001",
"fb": "3001",
"sqsj": "2025-01-30",
"yyqx": "内部使用",
"yyfkUrl": "https://example.com/attachment.pdf",
"yysy": "合同盖章",
"xyywjUrl": "https://example.com/contract.pdf",
"yysx": "公章",
"ywxtdjbh": "DJ-2025-0001",
"bizCallbackKey": "seal-callback"
}
```
| 参数 | 必填 | 说明 |
|------|------|------|
| operatorUserId | 是 | 操作人 iWork 用户 ID |
| jbr | 是 | 用印申请人 |
| yybm | 是 | 用印部门 ID |
| fb | 是 | 用印单位(分部 ID |
| sqsj | 是 | 申请时间 (yyyy-MM-dd) |
| yyqx | 是 | 用印去向 |
| xyywjUrl | 是 | 用印材料附件 URL |
| yysx | 是 | 用印事项 |
| ywxtdjbh | 是 | 业务系统单据编号 |
| bizCallbackKey | 否 | 业务回调标识 |
| yyfkUrl | 否 | 用印依据附件 URL |
| yysy | 否 | 用印事由 |
### 3.2 通用流程创建
**接口地址**`POST /admin-api/system/integration/iwork/workflow/create-generic`
**请求参数**
```json
{
"operatorUserId": "1001",
"workflowId": 54,
"payload": {
"requestName": "用印-DJ-2025-0001",
"mainData": [
{"fieldName": "jbr", "fieldValue": "1001"},
{"fieldName": "yybm", "fieldValue": "2001"}
]
},
"ywxtdjbh": "DJ-2025-0001",
"bizCallbackKey": "seal-callback"
}
```
| 参数 | 必填 | 说明 |
|------|------|------|
| operatorUserId | 是 | 操作人 iWork 用户 ID |
| workflowId | 是 | 流程模板 ID |
| payload | 是 | 透传给 iWork 的业务参数 |
| ywxtdjbh | 否 | 业务编码 |
| bizCallbackKey | 否 | 业务回调标识 |
### 3.3 iWork 回调接口
**接口地址**`POST /admin-api/system/integration/iwork/callback/file`
**说明**:此接口供 iWork 系统回调,无需认证(@PermitAll, @TenantIgnore
**iWork 侧配置**:需要在 iWork 系统中配置回调地址,当流程完成时自动调用此接口。
**请求参数**
```json
{
"requestId": "3603649",
"businessCode": "DJ-2025-0001",
"fileUrl": "https://iwork.example.com/signed-file.pdf",
"fileName": "已签章合同.pdf",
"status": "COMPLETED"
}
```
| 参数 | 必填 | 说明 |
|------|------|------|
| requestId | 是 | iWork 请求编号(与创建流程时返回的一致) |
| businessCode | 是 | 业务编码(与创建流程时传入的 ywxtdjbh 一致) |
| fileUrl | 是 | 签章后文件 URL |
| fileName | 否 | 文件名称 |
| status | 否 | 业务状态 |
**回调处理逻辑**
1. 根据 `requestId` 查询流程创建日志,获取 `bizCallbackKey`
2. 更新日志状态为 `CALLBACK_PENDING`
3. 发送 MQ 消息通知业务模块(仅当 `bizCallbackKey` 存在时)
4. 返回处理结果
## 4. MQ 消息机制
### 4.1 消息流程图
```
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ iWork 回调 │───▶│ System 模块 │───▶│ RocketMQ │───▶│ 业务消费者 │
│ │ │ (Producer) │ │ │ │ │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 更新日志状态 │◀───│ System 模块 │◀───│ RocketMQ │◀───│ 返回处理结果 │
│ │ │ (Listener) │ │ │ │ │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
```
### 4.2 Topic 定义
| Topic | 说明 |
|-------|------|
| SYSTEM_IWORK_BIZ_CALLBACK | 回调通知消息System → 业务模块) |
| SYSTEM_IWORK_BIZ_CALLBACK_RESULT | 处理结果消息(业务模块 → System |
### 4.3 回调通知消息 (IWorkBizCallbackMessage)
```java
{
"requestId": "3603649",
"bizCallbackKey": "seal-callback",
"payload": { /* 回调原始数据 */ },
"attempt": 0,
"maxAttempts": 3
}
```
**Tag 规则**:消息 tag = `bizCallbackKey`,业务模块按 tag 订阅
### 4.4 处理结果消息 (IWorkBizCallbackResultMessage)
```java
{
"requestId": "3603649",
"bizCallbackKey": "seal-callback",
"success": true,
"errorMessage": null,
"attempt": 0,
"maxAttempts": 3,
"payload": { /* 原始数据,用于重试 */ }
}
```
## 5. 业务模块接入指南
### 5.1 添加依赖
```xml
<dependency>
<groupId>com.zt.plat</groupId>
<artifactId>zt-module-system-api</artifactId>
</dependency>
```
### 5.2 实现消费者
```java
@Slf4j
@Component
@RequiredArgsConstructor
@RocketMQMessageListener(
topic = IWorkBizCallbackMessage.TOPIC,
consumerGroup = IWorkBizCallbackMessage.TOPIC + "_YOUR_BIZ_KEY",
selectorExpression = "your-biz-callback-key" // 与 bizCallbackKey 一致
)
public class YourBizCallbackConsumer implements RocketMQListener<IWorkBizCallbackMessage> {
private final RocketMQTemplate rocketMQTemplate;
@Override
public void onMessage(IWorkBizCallbackMessage message) {
log.info("收到 iWork 回调: requestId={}", message.getRequestId());
IWorkBizCallbackResultMessage result;
try {
// 处理业务逻辑
processCallback(message);
result = IWorkBizCallbackResultMessage.builder()
.requestId(message.getRequestId())
.bizCallbackKey(message.getBizCallbackKey())
.success(true)
.attempt(message.getAttempt())
.maxAttempts(message.getMaxAttempts())
.payload(message.getPayload())
.build();
} catch (Exception e) {
log.error("处理回调失败", e);
result = IWorkBizCallbackResultMessage.builder()
.requestId(message.getRequestId())
.bizCallbackKey(message.getBizCallbackKey())
.success(false)
.errorMessage(e.getMessage())
.attempt(message.getAttempt())
.maxAttempts(message.getMaxAttempts())
.payload(message.getPayload())
.build();
}
// 发送处理结果
rocketMQTemplate.syncSend(IWorkBizCallbackResultMessage.TOPIC, result);
}
private void processCallback(IWorkBizCallbackMessage message) {
// 业务处理逻辑
// 1. 解析 payload 获取回调数据
// 2. 更新业务状态
// 3. 保存签章文件等
}
}
```
### 5.3 关键配置项
| 配置项 | 说明 |
|--------|------|
| consumerGroup | 消费者组,建议格式:`TOPIC + "_" + bizCallbackKey` |
| selectorExpression | Tag 过滤,必须与发起流程时的 `bizCallbackKey` 一致 |
### 5.4 注意事项
1. **bizCallbackKey 唯一性**:每个业务场景使用独立的 bizCallbackKey
2. **幂等处理**:消费者需实现幂等,同一 requestId 可能重复投递
3. **必须返回结果**:处理完成后必须发送 `IWorkBizCallbackResultMessage`
4. **错误信息**:失败时填写 errorMessage便于问题排查
## 6. 重试机制
### 6.1 重试流程
```
业务处理失败 → 返回 success=false → System Listener 接收
检查 attempt < maxAttempts?
↓ ↓
是 否
↓ ↓
延迟后重新投递 标记最终失败
```
### 6.2 配置参数
```yaml
iwork:
callback:
retry:
max-attempts: 3 # 最大重试次数
delay-seconds: 5 # 重试间隔(秒)
```
### 6.3 手工重试
**接口地址**`POST /admin-api/system/integration/iwork/log/retry`
```json
{
"requestId": "3603649"
}
```
## 7. 日志查询
### 7.1 分页查询接口
**接口地址**`POST /admin-api/system/integration/iwork/log/page`
**请求参数**
```json
{
"requestId": "3603649",
"businessCode": "DJ-2025-0001",
"bizCallbackKey": "seal-callback",
"status": 4,
"pageNo": 1,
"pageSize": 10
}
```
## 8. 本地开发调试
### 8.1 隔离测试环境
为避免与测试环境消息冲突,本地开发时需修改:
1. **Listener 消费者组**:添加本地标识后缀
```java
consumerGroup = IWorkBizCallbackResultMessage.TOPIC + "_CONSUMER_local"
```
2. **Listener Tag 过滤**:使用本地专用 tag
```java
selectorExpression = "local_test"
```
3. **业务消费者**:同样使用本地专用 bizCallbackKey
```java
selectorExpression = "your-biz-key_local"
```
4. **数据库记录**:将 `biz_callback_key` 设为本地专用值
### 8.2 调试建议
- 使用独立的 `bizCallbackKey` 避免消息串扰
- 检查 RocketMQ 控制台确认消息投递情况
- 关注日志中的 `requestId` 进行链路追踪
## 9. 常见问题
### Q1: 业务消费者收不到消息?
检查项:
- `selectorExpression` 是否与 `bizCallbackKey` 一致
- 消费者组名是否正确
- RocketMQ 连接是否正常
### Q2: 收到重复消息?
可能原因:
- 多个环境的 Listener 都在消费同一 topic
- 解决:使用独立的消费者组和 tag 过滤
### Q3: 重试不生效?
检查项:
- 是否正确返回了 `IWorkBizCallbackResultMessage`
- `success` 字段是否为 `false`
- 配置的 `max-attempts` 是否大于当前 `attempt`
## 10. 相关代码位置
| 组件 | 路径 |
|------|------|
| Controller | `zt-module-system-server/.../controller/admin/integration/iwork/IWorkIntegrationController.java` |
| Service | `zt-module-system-server/.../service/integration/iwork/impl/IWorkIntegrationServiceImpl.java` |
| 日志 Service | `zt-module-system-server/.../service/integration/iwork/impl/IWorkWorkflowLogServiceImpl.java` |
| MQ Producer | `zt-module-system-server/.../mq/iwork/IWorkBizCallbackProducer.java` |
| MQ Listener | `zt-module-system-server/.../mq/iwork/IWorkBizCallbackListener.java` |
| 消息定义 | `zt-module-system-api/.../mq/iwork/IWorkBizCallbackMessage.java` |
| 配置类 | `zt-module-system-server/.../framework/integration/iwork/config/IWorkProperties.java` |