| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- package com.zsElectric.boot.charging.aspect;
- import cn.hutool.core.util.StrUtil;
- import com.fasterxml.jackson.annotation.JsonInclude;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.zsElectric.boot.charging.entity.ThirdPartyApiLog;
- import com.zsElectric.boot.charging.service.ThirdPartyApiLogService;
- import com.zsElectric.boot.common.util.electric.ChargingUtil;
- import com.zsElectric.boot.common.util.electric.RequestParmsEntity;
- import com.zsElectric.boot.common.util.electric.ResponseParmsEntity;
- import jakarta.servlet.http.HttpServletRequest;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Pointcut;
- import org.springframework.stereotype.Component;
- import org.springframework.web.context.request.RequestContextHolder;
- import org.springframework.web.context.request.ServletRequestAttributes;
- import java.time.LocalDateTime;
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Map;
- import java.util.Set;
- /**
- * 第三方接口日志记录切面
- * 拦截 LinkDataController 和 ChargingBusinessController 的所有方法,自动记录请求和响应日志
- *
- * @author system
- * @since 2025-01-02
- */
- @Slf4j
- @Aspect
- @Component
- @RequiredArgsConstructor
- public class ThirdPartyApiLogAspect {
- private final ThirdPartyApiLogService thirdPartyApiLogService;
- private final ObjectMapper objectMapper;
- private final ChargingUtil chargingUtil;
-
- /** 需要保留的关键请求头 */
- private static final Set<String> IMPORTANT_HEADERS = new HashSet<>(Arrays.asList(
- "content-type", "authorization", "content-length"
- ));
- /**
- * 定义切入点: LinkDataController 的所有方法
- */
- @Pointcut("execution(* com.zsElectric.boot.charging.controller.LinkDataController.*(..))")
- public void linkDataControllerPointcut() {
- }
- /**
- * 定义切入点: ChargingBusinessController 的所有方法
- */
- @Pointcut("execution(* com.zsElectric.boot.charging.controller.ChargingBusinessController.*(..))")
- public void chargingBusinessControllerPointcut() {
- }
- /**
- * 环绕通知: 记录 LinkDataController 接口日志
- */
- @Around("linkDataControllerPointcut()")
- public Object aroundLinkDataController(ProceedingJoinPoint joinPoint) throws Throwable {
- return recordApiLog(joinPoint, "LinkDataController", 2); // 2-接收推送
- }
- /**
- * 环绕通知: 记录 ChargingBusinessController 接口日志
- */
- @Around("chargingBusinessControllerPointcut()")
- public Object aroundChargingBusinessController(ProceedingJoinPoint joinPoint) throws Throwable {
- return recordApiLog(joinPoint, "ChargingBusinessController", 1); // 1-请求出去
- }
- /**
- * 记录接口日志的通用方法
- */
- private Object recordApiLog(ProceedingJoinPoint joinPoint, String controllerName, Integer logType) throws Throwable {
- long startTime = System.currentTimeMillis();
- ThirdPartyApiLog apiLog = new ThirdPartyApiLog();
-
- // 获取 HttpServletRequest
- ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
- HttpServletRequest request = attributes != null ? attributes.getRequest() : null;
-
- try {
- // 设置基本信息
- apiLog.setLogType(logType);
- apiLog.setControllerName(controllerName);
- LocalDateTime now = LocalDateTime.now();
- apiLog.setCreatedTime(now);
- apiLog.setUpdatedTime(now);
-
- if (request != null) {
- // 请求信息
- apiLog.setRequestMethod(request.getMethod());
- apiLog.setRequestUrl(request.getRequestURL().toString());
- apiLog.setInterfaceName(request.getRequestURI());
- apiLog.setInterfaceDescription(getInterfaceDescription(request.getRequestURI()));
- apiLog.setClientIp(getClientIp(request));
- apiLog.setUserAgent(request.getHeader("User-Agent"));
-
- // 请求头(只保留关键信息)
- apiLog.setRequestHeaders(getSimplifiedHeaders(request));
-
- // 请求参数
- Map<String, String[]> parameterMap = request.getParameterMap();
- if (!parameterMap.isEmpty()) {
- // 简化参数格式,单值的数组转为简单字符串
- Map<String, Object> simplifiedParams = new HashMap<>();
- for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
- String[] values = entry.getValue();
- if (values != null && values.length == 1) {
- simplifiedParams.put(entry.getKey(), values[0]);
- } else {
- simplifiedParams.put(entry.getKey(), values);
- }
- }
- apiLog.setRequestParams(objectMapper.writeValueAsString(simplifiedParams));
- }
-
- // 请求体(从切点参数中获取)
- Object[] args = joinPoint.getArgs();
- if (args != null && args.length > 0) {
- for (Object arg : args) {
- if (arg != null && !(arg instanceof HttpServletRequest) && !(arg instanceof jakarta.servlet.http.HttpServletResponse)) {
- // 序列化时忽略null值
- ObjectMapper cleanMapper = objectMapper.copy();
- cleanMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
- apiLog.setRequestBody(cleanMapper.writeValueAsString(arg));
-
- // 尝试提取业务字段
- extractBusinessFields(arg, apiLog);
-
- // 尝试解密请求数据(针对 RequestParmsEntity 类型)
- decryptRequestData(arg, apiLog);
- break;
- }
- }
- }
- }
-
- // 执行目标方法
- Object result = joinPoint.proceed();
-
- // 记录响应
- long endTime = System.currentTimeMillis();
- apiLog.setResponseTime(endTime - startTime);
- apiLog.setResponseStatus(200);
- apiLog.setIsSuccess(1);
-
- if (result != null) {
- // 序列化时忽略null值
- ObjectMapper cleanMapper = objectMapper.copy();
- cleanMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
- apiLog.setResponseBody(cleanMapper.writeValueAsString(result));
-
- // 解密响应数据(针对 ResponseParmsEntity 类型)
- decryptResponseData(result, apiLog);
- }
-
- // 异步保存日志
- thirdPartyApiLogService.saveLogAsync(apiLog);
-
- return result;
-
- } catch (Exception e) {
- // 记录异常
- long endTime = System.currentTimeMillis();
- apiLog.setResponseTime(endTime - startTime);
- apiLog.setResponseStatus(500);
- apiLog.setIsSuccess(0);
- apiLog.setErrorMessage(e.getMessage());
-
- // 异步保存日志
- thirdPartyApiLogService.saveLogAsync(apiLog);
-
- throw e;
- }
- }
- /**
- * 解密请求数据
- * 针对 LinkDataController 接收的 RequestParmsEntity 类型参数进行解密
- */
- private void decryptRequestData(Object requestBody, ThirdPartyApiLog apiLog) {
- try {
- if (requestBody instanceof RequestParmsEntity) {
- RequestParmsEntity requestParms = (RequestParmsEntity) requestBody;
- String encryptedData = requestParms.getData();
-
- if (StrUtil.isNotBlank(encryptedData)) {
- // 使用 ChargingUtil 解密(与业务代码保持一致)
- String decryptedData = chargingUtil.decryptData(encryptedData);
- apiLog.setDecryptedRequestData(decryptedData);
- log.debug("请求数据解密成功: {}", decryptedData);
- }
- }
- } catch (Exception e) {
- log.warn("解密请求数据失败: {}", e.getMessage());
- }
- }
- /**
- * 解密响应数据
- * 针对返回的 ResponseParmsEntity 类型响应进行解密
- */
- private void decryptResponseData(Object responseBody, ThirdPartyApiLog apiLog) {
- try {
- if (responseBody instanceof ResponseParmsEntity) {
- ResponseParmsEntity responseParms = (ResponseParmsEntity) responseBody;
- String encryptedData = responseParms.getData();
-
- if (StrUtil.isNotBlank(encryptedData)) {
- // 使用 ChargingUtil 解密(与业务代码保持一致)
- String decryptedData = chargingUtil.decryptData(encryptedData);
- apiLog.setDecryptedResponseData(decryptedData);
- log.debug("响应数据解密成功: {}", decryptedData);
- }
- }
- } catch (Exception e) {
- log.warn("解密响应数据失败: {}", e.getMessage());
- }
- }
- /**
- * 提取业务字段
- */
- private void extractBusinessFields(Object requestBody, ThirdPartyApiLog apiLog) {
- try {
- String json = objectMapper.writeValueAsString(requestBody);
- Map<String, Object> map = objectMapper.readValue(json, Map.class);
-
- // 提取运营商ID
- if (map.containsKey("OperatorID")) {
- apiLog.setOperatorId(String.valueOf(map.get("OperatorID")));
- } else if (map.containsKey("operatorID")) {
- apiLog.setOperatorId(String.valueOf(map.get("operatorID")));
- }
-
- // 提取充电站ID
- if (map.containsKey("StationID")) {
- apiLog.setStationId(String.valueOf(map.get("StationID")));
- } else if (map.containsKey("stationID")) {
- apiLog.setStationId(String.valueOf(map.get("stationID")));
- }
-
- // 提取充电桩ID
- if (map.containsKey("ConnectorID")) {
- apiLog.setConnectorId(String.valueOf(map.get("ConnectorID")));
- } else if (map.containsKey("connectorID")) {
- apiLog.setConnectorId(String.valueOf(map.get("connectorID")));
- }
-
- // 提取业务流水号
- if (map.containsKey("StartChargeSeq")) {
- apiLog.setBusinessSeq(String.valueOf(map.get("StartChargeSeq")));
- } else if (map.containsKey("startChargeSeq")) {
- apiLog.setBusinessSeq(String.valueOf(map.get("startChargeSeq")));
- } else if (map.containsKey("EquipAuthSeq")) {
- apiLog.setBusinessSeq(String.valueOf(map.get("EquipAuthSeq")));
- } else if (map.containsKey("equipAuthSeq")) {
- apiLog.setBusinessSeq(String.valueOf(map.get("equipAuthSeq")));
- } else if (map.containsKey("EquipBizSeq")) {
- apiLog.setBusinessSeq(String.valueOf(map.get("EquipBizSeq")));
- } else if (map.containsKey("equipBizSeq")) {
- apiLog.setBusinessSeq(String.valueOf(map.get("equipBizSeq")));
- }
-
- } catch (Exception e) {
- log.debug("提取业务字段失败: {}", e.getMessage());
- }
- }
- /**
- * 获取简化的请求头信息(只保留关键字段)
- */
- private String getSimplifiedHeaders(HttpServletRequest request) {
- try {
- Map<String, String> headers = new HashMap<>();
- for (String headerName : IMPORTANT_HEADERS) {
- String headerValue = request.getHeader(headerName);
- if (StrUtil.isNotBlank(headerValue)) {
- // 对于 authorization 只保留类型,不记录完整 token
- if ("authorization".equalsIgnoreCase(headerName) && headerValue.length() > 20) {
- headers.put(headerName, headerValue.substring(0, 20) + "...");
- } else {
- headers.put(headerName, headerValue);
- }
- }
- }
- return headers.isEmpty() ? null : objectMapper.writeValueAsString(headers);
- } catch (Exception e) {
- log.error("获取请求头失败: {}", e.getMessage());
- return null;
- }
- }
- /**
- * 获取接口中文说明
- * 根据接口路径返回对应的中文说明
- */
- private String getInterfaceDescription(String uri) {
- if (StrUtil.isBlank(uri)) {
- return null;
- }
-
- // LinkDataController 接口说明
- if (uri.contains("/query_token")) {
- return "获取token";
- } else if (uri.contains("/notification_start_charge_result")) {
- return "推送启动充电结果";
- } else if (uri.contains("/notification_equip_charge_status")) {
- return "推送充电状态";
- } else if (uri.contains("/notification_stop_charge_result")) {
- return "推送停止充电结果";
- } else if (uri.contains("/notification_charge_order_info")) {
- return "推送充电订单信息";
- } else if (uri.contains("/notification_stationStatus")) {
- return "设备状态变化推送";
- }
- // ChargingBusinessController 接口说明
- else if (uri.contains("/queryEquipBusinessPolicy")) {
- return "查询业务策略信息";
- } else if (uri.contains("/queryEquipAuth")) {
- return "请求设备认证";
- } else if (uri.contains("/queryStationsInfo")) {
- return "查询充电站信息";
- } else if (uri.contains("/queryStationStatus")) {
- return "设备接口状态查询";
- } else if (uri.contains("/startCharging")) {
- return "请求启动充电";
- } else if (uri.contains("/queryChargingStatus")) {
- return "查询充电状态";
- } else if (uri.contains("/stopCharging")) {
- return "请求停止充电";
- }
-
- return null;
- }
- /**
- * 获取客户端真实IP
- */
- private String getClientIp(HttpServletRequest request) {
- String ip = request.getHeader("X-Forwarded-For");
- if (StrUtil.isNotBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
- // 多次反向代理后会有多个IP值,第一个为真实IP
- int index = ip.indexOf(',');
- if (index != -1) {
- return ip.substring(0, index);
- }
- return ip;
- }
-
- ip = request.getHeader("X-Real-IP");
- if (StrUtil.isNotBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
- return ip;
- }
-
- return request.getRemoteAddr();
- }
- }
|