SpringBoot拦截器半自动加载PathPatterns

2019-07-01  本文已影响0人  夏天以后灬

1. 序

SpringBoot中我们会用到拦截器Interceptor,去拦截一些请求,处理相应的业务,如登录验证等,一般我们都是通过手写PathPatterns。

原代码如下:

 registry.addInterceptor(tokenInterceptor)
                    .addPathPatterns("/**")
                    .excludePathPatterns("/api/hello")

当excludePathPatterns越多的时候代码就不美观,往往在开发的时候会忘记了。
现提供一种通过注解方式去半自动添加到PathPatterns中。

2. 实现

1.自定义注解Permission

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Permission {
    // 这里可自行修改,添加一些变量
}

2.控制器方法添加Permission注解

@RestController
@RequestMapping("/api")
public class TestController {

    @Permission
    @GetMapping("/hello")
    public String hello() {
        return "hello world!!";
    }
}

3.配置WebMvcConfigurer

@Configuration
public class WebAppConfigurer implements WebMvcConfigurer, ApplicationContextAware {

    private static Logger logger = LoggerFactory.getLogger(WebAppConfigurer.class);

    // 验证Token拦截器
    @Autowired
    TokenInterceptor tokenInterceptor;
  
   // SpringBoot上下文     
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    // 通过实现ApplicationContextAware来获取SpringBoot上下文
        this.applicationContext = applicationContext;
    }

   // 循环添加到set中 
    private void addExcludePath(Set<String> excludePath, String[] prefixValues, String[] suffixValues) {
        if (suffixValues == null) suffixValues = new String[]{""};
        for (String prefix : prefixValues) {
            for (String suffix : suffixValues) {
                String path = "/" + prefix;
                if (suffix.length() != 0) {
                    path += "/" + suffix;
                }
                excludePath.add(path.replaceAll("/+", "/"));
            }
        }
    }

   // 获取不需要Token验证的path列表
    private List<String> listExcludePath() {
        // 获取有添加RestController的Bean
        Map<String, Object> controllerBeanMap = applicationContext.getBeansWithAnnotation(Controller.class);
        Set<String> excludePath = new HashSet<>();
        try {
            for (Object controller : controllerBeanMap.values()) {
                Class<?> controllerClass = controller.getClass();
                RequestMapping controllerMapping = controllerClass.getAnnotation(RequestMapping.class);
                // 获取url的前缀
                String[] prefixValues = {""};
                if (controllerMapping != null) {
                    prefixValues = controllerMapping.value();
                }
                // 获取当前类的方法,不含父类方法
                Method[] controllerMethods = controllerClass.getMethods();
                for (Method method : controllerMethods) {
                    // 判断是否加了Permission注解
                    Permission permission = method.getAnnotation(Permission.class);
                    if (permission != null) {
                        // 获取所有注解
                        Annotation[] annotations = method.getAnnotations();
                        for (Annotation annotation : annotations) {
                            // 获取RequestMapping、GetMapping...等的value值
                            Class<? extends Annotation> type = annotation.annotationType();
                            if (type.isAnnotationPresent(RequestMapping.class)
                                    || type.isAnnotationPresent(Mapping.class)) {
                // 反射调用value()方法,获取内容
                                Method valueMethod = type.getDeclaredMethod("value");
                                String[] value = (String[]) valueMethod.invoke(annotation);
                                addExcludePath(excludePath, prefixValues, value);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("加载permission异常", e);
        }
        return new ArrayList<>(excludePath);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        if (tokenInterceptor != null) {
            // 获取不需要token的url列表
        List<String> excludePathList = listExcludePath();

            registry.addInterceptor(tokenInterceptor)
                    .addPathPatterns("/**")
                    .excludePathPatterns(excludePathList);
        }

    }

}

3. 扩展

这里只是给出一个最简单、常见的逻辑。
可以根据业务需要对Permission注解添加变量修改,实现符合自己项目的业务逻辑。

上一篇下一篇

猜你喜欢

热点阅读