Configure logs in AOP mode, print uri, url, input parameter name, input parameter value, and return result.

1、maven的pom配置,javassist和gson的jar依赖。

<!--GSON  add by yxt 2020.10.15 -->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.6.2</version>
</dependency>

<!--javassist  add by yxt 2020.10.15 -->
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.20.0-GA</version>
</dependency>
2、java的aop配置代码:


package com.brilliance.avictc.wealth.filter;

import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

import java.lang.reflect.Method;

import com.google.gson.Gson;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @describe: 统一处理打印入参到日志
 * @date: 2020-10-15
 * @author: yxt
 */
@Component  //声明组件
@Aspect //  声明切面
@ComponentScan  //组件自动扫描
@EnableAspectJAutoProxy //spring自动切换JDK动态代理和CGLIB
public class LoggerByAop {

    /**
     *自定义日志
     */
    private Logger logger = LoggerFactory.getLogger(LoggerByAop.class);

    /**
     * Before : 在方法执行前进行切面
     * execution : 定义切面表达式,多个用||分隔
     * public * com.eparty.ccp.*.impl..*.*(..)
     * *  *..*.*.controller..*.*(..)
     * public :匹配所有目标类的public方法,不写则匹配所有访问权限
     * 第一个* :方法返回值类型,*代表所有类型
     * 第二个* :包路径的通配符
     * 第三个..* :表示impl这个目录下所有的类,包括子目录的类
     * 第四个*(..) : *表示所有任意方法名,..表示任意参数
     * @param point 切面
     */
    @Before("execution(public * com.brilliance.avictc.wealth.controller.*.*(..)) || execution(* com.brilliance.avictc.wealth.service.UAPApiService.*(..))||execution(public * com.brilliance.avictc.wealth.property.controller.*.*(..))")
    public void before(JoinPoint point) {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime",startTime);
        this.printMethodParams(point);
    }

    /**
     * 打印类method的名称以及参数
     * @param point 切面
     */
    public void printMethodParams(JoinPoint point){
        if(point == null){
            return;
        }
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        // long costTime = System.currentTimeMillis() - (long) request.getAttribute("startTime");
        //String url = request.getRequestURL().toString();
        String uri = request.getRequestURI();
        // logger.info("uri为:{}___{},————————总耗时:{}",uri,endTime-startTime);
         // 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 {
             // 获取方法参数名称
            Map<Object, Object> paramMap = new HashMap<>();
            Map<String, String[]>maps =  request.getParameterMap();
            if(maps != null){
                for (Map.Entry<String, String[]> entry : maps.entrySet()) {
                    paramMap.put(entry.getKey(),Arrays.toString(entry.getValue()));
//                param = entry.getKey() + ":"+Arrays.toString(entry.getValue())+";";
                }
            }
            String param = paramMap.toString();
            //String[] paramNames = getFieldsName(class_name, method_name);
            String[] paramNamesCrm = getFieldsName(class_name, method_name);
             // 打印方法的参数名和参数值
            String paramCrm = logParam(paramNamesCrm, method_args);
            if("com.brilliance.avictc.wealth.service.UAPApiService".equals(class_name)){
                logger.info("..... 调用crm接口入参信息 .....:uri:{},{}.{}:{}" , uri, class_name, method_name, paramCrm);
            }else{
                logger.info("***** 客户端接口入参信息 *****:uri:{},{}.{}:{}",uri, class_name, method_name, param);
            }

        } catch (Exception e) {
            logger.error("切面获取入参的参数名和参数值时,发生异常,异常信息为:"+e);
        }
    }

    /**
     * 使用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;
        }
    }


    /**
     * 打印方法参数值  基本类型直接打印,非基本类型需要重写toString方法
     * @param paramsArgsName    方法参数名数组
     * @param paramsArgsValue   方法参数值数组
     */
    private String logParam(String[] paramsArgsName,Object[] paramsArgsValue){
        String resultStr = "";
        if(ArrayUtils.isEmpty(paramsArgsName) || ArrayUtils.isEmpty(paramsArgsValue)){
            logger.info("该方法没有参数");
            return resultStr;
        }
        // StringBuffer buffer = new StringBuffer();
        Map<String, Object> argsMap = new HashMap<>();
        for (int i=0;i<paramsArgsName.length;i++){
            //参数名
            String name = paramsArgsName[i];
            //参数值
            Object value = paramsArgsValue[i];
            argsMap.put(name,value);
            // buffer.append(name +" = ");
//            if(isPrimite(value.getClass())){
//                buffer.append(value + "  ,");

//            }else {
//                buffer.append(value.toString() + "  ,");
//            }
        }
        resultStr = argsMap.toString();
        return resultStr;
    }

    // 统一切点,对com.hangtian.admin.controller及其子包中所有的类的所有方法切面
    @Pointcut("execution(public * com.brilliance.avictc.wealth.controller.*.*(..)) || execution(* com.brilliance.avictc.wealth.service.UAPApiService.*(..))||execution(public * com.brilliance.avictc.wealth.property.controller.*.*(..))")
     public void Pointcut() {
    }

    @AfterReturning(value="Pointcut()",returning="rvt")
     public void after(JoinPoint joinPoint,Object rvt){
         MethodSignature sig1 = (MethodSignature)joinPoint.getSignature();
         Method method1 = sig1.getMethod();
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        long costTime = System.currentTimeMillis() - (long) request.getAttribute("startTime");
         if(null != rvt && null != method1.getDeclaringClass()){
             try{
                 if("com.brilliance.avictc.wealth.service.UAPApiService".equals(method1.getDeclaringClass().getName())){
                     logger.info("----- 调用crm接口返回结果 -----:time:{},{}.{}:{}" ,costTime, method1.getDeclaringClass().getName(),method1.getName(),new Gson().toJson(rvt));
                 }else{
                     logger.info("===== 客户端返结果为 =====:time:{},{}.{} :{}",costTime, method1.getDeclaringClass().getName(),method1.getName(),new Gson().toJson(rvt));
                 }
             }catch (Exception e){
                 logger.error("切面获取返回值时,发生异常,异常信息为:"+e);
             }
         }
    }
}

 

Guess you like

Origin blog.csdn.net/weixin_41267342/article/details/109120191