All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.emily.infrastructure.autoconfigure.exception.handler.GlobalExceptionCustomizer Maven / Gradle / Ivy

package com.emily.infrastructure.autoconfigure.exception.handler;

import com.emily.infrastructure.autoconfigure.response.annotation.ApiResponseWrapperIgnore;
import com.emily.infrastructure.autoconfigure.servlet.interceptor.ParameterInterceptor;
import com.emily.infrastructure.core.constant.AttributeInfo;
import com.emily.infrastructure.core.context.holder.LocalContextHolder;
import com.emily.infrastructure.core.context.holder.ServletStage;
import com.emily.infrastructure.core.entity.BaseLogger;
import com.emily.infrastructure.core.entity.BaseLoggerBuilder;
import com.emily.infrastructure.core.entity.BaseResponseBuilder;
import com.emily.infrastructure.core.exception.HttpStatusType;
import com.emily.infrastructure.core.exception.PrintExceptionInfo;
import com.emily.infrastructure.core.helper.RequestHelper;
import com.emily.infrastructure.core.helper.RequestUtils;
import com.emily.infrastructure.core.helper.ThreadPoolHelper;
import com.emily.infrastructure.date.DateComputeUtils;
import com.emily.infrastructure.date.DateConvertUtils;
import com.emily.infrastructure.date.DatePatternInfo;
import com.emily.infrastructure.json.JsonUtils;
import com.emily.infrastructure.logger.LoggerFactory;
import com.emily.infrastructure.sensitive.SensitiveUtils;
import com.google.common.collect.Maps;
import jakarta.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.method.HandlerMethod;

import java.lang.reflect.Method;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;

/**
 * 异常处理基础类
 *
 * @author Emily
 * @since Created in 2022/7/8 1:43 下午
 */
public class GlobalExceptionCustomizer {

    private static final Logger logger = LoggerFactory.getModuleLogger(GlobalExceptionCustomizer.class, "api", "request");

    /**
     * 对API请求异常处理,
     * 1.如果标记了ApiResponseWrapperIgnore注解,则统一去除包装
     * 2.否则添加外层包装
     *
     * @param handlerMethod  控制器方法处理对象
     * @param httpStatusType 异常状态枚举
     * @return 包装或为包装的结果
     */
    public static Object getApiResponseWrapper(HandlerMethod handlerMethod, HttpStatusType httpStatusType) {
        return getApiResponseWrapper(handlerMethod, httpStatusType.getStatus(), httpStatusType.getMessage());
    }

    /**
     * 对API请求异常处理,
     * 1.如果标记了ApiResponseWrapperIgnore注解,则统一去除包装
     * 2.否则添加外层包装
     *
     * @param handlerMethod 控制器方法处理对象
     * @param status        状态码
     * @param message       异常提示消息
     * @return 包装或为包装的结果
     */
    public static Object getApiResponseWrapper(HandlerMethod handlerMethod, int status, String message) {
        if (Objects.nonNull(handlerMethod)) {
            // 获取控制器方法
            Method method = handlerMethod.getMethod();
            if (method.isAnnotationPresent(ApiResponseWrapperIgnore.class)) {
                return message;
            }
        }
        return BaseResponseBuilder.create().withStatus(status).withMessage(message).build();
    }

    /**
     * 记录错误日志
     * ----------------------------------------------------------------------
     * 打印错误日志的场景:
     * 1.请求阶段标识为ServletStage.BEFORE_PARAMETER,即:部分参数校验异常;
     * 2.抛出的错误异常为HttpRequestMethodNotSupportedException,此异常不会进入{@link ParameterInterceptor},即:405 Method Not Allowed
     * ----------------------------------------------------------------------
     *
     * @param ex      异常对象
     * @param request 请求对象
     */
    public static void recordErrorMsg(Throwable ex, HttpServletRequest request) {
        //----------------------前置条件判断------------------------
        if (!(ServletStage.BEFORE_PARAMETER.equals(LocalContextHolder.current().getServletStage())
                || ex instanceof HttpRequestMethodNotSupportedException)) {
            return;
        }
        BaseLoggerBuilder builder = BaseLoggerBuilder.create()
                //系统编号
                .withSystemNumber(LocalContextHolder.current().getSystemNumber())
                //事务唯一编号
                .withTraceId(LocalContextHolder.current().getTraceId())
                //请求URL
                .withUrl(request.getRequestURI())
                //客户端IP
                .withClientIp(RequestUtils.getClientIp())
                //服务端IP
                .withServerIp(RequestUtils.getServerIp())
                //版本类型
                .withAppType(LocalContextHolder.current().getAppType())
                //版本号
                .withAppVersion(LocalContextHolder.current().getAppVersion())
                //触发时间
                .withTriggerTime(DateConvertUtils.format(LocalDateTime.now(), DatePatternInfo.YYYY_MM_DD_HH_MM_SS_SSS))
                //请求参数
                .withRequestParams(getRequestParams(ex, request))
                //响应体
                .withBody(PrintExceptionInfo.printErrorInfo(ex))
                //耗时(未处理任何逻辑)
                .withSpentTime(DateComputeUtils.minusMillis(Instant.now(), LocalContextHolder.current().getStartTime()));
        //日志
        BaseLogger baseLogger = builder.build();
        //API耗时
        LocalContextHolder.current().setSpentTime(baseLogger.getSpentTime());
        //记录日志到文件
        ThreadPoolHelper.defaultThreadPoolTaskExecutor().execute(() -> logger.info(JsonUtils.toJSONString(baseLogger)));
        //--------------------------后通知特殊条件判断-------------------------
        if (ex instanceof HttpRequestMethodNotSupportedException) {
            LocalContextHolder.unbind(true);
        }
    }

    /**
     * 获取请求参数
     *
     * @param ex      异常对象
     * @param request servlet对象
     * @return 请求参数
     */
    private static Map getRequestParams(Throwable ex, HttpServletRequest request) {
        Map paramsMap = Collections.emptyMap();
        //请求参数
        if (ex instanceof BindException) {
            BindingResult bindingResult = ((BindException) ex).getBindingResult();
            if (Objects.nonNull(bindingResult.getTarget())) {
                paramsMap = Maps.newLinkedHashMap();
                paramsMap.put(AttributeInfo.HEADERS, RequestHelper.getHeaders(request));
                paramsMap.put(AttributeInfo.PARAMS, SensitiveUtils.acquireElseGet(bindingResult.getTarget()));
            }
        }
        if (CollectionUtils.isEmpty(paramsMap)) {
            paramsMap = RequestHelper.getApiArgs(request);
        }
        return paramsMap;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy