什么是注解

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnoation {
		int value() default 0;
		String word() default "word";
}

上面是一个自定义注解的方式,我们可以看到,存在注解的注解,也就是元注解,常用的元注解有

  • @Target 标识注解的应用范围,可以是
    • ElementType.TYPE 类或方法
    • ElementType.FIELD 字段
    • ElementType.METHOD 方法
    • ElementType.CONSTRUCTOR 构造函数
    • ElementType.PARAMETER 参数
  • @Retention 标识注解的生命周期,通常是
    • RetentionPolicy.SOURCE 仅编译器
    • RetentionPolicy.CLASS 仅class文件
    • RetentionPolicy.RUNTIME 运行期—常用

​ 除了元注解之外,我们还能定义注解的参数和默认值(代码中的value和word),这样我们在将注解添加到某个类或方法上时可以设置变量的值,至于变量的值有什么作用,可以在下面项目当中的使用场景来理解一下。

springboot项目当中的使用场景

aop切点定义

  1. 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnoation {
	String value() default "";
}
  1. 编写切面类
@Aspect
@Component
public class LogAspect {
	@Pointcut(value = "@annotation(com.wuweizhao.test.aspect.LogAnnoation)")
	public void methodPointcut(){
	}

	@Around(value= "methodPointcut() && @annotation(logAnnoation)")
	public Object around(ProceedingJoinPoint point, LogAnnoation logAnnoation) throws Throwable{
		Object obj = null;
		Object[] args = point.getArgs();
		System.out.println(logAnnoation.value());
		System.out.println("before");
		obj = point.proceed(args);
		MethodSignature signature = (MethodSignature) point.getSignature();
		String methodName = signature.getDeclaringTypeName() + "." + signature.getName();
		System.out.println("after " + methodName);
		return obj;
	}
}
  • 此处我们使用了@Around环绕切面,定义了切面的切点是带有注解LogAnnoation 的方法
  • 在切面执行前后我们分别打印了日志以及打印出了注解所设置的值以及调用的方法名称
  1. 在接口上添加注解并设置值
	@RequestMapping(value="/getHeaders",method = RequestMethod.GET)
	@ResponseBody
	@LogAnnoation(value = "hello")
	public String getHeader(HttpServletRequest request){
		Map headerMap = new HashMap();

		Enumeration names = request.getHeaderNames();
		while (names.hasMoreElements()) {
			String name = names.nextElement().toString();
			String value = request.getHeader(name);
			headerMap.put(name, value);
		}

		return JSON.toJSONString(headerMap, true);
	}
  1. 启动,调用接口,可以看到控制台输出
hello
before
after com.wuweizhao.test.controller.HelloController.getHeader

成功进入切面以及打印出对应的内容。

自定义注解+登录拦截

此处我们还是以上面的LogAnnoation 为例子,我们添加拦截器MyAuthorityManageInterceptor

public class MyAuthorityManageInterceptor  extends HandlerInterceptorAdapter {
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		HandlerMethod handlerMethod = (HandlerMethod) handler;

		Method method = handlerMethod.getMethod();
		LogAnnoation annotation = method.getAnnotation(LogAnnoation.class);
		if (annotation == null) {
			return true;
		} else {
			System.out.println("登录校验不通过");
			response.getWriter().print("no permission");
			return false;
		}
	}
}
  • 此处我们先默认加了注解之后都是校验不通过的,具体业务上可以在校验的逻辑中增加相应的判断代码
  • 此处我们是获得了方法上面的注解,更多情况下我们的注解可能会加在类上面,对整个类的所有方法都需要添加登录拦截,可以通过获得类上的注解来实现
LogAnnoation annotation = handlerMethod.getBean().getClass().getAnnotation(LogAnnoation.class)
  • 注意不要忘了在配置中添加拦截器配置
@Configuration
public class CustomWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		super.addInterceptors(registry);
		registry.addInterceptor(new MyAuthorityManageInterceptor());
	}
}

此时,我们再去访问加了@LogAnnoation的接口,会直接返回 no permission

参考