自定义注解实现记录操作日志

应用场景

在开发过程中我们会遇到需要使用自定义注解的需求,比如记录后台操作日志、接口权限检查等。

元注解

用来修饰注解的注解叫做元注解。
常用的元注解有@Target、@Retention、@Documented、@Inherited

@Target 定义注解的使用目标,也就是能被哪些Java元素所使用。它需要 ElementType 枚举来定义。

/**
 * @Target
 **/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}
/**
 * ElementType
 **/
public enum ElementType {

    /** 类、接口(包括注解类型),或者枚举 */
    TYPE,
    
    /** 属性 */
    FIELD,

    /** 方法 */
    METHOD,

    /** 方法形参 */
    PARAMETER,

    /** 构造参数 */
    CONSTRUCTOR,

    /** 局部变量 */
    LOCAL_VARIABLE,

    /** 注解 */
    ANNOTATION_TYPE,

    /** 包 */
    PACKAGE,

    /** 类型变量 */
    TYPE_PARAMETER,

    /** 任何使用类型(例如声明语句、泛型和强制转换语句中的类型) */
    TYPE_USE
}

@Retention定义注解的生命周期。它需要 RetentionPolicy 枚举来定义。

/**
 * @Retention
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}
/**
 * RetentionPolicy
 */
public enum RetentionPolicy {
    /**
     * 注解将被编译器忽略,只在源文件中能看到
     */
    SOURCE,

    /**
     * 注解会被编译到Class文件中,但JVM会忽略它
     */
    CLASS,

    /**
     * 由JVM加载,包含在类文件中,在运行时可以被获取到,实际开发中用到的基本上都是这个
     */
    RUNTIME
}

@Documented定义自定义注解是否生成到JavaDoc文档中。
@Inherited使用此注解后,子类也会拥有这个注解。只有当@Target被定义为ElementType.TYPE时起作用

自定义注解

/**
 * 后台操作日志注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {

    /**
     * 描述
     */
    String value();
    
    //设置默认值方式
    //String test() default "aaaa";
}

通过AOP方式保存操作日志

@Slf4j
@Aspect
@AllArgsConstructor
public class SysLogAspect {

    @SneakyThrows
    @Around("@annotation(sysLog)")
    public Object around(ProceedingJoinPoint point, SysLog sysLog) {
        String strClassName = point.getTarget().getClass().getName();
        String strMethodName = point.getSignature().getName();
        log.warn("[类名]:{},[方法]:{}", strClassName, strMethodName);

		//从request中获取请求参数,保存操作日志
		HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
		.....

        return point.proceed();

    }
}

//注入SysLogAspect
@Bean
public SysLogAspect sysLogAspect() {
	return new SysLogAspect();
}

通过拦截器方式保存操作日志

/**
 * 操作日志拦截器
 */
public class SysLogInterceptor extends HandlerInterceptorAdapter {

	@Inject
	private SysLogService sysLogService;

	/**
	 * 请求前处理
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		if (handler instanceof HandlerMethod) {
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			SysLog sysLog = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), SysLog.class);
			if (sysLog != null) {
				//封装操作日志记录,保存到request中
				SysLogEntity sysLogEntity = new SysLogEntity();
				...
				request.setAttribute("SYS_LOG", sysLogEntity);
			}
		}
		return super.preHandle(request, response, handler);
	}

	/**
	 * 请求后处理
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
		if (handler instanceof HandlerMethod) {
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			SysLog sysLog = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), SysLog.class);
			if (sysLog != null) {
				SysLogEntity sysLogEntity = (SysLogEntity) request.getAttribute("SYS_LOG");
				if (sysLogEntity != null && sysLogEntity.getId() == null) {
					sysLogService.create(sysLogEntity);
				}
			}
		}
	}

}

你可能感兴趣的:(Java)