Spring Boot2.x使用AOP进行请求和响应日志的打印

主要步骤

    • 1.导入jar包
    • 2.配置yml文件
    • 3.编写AOP切面
    • 4、日志切面的优化

1.导入jar包

加入该包后,spring boot默认就会开启aop了。


<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-aopartifactId>
dependency>

2.配置yml文件

强制使用cglib进行动态代理,默认使用的是Java的动态代理。

spring:
	aop:
	    #使用cglib进行代理
	    proxy-target-class: true

3.编写AOP切面

@Aspect
@Component
public class ControllerRequestAdvice {

	// 用于存放当前线程的请求时间,方便在日志中查看
    private static final ThreadLocal<Long> timeThreadLocal = new ThreadLocal<Long>();

    public static final Logger logger = LoggerFactory.getLogger(ControllerRequestAdvice.class);

    /**
     * 定义切点
     * execution表达式可以百度下,这里代表是controller下的所有public方法
     */
    @Pointcut("execution(public * per.mx.xxx.controller.*.*(..))")
    public void log() {

    }

    /**
     * 处理请求前处理
     *
     * @param joinPoint 连接点
     */
    @Before("log()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String client = request.getRemoteAddr();
        String method = request.getMethod();
        String requestURI = request.getRequestURI();
        String token = request.getHeader("token");
        Object[] args = joinPoint.getArgs();
        Map<String, Object> params = new HashMap<>();
        if (args.length > 0) {
            params = getParamMap(args);
        }
        long currentTimeMillis = System.currentTimeMillis();
        timeThreadLocal.set(currentTimeMillis);
        StringBuffer sb = new StringBuffer();
        sb.append("Request_").append(currentTimeMillis).append(" ");
        sb.append("<").append(client).append(">");
        sb.append(" ").append(method).append(" ");
        sb.append("\"").append(requestURI).append("\"");
        sb.append(" token:").append(token).append(" ");
        sb.append("params").append("=>").append(JSON.toJSONString(params));

        logger.info(sb.toString());
    }

    /**
     * 利用反射获取参数信息
     *
     * @return
     */
    private Map<String, Object> getParamMap(Object[] params) {
        Map<String, Object> map = new HashMap<String, Object>();
        for (Object param : params) {
        	if (param == null) {
                continue;
            }
            // 一些特殊的类不需要进行打印,他们的字段太多太多
            if (param instanceof HttpSession) {
                continue;
            }
            // 单文件
            if (param instanceof MultipartFile) {
                map.put("file", getFileParam((MultipartFile) param));
                continue;
            }
            // 多文件
            if (param instanceof MultipartFile[]) {
                MultipartFile[] files = (MultipartFile[]) param;
                Map<String, Object> tmp = new HashMap<>();
                for (MultipartFile file : files) {
                    Map<String, Object> fileParam = getFileParam(file);
                    tmp.put("file", fileParam);
                }
                map.put("files", tmp);
                continue;
            }
            // 处理没有用vm封装的参数
            if (param instanceof String || param instanceof Integer || param instanceof Boolean ||
                    param instanceof Byte || param instanceof Short || param instanceof Long ||
                    param instanceof Character || param instanceof Float || param instanceof Double) {
                map.put(param.getClass().getSimpleName(), param.toString());
                continue;
            }
            Field[] fields = param.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);// 设置访问private修饰的字段的值
                Object val = new Object();
                try {
                    val = field.get(param);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                map.put(field.getName(), val);
            }
        }
        return map;
    }

    /**
     * 处理请求后返回
     *
     * @param obj 返回值
     */
    @AfterReturning(pointcut = "log()", returning = "obj")
    public void afterReturning(Object obj) {
        logger.info("Response_" + timeThreadLocal.get() + " => " + JSON.toJSONString(obj));
    }

	/**
	 * 处理文件参数
	 * 
	 * @param file 文件
	 */
    private Map<String, Object> getFileParam(MultipartFile file) {
        Map<String, Object> fileMap = new HashMap<>();
        fileMap.put("文件名", file.getOriginalFilename());
        fileMap.put("文件类型", file.getContentType());
        fileMap.put("文件大小", FileUtil.getFileSize(file.getSize()));
        return fileMap;
    }
}

4、日志切面的优化

@Aspect
@Component
public class ControllerRequestAdvice {

    private static final ThreadLocal<Long> timeThreadLocal = new ThreadLocal<Long>();

    public static final Logger logger = LoggerFactory.getLogger(ControllerRequestAdvice.class);

    /**
     * 定义切点
     */
    @Pointcut("execution(public * per.mx.xxx.controller.*.*(..))")
    public void log() {

    }

    /**
     * 处理请求前处理
     *
     * @param joinPoint 连接点
     */
    @Before("log()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String[] parameterNames = methodSignature.getParameterNames();
        Object[] args = joinPoint.getArgs();

        String client = request.getRemoteAddr();
        String method = request.getMethod();
        String requestURI = request.getRequestURI();
        String token = request.getHeader("token");

        long currentTimeMillis = System.currentTimeMillis();
        timeThreadLocal.set(currentTimeMillis);

        Map<String, Object> params = new HashMap<>();
        for (int i = 0; i < parameterNames.length; i++) {
            String parameterName = parameterNames[i];
            Object parameterValue = args[i];
            if (parameterValue instanceof MultipartFile) {
                Map<String, Object> f = getFileParam((MultipartFile) parameterValue);
                params.put(parameterName, f);
                continue;
            }
            params.put(parameterName, parameterValue);
        }

        StringBuffer sb = new StringBuffer();
        sb.append("Request_").append(currentTimeMillis).append(" ");
        sb.append("<").append(client).append(">");
        sb.append(" ").append(method).append(" ");
        sb.append("\"").append(requestURI).append("\"");
        sb.append(" token:").append(token).append(" ");
        sb.append("params").append("=>").append(JSON.toJSONString(params));

        logger.info(sb.toString());
    }

    /**
     * 处理请求后返回
     *
     * @param obj 返回值
     */
    @AfterReturning(pointcut = "log()", returning = "obj")
    public void afterReturning(Object obj) {
        logger.info("Response_" + timeThreadLocal.get() + " => " + JSON.toJSONString(obj));
    }

    private Map<String, Object> getFileParam(MultipartFile file) {
        Map<String, Object> params = new HashMap<>();
        params.put("文件名", file.getOriginalFilename());
        params.put("文件类型", file.getContentType());
        params.put("文件大小", FileUtil.getFileSize(file.getSize()));
        return params;
    }
}

你可能感兴趣的:(Spring,Boot)