Refactor credit parse to use remote HTML paths

This commit is contained in:
wkc
2026-05-13 14:20:42 +08:00
parent b822cc202e
commit be443d1b31
18 changed files with 473 additions and 171 deletions

View File

@@ -1,6 +1,8 @@
package com.ruoyi.lsfx.client;
import com.ruoyi.lsfx.domain.response.CreditParseResponse;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.lsfx.domain.response.CreditParseInvokeResponse;
import com.ruoyi.lsfx.exception.LsfxApiException;
import com.ruoyi.lsfx.util.HttpUtil;
import jakarta.annotation.Resource;
@@ -8,7 +10,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
@@ -22,26 +23,51 @@ public class CreditParseClient {
@Value("${credit-parse.api.url}")
private String creditParseUrl;
public CreditParseResponse parse(String model, String hType, File file) {
@Value("${credit-parse.api.org-code:902000}")
private String orgCode;
@Value("${credit-parse.api.run-type:1}")
private String runType;
@Value("${credit-parse.api.model:LXCUSTALL}")
private String defaultModel;
public CreditParseInvokeResponse parse(String remotePath) {
return parse(defaultModel, remotePath);
}
public CreditParseInvokeResponse parse(String model, String remotePath) {
long startTime = System.currentTimeMillis();
log.info("【征信解析】开始调用: fileName={}, model={}, hType={}", file.getName(), model, hType);
String actualModel = StringUtils.isBlank(model) ? defaultModel : model;
log.info("【征信解析】开始调用: model={}, remotePath={}", actualModel, remotePath);
try {
Map<String, Object> params = new HashMap<>();
params.put("model", model);
params.put("hType", hType);
params.put("file", file);
params.put("serialNum", buildSerialNum());
params.put("orgCode", orgCode);
params.put("runType", runType);
params.put("remotePath", remotePath);
params.put("model", actualModel);
CreditParseResponse response = httpUtil.uploadFile(creditParseUrl, params, null, CreditParseResponse.class);
CreditParseInvokeResponse response = httpUtil.postUrlEncodedForm(
creditParseUrl, params, null, CreditParseInvokeResponse.class);
long elapsed = System.currentTimeMillis() - startTime;
log.info("【征信解析】调用完成: statusCode={}, cost={}ms",
response != null ? response.getStatusCode() : null, elapsed);
log.info("【征信解析】调用完成: success={}, code={}, businessStatusCode={}, cost={}ms",
response != null ? response.getSuccess() : null,
response != null ? response.getCode() : null,
response != null && response.getData() != null && response.getData().getMappingOutputFields() != null
? response.getData().getMappingOutputFields().getStatusCode() : null,
elapsed);
return response;
} catch (Exception e) {
log.error("【征信解析】调用失败: fileName={}, model={}, hType={}, error={}",
file.getName(), model, hType, e.getMessage(), e);
log.error("【征信解析】调用失败: model={}, remotePath={}, error={}",
actualModel, remotePath, e.getMessage(), e);
throw new LsfxApiException("征信解析调用失败: " + e.getMessage(), e);
}
}
private String buildSerialNum() {
return "CCDI_CREDIT_" + System.currentTimeMillis() + "_" + IdUtils.fastSimpleUUID();
}
}

View File

@@ -4,7 +4,7 @@ import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.lsfx.client.CreditParseClient;
import com.ruoyi.lsfx.domain.response.CreditParseResponse;
import com.ruoyi.lsfx.domain.response.CreditParseInvokeResponse;
import com.ruoyi.lsfx.exception.LsfxApiException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@@ -14,13 +14,6 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
@Tag(name = "征信解析接口测试", description = "用于测试征信解析接口")
@Anonymous
@@ -29,56 +22,27 @@ import java.nio.file.StandardCopyOption;
public class CreditParseController {
private static final String DEFAULT_MODEL = "LXCUSTALL";
private static final String DEFAULT_HTYPE = "PERSON";
@Resource
private CreditParseClient creditParseClient;
@Operation(summary = "解析征信HTML", description = "传征信HTML文件并调用外部解析服务")
@Operation(summary = "解析征信HTML", description = "征信HTML远程地址并调用外部解析服务")
@PostMapping("/parse")
public AjaxResult parse(@Parameter(description = "征信HTML文件") @RequestParam("file") MultipartFile file,
@Parameter(description = "解析模型默认LXCUSTALL") @RequestParam(required = false) String model,
@Parameter(description = "主体类型默认PERSON") @RequestParam(required = false) String hType) {
if (file == null || file.isEmpty()) {
return AjaxResult.error("征信HTML文件不能为空");
}
String originalFilename = file.getOriginalFilename();
if (StringUtils.isBlank(originalFilename)) {
return AjaxResult.error("文件名不能为空");
}
String lowerCaseName = originalFilename.toLowerCase();
if (!lowerCaseName.endsWith(".html") && !lowerCaseName.endsWith(".htm")) {
return AjaxResult.error("仅支持 HTML 格式文件");
public AjaxResult parse(@Parameter(description = "征信HTML远程访问地址") @RequestParam("remotePath") String remotePath,
@Parameter(description = "模型编码默认LXCUSTALL") @RequestParam(required = false) String model) {
if (StringUtils.isBlank(remotePath)) {
return AjaxResult.error("征信HTML远程地址不能为空");
}
String actualModel = StringUtils.isBlank(model) ? DEFAULT_MODEL : model;
String actualHType = StringUtils.isBlank(hType) ? DEFAULT_HTYPE : hType;
Path tempFile = null;
try {
String suffix = lowerCaseName.endsWith(".htm") ? ".htm" : ".html";
tempFile = Files.createTempFile("credit_parse_", suffix);
Files.copy(file.getInputStream(), tempFile, StandardCopyOption.REPLACE_EXISTING);
File convertedFile = tempFile.toFile();
CreditParseResponse response = creditParseClient.parse(actualModel, actualHType, convertedFile);
CreditParseInvokeResponse response = creditParseClient.parse(actualModel, remotePath);
return AjaxResult.success(response);
} catch (LsfxApiException e) {
return AjaxResult.error(e.getMessage());
} catch (IOException e) {
return AjaxResult.error("文件转换失败:" + e.getMessage());
} catch (Exception e) {
return AjaxResult.error("征信解析失败:" + e.getMessage());
} finally {
if (tempFile != null) {
try {
Files.deleteIfExists(tempFile);
} catch (IOException ignored) {
// 忽略临时文件删除失败,避免影响主流程返回
}
}
}
}
}

View File

@@ -0,0 +1,9 @@
package com.ruoyi.lsfx.domain.response;
import lombok.Data;
@Data
public class CreditParseInvokeData {
private CreditParseResponse mappingOutputFields;
}

View File

@@ -0,0 +1,13 @@
package com.ruoyi.lsfx.domain.response;
import lombok.Data;
@Data
public class CreditParseInvokeResponse {
private Boolean success;
private Integer code;
private CreditParseInvokeData data;
}

View File

@@ -206,6 +206,47 @@ public class HttpUtil {
}
}
/**
* 发送POST请求application/x-www-form-urlencoded格式带请求头
* @param url 请求URL
* @param params 表单参数
* @param headers 请求头
* @param responseType 响应类型
* @return 响应对象
*/
public <T> T postUrlEncodedForm(String url, Map<String, Object> params, Map<String, String> headers, Class<T> responseType) {
try {
HttpHeaders httpHeaders = createHeaders(headers);
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
if (params != null) {
params.forEach((key, value) -> {
if (value != null) {
body.add(key, value.toString());
}
});
}
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, httpHeaders);
ResponseEntity<T> response = restTemplate.postForEntity(url, requestEntity, responseType);
if (!response.getStatusCode().is2xxSuccessful()) {
throw new LsfxApiException("API调用失败HTTP状态码: " + response.getStatusCode());
}
T responseBody = response.getBody();
if (responseBody == null) {
throw new LsfxApiException("API返回数据为空");
}
return responseBody;
} catch (RestClientException e) {
throw new LsfxApiException("网络请求失败: " + e.getMessage(), e);
}
}
/**
* 上传文件Multipart格式
* @param url 请求URL