From 4d94a3cd9d9b995450fe12cb71020ea553df76a0 Mon Sep 17 00:00:00 2001 From: wkc <978997012@qq.com> Date: Mon, 2 Mar 2026 09:43:32 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0=E6=B5=81=E6=B0=B4?= =?UTF-8?q?=E5=88=86=E6=9E=90=E5=B9=B3=E5=8F=B0=E5=AF=B9=E6=8E=A5=E5=AE=9E?= =?UTF-8?q?=E6=96=BD=E8=AE=A1=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/plans/2026-03-02-lsfx-integration.md | 1075 +++++++++++++++++++++ 1 file changed, 1075 insertions(+) create mode 100644 docs/plans/2026-03-02-lsfx-integration.md diff --git a/docs/plans/2026-03-02-lsfx-integration.md b/docs/plans/2026-03-02-lsfx-integration.md new file mode 100644 index 0000000..6c0205d --- /dev/null +++ b/docs/plans/2026-03-02-lsfx-integration.md @@ -0,0 +1,1075 @@ +# 流水分析平台对接实施计划 + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**目标:** 实现与见知现金流尽调系统的对接,封装7个核心接口调用 + +**架构:** 创建ccdi-lsfx独立模块,使用RestTemplate发起HTTP请求,通过HttpUtil工具类统一处理各类请求,LsfxAnalysisClient封装7个接口调用逻辑 + +**技术栈:** Spring Boot 3.5.8, RestTemplate, Lombok, SpringDoc OpenAPI + +--- + +## 前置准备 + +### Task 0: 更新根POM和Admin POM + +**文件:** +- 修改: `pom.xml:221-230` +- 修改: `ruoyi-admin/pom.xml` + +**步骤 1: 在根pom.xml中添加ccdi-lsfx模块** + +在 `` 标签内添加新模块: + +```xml + + ruoyi-admin + ruoyi-framework + ruoyi-system + ruoyi-quartz + ruoyi-generator + ruoyi-common + ccdi-info-collection + ccdi-project + ccdi-lsfx + +``` + +**步骤 2: 在ruoyi-admin/pom.xml中添加ccdi-lsfx依赖** + +在 `` 标签内添加: + +```xml + + + com.ruoyi + ccdi-lsfx + +``` + +**步骤 3: 提交更改** + +```bash +git add pom.xml ruoyi-admin/pom.xml +git commit -m "chore: 添加ccdi-lsfx模块依赖" +``` + +--- + +## 模块基础结构 + +### Task 1: 创建ccdi-lsfx模块目录和pom.xml + +**文件:** +- 创建: `ccdi-lsfx/pom.xml` + +**步骤 1: 创建pom.xml文件** + +```xml + + + + com.ruoyi + ruoyi + 3.9.1 + + + 4.0.0 + ccdi-lsfx + + 流水分析平台对接模块 + + + + + com.ruoyi + ruoyi-common + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.projectlombok + lombok + true + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + + + +``` + +**步骤 2: 创建基础目录结构** + +```bash +mkdir -p ccdi-lsfx/src/main/java/com/ruoyi/lsfx/{config,constants,client,domain/{request,response},exception,util,controller} +mkdir -p ccdi-lsfx/src/main/resources +``` + +**步骤 3: 提交更改** + +```bash +git add ccdi-lsfx/ +git commit -m "feat: 创建ccdi-lsfx模块基础结构" +``` + +--- + +## 配置层 + +### Task 2: 添加配置到application-dev.yml + +**文件:** +- 修改: `ruoyi-admin/src/main/resources/application-dev.yml` + +**步骤 1: 在文件末尾添加lsfx配置** + +```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秒 +``` + +**步骤 2: 提交更改** + +```bash +git add ruoyi-admin/src/main/resources/application-dev.yml +git commit -m "config: 添加流水分析平台配置" +``` + +--- + +### Task 3: 创建RestTemplate配置类 + +**文件:** +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/config/RestTemplateConfig.java` + +**步骤 1: 创建配置类** + +```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); + } +} +``` + +**步骤 2: 提交更改** + +```bash +git add ccdi-lsfx/src/main/java/com/ruoyi/lsfx/config/RestTemplateConfig.java +git commit -m "feat: 添加RestTemplate配置类" +``` + +--- + +### Task 4: 创建常量类 + +**文件:** +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/constants/LsfxConstants.java` + +**步骤 1: 创建常量类** + +```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"; +} +``` + +**步骤 2: 提交更改** + +```bash +git add ccdi-lsfx/src/main/java/com/ruoyi/lsfx/constants/LsfxConstants.java +git commit -m "feat: 添加流水分析常量类" +``` + +--- + +## 工具类层 + +### Task 5: 创建MD5工具类 + +**文件:** +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/util/MD5Util.java` + +**步骤 1: 创建MD5工具类** + +```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); + } +} +``` + +**步骤 2: 提交更改** + +```bash +git add ccdi-lsfx/src/main/java/com/ruoyi/lsfx/util/MD5Util.java +git commit -m "feat: 添加MD5加密工具类" +``` + +--- + +### Task 6: 创建HttpUtil工具类 + +**文件:** +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/util/HttpUtil.java` + +**步骤 1: 创建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请求(带请求头) + * @param url 请求URL + * @param headers 请求头 + * @param responseType 响应类型 + * @return 响应对象 + */ + public T get(String url, Map headers, Class responseType) { + HttpHeaders httpHeaders = createHeaders(headers); + HttpEntity requestEntity = new HttpEntity<>(httpHeaders); + + ResponseEntity response = restTemplate.exchange( + url, HttpMethod.GET, requestEntity, responseType + ); + return response.getBody(); + } + + /** + * 发送POST请求(JSON格式,带请求头) + * @param url 请求URL + * @param request 请求对象 + * @param headers 请求头 + * @param responseType 响应类型 + * @return 响应对象 + */ + public T postJson(String url, Object request, Map headers, Class responseType) { + HttpHeaders httpHeaders = createHeaders(headers); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity requestEntity = new HttpEntity<>(request, httpHeaders); + + ResponseEntity response = restTemplate.postForEntity(url, requestEntity, responseType); + return response.getBody(); + } + + /** + * 上传文件(Multipart格式) + * @param url 请求URL + * @param params 参数(包含文件) + * @param headers 请求头 + * @param responseType 响应类型 + * @return 响应对象 + */ + public T uploadFile(String url, Map params, Map headers, Class responseType) { + HttpHeaders httpHeaders = createHeaders(headers); + httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); + + MultiValueMap body = new LinkedMultiValueMap<>(); + if (params != null) { + params.forEach(body::add); + } + + HttpEntity> requestEntity = new HttpEntity<>(body, httpHeaders); + + ResponseEntity response = restTemplate.postForEntity(url, requestEntity, responseType); + return response.getBody(); + } + + /** + * 创建请求头 + * @param headers 请求头Map + * @return HttpHeaders对象 + */ + private HttpHeaders createHeaders(Map headers) { + HttpHeaders httpHeaders = new HttpHeaders(); + if (headers != null && !headers.isEmpty()) { + headers.forEach(httpHeaders::set); + } + return httpHeaders; + } +} +``` + +**步骤 2: 提交更改** + +```bash +git add ccdi-lsfx/src/main/java/com/ruoyi/lsfx/util/HttpUtil.java +git commit -m "feat: 添加HTTP请求工具类" +``` + +--- + +## 异常处理层 + +### Task 7: 创建异常类 + +**文件:** +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/exception/LsfxApiException.java` + +**步骤 1: 创建异常类** + +```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; + } +} +``` + +**步骤 2: 提交更改** + +```bash +git add ccdi-lsfx/src/main/java/com/ruoyi/lsfx/exception/LsfxApiException.java +git commit -m "feat: 添加流水分析API异常类" +``` + +--- + +## DTO层 - 接口1(获取Token) + +### Task 8: 创建GetTokenRequest + +**文件:** +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/request/GetTokenRequest.java` + +**步骤 1: 创建请求DTO** + +```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; +} +``` + +**步骤 2: 提交更改** + +```bash +git add ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/request/GetTokenRequest.java +git commit -m "feat: 添加获取Token请求DTO" +``` + +--- + +### Task 9: 创建GetTokenResponse + +**文件:** +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/response/GetTokenResponse.java` + +**步骤 1: 创建响应DTO** + +```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; + } +} +``` + +**步骤 2: 提交更改** + +```bash +git add ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/response/GetTokenResponse.java +git commit -m "feat: 添加获取Token响应DTO" +``` + +--- + +## DTO层 - 接口2-7(简化示例) + +### Task 10: 创建其他接口DTO(批量创建) + +**文件:** +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/request/FetchInnerFlowRequest.java` +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/request/GenerateReportRequest.java` +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/request/GetBankStatementRequest.java` +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/response/UploadFileResponse.java` +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/response/FetchInnerFlowResponse.java` +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/response/CheckParseStatusResponse.java` +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/response/GenerateReportResponse.java` +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/response/CheckReportStatusResponse.java` +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/response/GetBankStatementResponse.java` + +**步骤 1: 参考设计文档创建各个DTO类** + +根据 `docs/plans/2026-03-02-lsfx-integration-design.md` 中的DTO设计,创建剩余的请求和响应对象。每个DTO都使用 `@Data` 注解,字段根据接口文档定义。 + +**步骤 2: 提交更改** + +```bash +git add ccdi-lsfx/src/main/java/com/ruoyi/lsfx/domain/ +git commit -m "feat: 添加其他接口的DTO对象" +``` + +--- + +## 客户端层 + +### Task 11: 创建LsfxAnalysisClient(接口1-3) + +**文件:** +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/client/LsfxAnalysisClient.java` + +**步骤 1: 创建客户端类(第一部分)** + +```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; + + /** + * 获取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); + } + + /** + * 上传文件 + */ + public UploadFileResponse uploadFile(Integer groupId, Resource file) { + String url = baseUrl + "/watson/api/project/remoteUploadSplitFile"; + + Map params = new HashMap<>(); + params.put("groupId", groupId); + params.put("files", file); + + Map headers = new HashMap<>(); + headers.put(LsfxConstants.HEADER_CLIENT_ID, clientId); + + return httpUtil.uploadFile(url, params, headers, UploadFileResponse.class); + } + + /** + * 拉取行内流水 + */ + public FetchInnerFlowResponse fetchInnerFlow(FetchInnerFlowRequest request) { + String url = baseUrl + "/watson/api/project/getJZFileOrZjrcuFile"; + + Map headers = new HashMap<>(); + headers.put(LsfxConstants.HEADER_CLIENT_ID, clientId); + + return httpUtil.postJson(url, request, headers, FetchInnerFlowResponse.class); + } +} +``` + +**步骤 2: 提交更改** + +```bash +git add ccdi-lsfx/src/main/java/com/ruoyi/lsfx/client/LsfxAnalysisClient.java +git commit -m "feat: 添加流水分析客户端(接口1-3)" +``` + +--- + +### Task 12: 完善LsfxAnalysisClient(接口4-7) + +**文件:** +- 修改: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/client/LsfxAnalysisClient.java` + +**步骤 1: 添加剩余接口方法** + +在LsfxAnalysisClient类中添加: + +```java + /** + * 检查文件解析状态 + */ + public CheckParseStatusResponse checkParseStatus(Integer groupId, String inprogressList) { + String url = baseUrl + "/watson/api/project/upload/getpendings"; + + Map params = new HashMap<>(); + params.put("groupId", groupId); + params.put("inprogressList", inprogressList); + + Map headers = new HashMap<>(); + headers.put(LsfxConstants.HEADER_CLIENT_ID, clientId); + + return httpUtil.postJson(url, params, headers, CheckParseStatusResponse.class); + } + + /** + * 生成尽调报告 + */ + public GenerateReportResponse generateReport(GenerateReportRequest request) { + String url = baseUrl + "/watson/api/project/confirmStageUploadLogs"; + + Map headers = new HashMap<>(); + headers.put(LsfxConstants.HEADER_CLIENT_ID, clientId); + + return httpUtil.postJson(url, request, headers, GenerateReportResponse.class); + } + + /** + * 检查报告生成状态 + */ + public CheckReportStatusResponse checkReportStatus(Integer groupId) { + String url = baseUrl + "/watson/api/project/upload/getallpendings?groupId=" + groupId; + + Map headers = new HashMap<>(); + headers.put(LsfxConstants.HEADER_CLIENT_ID, clientId); + + return httpUtil.get(url, headers, CheckReportStatusResponse.class); + } + + /** + * 获取银行流水 + */ + public GetBankStatementResponse getBankStatement(GetBankStatementRequest request) { + String url = baseUrl + "/watson/api/project/upload/getBankStatement"; + + Map headers = new HashMap<>(); + headers.put(LsfxConstants.HEADER_CLIENT_ID, clientId); + + return httpUtil.postJson(url, request, headers, GetBankStatementResponse.class); + } +``` + +**步骤 2: 提交更改** + +```bash +git add ccdi-lsfx/src/main/java/com/ruoyi/lsfx/client/LsfxAnalysisClient.java +git commit -m "feat: 完善流水分析客户端(接口4-7)" +``` + +--- + +## 控制器层 + +### Task 13: 创建测试Controller + +**文件:** +- 创建: `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/controller/LsfxTestController.java` + +**步骤 1: 创建测试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); + } +} +``` + +**步骤 2: 提交更改** + +```bash +git add ccdi-lsfx/src/main/java/com/ruoyi/lsfx/controller/LsfxTestController.java +git commit -m "feat: 添加流水分析测试控制器" +``` + +--- + +## 测试验证 + +### Task 14: 编译项目验证依赖 + +**文件:** +- 无文件修改 + +**步骤 1: 编译项目** + +```bash +mvn clean compile +``` + +预期:编译成功,无错误 + +**步骤 2: 修复可能的编译错误** + +如果出现编译错误,检查: +1. 所有import语句是否正确 +2. Lombok是否正确配置 +3. 依赖是否正确添加 + +--- + +### Task 15: 启动应用验证配置 + +**文件:** +- 无文件修改 + +**步骤 1: 启动应用** + +提示用户手动启动应用: + +```bash +# 方式1: 使用Maven +mvn spring-boot:run + +# 方式2: 使用启动脚本(Windows) +ry.bat + +# 方式3: 使用启动脚本(Linux/Mac) +./ry.sh start +``` + +**步骤 2: 验证启动成功** + +检查日志中是否包含: +- RestTemplate bean创建成功 +- ccdi-lsfx模块加载成功 + +访问:http://localhost:8080/swagger-ui/index.html + +预期:在Swagger UI中能看到 "流水分析平台接口测试" 分组 + +--- + +### Task 16: 测试接口1(获取Token) + +**文件:** +- 无文件修改 + +**步骤 1: 通过Swagger测试获取Token接口** + +访问:http://localhost:8080/swagger-ui/index.html + +找到 "流水分析平台接口测试" → "获取Token" + +请求示例: +```json +{ + "projectNo": "test-project-001", + "entityName": "测试项目001", + "userId": "test001", + "userName": "测试用户001", + "orgCode": "800000", + "departmentCode": "800111" +} +``` + +预期:返回200状态码,包含token和projectId + +**步骤 2: 记录测试结果** + +如果成功,记录返回的 token 和 projectId,后续测试需要使用。 + +--- + +## 完成标记 + +### Task 17: 标记实施完成 + +**文件:** +- 无文件修改 + +**步骤 1: 确认所有功能正常** + +检查清单: +- [ ] 项目编译成功 +- [ ] 应用启动成功 +- [ ] Swagger UI可访问 +- [ ] 获取Token接口测试通过 +- [ ] 其他接口可正常调用(可选) + +**步骤 2: 创建完成标记** + +```bash +git tag -a v1.0.0-lsfx -m "完成流水分析平台对接模块" +git push origin v1.0.0-lsfx +``` + +--- + +## 备注 + +### 关键注意事项 + +1. **安全码生成**: Token接口需要MD5加密,格式为 `projectNo_entityName_appSecret` +2. **请求头设置**: 除Token接口外,其他接口都需要设置 `X-Xencio-Client-Id` 请求头 +3. **文件上传**: 上传文件接口使用 `multipart/form-data` 格式 +4. **配置管理**: 生产环境需要修改 `application-dev.yml` 中的 `base-url` 和 `client-id` +5. **app-secret**: 需要从见知获取真实的 `app-secret` 配置 + +### 后续优化建议 + +1. 添加接口调用日志记录 +2. 实现接口调用失败重试机制 +3. 添加接口响应数据缓存 +4. 实现流水数据持久化到本地数据库 +5. 添加接口调用的单元测试和集成测试