Files
zt-dsc/docs/iWork集成说明.md
2025-11-28 18:12:00 +08:00

14 KiB
Raw Permalink Blame History

iWork 统一集成使用说明

本文档介绍如何在 System 模块中使用项目已实现的统一 iWork 流程发起能力controller + service + properties。内容包含配置项、调用方式内部 Java 调用 & 外部 HTTP 调用)、请求/响应示例、错误处理、缓存与 Token 生命周期、典型问题与排查步骤。


概览

项目在 system 模块下实现了一套对外统一的 iWork 集成能力:

  • 提供管理端接口REST路径前缀/system/integration/iwork
  • 提供 Service 层 IWorkIntegrationService,供其它模块以 Spring Bean 注入方式直接调用。
  • 使用 IWorkProperties 绑定 application.ymliwork 的配置项。
  • Token / 会话采用本地 Caffeine 缓存缓存(按 appId + operatorUserId 缓存 session并在到期前按配置提前刷新。
  • 使用统一配置的 appId、公钥以及默认流程编号无需再维护多套凭证。

配置YAML

application.yml(或 profile添加或修改如下项示例摘自 zt-server/src/main/resources/application.yaml

iwork:
  base-url: https://iwork.example.com
  app-id: my-iwork-app            # 固定使用的 iWork 应用编号
  client-public-key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...   # 与 iWork 约定的客户端公钥Base64
  user-id: system                 # 默认操作用户(当调用未指定 operatorUserId 时使用)
  org:
    token-seed: 5936562a-d47c-4a29-9b74-b310e6c971b7
    paths:
      subcompany-page: /api/hrm/resful/getHrmsubcompanyWithPage
      department-page: /api/hrm/resful/getHrmdepartmentWithPage
      job-title-page: /api/hrm/resful/getJobtitleInfoWithPage
      user-page: /api/hrm/resful/getHrmUserInfoWithPage
      sync-subcompany: /api/hrm/resful/synSubcompany
      sync-department: /api/hrm/resful/synDepartment
      sync-job-title: /api/hrm/resful/synJobtitle
      sync-user: /api/hrm/resful/synHrmresource
  workflow-id: 54                 # 当调用方未传 workflowId 时使用的默认流程编号
  paths:
    register: /api/ec/dev/auth/regist
    apply-token: /api/ec/dev/auth/applytoken
    user-info: /api/workflow/paService/getUserInfo
    create-workflow: /api/workflow/paService/doCreateRequest
    void-workflow: /api/workflow/paService/doCancelRequest
  token:
    ttl-seconds: 3600               # token 有效期(秒)
    refresh-ahead-seconds: 60       # 在到期前多少秒认为需要刷新
  client:
    connect-timeout: 5s
    response-timeout: 30s

说明:

  • base-url 为 iWork 网关的基础地址,不能留空。
  • app-idclient-public-key 共同构成注册/申请 token 所需的凭据信息,由配置统一提供,不再支持多套切换。
  • workflow-id 提供全局默认流程编号,单次调用也可通过 workflowId 覆盖。
  • 请求头键名固定为 app-idclient-public-keysecrettokentimeuser-id,无需在配置中重复声明。
  • org.* 配置负责 iWork 人力组织 REST 代理:token-seed 为与 iWork 约定的标识,系统会自动将其与毫秒时间戳拼接并计算 MD5 生成 key,无需额外传递 token。

典型调用路径Controller

Controller 暴露的 REST 接口:

  • POST /system/integration/iwork/user/resolve

    • 说明:根据外部识别信息查找 iWork 的用户编号userId
    • 请求:见下方 Resolve User 示例。
  • POST /system/integration/iwork/workflow/create

    • 说明:在 iWork 中发起流程。
    • 请求:见下方 Create Workflow 示例。
  • POST /system/integration/iwork/workflow/void

    • 说明:作废/干预流程。
    • 请求:见下方 Void Workflow 示例。

这些接口的响应均使用项目的 CommonResult 封装,实际返回的业务对象在 data 字段。


人力组织 REST 接口key + ts

为对接 PDF 所述的人力组织 RESTFUL 接口Controller 额外暴露了以下代理端点,用于通过 key + ts 生成的 token 与 iWork 交互:

  • POST /system/integration/iwork/hr/subcompany/page —— 请求体传入 paramsMap对应 getHrmsubcompanyWithPage
  • POST /system/integration/iwork/hr/department/page —— 对应 getHrmdepartmentWithPage
  • POST /system/integration/iwork/hr/job-title/page —— 对应 getJobtitleInfoWithPage
  • POST /system/integration/iwork/hr/user/page —— 对应 getHrmUserInfoWithPage
  • POST /system/integration/iwork/hr/subcompany/sync —— 请求体传入 dataList<Map>),对应 synSubcompany
  • POST /system/integration/iwork/hr/department/sync —— 对应 synDepartment
  • POST /system/integration/iwork/hr/job-title/sync —— 对应 synJobtitle
  • POST /system/integration/iwork/hr/user/sync —— 对应 synHrmresource

所有请求均自动封装为 application/x-www-form-urlencoded,并把 token 字段设置为 {"key":"<md5>","ts":"<timestamp>"},无需调用方重复计算。


请求 VO 说明(重要字段)

  • IWorkBaseReqVO公用字段

    • appId (String):为兼容历史接口保留,系统始终使用配置项 iwork.app-id
    • operatorUserId (String):在 iWork 内部代表操作人的用户编号(可为空,框架会使用 properties.userId)。
    • forceRefreshToken (Boolean):是否强制刷新 token例如遇到 token 错误时强制刷新)。
  • IWorkUserInfoReqVO用于解析用户

    • identifierKey (String):外部标识 key必须例如 "loginid")。
    • identifierValue (String):外部标识值(必须,例如用户名)。
    • payload (Map):额外的请求载荷,会与 identifier 合并后发送到 iWork。
    • queryParams (Map):如果需要通过查询参数传递额外信息,可使用此字段。
  • IWorkUserInfoRespVO解析用户响应

    • userId (String):从 iWork 响应中解析出的用户编号(如果能解析到)。
    • success / message:调用成功标志与提示信息。
  • IWorkWorkflowCreateReqVO统一用印流程发起

    • workflowId (String):流程模板 ID必填不再回退到配置。
    • jbr用印申请人iWork 人员 ID必填
    • yybm:用印部门 ID必填
    • fb:用印单位/分部 ID必填
    • sqsj申请时间yyyy-MM-dd必填
    • yyqx:用印去向(必填)。
    • yyfkUrl:用印依据附件 URL可选
    • yysy:用印事由或摘要(可选)。
    • xyywjUrl:用印材料附件 URL必填
    • yysx:用印事项(必填)。
    • ywxtdjbh:业务系统单据编号(必填,同时用于生成流程标题“用印-{ywxtdjbh}”)。
    • 额外字段不再支持Service 会根据以上字段自动补齐固定流程类型 (lclx=2979600781334966993) 与签署动作 (qsdz=CORPORATE)。
  • IWorkWorkflowVoidReqVO作废

    • requestId (String):流程请求编号(必填)。
    • reasonextraParamsformExtras 等用于传递作废原因或额外字段。
  • IWorkFormFieldVO表单字段

    • fieldName (String):字段名(必填),与 iWork 表单字段 key 对应。
    • fieldValue (String):字段值(必填)。
  • IWorkDetailRecordVO明细记录

    • recordOrder (Integer):可选记录序号(从 0 开始),用于 iWork 明细排序。
    • fields (List<IWorkFormFieldVO>):该明细行下的字段集合(必填)。
  • IWorkDetailTableVO明细表

    • tableDBName (String)iWork 明细表表名(必填,如 formtable_main_26_dt1)。
    • records (List<IWorkDetailRecordVO>):明细记录集合(必填)。

