Java使用自定义注解打印接口日志

2,495 阅读3分钟

开头

日志在一个项目中是不可或缺的,如果是单一的API服务端,可采用切面拦截所有Controller的请求,已达到目的,若是前后端不分离项目,则使用注解会更佳。

首先定义注解

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface WebLog {

  boolean flag() default true;

  String title() default "";
}

我在这里定义了一个是否使用的标志和标题,大家可以拓展,以下是解释注解的说明:

* @Target 注解可修饰的对象范围,ElementType.METHOD 作用于方法,ElementType.TYPE 作用于类
* (ElementType)取值有:
*     1.CONSTRUCTOR:用于描述构造器
*     2.FIELD:用于描述域
*     3.LOCAL_VARIABLE:用于描述局部变量
*     4.METHOD:用于描述方法
*     5.PACKAGE:用于描述包
*     6.PARAMETER:用于描述参数
*     7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
* @Retention 定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;
* 而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,
* 而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。
* 使用这个meta-Annotation可以对 Annotation的“生命周期”限制。
* (RetentionPoicy)取值有:
*     1.SOURCE:在源文件中有效(即源文件保留)
*     2.CLASS:在class文件中有效(即class保留)
*     3.RUNTIME:在运行时有效(即运行时保留)
*
* @Inherited
* 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。
* 如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

第二步添加切面

@Aspect
@Slf4j
@Component
public class WebLogAspect {

   @Pointcut(value = "@annotation(com.qqri.api.annotation.WebLog)")
   public void webLog() {
   }

   @Before(value = "webLog()")
   public void doBefore(JoinPoint joinPoint) throws Exception {
       WebLog webLog = getAnnotationLog(joinPoint);
       //获取是否有注解
       if (webLog == null) {
           return;
       }
       boolean flag = webLog.flag();
       if (flag) {
           // 接收到请求,记录请求内容
           ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
           HttpServletRequest request = attributes.getRequest();
           // 记录下请求内容
           log.info("Description :" + webLog.title());
           log.info("URL : " + request.getRequestURL().toString());
           log.info("HTTP_METHOD : " + request.getMethod());
           log.info("IP : " + IpUtil.getIpAddress(request));
           log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
           log.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
       }
   }


   /**
    * 是否存在注解,如果存在就获取
    */
   private WebLog getAnnotationLog(JoinPoint joinPoint) throws Exception {
       Signature signature = joinPoint.getSignature();
       MethodSignature methodSignature = (MethodSignature) signature;
       Method method = methodSignature.getMethod();

       if (method != null) {
           return method.getAnnotation(WebLog.class);
       }
       return null;
   }

   @AfterReturning(returning = "reValue", pointcut = "webLog()")
   public void doAfterReturning(JoinPoint joinPoint, Object reValue) throws Exception {
       WebLog webLog = getAnnotationLog(joinPoint);
       if (webLog == null) {
           return;
       }
       boolean flag = webLog.flag();
       if (flag) {
           // 处理完请求,返回内容
           log.info("RESPONSE : " + reValue);
       }
   }
}

切点为定义的日志注解,从请求方法中获取是否包含该注解,并且flag标志为true。 在切面中可以做更多的操作,例如保存到数据库,保存这个步骤建议作为异步化处理。

第三步添加注解

在接口方法上添加注解@WebLog()

    @WebLog(title = "获取今日运势接口")
    @RequestLimit(second = 2, maxCount = 5)
    @ApiOperation(value = "获取今日运势接口", notes = "获取今日运势接口")
    @GetMapping("/get/{qq}")
    public RestfulResponse getFortuneOfToday(@PathVariable String qq) {
        return qrFortuneService.getFortuneOfToday(qq);
    }

日志打印效果如下:

2019-08-02 09:17:59.243  INFO 8580 --- [io-8081-exec-16] com.qqri.api.aspect.WebLogAspect         : Description :登录接口
2019-08-02 09:17:59.243  INFO 8580 --- [io-8081-exec-16] com.qqri.api.aspect.WebLogAspect         : URL : http://localhost:8081/qr_admin_main/login
2019-08-02 09:17:59.243  INFO 8580 --- [io-8081-exec-16] com.qqri.api.aspect.WebLogAspect         : HTTP_METHOD : POST
2019-08-02 09:17:59.244  INFO 8580 --- [io-8081-exec-16] com.qqri.api.aspect.WebLogAspect         : IP : 0:0:0:0:0:0:0:1
2019-08-02 09:17:59.244  INFO 8580 --- [io-8081-exec-16] com.qqri.api.aspect.WebLogAspect         : CLASS_METHOD : com.qqri.api.controller.admin.QrAdminMainController.login
2019-08-02 09:17:59.244  INFO 8580 --- [io-8081-exec-16] com.qqri.api.aspect.WebLogAspect         : ARGS : [QrUser(userId=null, deptId=null, loginName=admin, userName=null, userType=null, email=null, phonenumber=null, sex=null, avatar=null, password=xxx.., salt=null, status=null, delFlag=null, loginIp=null, loginDate=null, createBy=null, createTime=null, updateBy=null, updateTime=null, remark=null), org.apache.shiro.web.servlet.ShiroHttpServletRequest@217b8748]
2019-08-02 09:17:59.908  INFO 8580 --- [io-8081-exec-16] com.qqri.api.aspect.WebLogAspect         : RESPONSE : RestfulResponse(status=30011, msg=登陆成功, data=null)