Spring MVC中的拦截器是一种可以在请求处理过程中对请求进行拦截和处理的机制。
拦截器可以用于执行一些公共的操作,例如日志记录、权限验证、数据转换等。在Spring MVC中,可以通过实现HandlerInterceptor接口来创建自定义的拦截器,并通过配置来指定拦截器的应用范围和顺序。
Spring MVC中的拦截器可以分为三种类型:
- 预处理拦截器(preHandle):在请求处理之前执行,可以用于做一些前置处理,例如权限验证、参数校验等。
- 后处理拦截器(postHandle):在请求处理之后、视图渲染之前执行,可以对处理结果进行修改或补充。
- 最终处理拦截器(afterCompletion):在请求处理完成之后执行,无论是否发生异常都会执行,用于资源清理等操作。
通过配置拦截器,我们可以灵活地控制请求的处理流程,并实现一些通用的功能,提高代码的复用性和可维护性。
SpringMVC拦截器 VS Servlet过滤器
Spring MVC拦截器和Servlet过滤器都可以用于在请求处理过程中对请求进行拦截和处理,但它们在实现机制和使用方式上有一些区别:
实现接口:
- Spring MVC拦截器:Spring MVC的拦截器是基于HandlerInterceptor接口实现的,可以通过实现该接口来创建自定义的拦截器。
- Servlet过滤器:Servlet过滤器是基于Filter接口实现的,可以通过实现该接口来创建自定义的过滤器。
使用范围:
- Spring MVC拦截器:Spring MVC的拦截器主要用于拦截Spring MVC的请求处理流程,可以在控制器方法执行前后进行处理。
- Servlet过滤器:Servlet过滤器可以在Servlet容器级别对所有请求进行过滤处理,不仅限于Spring MVC。
执行顺序:
- Spring MVC拦截器:可以通过配置来指定拦截器的执行顺序,并且可以在拦截器链中控制多个拦截器的执行顺序。
- Servlet过滤器:过滤器的执行顺序由其在web.xml文件中的配置顺序决定,无法控制多个过滤器的执行顺序。
依赖关系:
- Spring MVC拦截器:Spring MVC拦截器依赖于Spring MVC框架,需要在Spring MVC配置文件中进行配置。
- Servlet过滤器:Servlet过滤器是Servlet规范的一部分,不依赖于具体的框架,可以在web.xml文件中配置。
总的来说,Spring MVC拦截器更适合用于对Spring MVC请求进行处理和控制,而Servlet过滤器更适合用于对Servlet容器级别的请求进行过滤处理。根据具体的需求和场景,可以选择合适的方式来实现请求的拦截和处理。
SpringMVC拦截器的执行原理
Spring MVC的拦截器底层执行原理主要是通过HandlerExecutionChain来实现的。
当客户端发送请求时,DispatcherServlet会根据请求的URL找到对应的HandlerMapping,然后获取到处理该请求的HandlerExecutionChain,其中包括HandlerInterceptor拦截器链和HandlerMethod处理方法。
具体执行流程如下:
- DispatcherServlet根据请求的URL找到对应的HandlerMapping,获取到HandlerExecutionChain。
- 在HandlerExecutionChain中,包含了一个HandlerInterceptor拦截器链和一个HandlerMethod处理方法。
- DispatcherServlet会依次调用拦截器链中的每个拦截器的preHandle方法,在处理方法执行前进行拦截处理。
- 如果所有拦截器的preHandle方法都返回true,则执行HandlerMethod处理方法处理请求。
- 处理方法执行完毕后,DispatcherServlet会依次调用拦截器链中的每个拦截器的postHandle方法,在处理方法执行后、视图渲染前进行拦截处理。
- 最后,DispatcherServlet会依次调用拦截器链中的每个拦截器的afterCompletion方法,在视图渲染完毕后进行拦截处理,无论处理方法是否发生异常都会执行。
通过这样的拦截器链机制,Spring MVC可以灵活地控制请求的处理流程,实现对请求的拦截和处理。同时,开发者也可以自定义拦截器并通过配置来实现特定的业务逻辑。
SpringMVC配置拦截器
SpringMVC中的拦截器需要实现HandlerInterceptor
接口
public class MyInterceptor implements HandlerInterceptor {
/**
* 处理请求的控制器方法前执行
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("request=" + request + ",response=" + response + ",handler=" + handler);
//返回true放行,false拦截
return true;
}
/**
* 在控制器方法处理请求后执行,控制器方法出现异常不执行
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor.postHandle");
}
/**
* 视图渲染完后立即执行,不管控制器方法是否出现异常
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor.afterCompletion");
}
}
拦截器中三个默认方法说明:
preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法。
postHandle:控制器方法执行之后执行postHandle()。
afterComplation:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()
SpringMVC的拦截器三种配置方式
方式1:使用bean标签
<mvc:interceptors>
<bean class="com.evan.interceptor.myInterceptor"/>
</mvc:interceptors>
方式2:引入外部bean
<bean class="com.evan.interceptor.MyInterceptor" id="myInterceptor"/>
<mvc:interceptors>
<ref bean="myInterceptor"/>
</mvc:interceptors>
方式3:使用注解方式
将拦截器的实现类注入到spring容器中
@Component //将实现类注入到容器中
public class MyInterceptor implements HandlerInterceptor {}
开启组件扫描
<context:component-scan base-package="com.evan.interceptor.MyInterceptor"/>
配置拦截器
<mvc:interceptors>
<!-- 扫描组件从Spring容器中获取实现类对象,该对象默认是实现类的驼峰类名 -->
<ref bean="myInterceptor"/>
</mvc:interceptors>
结论:
以上三种方式:都是对所有请求进行拦截
bean标签和ref标签配置的拦截器默认对DispatcherServlet
处理的所有的请求进行拦截或放行。
排除指定的拦截请求
<mvc:interceptors>
<!--<bean class="com.evan.interceptor.FirstInterceptor"/>-->
<!--<ref bean="firstInterceptor"/>-->
<mvc:interceptor>
<!-- 配置需要拦截的请求的请求路径,/**表示所有请求 -->
<mvc:mapping path="/**"/>
<!-- 排除拦截的请求的请求路径-->
<mvc:exclude-mapping path="/test/hello"/>
<!-- 配置拦截器 -->
<ref bean="firstInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
注意:排除指定请求拦截,需要指定请求在拦截请求内部,拦截是向下兼容。
比如:拦截请求:/user/** 排除拦截需要在/user下/user/get1 /user/get2 ...
配置类方式配置拦截器
1.默认拦截全部请求
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = {"com.evan.interceptor"})
public class SpringMvcConfig implements WebMvcConfigurer {
//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//将拦截器添加到Springmvc环境,默认拦截所有Springmvc分发的请求
registry.addInterceptor(new MyInterceptor());
}
}
2.精确配置
@Override
public void addInterceptors(InterceptorRegistry registry) {
//精准匹配,设置拦截器处理指定请求 路径可以设置一个或者多个,为项目下路径即可
//可以使用/* 和 /** 进行模糊匹配
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/user/get1","/user/get2");
}
3.排除配置
//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//排除匹配,排除应该在匹配的范围内排除
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/user/**","/user/get/one")
.excludePathPatterns("/user/get/two");
}
多个拦截器的执行顺序
通过观察源码:
1、若每个拦截器的preHandle()都返回true,则多个拦截器的执行顺序是按照在SpringMVC配置文件的配置顺序执行。
2、若多个拦截器中的某个拦截器的preHandle()返回false。preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的拦截器的afterComplation()会执行。
说明:
preHandle()会按照配置的顺序执行(由上而下),而postHandle()和afterComplation()会按照配置的反序执行(由下而上)。