Java内部调用示例

项目同时提供 IWorkIntegrationService Bean可直接注入并调用

import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkOperationRespVO;
import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkWorkflowCreateReqVO;
import com.zt.plat.module.system.service.integration.iwork.IWorkIntegrationService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@RequiredArgsConstructor
@Component
public class MyService {
  private final IWorkIntegrationService iworkService;

  public void startSealFlow() {
    IWorkWorkflowCreateReqVO req = new IWorkWorkflowCreateReqVO();
    req.setWorkflowId("54");
    req.setJbr("1001");
    req.setYybm("2001");
    req.setFb("3001");
    req.setSqsj("2025-01-01");
    req.setYyqx("对外邮寄");
    req.setYyfkUrl("https://files.example.com/evidence.pdf");
    req.setYysy("与客户合同用印");
    req.setXyywjUrl("https://files.example.com/contract.pdf");
    req.setYysx("合同用印");
    req.setYwxtdjbh("DJ-2025-0001");

    IWorkOperationRespVO resp = iworkService.createWorkflow(req);
    if (resp.isSuccess()) {
      // 处理成功,例如记录 requestId
    }
  }
}

说明:

  • 若需使用特定凭证,可设置 req.setAppId("my-iwork-app")
  • 若需覆盖默认流程模板,可调用 req.setWorkflowId(123L) 指定。
  • 若希望以特定 iWork 操作人发起,可设置 req.setOperatorUserId("1001")

HTTP外部调用示例cURL

  1. Resolve user
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "appId":"my-iwork-app",
    "identifierKey":"loginid",
    "identifierValue":"zhangsan"
  }' \
  https://your-zt-server/admin-api/system/integration/iwork/user/resolve

成功返回示例CommonResult 包装):

{
  "code": 0,
  "msg": "success",
  "data": {
    "userId": "1001",
    "success": true,
    "payload": { ... },
    "rawBody": "{...}"
  }
}
  1. Create workflow
