自定义注解+aop完成controller打印入参和出参日志

自定义注解+aop完成controller打印入参和出参日志

  • 写在前面
    • 开始上代码

写在前面

相信大家在开发的时候面对controller层有打印日志的习惯,controller层无需过多代码,基本上包括入参日志打印,调用service层方法,打印返回值结果,便于后期定位问题,再有就是对controller进行try catch处理,而我作为一名很懒的开发者,基本上就是看着别人的代码复制粘贴一遍,入参和返回值的日志打印,往往复制的时候把别人的方法名,类名都复制,简直是无脑复制,在后期定位问题的时候也给自己挖坑,最主要的是为了减少冗余代码,实现健壮性代码的基本要求,这次来个大保健,哦,不对, 是来个小重构,使用aop+注解。

开始上代码

对于需要引入什么aop pom文件这里就不多废话,自行google,自定义一个注解,用于标注在controller方法上.

@Aspect
@Component
@Slf4j
@Profile({"dev", "test"})
public class WebLogAspect {

然后就是一个切面

 /**
     * 换行符
     */
    private static final String LINE_SEPARATOR = System.lineSeparator();

    /**
     * 以自定义 @WebLog 注解为切点
     */
    @Pointcut("@annotation(com.demo.anno.WebLog)")
    public void test() {
    }

    /**
     * 在切点之前织入
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Before("test() && @annotation(webLog)")
    public void doBefore(JoinPoint joinPoint, WebLog webLog) throws Throwable {
        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 获取 @WebLog 注解的描述信息
        String methodDescription = getAspectLogDescription(joinPoint);

        // 打印请求相关参数
        log.info("==================================【{}】【{}】Start =================================", joinPoint.getTarget().getClass().getSimpleName(), joinPoint.getSignature().getName());
        // 打印描述信息
        log.info("Description    : {}", methodDescription);
        // 打印请求入参
        log.info("【Request Args】   : {}", new repack.com.google.gson.Gson().toJson(joinPoint.getArgs()));
    }

    /**
     * 在切点之后织入
     *
     * @throws Throwable
     */
    @After("test()")
    public void doAfter(JoinPoint joinPoint) throws Throwable {
        // 接口结束后换行,方便分割查看
        log.info("==================================【{}】【{}】 End =================================" + LINE_SEPARATOR, joinPoint.getTarget().getClass().getSimpleName(), joinPoint.getSignature().getName());

    }

    /**
     * 环绕
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("test()")
    public Result<Object> doAround(ProceedingJoinPoint proceedingJoinPoint) {
        long startTime = System.currentTimeMillis();
        Result result = null;
        try {
            result = (Result<Object>) proceedingJoinPoint.proceed();
            log.info("【Response Args】  : {}", new Gson().toJson(result));
            return result;
        } catch (BizException e) {
            result = new Result<>(ResultConstant.FAIL_CODE, ResultConstant.FAIL, e.getMessage());
            log.info("The method 【{}】 occurs exception: {}", proceedingJoinPoint.getSignature().getName(), e);
        } catch (Throwable throwable) {
            result = new Result<>(ResultConstant.FAIL_CODE, ResultConstant.FAIL, throwable.getMessage());
            log.info("The method 【{}】 occurs exception: {}", proceedingJoinPoint.getSignature().getName(), throwable);
        }
        // 打印出参
        log.info("【Response Args】  : {}", new Gson().toJson(result));
        // 执行耗时
        log.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
        return result;
    }


    /**
     * 获取切面注解的描述
     *
     * @param joinPoint 切点
     * @return 描述信息
     * @throws Exception
     */
    public String getAspectLogDescription(JoinPoint joinPoint)
            throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        StringBuilder description = new StringBuilder("");
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    description.append(method.getAnnotation(WebLog.class).desc());
                    break;
                }
            }
        }
        return description.toString();
    }

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface WebLog {
    String desc() default "";
}

然后再开始写一个切面
@Aspect
@Component
@Slf4j
@Profile({"dev", "test"})
public class WebLogAspect {
    /**
     * 换行符
     */
    private static final String LINE_SEPARATOR = System.lineSeparator();

    /**
     * 以自定义 @WebLog 注解为切点
     */
    @Pointcut("@annotation(com.demo.anno.WebLog)")
    public void test() {
    }

    /**
     * 在切点之前织入
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Before("test() && @annotation(webLog)")
    public void doBefore(JoinPoint joinPoint, WebLog webLog) throws Throwable {
        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 获取 @WebLog 注解的描述信息
        String methodDescription = getAspectLogDescription(joinPoint);

        // 打印请求相关参数
        log.info("==================================【{}】【{}】Start =================================", joinPoint.getTarget().getClass().getSimpleName(), joinPoint.getSignature().getName());
        // 打印描述信息
        log.info("Description    : {}", methodDescription);
        // 打印请求入参
        log.info("【Request Args】   : {}", new repack.com.google.gson.Gson().toJson(joinPoint.getArgs()));
    }

    /**
     * 在切点之后织入
     *
     * @throws Throwable
     */
    @After("test()")
    public void doAfter(JoinPoint joinPoint) throws Throwable {
        // 接口结束后换行,方便分割查看
        log.info("==================================【{}】【{}】 End =================================" + LINE_SEPARATOR, joinPoint.getTarget().getClass().getSimpleName(), joinPoint.getSignature().getName());

    }

    /**
     * 环绕
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("test()")
    public Result<Object> doAround(ProceedingJoinPoint proceedingJoinPoint) {
        long startTime = System.currentTimeMillis();
        Result result = null;
        try {
            result = (Result<Object>) proceedingJoinPoint.proceed();
            log.info("【Response Args】  : {}", new Gson().toJson(result));
            return result;
        } catch (BizException e) {
            result = new Result<>(ResultConstant.FAIL_CODE, ResultConstant.FAIL, e.getMessage());
            log.info("The method 【{}】 occurs exception: {}", proceedingJoinPoint.getSignature().getName(), e);
        } catch (Throwable throwable) {
            result = new Result<>(ResultConstant.FAIL_CODE, ResultConstant.FAIL, throwable.getMessage());
            log.info("The method 【{}】 occurs exception: {}", proceedingJoinPoint.getSignature().getName(), throwable);
        }
        // 打印出参
        log.info("【Response Args】  : {}", new Gson().toJson(result));
        // 执行耗时
        log.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
        return result;
    }


    /**
     * 获取切面注解的描述
     *
     * @param joinPoint 切点
     * @return 描述信息
     * @throws Exception
     */
    public String getAspectLogDescription(JoinPoint joinPoint)
            throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        StringBuilder description = new StringBuilder("");
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    description.append(method.getAnnotation(WebLog.class).desc());
                    break;
                }
            }
        }
        return description.toString();
    }

当然它山之石可以攻玉,感谢大神的文章借鉴,来源:

你可能感兴趣的:(springboot,+,aop,+自定义注解)