|
|
1 viikko sitten | |
|---|---|---|
| .. | ||
| .mvn | 2 viikkoa sitten | |
| src | 1 viikko sitten | |
| .gitignore | 2 viikkoa sitten | |
| ERP-YIDA-PUSH-API.md | 1 viikko sitten | |
| README.md | 1 viikko sitten | |
| pom.xml | 1 viikko sitten | |
明磊业务集成服务。工程基于 Spring Boot 构建,通过统一的 malk:mjava 客户端对接钉钉和宜搭,同时提供明磊内部外部接口的转发能力。
| 技术 | 版本或用途 |
|---|---|
| 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 | 单元测试和客户端调用测试 |
工程采用典型的 Controller - Service - Impl 分层结构:
MjavaMingleiApplication
|
v
Controller 层 接收 HTTP 请求、校验参数、返回 HTTP 响应
|
v
Service 接口层 定义业务能力和模块边界
|
v
ServiceImpl 层 编排宜搭、钉钉或外部 T100 调用
|
+--> malk YDClient / DDClient
+--> DingTalk Open Platform
+--> 明磊外部 T100 HTTP 接口
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 单元测试和集成上下文测试
MjavaYidaConfiguration 注册两套独立的宜搭客户端:
coordinationOfficeYidaClient:明磊锂能协调办公应用。masterDataYidaClient:明磊锂能应用主数据。两套客户端使用各自的 appType 和 systemToken,业务实现通过 @Qualifier 选择,避免多个 YDClient Bean 注入时产生歧义。钉钉客户端由 malk 包提供,宜搭客户端内部通过 YDClientImpl 调用表单和流程接口。
相关类:YidaProcessController、YidaProcessService、YidaProcessServiceImpl、YidaProcessHandler、BomYidaProcessHandler。
统一入口根据请求体的 type 分发处理器。type 的业务含义是目标宜搭表单的 formUuid,不是自定义的业务名称。例如 BOM 表单使用:
FORM-04001902BF9C40E6859102569FE139179LWH
分发前会去除首尾空格并转为大写匹配。新增表单时,应新增一个 YidaProcessHandler 实现类,并让 getType() 返回该表单的 formUuid;表单 ID、流程编码和应用凭证由实现类或配置管理,不由调用方传入。
处理流程如下:
@Valid 校验请求体。YidaProcessServiceImpl 根据规范化后的表单 ID 查找处理器。YidaOperationParam。YDClient.operateData(..., FORM_OPERATION.start) 发起宜搭流程。相关类:MingleiDocumentService、MingleiDocumentServiceImpl、YidaProcessController。
主数据查询固定使用主数据应用客户端和目标表单 ID。支持两种查询方式:
records、totalCount、pageNumber。dept_id > user_id > dept_name。传入 user_id 时,先调用钉钉通讯录接口取得员工所属部门,再按部门 ID 查询。查询成功后仅提取一级至四级部门主管和部门分管领导字段对应的钉钉 userId。MingleiDocumentServiceImpl.listDepartmentUserIds 先取得钉钉访问令牌,再按 type 决定查询范围:0 获取指定部门及所有子部门,1 仅获取指定部门;随后逐个读取部门成员并按首次出现顺序去重,返回用户 ID 列表。
相关类:MingleiPortController、MingleiPortService、MingleiPortServiceImpl。
该模块是本服务提供的本地触发入口,收到精简的 head 和 detail 后,由服务端补齐固定的外层协议结构,再通过 RestTemplate 调用明磊外部接口。连接超时为 10 秒,读取超时为 30 秒,目标 URL 和接入密钥通过配置注入。
POST /api/yida/process-instances
Content-Type: application/json
请求示例:
{
"type": "FORM-04001902BF9C40E6859102569FE139179LWH",
"userId": "dingTalkUserId",
"dataTitle": "流程标题",
"fields": {
"textField_xxx": "字段值"
}
}
userId 也可使用请求别名 originatorUserId。fields 的键必须是目标宜搭表单真实存在的字段 ID。成功返回 HTTP 201 Created:
{
"code": 200,
"isSuccess": true,
"result": {
"processInstanceId": "宜搭流程实例 ID"
}
}
该接口使用统一的 ApiResponse 包装格式,流程实例 ID 位于 result.processInstanceId。
GET /api/yida/minglei/forms/instances?page=1&size=20
page 从 1 开始,size 范围为 1 至 100。成功响应为宜搭查询结果的服务端整理结构:
{
"records": [],
"totalCount": 0,
"pageNumber": 1
}
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"
}
POST /api/yida/minglei/departments/users
Content-Type: application/json
请求体:
{
"dept_Id": "123456",
"type": 0
}
type 为必填字段:0 表示穿透查询子部门,1 表示仅查询指定部门。
成功响应统一为 code、isSuccess、result 三层结构:
{
"code": 200,
"isSuccess": true,
"result": [
"449856319",
"715357119"
]
}
POST /api/minglei/ports/supplier-price-approvals
Content-Type: application/json
请求体只需要提供协议中的 head 和 detail:
{
"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": ""
}
]
}
服务端会自动补齐 type、host、service、datakey、payload 等固定协议字段,并返回外部接口的原始 JSON 响应。
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 日志。
新增接口优先使用 ApiResponse<T>,成功响应约定为:
{
"code": 200,
"isSuccess": true,
"result": {}
}
部门成员接口使用专用的 DepartmentUserIdsResponse。历史单据查询接口为兼容已有调用方,保留当前响应结构;流程发起接口使用 ApiResponse。
异常处理分为两层:
GlobalExceptionHandler 处理配置缺失,返回 HTTP 412;未分类的外部调用异常记录错误日志并返回 HTTP 502。配置文件为 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,并对 password、secret、token、authorization、accessToken、systemToken、key 等字段脱敏。日志目录必须对运行账号可写,否则可能导致 Logback 初始化失败。
环境要求: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
测试代码位于 src/test/java,覆盖:
ApiResponse 和部门用户响应的 JSON 结构。执行测试:
mvn test
新增可发起的宜搭流程时,按以下步骤实现:
XxxYidaProcessHandler,实现 YidaProcessHandler。FORM_UUID,让 getType() 返回该表单 ID。startProcess 中选择正确的 YDClient,组装表单 ID、流程编码和表单字段。YidaProcessServiceImplTest 增加表单 ID 分发测试。调用方只传 type、发起人、标题和 fields,不传应用凭证、表单 ID 或流程编码之外的服务端配置。不同宜搭应用必须使用对应的具名客户端,避免协调办公和主数据凭证混用。
LOGGING_FILE_PATH 目录是否存在以及运行账号是否具有写权限。