SpringBoot利用AOP拦截自定义注解(以日志为例)

SpringBoot利用AOP拦截自定义注解(以日志为例)

这波操作有两个动作,一个是自定义注解,另一个是AOP拦截注解,下面按步进行:

  • 自定义注解:
package com.pilot.basic.system.annotation;

/**
 * @name: OperateLog
 * @author: lyr.
 * @date: 2019/9/9.
 * @version: 1.0
 * @Description:自定义日志注解
 */

import java.lang.annotation.*;

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperateLog {
    /**
     * 要执行的操作类型
     **/
    String methodDesc() default "";

    /**
     * 要执行的操作名称
     **/
    String moduleName() default "";
}

说明:之所以要定义上面两个方法,是因为日志需要记录请求的方法的详细描述,以供用户知道这个方法是干嘛的,比如:

然而,这两个属性又不能通过“JoinPoint”来获取到,所以这里要作为注解的参数来获取。具体是这样获取到的,在使用注解时,写上这两个属性的值即可,如下:

  • AOP拦截注解:
package com.pilot.basic.system.annotation;

/**
 * @name: OperateLogAspect
 * @author: lyr.
 * @date: 2019/9/9.
 * @version: 1.0
 * @Description:
 */
@Aspect
@Component
public class OperateLogAspect {

    //注入Service用于把日志保存数据库
    @Autowired
    FeignLog feignLog;

    private static final Logger logger = LoggerFactory.getLogger(OperateLogAspect.class);
    private static ThreadLocal<String> key = new ThreadLocal();

    //Controller层切点
    @Pointcut("@annotation(com.pilot.basic.system.annotation.OperateLog)")
    public void controllerAspect() {
    }

    /**
     * 前置通知 用于拦截Controller层记录用户的操作
     *
     * @param joinPoint 切点
     */
    @Before("controllerAspect()&&@annotation(operateLog)")
    public void doBefore(JoinPoint joinPoint,OperateLog operateLog) {
        System.out.println("==========执行controller前置通知===============");
        if (logger.isInfoEnabled()) {
            logger.info("before " + joinPoint);
        }
    }

   /**
     * 后置通知 用于拦截Controller层记录用户的操作
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "controllerAspect()",returning = "obj")
    public void after(JoinPoint joinPoint, Object obj) {

        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes()).getRequest();
            //请求的IP
            String ip = request.getRemoteAddr();
            String targetName = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            Object[] arguments = joinPoint.getArgs();
            Class targetClass = Class.forName(targetName);
            Method[] methods = targetClass.getMethods();
            String methodDesc = "";
            String moduleName = "";
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    Class[] clazzs = method.getParameterTypes();
                    if (clazzs.length == arguments.length) {
                        methodDesc = method.getAnnotation(OperateLog.class).methodDesc();
                        moduleName = method.getAnnotation(OperateLog.class).moduleName();
                        break;
                    }
                }
            }

            //获取请求参数
            String params = "";
            if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
                for (int i = 0; i < joinPoint.getArgs().length; i++) {
                    params += JSON.toJSONString(joinPoint.getArgs()[i]) + ";";
                }
            }

            //获取返回结果
            key.remove();
            ResponseResult result = null;
            int statusCode = 0;
            if (obj != null) {
            if (obj instanceof ResponseResult) {
                result = (ResponseResult)obj;
                statusCode = result.getStatus();
            } else if(obj instanceof ResponsePageResult){
                   ResponsePageResult result1 = (ResponsePageResult)obj;
                }
            }
            //*========控制台输出=========*//
            System.out.println("=====controller后置通知开始=====");
            System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()") + "." + methodDesc);
            System.out.println("方法描述:" + moduleName);
            System.out.println("请求IP:" + ip);
            //*========数据库日志=========*//
            OperateLogParam operateLogParam = new OperateLogParam();
           Param.setActionName(joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()");
            operateLogParam.setMethodDesc(methodDesc);
            operateLogParam.setModuleName(moduleName);
            operateLogParam.setOperatorTime(LocalDateTime.now());
            operateLogParam.setRequestIp(ip);
            operateLogParam.setRequestParam(params);
         operateLogParam.setRequestUrl(request.getRequestURL().toString() + "  " + request.getMethod());
            operateLogParam.setResponseCode(String.valueOf(statusCode));
            feignLog.insert(operateLogParam);
            System.out.println("=====controller后置通知结束=====");
        } catch (Exception e) {
            //记录本地异常日志
            logger.error("==后置通知异常==");
            logger.error("异常信息:{}", e.getMessage());
        }
    }

}

说明:需要注意的是这里的写法(如图),决定了你拦截的是什么,这里用的是@annotation注解,还有@target等,可以探究下这些注解的区别,这里先不多做说明。

如上两步就完成了SpringBoot利用AOP拦截自定义日志注解。不过在写拦截器时调用了微服务,所以下一篇以此为例来简单说下基于springcloud的微服务调用问题。

发布了26 篇原创文章 · 获赞 4 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/y_onghuming/article/details/100705425