注解
Java目前只内置了三种标准注解
四种元注解,元注解专职负责注解其他的注解
如何在运行时获取注解的值?java在java.lang.reflect包中定义了AnnotatedElement接口,Class,Method,Field等都实现了该接口,通过该接口提供的方法,就可以获得我们需要的信息,并且该接口的方法返回的数组可以由调用方修改,而不影响返回到其他调用方的数组。
AnnotatedElement接口的一部分方法
java.lang.Class中的getDeclared**表示获取自己的东西,而get**方法表示获取自己的和父类的东西,这个接口沿用了这种命名方式
使用
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface FruitName { // 当不指定默认值时,则必须在写注解的时候写上这个属性的值 String value() default ""; String alias() default ""; }
public enum Color { BLUE, RED, GREEN }
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface FruitColor { Color fruitColor() default Color.GREEN; }
测试类
public class Apple { // 当只想给value赋值时,可以使用如下快捷方式 // @FruitName("apple") // 当多个属性赋值时,必须采用key=value的形式 @FruitName(value = "apple", alias = "iphone") private String name; @FruitColor(fruitColor = Color.RED) private String color; public static void main(String[] args) { Field[] fields = Apple.class.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(FruitName.class)) { FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class); // fruitName is apple System.out.println("fruitName is " + fruitName.value()); // alias is iphone System.out.println("alias is " + fruitName.alias()); } else if (field.isAnnotationPresent(FruitColor.class)) { FruitColor fruitColor = (FruitColor) field.getAnnotation(FruitColor.class); // fruitColor is RED System.out.println("fruitColor is " + fruitColor.fruitColor().name()); } } } }
自定义注解+拦截器实现权限管理
自定义注解一般用在日志记录,权限管理的部分,配置动态数据源一般也会用自定义注解配合AOP来完成动态切库
写了一个自定义注解配合拦截器实现权限管理的小Demo,用的是Spring Boot框架
定义权限注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Authority { String value() default "admin"; }
增加拦截器
public class AuthorityInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); Authority authority = method.getAnnotation(Authority.class); if (authority == null) { // 如果注解为null, 说明不需要拦截, 直接放过 return true; } // 这里为了方便直接传递了参数 // 一般的做法是用户第一次登录,将信息放到session中 // 以后每次操作时从request中获取session,从session中获取用户信息 // 然后根据用户信息从数据库中查权限信息 String userAuthority = httpServletRequest.getParameter("userAuthority"); if (!userAuthority.equals("admin")) { // 脱离了Spring MVC的返回流程,重新编码 httpServletResponse.setCharacterEncoding("utf-8"); httpServletResponse.setContentType("application/json;charset=UTF-8"); PrintWriter out = httpServletResponse.getWriter(); out.print("没有权限"); out.flush(); out.close(); return false; } return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
配置拦截器
@Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthorityInterceptor()).addPathPatterns("/**"); } }
测试Controller
@RestController public class UserController { // 这个是为了测试没有注解时,是否会拦截 @RequestMapping(value = "login", method = RequestMethod.GET) public Map login() { Map<String, String> map = new HashMap<>(); map.put("msg", "login success"); return map; } @Authority() @RequestMapping(value = "queryAllProduct", method = RequestMethod.GET) public Map queryAllProduct() { Map<String, String> map = new HashMap<>(); map.put("msg", "this is all data"); return map; } }
测试