SpringMVC一步到位精通拦截器
作者:Hhzzy99
前言
在上一篇文章中讲完了SpringMVC的大部分知识,此篇文章中主要讲解拦截器。上一篇文章🚩
拦截器的使用是非常普遍的。例如在 OA系统中通过拦截器可以拦截未登录的用户,或者使用它来验证己登录用户是否有相应的操作权限等。SpringMVC
中提供了拦截器功能,通过配置即可对请求进行拦截处理。
拦截器概述
SpringMVC 中的拦截器 (Interceptor
)类似于 Servlet 中的过滤器(Filter
),它主要用于拦截用户请求并做相应的处理。例如通过拦截器可以进行权限验证、判断用户是否己登录等。
拦截器的定义
要使用SpringMVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义:
- 一种是通过实现
HandlerInterceptor
接口或者继承HandlerInterceptor
接口的实现类(如HandlerInterceptorAdapter
)来定义。 - 另一种是通过实现
WebRequestInterceptor
接口或继承WebRequestInterceptor
接口的实现类来定义。
实现HandlerInterceptor
接口的定义方式为例,自定义拦截器类的代码如下所示:
public class UserInterceptor implements HandlerInterceptor { public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception { System.out.println("UserInterceptor...preHandle"); //对拦截的请求进行放行处理(true为放行,false为不放行) return true; } public void postHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("UserInterceptor...postHandle"); } public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("UserInterceptor...afterCompletion"); } }
从上述代码可以看出,自定义的拦截器类实现了 HandlerInterceptor
接口,并实现了接口中的3 个方法。关于这3个方法的具体描述如下:
preHandle()
方法:该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true
时,表示继续向下执行; 当其返回值为false
时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。postHandle()
方法:该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。afterCompletion()
方法:该方法在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。
拦截器的配置
要使自定义的拦截器类生效,需要在SpringMVC的配置文件中进行配置,配置代码如下:
<!--配置拦截器--> <mvc:interceptors> <!--使用bean直接定义在<mvc:interceptor>下面的Interceptor 将拦截所有请求--> <bean class="com.hzy.interceptor.UserInterceptor"/> <!--拦截器1--> <mvc:interceptor> <!--配置拦截器作用的路径--> <mvc:mapping path="/**"/> <!--配置不需要拦截器作用的路径--> <mvc:exclude-mapping path=""/> <!--定义在<mvc:interceptor>下面,表示对匹配路径的请求才进行拦截--> <bean class="com.hzy.interceptor.Interceptor1"/> </mvc:interceptor> <!--拦截器2--> <mvc:interceptor> <mvc:mapping path="/hello"/> <bean class="com.hzy.interceptor.Interceptor2"/> </mvc:interceptor> ...... </mvc:interceptors>
在上述代码中, <mvc:interceptors>
元素用于配置一组拦截器,其子元素<bean>
中定义的是全局拦截器,它会拦截所有的请求;而<mvc:interceptor>
元素中定义的是指定路径的拦截器,它会对指定路径下的请求生效。<mvc:interceptor>
元素的子元素<mvc:mapping>
用于配置拦截器作用的路径,该路径在其属性 path
中定义。如上述代码中 path
的属性值 “/**”
表示拦截所有路径, “/hello”
表示拦截所有以“hello”
结尾的路径。如果在请求路径中包含不需要拦截的内容,还可以通过 <mvc:exclude-mapping>
元素进行配置。
拦截器的执行流程
拦截器的执行是有一定顺序的,该顺序与配置文件中所定义的拦截器的顺序相关。
单个拦截器的执行流程
如果在项目中只定义了一个拦截器,那么该拦截器在程序中的执行流程如下图所示。从中可以看出,程序首先会执行拦截器类中的 preHandle()
方法,如果该方法的返回值为 true
,则程序就会继续向下执行处理器中的方法,否则将不再向下执行:在业务处理器(即控制器Controller
类)处理完请求后,会执行 postHandle()
方法,然后通过 DispatcherServlet
向客户端返回响应;在 DispatcherServlet
处理完请求后,才会执行 afterCompletion()
方法。
简单的案例
web.xml中配置SpringMVC的前端过滤器和初始化加载配置文件等信息。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <servlet> <!--配置前端过滤器--> <servlet-name>spring-mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--初始化时加载配置文件--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-config.xml</param-value> </init-param> <!--表示容器在启动时立即加载Servlet--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>spring-mvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
在src下创建com.hzy.controller包,并在里面创建控制器类HelloController
,
@Controller public class HelloController { @RequestMapping("/hello") public String hello(){ System.out.println("Hello"); return "success"; } }
在src下创建com.hzy.interceptor包,并在里面创建拦截器类UserInterceptor
,该类需要实现HandlerInterceptor
接口。
public class UserInterceptor implements HandlerInterceptor { public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception { System.out.println("UserInterceptor...preHandle"); //对拦截的请求进行放行处理(true为放行,false为不放行) return true; } public void postHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("UserInterceptor...postHandle"); } public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("UserInterceptor...afterCompletion"); } }
在resources目录下创建springmvc-config.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--指定需要扫描的包--> <context:component-scan base-package="com.hzy.controller"/> <!--定义视图解析器--> <bean id="internalResourceViewResolve" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--设置前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--设置后缀--> <property name="suffix" value=".jsp"/> </bean> <mvc:annotation-driven/> <!--配置拦截器--> <mvc:interceptors> <!--使用bean直接定义在<mvc:interceptor>下面的Interceptor 将拦截所有请求--> <bean class="com.hzy.interceptor.UserInterceptor"/> </mvc:interceptors> </beans>
在WEB-INF目录下创建一个jsp文件夹,并在里面创建一个页面文件success.jsp,然后在<body>
里面显示任意信息。发布并启动项目,访问http://localhost:8080/springMvc_SSM/hello (注意你的访问路径可能和我不一样哦)
结果:
控制台
多个拦截器的执行流程
在大型项目中,通常会定义很多拦截器来实现不同的功能。多个拦截器的执行顺序如图所示。这里假设有两个拦截器 Interceptor1
和 Interceptor2
,并且在配置文件中,Interceptor1
拦截器配置在前。
从图上可以看出,当有多个拦截器同时工作时,它们的preHandle()
方法会按照配置文件中拦截器的配置顺序执行,而它们的postHandle()
方法和afterCompletion()
方法则会按照配置顺序的反序执行。
下为了验证上述描述,下面就修改上面的代码来演示多个拦截器的执行。
在com.hzy.interceptor包中创建两个拦截器类Interceptor1和Interceptor2。
Interceptor1.java
public class Interceptor1 implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("Interceptor1...preHandle"); return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("Interceptor1...postHandle"); } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("Interceptor1...afterCompletion"); } }
Interceptor2.java
public class Interceptor2 implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("Interceptor2...preHandle"); return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("Interceptor2...postHandle"); } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("Interceptor2...afterCompletion"); } }
springmvc-config.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--指定需要扫描的包--> <context:component-scan base-package="com.hzy.controller"/> <!--定义视图解析器--> <bean id="internalResourceViewResolve" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--设置前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--设置后缀--> <property name="suffix" value=".jsp"/> </bean> <mvc:annotation-driven/> <!--配置拦截器--> <mvc:interceptors> <!--使用bean直接定义在<mvc:interceptor>下面的Interceptor 将拦截所有请求--> <bean class="com.hzy.interceptor.UserInterceptor"/> <!--拦截器1--> <mvc:interceptor> <!--配置拦截器作用的路径--> <mvc:mapping path="/**"/> <!--配置不需要拦截器作用的路径--> <!-- <mvc:exclude-mapping path=""/>--> <!--定义在<mvc:interceptor>下面,表示对匹配路径的请求才进行拦截--> <bean class="com.hzy.interceptor.Interceptor1"/> </mvc:interceptor> <!--拦截器2--> <mvc:interceptor> <mvc:mapping path="/hello"/> <bean class="com.hzy.interceptor.Interceptor2"/> </mvc:interceptor> </mvc:interceptors> </beans>
上述拦截器的配置代码中,第一个拦截器会作用于所有路径下的请求,而第二个拦截器会作用于“/hello”
结尾的请求。运行项目得到结果:
页面输出跟前面一样。
控制台输出:
从图中可以看出,程序先执行了前面两个拦截器类中的preHandle()
方法,这两个方法的执行顺序与配置文件中定义的顺序相同;然后执行了控制器中类中的hello()
方法;最后执行了两个拦截器类中的postHandle()
方法和afterCompletion()
方法,且这两个方法的执行顺序与配置文件中所定义的拦截器顺序相反。
到此这篇关于SpringMVC一步到位精通拦截器的文章就介绍到这了,更多相关SpringMVC拦截器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!