springboot 注解+AOP实现接口方法出入参打印

注解+AOP实现接口方法出入参打印

    • 0、前言
    • 1、自定义注解
    • 2、定义AOP
    • 3、封装日志打印方法

0、前言

针对加入spring bean容器的实例方法,通过注解+aop实现打印方法调用的出入参,通过注解可以配置是否打印出入参,出入参中的单列集合或双列集合是否打印,选择非全量打印只会打印集合的大小

1、自定义注解

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface LogFormatConsole {

    /**
     * 入参
     * 是否打印全量参数   true-集合类型全量打印 false-集合类型只打印数量
     */
    boolean isFullPrintReq() default true;

    /**
     * 出参
     * 是否打印全量参数  true-集合类型全量打印 false-集合类型只打印数量
     */
    boolean isFullPrintResp() default false;

    /**
     * 是否打印入参 默认打印
     */
    boolean isPrintReqParam() default true;

    /**
     * 是否打印出参 默认打印
     */
    boolean isPrintRespParam() default true;
}

2、定义AOP

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.lqt.hospital.platform.common.annotation.LogFormatConsole;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;

import static com.lqt.hospital.platform.common.utils.ToolsUtil.*;

/**
 * @DATE: 2023/12/28 18:45
 * @Author: 小爽帅到拖网速
 */
@Aspect
@Component
public class FormatConsoleAop {

    /**
     * 日志打印切入点
     */
    @Pointcut("@within(com.lqt.hospital.platform.common.annotation.LogFormatConsole) || @annotation(com.lqt.hospital.platform.common.annotation.LogFormatConsole)")
    private void consolePointCut() {
    }

    @Around("consolePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // 获取目标签名和方法
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        // 目标方法名
        String methodName = method.getName();
        // 获取目标方法注解
        LogFormatConsole anno = method.getAnnotation(LogFormatConsole.class);
        // 是否全量打印集合参数-入参
        boolean fullPrintReq = anno.isFullPrintReq();
        // 是否全量打印集合参数-出参
        boolean fullPrintResp = anno.isFullPrintResp();
        // 是否打印入参
        boolean printReqParam = anno.isPrintReqParam();
        // 是否打印出参
        boolean printRespParam = anno.isPrintRespParam();
        if (printReqParam) {
            // 打印入参
            // 获取方法的参数列表
            String[] parameterNames = signature.getParameterNames();
            // 获取参数值
            Object[] args = point.getArgs();
            if (args.length > 0) {
                // 构建请求入参集
                Map<String, Object> reqParamMap = buildReqParamMap(fullPrintReq, parameterNames, args);
                // 打印请求入参
                formatConsoleInfoLogReq(methodName, reqParamMap, (boolean) reqParamMap.get("fullPrintReq"));
            }
        }
        // 执行目标方法
        Object result = point.proceed();
        if (printRespParam) {
            // 打印出参
            formatConsoleInfoLogResp(methodName, result, fullPrintResp);
        }
        return result;
    }

    /**
     * 构建请求入参集
     */
    private Map<String, Object> buildReqParamMap(boolean fullPrintReq, String[] parameterNames, Object[] args) {
        String sizeStr;
        Map<String, Object> reqParamMap = Maps.newHashMap();
        boolean nofullPrintFlag = false;
        for (int i = 0; i < Math.min(parameterNames.length, args.length); i++) {
            // 参数值
            final Object arg = args[i];
            // 参数名
            final String parameterName = parameterNames[i];
            if (ObjectUtil.hasEmpty(arg, parameterName)) {
                continue;
            }
            if (arg instanceof HttpServletRequest) {
                // 提取HttpServletRequest有效信息
                putReqHeaderIntoMap(reqParamMap, (HttpServletRequest) arg);
            } else if (!fullPrintReq) {
                // 标识部分不全量打印
                nofullPrintFlag = true;
                // 针对集合参数,打印集合大小
                if (arg instanceof Collection) {
                    // 单列集合
                    sizeStr = "size=" + ((Collection<?>) arg).size();
                    reqParamMap.put(parameterName, sizeStr);
                }
                // else if (args[i] instanceof Map) {
                //     // 双列集合
                //     sizeStr = "size=" + ((Map) args[i]).size();
                //     reqParamMap.put(parameterNames[i], sizeStr);
                // }
                else {
                    // pojo
                    reqParamMap.put(parameterName, arg);
                }
            } else {
                // pojo
                reqParamMap.put(parameterName, arg);
            }
        }
        if (!fullPrintReq) {
            // 标识部分不全量打印
            fullPrintReq = nofullPrintFlag;
        }
        reqParamMap.put("fullPrintReq", fullPrintReq);
        return reqParamMap;
    }

    /**
     * 提取HttpServletRequest有效信息
     */
    private void putReqHeaderIntoMap(Map<String, Object> map, HttpServletRequest request) {
        String unitId = request.getHeader("UnitId");
        String userId = request.getHeader("UserId");
        map.put("unitId", unitId);
        map.put("userId", userId);
    }

}

3、封装日志打印方法

@Log4j2
public class ToolsUtil {  

	 /**
     * 格式化打印info日志
     *
     * @param methodName     方法名
     * @param mainMsg        主信息
     * @param param          参数
     * @param isFullPrint 是否不打印全量参数  true-集合类型只打印数量 false-集合类型全量打印
     */
    public static void formatConsoleInfoLog(String methodName, String mainMsg, Object param, boolean isFullPrint) {
        if (ObjectUtil.hasEmpty(methodName, param)) {
            return;
        }
        String paramStr = null;
        if (param instanceof Number) {
            // 数值类型
            paramStr = param.toString();
        } else if (!isFullPrint) {
            // 不进行全量打印
            if (param instanceof Collection) {
                // 单列集合
                paramStr = String.valueOf(((Collection<?>) param).size());
                mainMsg = mainMsg + "size";
            }
            // else if (param instanceof Map) {
            //     // 双列集合
            //     paramStr = String.valueOf(((Map) param).size());
            //     mainMsg = mainMsg + "size";
            // }
            else if (param instanceof Result) {
                // 针对Result data里边存在的单列或双列集合进行处理
                Object data = ((Result<?>) param).getData();
                if (data instanceof Collection) {
                    data = "size=" + ((Collection<?>) data).size();
                }
                // else if (data instanceof Map) {
                //     data = "size=" + ((Map) data).size();
                // }
                ((Result) param).setData(data);
                paramStr = JSONUtil.toJsonStr(param);
            }
        } else {
            // pojo
            paramStr = JSONUtil.toJsonStr(param);
        }
        log.info("[{}] {}:{}", methodName, mainMsg, paramStr);
    }

    /**
     * 格式化打印info日志-请求入参
     *
     * @param methodName     方法名
     * @param param          参数
     * @param isFullPring 是否不打印全量参数  true-集合类型只打印数量 false-集合类型全量打印
     */
    public static void formatConsoleInfoLogReq(String methodName, Object param, boolean isFullPring) {
        formatConsoleInfoLog(methodName, "请求入参", param, isFullPring);
    }

    /**
     * 格式化打印info日志-请求出参
     *
     * @param methodName     方法名
     * @param param          参数
     * @param isFullPring 是否不打印全量参数  true-集合类型只打印数量 false-集合类型全量打印
     */
    public static void formatConsoleInfoLogResp(String methodName, Object param, boolean isFullPring) {
        formatConsoleInfoLog(methodName, "接口出参", param, isFullPring);
    }
}

你可能感兴趣的:(SpringBoot,spring,boot,后端,java)