From d89bae0bd0d8c6bb15f49cf85db2112ec04d2948 Mon Sep 17 00:00:00 2001 From: wangxiu <1422795692@qq.com> Date: Fri, 10 Jul 2026 13:24:49 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=B9=B6=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/docking/client/GenericApiClient.java | 9 ++- .../docking/exception/ApiCallException.java | 7 ++ .../docking/service/ApiInvokeLogService.java | 35 +++++++++ .../docking/service/GenericApiService.java | 48 +++--------- .../service/PaymentProfileService.java | 12 +++ .../service/impl/ApiInvokeLogServiceImpl.java | 77 +++++++++++++++++++ 6 files changed, 150 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/lyxh/api/docking/client/GenericApiClient.java b/src/main/java/com/lyxh/api/docking/client/GenericApiClient.java index 933032b..1be0025 100644 --- a/src/main/java/com/lyxh/api/docking/client/GenericApiClient.java +++ b/src/main/java/com/lyxh/api/docking/client/GenericApiClient.java @@ -13,6 +13,7 @@ import org.slf4j.LoggerFactory; import org.springframework.http.*; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpStatusCodeException; import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; @@ -77,7 +78,8 @@ public class GenericApiClient { if (respBody == null) { throw new ApiCallException("NULL_RESPONSE", "Empty response body", "") - .withRequest(url, reqHeadersJson); + .withRequest(url, reqHeadersJson) + .withStatusCode(httpStatus); } return new ApiCallResult(requestId, url, reqHeadersJson, reqBodyJson, @@ -105,8 +107,11 @@ public class GenericApiClient { long elapsed = System.currentTimeMillis() - start; log.error("Third-party HTTP error after {} attempts: url={} requestId={}", attempt, url, requestId, e); + Integer statusCode = e instanceof HttpStatusCodeException + ? ((HttpStatusCodeException) e).getRawStatusCode() : null; throw new ApiCallException("HTTP_ERROR", e.getMessage(), "") - .withRequest(url, reqHeadersJson); + .withRequest(url, reqHeadersJson) + .withStatusCode(statusCode); } } } diff --git a/src/main/java/com/lyxh/api/docking/exception/ApiCallException.java b/src/main/java/com/lyxh/api/docking/exception/ApiCallException.java index d131fda..9ccd70d 100644 --- a/src/main/java/com/lyxh/api/docking/exception/ApiCallException.java +++ b/src/main/java/com/lyxh/api/docking/exception/ApiCallException.java @@ -6,6 +6,7 @@ public class ApiCallException extends RuntimeException { private final String responseBody; private String reqUrl; private String reqHeaders; + private Integer httpStatusCode; public ApiCallException(String code, String message, String responseBody) { super(message); @@ -19,8 +20,14 @@ public class ApiCallException extends RuntimeException { return this; } + public ApiCallException withStatusCode(Integer httpStatusCode) { + this.httpStatusCode = httpStatusCode; + return this; + } + public String getCode() { return code; } public String getResponseBody() { return responseBody; } public String getReqUrl() { return reqUrl; } public String getReqHeaders() { return reqHeaders; } + public Integer getHttpStatusCode() { return httpStatusCode; } } diff --git a/src/main/java/com/lyxh/api/docking/service/ApiInvokeLogService.java b/src/main/java/com/lyxh/api/docking/service/ApiInvokeLogService.java index f47ba2b..f2aa1db 100644 --- a/src/main/java/com/lyxh/api/docking/service/ApiInvokeLogService.java +++ b/src/main/java/com/lyxh/api/docking/service/ApiInvokeLogService.java @@ -1,7 +1,42 @@ package com.lyxh.api.docking.service; import com.baomidou.mybatisplus.extension.service.IService; +import com.lyxh.api.docking.client.ApiCallResult; import com.lyxh.api.docking.entity.ApiInvokeLog; +import com.lyxh.api.docking.entity.ThirdPartyConfig; +import com.lyxh.api.docking.exception.ApiCallException; public interface ApiInvokeLogService extends IService { + + + /** + * 调用成功的日志记录 + * @param config 三方API配置 + * @param thirdPartyCode 三方标识 + * @param apiCode 接口标识 + * @param weOrderNo 系统订单号 + * @param csOrderNo 客户订单号 + * @param dsOrderNo 三方订单号 + * @param result 三方响应结果 + * @param errorMessage 错误信息 + */ + void saveInvokeLog(ThirdPartyConfig config, String thirdPartyCode, String apiCode, + String weOrderNo, String csOrderNo, String dsOrderNo, + ApiCallResult result, String errorMessage); + + + /** + * 调用失败的日志记录 + * @param configGroup + * @param thirdPartyCode 三方标识 + * @param apiCode 接口标识 + * @param requestBody 三方相应 + * @param weOrderNo 系统订单号 + * @param csOrderNo 客户订单号 + * @param e 系统异常 + */ + void logError(String configGroup, String thirdPartyCode, String apiCode, + Object requestBody, String weOrderNo, String csOrderNo, + ApiCallException e); + } diff --git a/src/main/java/com/lyxh/api/docking/service/GenericApiService.java b/src/main/java/com/lyxh/api/docking/service/GenericApiService.java index f826b9e..a7c6a92 100644 --- a/src/main/java/com/lyxh/api/docking/service/GenericApiService.java +++ b/src/main/java/com/lyxh/api/docking/service/GenericApiService.java @@ -1,11 +1,8 @@ package com.lyxh.api.docking.service; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.lyxh.api.docking.client.ApiCallResult; import com.lyxh.api.docking.client.GenericApiClient; import com.lyxh.api.docking.entity.ApiCacheData; -import com.lyxh.api.docking.entity.ApiInvokeLog; import com.lyxh.api.docking.entity.ThirdPartyConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,8 +31,6 @@ public class GenericApiService { private ApiCacheDataService cacheDataService; @Autowired private ApiInvokeLogService invokeLogService; - @Autowired - private ObjectMapper objectMapper; /** * 执行第三方 API 调用(含缓存、日志),返回响应体原始 JSON @@ -84,8 +79,8 @@ public class GenericApiService { ? dsOrderNoExtractor.apply(respBodyJson) : null; - // 5. 记录调用日志 - saveInvokeLog(config, thirdPartyCode, apiCode, weOrderNo, csOrderNo, dsOrderNo, result, null); + // 5. 记录调用日志(成功) + invokeLogService.saveInvokeLog(config, thirdPartyCode, apiCode, weOrderNo, csOrderNo, dsOrderNo, result, null); // 6. 写缓存 if (isCacheEnabled(config) && cacheKey != null) { @@ -109,28 +104,16 @@ public class GenericApiService { return config.getEnableCache() != null && config.getEnableCache() == 1; } - private void saveInvokeLog(ThirdPartyConfig config, String thirdPartyCode, String apiCode, - String weOrderNo, String csOrderNo, String dsOrderNo, - ApiCallResult result, String errorMessage) { - ApiInvokeLog logEntity = new ApiInvokeLog(); - logEntity.setConfigId(config.getId()); - logEntity.setThirdPartyCode(thirdPartyCode); - logEntity.setApiCode(apiCode); - logEntity.setCsOrderNo(csOrderNo); - logEntity.setWeOrderNo(weOrderNo); - logEntity.setDsOrderNo(dsOrderNo); - logEntity.setReqUrl(result.getUrl()); - logEntity.setReqMethod("POST"); - logEntity.setReqHeaders(result.getReqHeadersJson()); - logEntity.setReqBody(result.getReqBodyJson()); - logEntity.setRespStatusCode(result.getHttpStatusCode()); - logEntity.setRespBody(result.getRespBodyJson()); - logEntity.setCostMillis((int) result.getCostMillis()); - logEntity.setErrorMessage(errorMessage); - invokeLogService.save(logEntity); - log.info("Invoke log saved: weOrderNo={}", weOrderNo); - } - + /** + * 记录缓存数据 + * @param config 三方API配置 + * @param apiCode 接口标识 + * @param cacheKey 缓存键 + * @param cacheValue 缓存值 + * @param weOrderNo 系统订单号 + * @param csOrderNo 客户订单号 + * @param dsOrderNo 三方订单号 + */ private void saveCache(ThirdPartyConfig config, String apiCode, String cacheKey, String cacheValue, String weOrderNo, String csOrderNo, String dsOrderNo) { Duration ttl = Duration.ofDays(config.getCacheTtlDays()); @@ -140,11 +123,4 @@ public class GenericApiService { log.info("Cache saved: weOrderNo={} apiCode={} cacheKey={}", weOrderNo, apiCode, cacheKey); } - private String toJson(Object obj) { - try { - return objectMapper.writeValueAsString(obj); - } catch (JsonProcessingException e) { - return "{}"; - } - } } diff --git a/src/main/java/com/lyxh/api/docking/service/PaymentProfileService.java b/src/main/java/com/lyxh/api/docking/service/PaymentProfileService.java index 39e9ca4..ef4e6c1 100644 --- a/src/main/java/com/lyxh/api/docking/service/PaymentProfileService.java +++ b/src/main/java/com/lyxh/api/docking/service/PaymentProfileService.java @@ -28,6 +28,9 @@ public class PaymentProfileService { @Autowired private GenericApiService genericApiService; + @Autowired + private ApiInvokeLogService invokeLogService; + @Autowired private ObjectMapper objectMapper; @@ -65,6 +68,15 @@ public class PaymentProfileService { } catch (JsonProcessingException e) { throw new ApiCallException("PARSE_ERROR", "Failed to parse Fortispay response: " + e.getMessage(), null); } catch (ApiCallException e) { + // 插入日志 (调用三方api失败) + invokeLogService.logError( + API_TYPE.getConfigGroup(), + API_TYPE.getThirdPartyCode(), + API_TYPE.getApiCode(), + ftRequest, + weOrderNo, + xRequestId, + e); throw e; } } diff --git a/src/main/java/com/lyxh/api/docking/service/impl/ApiInvokeLogServiceImpl.java b/src/main/java/com/lyxh/api/docking/service/impl/ApiInvokeLogServiceImpl.java index 74f1810..f8acc03 100644 --- a/src/main/java/com/lyxh/api/docking/service/impl/ApiInvokeLogServiceImpl.java +++ b/src/main/java/com/lyxh/api/docking/service/impl/ApiInvokeLogServiceImpl.java @@ -1,13 +1,90 @@ package com.lyxh.api.docking.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.lyxh.api.docking.client.ApiCallResult; import com.lyxh.api.docking.entity.ApiInvokeLog; +import com.lyxh.api.docking.entity.ThirdPartyConfig; +import com.lyxh.api.docking.exception.ApiCallException; import com.lyxh.api.docking.mapper.ApiInvokeLogMapper; import com.lyxh.api.docking.service.ApiInvokeLogService; +import com.lyxh.api.docking.service.ThirdPartyConfigService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class ApiInvokeLogServiceImpl extends ServiceImpl implements ApiInvokeLogService { + + private static final Logger log = LoggerFactory.getLogger(ApiInvokeLogService.class); + + @Autowired + private ThirdPartyConfigService configService; + + @Autowired + private ObjectMapper objectMapper; + + @Override + public void saveInvokeLog(ThirdPartyConfig config, String thirdPartyCode, String apiCode, String weOrderNo + , String csOrderNo, String dsOrderNo, ApiCallResult result, String errorMessage) { + saveInvokeLogInternal(config.getId(), thirdPartyCode, apiCode, weOrderNo, csOrderNo, dsOrderNo, + result.getUrl(), result.getReqHeadersJson(), result.getReqBodyJson(), + result.getHttpStatusCode(), result.getRespBodyJson(), (int) result.getCostMillis(), + errorMessage); + } + + + @Override + public void logError(String configGroup, String thirdPartyCode, String apiCode, Object requestBody, String weOrderNo + , String csOrderNo, ApiCallException e) { + ThirdPartyConfig config = configService.getEnabledConfig(configGroup, thirdPartyCode, apiCode); + Long configId = config != null ? config.getId() : null; + + String reqBodyJson = toJson(requestBody); + String errorMessage = "[" + e.getCode() + "] " + e.getMessage(); + + saveInvokeLogInternal( + configId, + thirdPartyCode, apiCode, weOrderNo, csOrderNo, null, // dsOrderNo = null + e.getReqUrl(), e.getReqHeaders(), reqBodyJson, + e.getHttpStatusCode(), null, null, // respBody, costMillis 为空 + errorMessage + ); + } + + + private String toJson(Object obj) { + try { + return objectMapper.writeValueAsString(obj); + } catch (JsonProcessingException e) { + return "{}"; + } + } + + private void saveInvokeLogInternal(Long configId, String thirdPartyCode, String apiCode, String weOrderNo + , String csOrderNo, String dsOrderNo, String reqUrl, String reqHeadersJson, String reqBodyJson + , Integer httpStatusCode, String respBodyJson, Integer costMillis, String errorMessage) { + ApiInvokeLog logEntity = new ApiInvokeLog(); + logEntity.setConfigId(configId); + logEntity.setThirdPartyCode(thirdPartyCode); + logEntity.setApiCode(apiCode); + logEntity.setCsOrderNo(csOrderNo); + logEntity.setWeOrderNo(weOrderNo); + logEntity.setDsOrderNo(dsOrderNo); + logEntity.setReqUrl(reqUrl); + logEntity.setReqMethod("POST"); + logEntity.setReqHeaders(reqHeadersJson); + logEntity.setReqBody(reqBodyJson); + logEntity.setRespStatusCode(httpStatusCode); + logEntity.setRespBody(respBodyJson); + logEntity.setCostMillis(costMillis); + logEntity.setErrorMessage(errorMessage); + this.save(logEntity); + log.info("Invoke log saved: weOrderNo={}", weOrderNo); + } + }