调整征信解析返回解析和日志

This commit is contained in:
wkc
2026-05-13 16:28:57 +08:00
parent be443d1b31
commit 9917d10e59
9 changed files with 149 additions and 19 deletions

View File

@@ -1,5 +1,6 @@
package com.ruoyi.lsfx.client;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.lsfx.domain.response.CreditParseInvokeResponse;
@@ -20,6 +21,9 @@ public class CreditParseClient {
@Resource
private HttpUtil httpUtil;
@Resource
private ObjectMapper objectMapper;
@Value("${credit-parse.api.url}")
private String creditParseUrl;
@@ -39,8 +43,6 @@ public class CreditParseClient {
public CreditParseInvokeResponse parse(String model, String remotePath) {
long startTime = System.currentTimeMillis();
String actualModel = StringUtils.isBlank(model) ? defaultModel : model;
log.info("【征信解析】开始调用: model={}, remotePath={}", actualModel, remotePath);
try {
Map<String, Object> params = new HashMap<>();
params.put("serialNum", buildSerialNum());
@@ -49,8 +51,11 @@ public class CreditParseClient {
params.put("remotePath", remotePath);
params.put("model", actualModel);
CreditParseInvokeResponse response = httpUtil.postUrlEncodedForm(
creditParseUrl, params, null, CreditParseInvokeResponse.class);
log.info("【征信解析】调用请求: url={}, params={}", creditParseUrl, toJson(params));
String responseJson = httpUtil.postUrlEncodedFormForString(creditParseUrl, params, null);
log.info("【征信解析】调用返回JSON: {}", responseJson);
CreditParseInvokeResponse response = objectMapper.readValue(responseJson, CreditParseInvokeResponse.class);
long elapsed = System.currentTimeMillis() - startTime;
log.info("【征信解析】调用完成: success={}, code={}, businessStatusCode={}, cost={}ms",
@@ -70,4 +75,12 @@ public class CreditParseClient {
private String buildSerialNum() {
return "CCDI_CREDIT_" + System.currentTimeMillis() + "_" + IdUtils.fastSimpleUUID();
}
private String toJson(Object value) {
try {
return objectMapper.writeValueAsString(value);
} catch (Exception e) {
return String.valueOf(value);
}
}
}

View File

@@ -0,0 +1,33 @@
package com.ruoyi.lsfx.domain.response;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import java.io.IOException;
public class CreditParsePayloadDeserializer extends JsonDeserializer<CreditParsePayload> {
@Override
public CreditParsePayload deserialize(JsonParser parser, DeserializationContext context) throws IOException {
ObjectCodec codec = parser.getCodec();
JsonNode node = codec.readTree(parser);
if (node == null || node.isNull()) {
return null;
}
if (node.isTextual()) {
String payloadText = node.asText();
if (payloadText == null || payloadText.trim().isEmpty()) {
return null;
}
node = codec.readTree(codec.getFactory().createParser(payloadText));
}
if (!node.isObject()) {
throw JsonMappingException.from(parser, "征信解析payload格式不支持");
}
return codec.treeToValue(node, CreditParsePayload.class);
}
}

View File

@@ -1,6 +1,7 @@
package com.ruoyi.lsfx.domain.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.Data;
@Data
@@ -11,5 +12,6 @@ public class CreditParseResponse {
@JsonProperty("status_code")
private String statusCode;
@JsonDeserialize(using = CreditParsePayloadDeserializer.class)
private CreditParsePayload payload;
}

View File

@@ -247,6 +247,45 @@ public class HttpUtil {
}
}
/**
* 发送POST请求application/x-www-form-urlencoded格式并返回原始JSON字符串
* @param url 请求URL
* @param params 表单参数
* @param headers 请求头
* @return 原始响应内容
*/
public String postUrlEncodedFormForString(String url, Map<String, Object> params, Map<String, String> headers) {
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<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
if (!response.getStatusCode().is2xxSuccessful()) {
throw new LsfxApiException("API调用失败HTTP状态码: " + response.getStatusCode());
}
String 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

View File

@@ -1,5 +1,6 @@
package com.ruoyi.lsfx.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.lsfx.client.CreditParseClient;
import com.ruoyi.lsfx.domain.response.CreditParseInvokeResponse;
@@ -68,35 +69,38 @@ class CreditParseControllerTest {
@Test
@SuppressWarnings({"unchecked", "rawtypes"})
void creditParseClient_shouldPostUrlEncodedRemotePathParameters() {
void creditParseClient_shouldParseSuccessResponseWithStringPayload() throws Exception {
HttpUtil httpUtil = mock(HttpUtil.class);
CreditParseClient parseClient = new CreditParseClient();
ObjectMapper objectMapper = new ObjectMapper();
ReflectionTestUtils.setField(parseClient, "httpUtil", httpUtil);
ReflectionTestUtils.setField(parseClient, "creditParseUrl", "http://tz/api/service/interface/invokeService/xfeature");
ReflectionTestUtils.setField(parseClient, "orgCode", "902000");
ReflectionTestUtils.setField(parseClient, "runType", "1");
ReflectionTestUtils.setField(parseClient, "defaultModel", "LXCUSTALL");
ReflectionTestUtils.setField(parseClient, "objectMapper", objectMapper);
CreditParseInvokeResponse response = new CreditParseInvokeResponse();
response.setSuccess(true);
response.setCode(1000);
when(httpUtil.postUrlEncodedForm(
String payload = "{\"lx_header\":{\"query_cert_no\":\"330101199001010011\",\"query_cust_name\":\"张三\",\"report_time\":\"2026-03-24\"},\"lx_debt\":{\"uncle_bank_house_bal\":\"1\"},\"lx_publictype\":{\"civil_cnt\":1}}";
when(httpUtil.postUrlEncodedFormForString(
eq("http://tz/api/service/interface/invokeService/xfeature"),
org.mockito.ArgumentMatchers.<Map<String, Object>>any(),
isNull(),
eq(CreditParseInvokeResponse.class)
)).thenReturn(response);
isNull()
)).thenReturn("{\"success\":true,\"code\":10000,\"data\":{\"mappingOutputFields\":{\"message\":\"\",\"status_code\":\"0\",\"payload\":"
+ objectMapper.writeValueAsString(payload) + "}}}");
String remotePath = "http://127.0.0.1:62318/profile/credit-html/a.html";
CreditParseInvokeResponse actual = parseClient.parse(remotePath);
assertSame(response, actual);
assertEquals(true, actual.getSuccess());
assertEquals(10000, actual.getCode());
assertEquals("330101199001010011", actual.getData().getMappingOutputFields()
.getPayload().getLxHeader().get("query_cert_no"));
ArgumentCaptor<Map<String, Object>> paramsCaptor = ArgumentCaptor.forClass((Class) Map.class);
verify(httpUtil).postUrlEncodedForm(
verify(httpUtil).postUrlEncodedFormForString(
eq("http://tz/api/service/interface/invokeService/xfeature"),
paramsCaptor.capture(),
isNull(),
eq(CreditParseInvokeResponse.class)
isNull()
);
Map<String, Object> params = paramsCaptor.getValue();