docs: 添加流水分析平台对接设计文档
- 定义ccdi-lsfx模块架构 - 设计7个接口的调用封装 - 采用RestTemplate + HttpUtil技术方案 - 包含完整配置、工具类、Client和测试Controller设计
This commit is contained in:
826
docs/plans/2026-03-02-lsfx-integration-design.md
Normal file
826
docs/plans/2026-03-02-lsfx-integration-design.md
Normal file
@@ -0,0 +1,826 @@
|
||||
# 流水分析平台对接设计文档
|
||||
|
||||
## 文档信息
|
||||
|
||||
- **创建日期**: 2026-03-02
|
||||
- **设计目标**: 实现与见知现金流尽调系统的对接,封装7个核心接口调用
|
||||
- **技术方案**: RestTemplate + 手动封装
|
||||
|
||||
---
|
||||
|
||||
## 一、需求概述
|
||||
|
||||
### 1.1 业务背景
|
||||
|
||||
系统需要与**见知现金流尽调系统**对接,用于拉取银行流水数据。通过调用流水分析平台提供的接口,实现以下功能:
|
||||
|
||||
- 创建项目并获取访问Token
|
||||
- 上传银行流水文件或拉取行内流水
|
||||
- 检查文件解析状态
|
||||
- 生成尽调报告
|
||||
- 获取流水明细数据
|
||||
|
||||
### 1.2 接口列表
|
||||
|
||||
共7个接口,调用流程如下:
|
||||
|
||||
```
|
||||
获取Token → 上传文件/拉取行内流水 → 检查解析状态 → 生成报告 → 检查报告状态 → 获取流水数据
|
||||
```
|
||||
|
||||
| 序号 | 接口名称 | 请求方式 | 说明 |
|
||||
|------|---------|---------|------|
|
||||
| 1 | 获取Token | POST | 创建项目并获取访问Token |
|
||||
| 2 | 上传文件 | POST | 上传银行流水文件 |
|
||||
| 3 | 拉取行内流水 | POST | 从数仓拉取行内流水 |
|
||||
| 4 | 检查解析状态 | POST | 轮询检查文件解析状态 |
|
||||
| 5 | 生成尽调报告 | POST | 确认文件后生成报告 |
|
||||
| 6 | 检查报告状态 | GET | 轮询检查报告生成状态 |
|
||||
| 7 | 获取银行流水 | POST | 分页获取流水明细 |
|
||||
|
||||
### 1.3 技术选型
|
||||
|
||||
**方案一:RestTemplate + 手动封装**(已选定)
|
||||
|
||||
**优点**:
|
||||
- ✅ 简单直接,符合task.md要求
|
||||
- ✅ Spring Boot自带,无需额外依赖
|
||||
- ✅ 完全控制请求细节(超时、拦截器、错误处理)
|
||||
- ✅ 易于测试和调试
|
||||
|
||||
---
|
||||
|
||||
## 二、架构设计
|
||||
|
||||
### 2.1 模块结构
|
||||
|
||||
创建新模块 `ccdi-lsfx` (流水分析对接模块),目录结构如下:
|
||||
|
||||
```
|
||||
ccdi-lsfx/
|
||||
├── pom.xml
|
||||
└── src/main/java/com/ruoyi/lsfx/
|
||||
├── config/
|
||||
│ └── RestTemplateConfig.java # RestTemplate配置
|
||||
├── constants/
|
||||
│ └── LsfxConstants.java # 常量定义
|
||||
├── client/
|
||||
│ └── LsfxAnalysisClient.java # 封装7个接口调用
|
||||
├── domain/
|
||||
│ ├── request/ # 请求DTO
|
||||
│ │ ├── GetTokenRequest.java # 接口1
|
||||
│ │ ├── UploadFileRequest.java # 接口2
|
||||
│ │ ├── FetchInnerFlowRequest.java # 接口3
|
||||
│ │ ├── CheckParseStatusRequest.java # 接口4
|
||||
│ │ ├── GenerateReportRequest.java # 接口5
|
||||
│ │ └── GetBankStatementRequest.java # 接口7
|
||||
│ └── response/ # 响应DTO
|
||||
│ ├── GetTokenResponse.java # 接口1
|
||||
│ ├── UploadFileResponse.java # 接口2
|
||||
│ ├── FetchInnerFlowResponse.java # 接口3
|
||||
│ ├── CheckParseStatusResponse.java # 接口4
|
||||
│ ├── GenerateReportResponse.java # 接口5
|
||||
│ ├── CheckReportStatusResponse.java# 接口6
|
||||
│ └── GetBankStatementResponse.java # 接口7
|
||||
├── exception/
|
||||
│ ├── LsfxApiException.java # API调用异常
|
||||
│ └── LsfxErrorCode.java # 错误码枚举
|
||||
├── util/
|
||||
│ ├── MD5Util.java # MD5加密工具
|
||||
│ └── HttpUtil.java # HTTP工具类
|
||||
└── controller/
|
||||
└── LsfxTestController.java # 测试控制器
|
||||
```
|
||||
|
||||
### 2.2 模块依赖
|
||||
|
||||
在根目录 `pom.xml` 的 `<modules>` 中添加:
|
||||
|
||||
```xml
|
||||
<module>ccdi-lsfx</module>
|
||||
```
|
||||
|
||||
在 `ruoyi-admin/pom.xml` 中添加:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ccdi-lsfx</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、配置设计
|
||||
|
||||
### 3.1 application-dev.yml 配置
|
||||
|
||||
```yaml
|
||||
# 流水分析平台配置
|
||||
lsfx:
|
||||
api:
|
||||
# 测试环境
|
||||
base-url: http://158.234.196.5:82/c4c3
|
||||
# 生产环境(注释掉测试环境后启用)
|
||||
# base-url: http://64.202.32.176/c4c3
|
||||
|
||||
# 认证配置
|
||||
app-id: remote_app
|
||||
app-secret: your_app_secret_here # 从见知获取
|
||||
client-id: c2017e8d105c435a96f86373635b6a09 # 测试环境固定值
|
||||
|
||||
# 接口路径配置
|
||||
endpoints:
|
||||
get-token: /account/common/getToken
|
||||
upload-file: /watson/api/project/remoteUploadSplitFile
|
||||
fetch-inner-flow: /watson/api/project/getJZFileOrZjrcuFile
|
||||
check-parse-status: /watson/api/project/upload/getpendings
|
||||
generate-report: /watson/api/project/confirmStageUploadLogs
|
||||
check-report-status: /watson/api/project/upload/getallpendings
|
||||
get-bank-statement: /watson/api/project/upload/getBankStatement
|
||||
|
||||
# RestTemplate配置
|
||||
connection-timeout: 30000 # 连接超时30秒
|
||||
read-timeout: 60000 # 读取超时60秒
|
||||
```
|
||||
|
||||
### 3.2 常量类
|
||||
|
||||
```java
|
||||
package com.ruoyi.lsfx.constants;
|
||||
|
||||
/**
|
||||
* 流水分析平台常量
|
||||
*/
|
||||
public class LsfxConstants {
|
||||
|
||||
/** 基础URL配置键 */
|
||||
public static final String BASE_URL_KEY = "lsfx.api.base-url";
|
||||
|
||||
/** 成功状态码 */
|
||||
public static final String SUCCESS_CODE = "200";
|
||||
|
||||
/** 文件解析成功状态 */
|
||||
public static final int PARSE_SUCCESS_STATUS = -5;
|
||||
public static final String PARSE_SUCCESS_DESC = "data.wait.confirm.newaccount";
|
||||
|
||||
/** 数据渠道编码 */
|
||||
public static final String DATA_CHANNEL_ZJRCU = "ZJRCU";
|
||||
|
||||
/** 分析类型 */
|
||||
public static final String ANALYSIS_TYPE = "-1";
|
||||
|
||||
/** 请求头 */
|
||||
public static final String HEADER_CLIENT_ID = "X-Xencio-Client-Id";
|
||||
public static final String HEADER_CONTENT_TYPE = "Content-Type";
|
||||
|
||||
/** 默认角色 */
|
||||
public static final String DEFAULT_ROLE = "VIEWER";
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 RestTemplate配置类
|
||||
|
||||
```java
|
||||
package com.ruoyi.lsfx.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* RestTemplate配置
|
||||
*/
|
||||
@Configuration
|
||||
public class RestTemplateConfig {
|
||||
|
||||
@Value("${lsfx.api.connection-timeout:30000}")
|
||||
private int connectionTimeout;
|
||||
|
||||
@Value("${lsfx.api.read-timeout:60000}")
|
||||
private int readTimeout;
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
|
||||
factory.setConnectTimeout(connectionTimeout);
|
||||
factory.setReadTimeout(readTimeout);
|
||||
return new RestTemplate(factory);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、核心类设计
|
||||
|
||||
### 4.1 DTO对象设计
|
||||
|
||||
#### 请求DTO示例(GetTokenRequest)
|
||||
|
||||
```java
|
||||
package com.ruoyi.lsfx.domain.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 获取Token请求参数
|
||||
*/
|
||||
@Data
|
||||
public class GetTokenRequest {
|
||||
|
||||
/** 项目编号 */
|
||||
private String projectNo;
|
||||
|
||||
/** 项目名称 */
|
||||
private String entityName;
|
||||
|
||||
/** 操作人员编号 */
|
||||
private String userId;
|
||||
|
||||
/** 操作人员姓名 */
|
||||
private String userName;
|
||||
|
||||
/** 见知提供appId */
|
||||
private String appId;
|
||||
|
||||
/** 安全码 md5(projectNo + "_" + entityName + "_" + appSecret) */
|
||||
private String appSecretCode;
|
||||
|
||||
/** 人员角色 */
|
||||
private String role;
|
||||
|
||||
/** 行社机构号 */
|
||||
private String orgCode;
|
||||
|
||||
/** 企业统信码或个人身份证号 */
|
||||
private String entityId;
|
||||
|
||||
/** 信贷关联人信息 */
|
||||
private String xdRelatedPersons;
|
||||
|
||||
/** 金综链流水日期ID */
|
||||
private String jzDataDateId;
|
||||
|
||||
/** 行内流水开始日期 */
|
||||
private String innerBSStartDateId;
|
||||
|
||||
/** 行内流水结束日期 */
|
||||
private String innerBSEndDateId;
|
||||
|
||||
/** 分析类型 */
|
||||
private String analysisType;
|
||||
|
||||
/** 客户经理所属营业部机构编码 */
|
||||
private String departmentCode;
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应DTO示例(GetTokenResponse)
|
||||
|
||||
```java
|
||||
package com.ruoyi.lsfx.domain.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 获取Token响应
|
||||
*/
|
||||
@Data
|
||||
public class GetTokenResponse {
|
||||
|
||||
/** 返回码 */
|
||||
private String code;
|
||||
|
||||
/** 响应状态 */
|
||||
private String status;
|
||||
|
||||
/** 消息 */
|
||||
private String message;
|
||||
|
||||
/** 成功标识 */
|
||||
private Boolean successResponse;
|
||||
|
||||
/** 响应数据 */
|
||||
private TokenData data;
|
||||
|
||||
@Data
|
||||
public static class TokenData {
|
||||
/** token */
|
||||
private String token;
|
||||
|
||||
/** 见知项目Id */
|
||||
private Integer projectId;
|
||||
|
||||
/** 项目编号 */
|
||||
private String projectNo;
|
||||
|
||||
/** 项目名称 */
|
||||
private String entityName;
|
||||
|
||||
/** 分析类型 */
|
||||
private Integer analysisType;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**说明**: 其他5个接口的DTO类结构类似,根据接口文档定义字段。
|
||||
|
||||
### 4.2 工具类设计
|
||||
|
||||
#### MD5Util
|
||||
|
||||
```java
|
||||
package com.ruoyi.lsfx.util;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* MD5加密工具类
|
||||
*/
|
||||
public class MD5Util {
|
||||
|
||||
/**
|
||||
* MD5加密
|
||||
* @param input 待加密字符串
|
||||
* @return MD5加密后的32位小写字符串
|
||||
*/
|
||||
public static String encrypt(String input) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] messageDigest = md.digest(input.getBytes());
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte b : messageDigest) {
|
||||
String hex = Integer.toHexString(0xff & b);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("MD5加密失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成安全码
|
||||
* @param projectNo 项目编号
|
||||
* @param entityName 项目名称
|
||||
* @param appSecret 应用密钥
|
||||
* @return MD5安全码
|
||||
*/
|
||||
public static String generateSecretCode(String projectNo, String entityName, String appSecret) {
|
||||
String raw = projectNo + "_" + entityName + "_" + appSecret;
|
||||
return encrypt(raw);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### HttpUtil
|
||||
|
||||
```java
|
||||
package com.ruoyi.lsfx.util;
|
||||
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* HTTP请求工具类
|
||||
*/
|
||||
@Component
|
||||
public class HttpUtil {
|
||||
|
||||
@Resource
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
/**
|
||||
* 发送GET请求(带请求头)
|
||||
*/
|
||||
public <T> T get(String url, Map<String, String> headers, Class<T> responseType) {
|
||||
HttpHeaders httpHeaders = createHeaders(headers);
|
||||
HttpEntity<Void> requestEntity = new HttpEntity<>(httpHeaders);
|
||||
|
||||
ResponseEntity<T> response = restTemplate.exchange(
|
||||
url, HttpMethod.GET, requestEntity, responseType
|
||||
);
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送POST请求(JSON格式,带请求头)
|
||||
*/
|
||||
public <T> T postJson(String url, Object request, Map<String, String> headers, Class<T> responseType) {
|
||||
HttpHeaders httpHeaders = createHeaders(headers);
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
HttpEntity<Object> requestEntity = new HttpEntity<>(request, httpHeaders);
|
||||
|
||||
ResponseEntity<T> response = restTemplate.postForEntity(url, requestEntity, responseType);
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件(Multipart格式)
|
||||
*/
|
||||
public <T> T uploadFile(String url, Map<String, Object> params, Map<String, String> headers, Class<T> responseType) {
|
||||
HttpHeaders httpHeaders = createHeaders(headers);
|
||||
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
if (params != null) {
|
||||
params.forEach(body::add);
|
||||
}
|
||||
|
||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, httpHeaders);
|
||||
|
||||
ResponseEntity<T> response = restTemplate.postForEntity(url, requestEntity, responseType);
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建请求头
|
||||
*/
|
||||
private HttpHeaders createHeaders(Map<String, String> headers) {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
if (headers != null && !headers.isEmpty()) {
|
||||
headers.forEach(httpHeaders::set);
|
||||
}
|
||||
return httpHeaders;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Client客户端类
|
||||
|
||||
```java
|
||||
package com.ruoyi.lsfx.client;
|
||||
|
||||
import com.ruoyi.lsfx.constants.LsfxConstants;
|
||||
import com.ruoyi.lsfx.domain.request.*;
|
||||
import com.ruoyi.lsfx.domain.response.*;
|
||||
import com.ruoyi.lsfx.util.HttpUtil;
|
||||
import com.ruoyi.lsfx.util.MD5Util;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流水分析平台客户端
|
||||
*/
|
||||
@Component
|
||||
public class LsfxAnalysisClient {
|
||||
|
||||
@Resource
|
||||
private HttpUtil httpUtil;
|
||||
|
||||
@Value("${lsfx.api.base-url}")
|
||||
private String baseUrl;
|
||||
|
||||
@Value("${lsfx.api.app-id}")
|
||||
private String appId;
|
||||
|
||||
@Value("${lsfx.api.app-secret}")
|
||||
private String appSecret;
|
||||
|
||||
@Value("${lsfx.api.client-id}")
|
||||
private String clientId;
|
||||
|
||||
// ==================== 接口1:获取Token ====================
|
||||
|
||||
public GetTokenResponse getToken(GetTokenRequest request) {
|
||||
String secretCode = MD5Util.generateSecretCode(
|
||||
request.getProjectNo(),
|
||||
request.getEntityName(),
|
||||
appSecret
|
||||
);
|
||||
request.setAppSecretCode(secretCode);
|
||||
request.setAppId(appId);
|
||||
|
||||
if (request.getAnalysisType() == null) {
|
||||
request.setAnalysisType(LsfxConstants.ANALYSIS_TYPE);
|
||||
}
|
||||
if (request.getRole() == null) {
|
||||
request.setRole(LsfxConstants.DEFAULT_ROLE);
|
||||
}
|
||||
|
||||
String url = baseUrl + "/account/common/getToken";
|
||||
return httpUtil.postJson(url, request, GetTokenResponse.class);
|
||||
}
|
||||
|
||||
// ==================== 接口2:上传文件 ====================
|
||||
|
||||
public UploadFileResponse uploadFile(Integer groupId, Resource file) {
|
||||
String url = baseUrl + "/watson/api/project/remoteUploadSplitFile";
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("groupId", groupId);
|
||||
params.put("files", file);
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put(LsfxConstants.HEADER_CLIENT_ID, clientId);
|
||||
|
||||
return httpUtil.uploadFile(url, params, headers, UploadFileResponse.class);
|
||||
}
|
||||
|
||||
// ==================== 接口3:拉取行内流水 ====================
|
||||
|
||||
public FetchInnerFlowResponse fetchInnerFlow(FetchInnerFlowRequest request) {
|
||||
String url = baseUrl + "/watson/api/project/getJZFileOrZjrcuFile";
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put(LsfxConstants.HEADER_CLIENT_ID, clientId);
|
||||
|
||||
return httpUtil.postJson(url, request, headers, FetchInnerFlowResponse.class);
|
||||
}
|
||||
|
||||
// ==================== 接口4:检查文件解析状态 ====================
|
||||
|
||||
public CheckParseStatusResponse checkParseStatus(Integer groupId, String inprogressList) {
|
||||
String url = baseUrl + "/watson/api/project/upload/getpendings";
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("groupId", groupId);
|
||||
params.put("inprogressList", inprogressList);
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put(LsfxConstants.HEADER_CLIENT_ID, clientId);
|
||||
|
||||
return httpUtil.postJson(url, params, headers, CheckParseStatusResponse.class);
|
||||
}
|
||||
|
||||
// ==================== 接口5:生成尽调报告 ====================
|
||||
|
||||
public GenerateReportResponse generateReport(GenerateReportRequest request) {
|
||||
String url = baseUrl + "/watson/api/project/confirmStageUploadLogs";
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put(LsfxConstants.HEADER_CLIENT_ID, clientId);
|
||||
|
||||
return httpUtil.postJson(url, request, headers, GenerateReportResponse.class);
|
||||
}
|
||||
|
||||
// ==================== 接口6:检查报告生成状态 ====================
|
||||
|
||||
public CheckReportStatusResponse checkReportStatus(Integer groupId) {
|
||||
String url = baseUrl + "/watson/api/project/upload/getallpendings?groupId=" + groupId;
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put(LsfxConstants.HEADER_CLIENT_ID, clientId);
|
||||
|
||||
return httpUtil.get(url, headers, CheckReportStatusResponse.class);
|
||||
}
|
||||
|
||||
// ==================== 接口7:获取银行流水 ====================
|
||||
|
||||
public GetBankStatementResponse getBankStatement(GetBankStatementRequest request) {
|
||||
String url = baseUrl + "/watson/api/project/upload/getBankStatement";
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put(LsfxConstants.HEADER_CLIENT_ID, clientId);
|
||||
|
||||
return httpUtil.postJson(url, request, headers, GetBankStatementResponse.class);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 异常类
|
||||
|
||||
```java
|
||||
package com.ruoyi.lsfx.exception;
|
||||
|
||||
/**
|
||||
* 流水分析平台API异常
|
||||
*/
|
||||
public class LsfxApiException extends RuntimeException {
|
||||
|
||||
private String errorCode;
|
||||
|
||||
public LsfxApiException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public LsfxApiException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public LsfxApiException(String errorCode, String message) {
|
||||
super(message);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、测试Controller设计
|
||||
|
||||
```java
|
||||
package com.ruoyi.lsfx.controller;
|
||||
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.lsfx.client.LsfxAnalysisClient;
|
||||
import com.ruoyi.lsfx.domain.request.*;
|
||||
import com.ruoyi.lsfx.domain.response.*;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 流水分析平台接口测试控制器
|
||||
*/
|
||||
@Tag(name = "流水分析平台接口测试", description = "用于测试流水分析平台的7个接口")
|
||||
@RestController
|
||||
@RequestMapping("/lsfx/test")
|
||||
public class LsfxTestController {
|
||||
|
||||
@Resource
|
||||
private LsfxAnalysisClient lsfxAnalysisClient;
|
||||
|
||||
@Operation(summary = "获取Token", description = "创建项目并获取访问Token")
|
||||
@PostMapping("/getToken")
|
||||
public AjaxResult getToken(@RequestBody GetTokenRequest request) {
|
||||
GetTokenResponse response = lsfxAnalysisClient.getToken(request);
|
||||
return AjaxResult.success(response);
|
||||
}
|
||||
|
||||
@Operation(summary = "上传流水文件", description = "上传银行流水文件到流水分析平台")
|
||||
@PostMapping("/uploadFile")
|
||||
public AjaxResult uploadFile(
|
||||
@Parameter(description = "项目ID") @RequestParam Integer groupId,
|
||||
@Parameter(description = "流水文件") @RequestParam("file") MultipartFile file
|
||||
) {
|
||||
Resource fileResource = file.getResource();
|
||||
UploadFileResponse response = lsfxAnalysisClient.uploadFile(groupId, fileResource);
|
||||
return AjaxResult.success(response);
|
||||
}
|
||||
|
||||
@Operation(summary = "拉取行内流水", description = "从数仓拉取行内流水数据")
|
||||
@PostMapping("/fetchInnerFlow")
|
||||
public AjaxResult fetchInnerFlow(@RequestBody FetchInnerFlowRequest request) {
|
||||
FetchInnerFlowResponse response = lsfxAnalysisClient.fetchInnerFlow(request);
|
||||
return AjaxResult.success(response);
|
||||
}
|
||||
|
||||
@Operation(summary = "检查文件解析状态", description = "轮询检查上传文件的解析状态")
|
||||
@PostMapping("/checkParseStatus")
|
||||
public AjaxResult checkParseStatus(
|
||||
@Parameter(description = "项目ID") @RequestParam Integer groupId,
|
||||
@Parameter(description = "文件ID列表") @RequestParam String inprogressList
|
||||
) {
|
||||
CheckParseStatusResponse response = lsfxAnalysisClient.checkParseStatus(groupId, inprogressList);
|
||||
return AjaxResult.success(response);
|
||||
}
|
||||
|
||||
@Operation(summary = "生成尽调报告", description = "确认文件后生成尽调报告")
|
||||
@PostMapping("/generateReport")
|
||||
public AjaxResult generateReport(@RequestBody GenerateReportRequest request) {
|
||||
GenerateReportResponse response = lsfxAnalysisClient.generateReport(request);
|
||||
return AjaxResult.success(response);
|
||||
}
|
||||
|
||||
@Operation(summary = "检查报告生成状态", description = "轮询检查尽调报告生成状态")
|
||||
@GetMapping("/checkReportStatus")
|
||||
public AjaxResult checkReportStatus(
|
||||
@Parameter(description = "项目ID") @RequestParam Integer groupId
|
||||
) {
|
||||
CheckReportStatusResponse response = lsfxAnalysisClient.checkReportStatus(groupId);
|
||||
return AjaxResult.success(response);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取银行流水列表", description = "分页获取银行流水数据")
|
||||
@PostMapping("/getBankStatement")
|
||||
public AjaxResult getBankStatement(@RequestBody GetBankStatementRequest request) {
|
||||
GetBankStatementResponse response = lsfxAnalysisClient.getBankStatement(request);
|
||||
return AjaxResult.success(response);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、Maven依赖配置
|
||||
|
||||
**ccdi-lsfx/pom.xml**
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.9.1</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>ccdi-lsfx</artifactId>
|
||||
|
||||
<description>流水分析平台对接模块</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 通用工具 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringDoc OpenAPI (Swagger) -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、实施要点
|
||||
|
||||
### 7.1 开发顺序
|
||||
|
||||
1. **创建模块结构** - 创建ccdi-lsfx模块及基础目录
|
||||
2. **添加配置** - 修改pom.xml,添加application.yml配置
|
||||
3. **实现工具类** - MD5Util、HttpUtil
|
||||
4. **创建DTO对象** - 7个接口的Request和Response类
|
||||
5. **实现Client** - LsfxAnalysisClient封装接口调用
|
||||
6. **创建测试Controller** - 提供测试端点
|
||||
7. **测试验证** - 使用Swagger测试各个接口
|
||||
|
||||
### 7.2 注意事项
|
||||
|
||||
1. **安全码生成** - Token接口需要MD5加密生成安全码
|
||||
2. **请求头设置** - 除Token接口外,其他接口需要设置X-Xencio-Client-Id请求头
|
||||
3. **文件上传** - 上传文件接口使用multipart/form-data格式
|
||||
4. **轮询检查** - 解析状态和报告状态需要轮询检查,直到处理完成
|
||||
5. **环境切换** - 测试环境和生产环境的URL和Client-Id不同,需配置切换
|
||||
|
||||
### 7.3 测试计划
|
||||
|
||||
1. 单元测试 - 测试MD5Util、HttpUtil工具类
|
||||
2. 集成测试 - 测试LsfxAnalysisClient的7个接口调用
|
||||
3. 端到端测试 - 通过Swagger测试完整的调用流程
|
||||
|
||||
---
|
||||
|
||||
## 八、后续扩展
|
||||
|
||||
### 8.1 可选增强功能
|
||||
|
||||
1. **日志记录** - 添加详细的接口调用日志
|
||||
2. **重试机制** - 对失败的接口调用添加自动重试
|
||||
3. **熔断降级** - 使用Resilience4j实现熔断和降级
|
||||
4. **数据持久化** - 将获取的流水数据保存到数据库
|
||||
5. **异步处理** - 使用异步方式处理耗时的接口调用
|
||||
|
||||
### 8.2 业务集成
|
||||
|
||||
未来可根据业务需求,将此模块集成到具体的业务场景中,如:
|
||||
- 员工异常行为调查时自动获取流水数据
|
||||
- 定期批量拉取流水数据
|
||||
- 与前端页面集成展示流水信息
|
||||
|
||||
---
|
||||
|
||||
## 九、参考文档
|
||||
|
||||
- [兰溪-流水分析对接.md](../../doc/对接流水分析/兰溪-流水分析对接.md)
|
||||
- [RestTemplate官方文档](https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#rest-client-access)
|
||||
- [Spring Boot官方文档](https://spring.io/projects/spring-boot)
|
||||
Reference in New Issue
Block a user