package com.zy.acs.manager.common.interceptor; import com.alibaba.fastjson.JSON; import com.zy.acs.framework.common.Cools; import com.zy.acs.framework.common.R; import com.zy.acs.framework.common.SnowflakeIdWorker; import com.zy.acs.manager.common.interceptor.IntegrationOpenApiInterceptor.IntegrationRequestContext; import com.zy.acs.manager.common.interceptor.IntegrationOpenApiInterceptor.RequestPayload; import com.zy.acs.manager.common.utils.IpTools; import com.zy.acs.manager.manager.entity.IntegrationRecord; import com.zy.acs.manager.manager.enums.IntegrationDirectionType; import com.zy.acs.manager.manager.enums.StatusType; import com.zy.acs.manager.manager.service.IntegrationRecordService; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.Date; import java.util.UUID; @Slf4j @ControllerAdvice public class IntegrationRecordAdvice implements ResponseBodyAdvice { private static final String HEADER_APP_KEY = "appkey"; private static final String HEADER_CALLER = "caller"; @Autowired private IntegrationRecordService integrationRecordService; @Resource private SnowflakeIdWorker snowflakeIdWorker; @Override public boolean supports(@NotNull MethodParameter methodParameter, @NotNull Class> aClass) { return true; } @Override public Object beforeBodyWrite(Object body, @NotNull MethodParameter methodParameter, @NotNull MediaType mediaType, @NotNull Class> aClass, @NotNull ServerHttpRequest serverHttpRequest, @NotNull ServerHttpResponse serverHttpResponse) { if (!(serverHttpRequest instanceof ServletServerHttpRequest)) { return body; } HttpServletRequest request = ((ServletServerHttpRequest) serverHttpRequest).getServletRequest(); IntegrationRequestContext context = IntegrationOpenApiInterceptor.getContext(request); if (context == null) { return body; } IntegrationRecord record = null; try { record = buildRecord(body, request, context, null); } catch (Exception e) { log.error("Failed to build integration log for {}", context.getHandler(), e); record = buildRecord(null, request, context, e); } finally { if (record != null) { try { integrationRecordService.syncRecord(record); } catch (Exception persistEx) { log.error("Failed to persist integration log for {}", context.getHandler(), persistEx); } } } return body; } private IntegrationRecord buildRecord(Object responseBody, HttpServletRequest request, IntegrationRequestContext context, Exception failure) { Date now = new Date(); RequestPayload payload = context.getPayload(); IntegrationRecord record = new IntegrationRecord(); record.setUuid(nextUuid()); record.setNamespace(context.getNamespaceType().name()); record.setUrl(payload.getUri()); record.setAppkey(request.getHeader(HEADER_APP_KEY)); record.setCaller(resolveCaller(request)); record.setDirection(IntegrationDirectionType.INBOUND.value); record.setTimestamp(String.valueOf(context.getStartAt())); record.setClientIp(IpTools.gainRealIp(request)); record.setRequest(safeToJson(payload)); record.setResponse(safeToJson(responseBody)); applyResult(record, responseBody, failure); record.setCostMs(cost(context.getStartAt())); record.setStatus(StatusType.ENABLE.val); record.setCreateTime(now); record.setUpdateTime(now); record.setMemo(context.getHandler()); return record; } private void applyResult(IntegrationRecord record, Object body, Exception failure) { if (failure != null) { record.setResult(0); record.setErr(failure.getMessage()); return; } if (!(body instanceof R)) { record.setResult(null); record.setErr(null); return; } R response = (R) body; Integer code = parseInteger(response.get("code")); if (code == null) { record.setResult(null); record.setErr(null); return; } boolean success = code == 200; record.setResult(success ? 1 : 0); record.setErr(success ? null : safeToString(response.get("msg"))); } private Integer parseInteger(Object codeObj) { if (codeObj == null) { return null; } if (codeObj instanceof Integer) { return (Integer) codeObj; } try { return Integer.parseInt(String.valueOf(codeObj)); } catch (NumberFormatException e) { return null; } } private String safeToJson(Object value) { if (value == null) { return null; } try { return JSON.toJSONString(value); } catch (Exception e) { log.warn("Failed to serialize value for integration log: {}", value.getClass().getName(), e); return String.valueOf(value); } } private String resolveCaller(HttpServletRequest request) { String caller = request.getHeader(HEADER_CALLER); if (Cools.isEmpty(caller)) { caller = request.getHeader(HEADER_APP_KEY); } return caller; } private int cost(long startAt) { long duration = System.currentTimeMillis() - startAt; if (duration < 0) { return 0; } return (int) duration; } private String nextUuid() { if (snowflakeIdWorker != null) { return String.valueOf(snowflakeIdWorker.nextId()).substring(3); } return UUID.randomUUID().toString().replace("-", ""); } private String safeToString(Object value) { return value == null ? null : String.valueOf(value); } }