curl -X POST -H "Content-Type: application/json" -d '{
  "workflowId":"54",
  "jbr":"1001",
  "yybm":"2001",
  "fb":"3001",
  "sqsj":"2025-01-01",
  "yyqx":"对外邮寄",
  "yyfkUrl":"https://files.example.com/evidence.pdf",
  "yysy":"与客户合同用印",
  "xyywjUrl":"https://files.example.com/contract.pdf",
  "yysx":"合同用印",
  "ywxtdjbh":"DJ-2025-0001"
}' https://your-zt-server/admin-api/system/integration/iwork/workflow/create

说明:外部仍以 JSON 请求调用本服务,系统在向 iWork 转发时会自动将负载转换为 application/x-www-form-urlencoded 表单(含 requestNameworkflowIdmainData 等字段)。

  1. Void workflow
curl -X POST -H "Content-Type: application/json" -d '{
  "requestId":"REQ-001",
  "reason":"作废原因",
  "appId":"my-iwork-app"
}' https://your-zt-server/admin-api/system/integration/iwork/workflow/void

核心逻辑与细节

  1. 基础参数解析

系统始终使用 application.yml 中配置的 app-idclient-public-key 与 iWork 通信。 请求体中的 appId 字段仅为兼容历史调用而保留,框架内部不会使用该值做切换。

  1. Workflow 模板解析

调用时优先使用请求体中的 workflowId。 若未显式传入,则回退到全局 iwork.workflow-id,若仍为空则抛出 IWORK_WORKFLOW_ID_MISSING

  1. 注册 + RSA + Token

    • 在首次或 token 过期时,会按以下步骤获取 session

      1. 向 iWork 的 register 接口发起请求Headers 包含 appId 与 clientPublicKey
      2. 从注册响应中获取 secretspk(服务端公钥),使用本地的 client 公钥做 RSA 加密(spk 用于加密),得到加密后的 secret 与 encryptedUserId。
      3. 使用注册返回的密钥申请 tokenapply-tokentoken 会被按 ttl-seconds 缓存。
    • IWorkIntegrationServiceImpl 中维护一个 Caffeine sessionCache,缓存 key 为 appId::operatorUserId

    • 当 token 接近到期(refresh-ahead-seconds)时会在下一次请求触发刷新。

  2. 请求构造

    • 用户解析、作废等场景继续以 application/json 调用 iWork。
    • 用印流程发起在转发至 iWork 时改为 application/x-www-form-urlencoded 表单,请求正文包含 requestNameworkflowId 及字符串化后的 mainData,与 iWork 网关当前要求保持一致。
      • 认证 HeaderIWorkProperties.Headers 中的常量控制,固定键名为 app-idclient-public-keysecrettokentimeuser-id
  3. 响应解析

    • 实现里对响应成功的判定比较宽松:检查 codestatussuccesserrno 等字段(支持布尔、字符串 0/1/success以判断是否成功并解析常见的 message 字段 msg|message|errmsg

常见错误与排查

  • baseUrl 未配置IWORK_BASE_URL_MISSING

    • 处理:确保 iwork.base-url 配置正确。
  • 配置缺失IWORK_CONFIGURATION_INVALID

    • 场景:app-idclient-public-keyuser-id 等关键字段没有配置或只包含空白字符。
    • 处理:在 application.yml 或配置中心中补充对应字段,确保它们与 iWork 侧一致。
  • 用印必填字段缺失IWORK_SEAL_REQUIRED_FIELD_MISSING

    • 场景:workflowIdjbryybmfbsqsjyyqxxyywjUrlyysxywxtdjbh 等任一字段为空。
    • 处理:根据返回的字段名称补齐相应值后重新发起。
  • RSA 加密/注册/申请 token 失败IWORK_REGISTER_FAILED / IWORK_APPLY_TOKEN_FAILED / IWORK_REMOTE_REQUEST_FAILED

    • 处理:通过日志查看 iWork 返回的 HTTP 状态码与 body确认请求头/路径/参数是否匹配 iWork 网关要求。
  • 用户解析失败

    • 确认 identifierKey/identifierValue 是否正确填写并与 iWork 的查询接口契合;可启用 forceRefreshToken 触发 session 刷新以排除 token 过期造成的问题。

进阶主题

  • 并发与缓存

    • sessionCache 最大条目数为 256若高并发/多凭证/多操作人场景,可能需调整容量。
  • 超时与 HTTP 客户端

    • IWorkProperties.client.response-timeout 可用于设定响应超时;连接超时通常由 Reactor Netty 全局配置控制。
  • 单元测试

    • 项目中已有 MockWebServer 测试样例(IWorkIntegrationServiceImplTest),可参考测试用例模拟 iWork 的注册、申请 token、用户查询、创建/作废流程的交互。

小结与建议

  • 在配置中补齐 iwork.app-idiwork.client-public-keyiwork.user-idiwork.workflow-id 等关键字段。
  • 优先在本地通过 IWorkIntegrationService Java API 调试,成功后再通过 Controller 的 REST 接口对外暴露。
  • 若遇到请求失败,查看应用日志([iWork] 前缀的日志)与 iWork 网关返回 body定位是注册、申请 token还是业务接口user-info/create/void失败。

文档已生成并保存到:docs/iWork集成说明.md