lfx 805f9053cd test: make MJS signature test location independent 6 днів тому
..
.mvn 56d0bf3d58 feat: add mjava-minglei project 2 тижнів тому
src 805f9053cd test: make MJS signature test location independent 6 днів тому
.gitignore 56d0bf3d58 feat: add mjava-minglei project 2 тижнів тому
ERP-YIDA-PUSH-API.md dcf2109939 明磊 1 тиждень тому
README.md dcf2109939 明磊 1 тиждень тому
pom.xml 5552e74cd7 明磊 1 тиждень тому

README.md

mjava-minglei

明磊业务集成服务。工程基于 Spring Boot 构建,通过统一的 malk:mjava 客户端对接钉钉和宜搭,同时提供明磊内部外部接口的转发能力。

1. 技术栈

技术 版本或用途
Java JDK 8
Spring Boot 2.7.18
Spring MVC REST Controller、参数绑定和异常处理
Spring Validation @Valid@NotBlank@NotEmpty 等请求校验
Maven 项目构建和依赖管理
com.malk:mjava 统一的钉钉、宜搭客户端和数据模型,当前版本 0.0.3
Jackson / Fastjson JSON 请求绑定、序列化和宜搭字段数据组装
RestTemplate 调用明磊外部 HTTP 接口
Logback + SLF4J 控制台、应用文件和错误文件日志
JUnit 5 + Mockito 单元测试和客户端调用测试

2. 工程架构

工程采用典型的 Controller - Service - Impl 分层结构:

MjavaMingleiApplication
        |
        v
Controller 层       接收 HTTP 请求、校验参数、返回 HTTP 响应
        |
        v
Service 接口层      定义业务能力和模块边界
        |
        v
ServiceImpl 层      编排宜搭、钉钉或外部 T100 调用
        |
        +--> malk YDClient / DDClient
        +--> DingTalk Open Platform
        +--> 明磊外部 T100 HTTP 接口

2.1 目录职责

src/main/java/com/malk/minglei
├── MjavaMingleiApplication.java       Spring Boot 启动类
├── config                             Bean、配置属性、HTTP 日志过滤器
├── controller                         REST 接口和局部异常处理
├── dto                                请求模型和统一响应模型
└── service
    ├── *.java                          业务接口
    └── impl                            业务实现和外部系统调用

src/main/resources
├── application.yml                    服务、钉钉、宜搭、外部接口配置
└── logback-spring.xml                 日志输出和滚动策略

src/test/java                           单元测试和集成上下文测试

2.2 配置和客户端装配

MjavaYidaConfiguration 注册两套独立的宜搭客户端:

  • coordinationOfficeYidaClient:明磊锂能协调办公应用。
  • masterDataYidaClient:明磊锂能应用主数据。

两套客户端使用各自的 appTypesystemToken,业务实现通过 @Qualifier 选择,避免多个 YDClient Bean 注入时产生歧义。钉钉客户端由 malk 包提供,宜搭客户端内部通过 YDClientImpl 调用表单和流程接口。

3. 业务模块

3.1 宜搭统一流程发起

相关类:YidaProcessControllerYidaProcessServiceYidaProcessServiceImplYidaProcessHandlerBomYidaProcessHandler

统一入口根据请求体的 type 分发处理器。type 的业务含义是目标宜搭表单的 formUuid,不是自定义的业务名称。例如 BOM 表单使用:

FORM-04001902BF9C40E6859102569FE139179LWH

分发前会去除首尾空格并转为大写匹配。新增表单时,应新增一个 YidaProcessHandler 实现类,并让 getType() 返回该表单的 formUuid;表单 ID、流程编码和应用凭证由实现类或配置管理,不由调用方传入。

处理流程如下:

  1. Controller 使用 @Valid 校验请求体。
  2. YidaProcessServiceImpl 根据规范化后的表单 ID 查找处理器。
  3. 具体处理器组装 YidaOperationParam
  4. 通过对应应用的 YDClient.operateData(..., FORM_OPERATION.start) 发起宜搭流程。
  5. Controller 返回宜搭流程实例 ID。

3.2 明磊主数据表单查询

相关类:MingleiDocumentServiceMingleiDocumentServiceImplYidaProcessController

主数据查询固定使用主数据应用客户端和目标表单 ID。支持两种查询方式:

  • 分页查询:返回宜搭查询结果中的 recordstotalCountpageNumber
  • 精准查询:条件优先级为 dept_id > user_id > dept_name。传入 user_id 时,先调用钉钉通讯录接口取得员工所属部门,再按部门 ID 查询。查询成功后仅提取一级至四级部门主管和部门分管领导字段对应的钉钉 userId

3.3 部门成员查询

MingleiDocumentServiceImpl.listDepartmentUserIds 先取得钉钉访问令牌,再按 type 决定查询范围:0 获取指定部门及所有子部门,1 仅获取指定部门;随后逐个读取部门成员并按首次出现顺序去重,返回用户 ID 列表。

