【整理】使用AOP打印接口参数

版权声明:如需非商业性转载,请保留署名,注明出处。如需商业性转载出版,请直接和我联系。 https://blog.csdn.net/btboyhappy/article/details/82383264

本文主要整理了使用AOP切面获取接口调用时的入参出参并打印相关日志的过程,修改打印范围可以通过修改@Around注解中的包名来修改,以下是实现代码:

package com.chongtong.aop;

import com.google.gson.Gson;
import javassist.*;
import javassist.bytecode.*;
import org.apache.commons.lang3.*;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.*;

import javax.servlet.http.HttpServletRequest;
import java.time.*;
import java.time.format.DateTimeFormatter;

@Aspect
@Component
public class LogAop {
    private Logger logger = LoggerFactory.getLogger(LogAop.class);
    private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * @param pjp
     * @return
     * @throws Throwable
     * @Title:doAround
     * @Description: 环绕触发
     */
    @Around("execution(* com.chongtong.web..*.*(..))")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        String inputParam = getMethodParams(pjp);
        // 获取请求地址
        String requestPath = request.getRequestURI();
        Instant startTime = Instant.now();
        // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
        Object obj = pjp.proceed();
        // result的值就是被拦截方法的返回值
        String result = obj instanceof String ? (String) obj : new Gson().toJson(obj);
        Instant endTime = Instant.now();
        String optTime = startTime.atZone(ZoneId.systemDefault()).format(dtf);
        long pro_time = Duration.between(startTime, endTime).toMillis();
        StringBuffer sb = new StringBuffer();
        sb.append("\n 用户名:").append("todo").append("\n 访问接口地址:").append(requestPath)
                .append("\n 开始请求的时间:").append(optTime).append("\n 接口耗时:").append(pro_time).append("ms")
                .append("\n 请求参数:{\"request\":").append(inputParam).append("}")
                .append("\n 响应参数:{\"result\":").append(result).append("}");
        logger.info(sb.toString());
        return obj;
    }

    /**
     * 打印类method的名称以及参数
     *
     * @param point 切面
     */
    public String getMethodParams(JoinPoint point) {
        if (point == null) {
            return null;
        }
        //Signature 包含了方法名、申明类型以及地址等信息
        String class_name = point.getTarget().getClass().getName();
        String method_name = point.getSignature().getName();
        // 重新定义日志
        logger = LoggerFactory.getLogger(point.getTarget().getClass());
        //获取方法的参数值数组。
        Object[] method_args = point.getArgs();
        try {
            //获取方法参数名称
            String[] paramNames = getFieldsName(class_name, method_name);
            //打印方法的参数名和参数值
            return logParam(paramNames, method_args);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 使用javassist来获取方法参数名称
     *
     * @param class_name  类名
     * @param method_name 方法名
     * @return
     * @throws Exception
     */
    private String[] getFieldsName(String class_name, String method_name) throws Exception {
        Class<?> clazz = Class.forName(class_name);
        String clazz_name = clazz.getName();
        ClassPool pool = ClassPool.getDefault();
        ClassClassPath classPath = new ClassClassPath(clazz);
        pool.insertClassPath(classPath);

        CtClass ctClass = pool.get(clazz_name);
        CtMethod ctMethod = ctClass.getDeclaredMethod(method_name);
        MethodInfo methodInfo = ctMethod.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute
                .getAttribute(LocalVariableAttribute.tag);
        if (attr == null) {
            return null;
        }
        String[] paramsArgsName = new String[ctMethod.getParameterTypes().length];
        int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;
        for (int i = 0; i < paramsArgsName.length; i++) {
            paramsArgsName[i] = attr.variableName(i + pos);
        }
        return paramsArgsName;
    }

    /**
     * 判断是否为基本类型:包括String
     *
     * @param clazz clazz
     * @return true:是; false:不是
     */
    private boolean isPrimite(Class<?> clazz) {
        if (clazz.isPrimitive() || clazz == String.class) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 打印方法参数值 基本类型直接打印,非基本类型需要转成json字符串方法
     *
     * @param paramsArgsName  方法参数名数组
     * @param paramsArgsValue 方法参数值数组
     * @return
     */
    private String logParam(String[] paramsArgsName, Object[] paramsArgsValue) {
        if (ArrayUtils.isEmpty(paramsArgsName) || ArrayUtils.isEmpty(paramsArgsValue)) {
            logger.info("该方法没有参数");
            return null;
        }
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < paramsArgsName.length; i++) {
            // 参数名
            String name = paramsArgsName[i];
            // 参数值
            Object value = paramsArgsValue[i];
            buffer.append(name + " = ");
            if (isPrimite(value.getClass())) {
                buffer.append(value + "  ,");
            } else {
                buffer.append(new Gson().toJson(value) + "  ,");
            }
        }
        return StringUtils.removeEndIgnoreCase(buffer.toString(), "  ,");
    }
}

猜你喜欢

转载自blog.csdn.net/btboyhappy/article/details/82383264