SpringAOP实现拦截Controller请求参数并输出到日志

一、实现的效果

请求:

http://localhost:8080/regist?username=king&age=12&password=123456

Controller:

@RestController
public class UserController {

    @RequestMapping("/regist")
    public Apiresult userRegister(@ModelAttribute User user) {
    //....
    return Apiresult.success("ok");
    }
    //user类包含username,age,password属性,并重写了tostring方法
}

控制台

---------Path: /regist
---------ClassName: UserController
---------MethodName: userRegister
---------ParamList: {username:king,age:12,password:123456}

二、这样做的原因

1.方便调试,和前台联调可以直接看到参数
2.记录信息,方便回查。

三、实现代码

package com.kingboy.common.tools.log;

import lombok.extern.log4j.Log4j;
import org.aspectj.lang.JoinPoint;
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.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Objects;
import java.util.stream.Stream;

/**
 * @author [email protected]
 * @date 2017/11/19 下午10:10
 * @desc 方法接收的参数日志.
 */
@Log4j
@Aspect
@Component
@ConditionalOnProperty(name = "king.log.enabled", havingValue = "true")
public class ParamInfoLog {

    @Pointcut("execution(* com.kingboy.controller..*(..))")
    public void controller() { }

    @Pointcut("execution(* com.kingboy.service..*(..))")
    public void service() { }

    @Pointcut("execution(* com.kingboy.repository..*(..))")
    public void repository() { }

    @Before("controller()")
    public void controller(JoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Long count = Stream.of(signature.getMethod().getDeclaredAnnotations())
                .filter(annotation -> annotation.annotationType() == RequestMapping.class)
                .count();
        String requestPath = count >= 1 ? signature.getMethod().getAnnotation(RequestMapping.class).value()[0] : "";

        String info = String.format("path:%s | %s", requestPath, getMethodInfo(point));
        log.info(info);
    }

    @Before("service()")
    public void service(JoinPoint point) {
        log.info(String.format("%s", getMethodInfo(point)));
    }

    @Before("repository()")
    public void repository(JoinPoint point) {
        log.info(String.format("%s", getMethodInfo(point)));
    }

    private String getMethodInfo(JoinPoint point) {
        String className = point.getSignature().getDeclaringType().getSimpleName();
        String methodName = point.getSignature().getName();
        String[] parameterNames = ((MethodSignature) point.getSignature()).getParameterNames();
        StringBuilder sb = null;
        if (Objects.nonNull(parameterNames)) {
            sb = new StringBuilder();
            for (int i = 0; i < parameterNames.length; i++) {
                String value = point.getArgs()[i] != null ? point.getArgs()[i].toString() : "null";
                sb.append(parameterNames[i] + ":" + value + "; ");
            }
        }
        sb = sb == null ? new StringBuilder() : sb;
        String info = String.format("class:%s | method:%s | args:%s", className, methodName, sb.toString());
        return info;
    }
}

更新时间 2018-09-06 00:50:25

根据项目实际情况进行了一定的优化,可以参考以下代码,日志使用的是lombok提供的注解,更换为自己的log即可

@Slf4j
@Aspect
@Component
public class ParamLogger {

    @Pointcut("execution(* com.kimzing.provider.web..*(..))")
    public void controller() {
    }

    @Pointcut("execution(* com.kimzing.provider.service..*(..))")
    public void service() {
    }

    @Pointcut("execution(* com.kimzing.provider.mapper..*(..))")
    public void repository() {
    }

    @Before("controller()")
    public void controller(JoinPoint point) {

    }

    @Around("controller()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        String uuid = RandomUtil.uuid();

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        log.info("\n\t请求标识: {}\n\t请求IP: {}\n\t请求路径: {}\n\t请求方式: {}\n\t方法描述: {}\n\t请求参数: {}",
                uuid, request.getRemoteAddr(), request.getRequestURL(), request.getMethod(),
                getMethodInfo(point), JSONObject.toJSONString(request.getParameterMap()));

        long startTime = System.currentTimeMillis();
        Object[] args = point.getArgs();
        Object retVal = point.proceed(args);
        long endTime = System.currentTimeMillis();

        log.info("\n\t请求标识: {} \n\t执行时间: {} ms \n\t返回值: {}", uuid, endTime - startTime, JSONObject.toJSONString(retVal));
        return retVal;
    }

    @Before("service()")
    public void service(JoinPoint point) {
        log.info("\n\tservice method: {}", getMethodInfo(point));
    }

    @Before("repository()")
    public void repository(JoinPoint point) {
        log.info("\n\trepository method: {}", getMethodInfo(point));
    }

    private String getMethodInfo(JoinPoint point) {
        ConcurrentHashMap info = new ConcurrentHashMap<>(3);

        info.put("class", point.getTarget().getClass().getSimpleName());
        info.put("method", point.getSignature().getName());

        String[] parameterNames = ((MethodSignature) point.getSignature()).getParameterNames();
        ConcurrentHashMap args = null;

        if (Objects.nonNull(parameterNames)) {
            args = new ConcurrentHashMap<>(parameterNames.length);
            for (int i = 0; i < parameterNames.length; i++) {
                String value = point.getArgs()[i] != null ? point.getArgs()[i].toString() : "null";
                args.put(parameterNames[i], value);
            }
            info.put("args", args);
        }

        return JSONObject.toJSONString(info);
    }

}

你可能感兴趣的:(☀框架技术)