3.4 明磊外部 T100 接口转发

相关类:MingleiPortControllerMingleiPortServiceMingleiPortServiceImpl

该模块是本服务提供的本地触发入口,收到精简的 headdetail 后,由服务端补齐固定的外层协议结构,再通过 RestTemplate 调用明磊外部接口。连接超时为 10 秒,读取超时为 30 秒,目标 URL 和接入密钥通过配置注入。

4. REST 接口

4.1 宜搭流程发起

POST /api/yida/process-instances
Content-Type: application/json

请求示例:

{
  "type": "FORM-04001902BF9C40E6859102569FE139179LWH",
  "userId": "dingTalkUserId",
  "dataTitle": "流程标题",
  "fields": {
    "textField_xxx": "字段值"
  }
}

userId 也可使用请求别名 originatorUserIdfields 的键必须是目标宜搭表单真实存在的字段 ID。成功返回 HTTP 201 Created

{
  "code": 200,
  "isSuccess": true,
  "result": {
    "processInstanceId": "宜搭流程实例 ID"
  }
}

该接口使用统一的 ApiResponse 包装格式,流程实例 ID 位于 result.processInstanceId

4.2 分页查询主数据单据

GET /api/yida/minglei/forms/instances?page=1&size=20

page 从 1 开始,size 范围为 1 至 100。成功响应为宜搭查询结果的服务端整理结构:

{
  "records": [],
  "totalCount": 0,
  "pageNumber": 1
}

4.3 精准查询主数据单据

POST /api/yida/minglei/forms/instances/query
Content-Type: application/json

请求示例:

{
  "dept_id": "123456",
  "user_id": "dingTalkUserId",
  "dept_name": "明磊锂能技术部"
}

返回示例:

{
  "employeeField_mszdqrl8": "一级部门主管 userId",
  "employeeField_mszdqrl9": "二级部门主管 userId",
  "employeeField_mszdqrla": "三级部门主管 userId",
  "employeeField_mszdqrlb": "四级部门主管 userId",
  "employeeField_mszdqrl3": "部门分管领导 userId"
}

4.4 查询部门及子部门全部成员

POST /api/yida/minglei/departments/users
Content-Type: application/json

请求体:

{
  "dept_Id": "123456",
  "type": 0
}

type 为必填字段:0 表示穿透查询子部门,1 表示仅查询指定部门。

成功响应统一为 codeisSuccessresult 三层结构:

{
  "code": 200,
  "isSuccess": true,
  "result": [
    "449856319",
    "715357119"
  ]
}

4.5 转发供应商价格审批接口

POST /api/minglei/ports/supplier-price-approvals
Content-Type: application/json

请求体只需要提供协议中的 headdetail

{
  "head": {
    "pmdidocno": "CH3",
    "pmdi001": "N",
    "pmdi034": "605188",
    "pmdidocdt": "2026-08-06",
    "pmdi004": "517022",
    "pmdi015": "2026-08-06",
    "pmdi016": "2027-06-01",
    "pmdi003": "A043",
    "pmdi002": "210721017",
    "pmdiud001": "N",
    "pmdistus": "I"
  },
  "detail": [
    {
      "pmdj011": "0.5000",
      "pmdj002": "524000059517022000000",
      "pmdj030": ""
    }
  ]
}

服务端会自动补齐 typehostservicedatakeypayload 等固定协议字段,并返回外部接口的原始 JSON 响应。

4.6 接收 ERP 推送宜搭数据

POST /api/erp/yida/push
Content-Type: application/json

当前阶段只接收并记录 ERP 推送数据,不调用宜搭、不发起流程、不落库。type 必须非空,当前允许任意单据类型;例如 cpmp402 表示核价通知流程。

请求体:

{
  "type": "cpmp402",
  "mainData": {
    "rq": "",
    "bm": "",
    "tjr": "ERP_USER_001",
    "gs": "",
    "t100id": "",
    "ent": "",
    "t100bm": ""
  },
  "detailData": [
    {
      "hjdh": "",
      "gysbh": "",
      "gysmc": "",
      "t100id": "",
      "ent": "",
      "yy": ""
    }
  ]
}

mainData 为固定主数据结构,其中 tjr 必填;detailData 必须存在,但不校验具体 JSON 类型,可传数组或对象(包括外层再包一层 detailData 的对象结构)。接口成功返回基座 McR.success(),Service 会记录请求和响应 JSON 日志。

5. 统一响应和异常处理

新增接口优先使用 ApiResponse<T>,成功响应约定为:

{
  "code": 200,
  "isSuccess": true,
  "result": {}
}

部门成员接口使用专用的 DepartmentUserIdsResponse。历史单据查询接口为兼容已有调用方,保留当前响应结构;流程发起接口使用 ApiResponse

