当然,一旦使用了通配符,就可能导致匹配的范围过大的问题!毕竟有相同前缀,但是后缀不同的若干个请求路径中,可能有些需要经过拦截器,而有些并不需要经过拦截器!例如:用户注册、用户登录都不必经过“登录拦截器”,但是修改资料、修改密码、修改头像、验证手机、验证邮箱等诸多操作都是需要经过“登录拦截器”,就会存在“如果不使用通配符,就必须一个个的配置拦截路径,工作量较大,如果使用通配符,可能将用户注册、用户登录也匹配进去,导致匹配过大”的问题!所以,SpringMVC还提供了配置“排除路径”的做法,也就是“在已经配置的路径范围中排除某些路径”,类似于“白名单”,其方法是:
public InterceptorRegistration excludePathPatterns(String... patterns) { return excludePathPatterns(Arrays.asList(patterns)); } public InterceptorRegistration excludePathPatterns(List<String> patterns) { this.excludePatterns.addAll(patterns); return this; }
例如,可以配置为:
registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/user/**") .excludePathPatterns("/user/reg.do", "/user/login.do");
以上代码就表示“以/user/开头的路径都是需要被拦截的,但是,/user/reg.do和/user/login.do这2个路径是例外的,不需要被拦截器处理”。
5. 过滤器与拦截器的区别
相似之处:
都可以使得若干个请求路径都执行过滤器组件/拦截器组件中的代码片断,都可以在执行之后选择“阻止”或“放行”,都有“链”的概念。
区别:
过滤器Filter是Java EE中的组件,只要是Java Web项目都可以使用过滤器,包括在SpringMVC项目中也可以使用过滤器;拦截器Interceptor是SpringMVC框架中的组件,只有使用了SpringMVC框架的项目,才可以使用拦截器,并且,只有被SpringMVC框架处理的请求才可能被拦截器所处理,例如,将DispatcherServlet映射的路径(在SpringMvcInitializer中getServletMappings()方法的返回值)配置为*.do时,只有以.do为后缀的请求才可能被拦截器处理,而例如.jpg类似的请求将不会被拦截器处理,当然,如果有必要的话,也可以将DispatcherServlet映射的路径配置为/*,则任何请求都可能被拦截器处理。
过滤器Filter可以配置若干个映射路径,可以使用通配符,但是,却不能从中剔除部分请求路径,也就是“不能配置白名单”,在配置时可能比较麻烦;拦截器Interceptor在配置映射的请求路径时,既可以配置拦截路径(黑名单),又可以配置排除路径(白名单),配置更加简单、灵活。
过滤器Filter是执行在所有Servlet组件之前的;而拦截器Interceptor的第1次执行是在DispatcherServlet之后,且在Controller之前的。
小结:
在SpringMVC项目中,应该优先使用拦截器Interceptor组件,除非某些代码片断必须在Servlet之前执行!
1. 关于@RequestMapping注解
在控制器类中,在处理请求的方法之前使用@RequestMapping,可以绑定请求路径与处理请求的方法,以至于当客户端请求该路径时,对应的方法就会被调用!
其实,还可以在控制器类的声明之前也添加该注解!例如:
@Controller
@RequestMapping("user")
public class UserController {
}
则该控制器中所有请求路径的资源名(各处理请求的方法之前配置的值)左侧都需要添加类上配置的值!
假设在以上UserController中,没有为类配置@RequestMapping之前,存在以下请求路径:
http://localhost:8080/springmvc/reg.do
http://localhost:8080/springmvc/login.do
注:以上路径中的springmvc是Context Path值。
为类配置了@RequestMapping("user")之后,请求路径就需要改为:
http://localhost:8080/springmvc/user/reg.do
http://localhost:8080/springmvc/user/login.do
在实际开发项目时,推荐为每一个控制器类之前配置该注解!
在控制器类之前也配置了@RequestMapping后,其配置值会与方法之前的@RequestMapping的配置值组合起来,形成完整的路径,无论是将@RequestMapping配置在哪个位置,在配置注解属性时,框架会自动添加必要的/,并且两端多余的/都是会忽略的!例如,以下各种配置方式是完全等效的:
所以,在实际应用时,一般推荐使用以上表格中的第1种做法,或第4种做法,也就是“要么在注解参数的左侧都不添加/符号,要么都添加/符号”。
关于@RequestMapping注解,其源代码中存在:
@AliasFor("path") String[] value() default {};
基于value是注解中的默认属性,所以,一直以来,使用@RequestMapping注解时配置的值,其实都是这个value属性的值,也就是说,以下2种配置方式是完全等效的:
@RequestMapping("reg.do") @RequestMapping(value = "reg.do")
由于在注解中声明的value的类型是String[]数组,所以,以上2种配置与以下2种配置都是完全等效的:
@RequestMapping({ "reg.do" }) @RequestMapping(value = { "reg.do" })
当注解参数的类型是某种数组类型,且需要配置的值只有1个值时,将该属性直接配置为数组元素的值,或配置为数组类型的值,都是允许的,且是等效的!
同时,基本该属性是数组类型的,所以,其实是可以配置多个路径的,例如:
@RequestMapping({ "reg.do", "register.do" })
如果注解参数中为value属性配置了2个值,就表示“通过这2个配置的请求路径中的任何一个都可以使得映射的方法被调用”!