异常处理分为两层:

  • Controller 局部处理请求体解析和参数校验失败,返回 HTTP 400。
  • GlobalExceptionHandler 处理配置缺失,返回 HTTP 412;未分类的外部调用异常记录错误日志并返回 HTTP 502。

6. 配置说明

配置文件为 src/main/resources/application.yml。生产环境建议通过环境变量注入,不要把真实密钥提交到代码仓库。

配置项 环境变量 用途
server.port SERVER_PORT HTTP 服务端口,默认 80
spring.profiles.active SPRING_PROFILES_ACTIVE Spring Profile,默认 dev
dingtalk.app-key DINGTALK_APP_KEY 钉钉应用 Key
dingtalk.app-secret DINGTALK_APP_SECRET 钉钉应用 Secret
minglei.yida.coordination-office.app-type YIDA_COORDINATION_OFFICE_APP_TYPE 协调办公应用编码
minglei.yida.coordination-office.system-token YIDA_COORDINATION_OFFICE_SYSTEM_TOKEN 协调办公应用 System Token
minglei.yida.master-data.app-type YIDA_MASTER_DATA_APP_TYPE 主数据应用编码
minglei.yida.master-data.system-token YIDA_MASTER_DATA_SYSTEM_TOKEN 主数据应用 System Token
minglei.port.supplier-price-approval-url MINGLEI_SUPPLIER_PRICE_APPROVAL_URL 外部 T100 接口地址
minglei.port.supplier-price-approval-key MINGLEI_SUPPLIER_PRICE_APPROVAL_KEY 外部接口接入密钥
logging.file.path LOGGING_FILE_PATH 日志目录,默认 logs

日志说明

Logback 同时输出:

  • 控制台日志。
  • ${LOGGING_FILE_PATH}/application.log 应用日志。
  • ${LOGGING_FILE_PATH}/error.log 错误日志。
  • archive 子目录中的按日期、大小滚动归档日志。

HttpRequestResponseLoggingFilter 会记录请求方法、URI、状态码、耗时、请求体和响应体,单个载荷最多记录 10KB,并对 passwordsecrettokenauthorizationaccessTokensystemTokenkey 等字段脱敏。日志目录必须对运行账号可写,否则可能导致 Logback 初始化失败。

7. 启动和构建

环境要求:JDK 8、Maven 3.6+,并确保能够访问项目依赖仓库及内部 malk 依赖。

# 根据实际环境填写,不要把真实凭证提交到 README 或代码仓库
$env:SERVER_PORT = "8080"
$env:DINGTALK_APP_KEY = "<dingTalk-app-key>"
$env:DINGTALK_APP_SECRET = "<dingTalk-app-secret>"
$env:YIDA_COORDINATION_OFFICE_APP_TYPE = "<coordination-office-app-type>"
$env:YIDA_COORDINATION_OFFICE_SYSTEM_TOKEN = "<coordination-office-system-token>"
$env:YIDA_MASTER_DATA_APP_TYPE = "<master-data-app-type>"
$env:YIDA_MASTER_DATA_SYSTEM_TOKEN = "<master-data-system-token>"

mvn clean package
mvn spring-boot:run

打包后也可以运行:

java -jar target\mjava-minglei-1.0.0-SNAPSHOT.jar

8. 测试

测试代码位于 src/test/java,覆盖:

  • Spring Boot 上下文加载。
  • ApiResponse 和部门用户响应的 JSON 结构。
  • 宜搭主数据查询条件、部门成员查询和负责人 ID 解析。
  • 宜搭流程处理器按表单 ID 分发。
  • 外部 T100 请求的固定协议组装和响应转发。

执行测试:

mvn test

9. 扩展宜搭表单流程

新增可发起的宜搭流程时,按以下步骤实现:

  1. 新建 XxxYidaProcessHandler,实现 YidaProcessHandler
  2. 定义该表单真实的 FORM_UUID,让 getType() 返回该表单 ID。
  3. startProcess 中选择正确的 YDClient,组装表单 ID、流程编码和表单字段。
  4. YidaProcessServiceImplTest 增加表单 ID 分发测试。
  5. 同步更新接口文档中的支持类型和请求示例。

调用方只传 type、发起人、标题和 fields,不传应用凭证、表单 ID 或流程编码之外的服务端配置。不同宜搭应用必须使用对应的具名客户端,避免协调办公和主数据凭证混用。

10. 安全和运维注意事项

  • 不要在 README、提交记录或日志中写入真实 App Secret、System Token、接入密钥或访问令牌。
  • 宜搭和钉钉接口所需的网络连通性、权限范围和组织数据权限由部署环境保证。
  • 当前 Controller 未内置业务鉴权;如需访问控制,应在网关或统一认证层配置。
  • 发生“日志文件拒绝访问”时,优先检查 LOGGING_FILE_PATH 目录是否存在以及运行账号是否具有写权限。
  • 发生宜搭配置不匹配时,确认应用编码、System Token 与处理器选择的客户端属于同一应用。