目录:
- 拦截器 :
- 1. 拦截器的 “概述”
- 2. 拦截器的 “定义” (创建“拦截器”对象)
- 3. 拦截器的 “配置” (让“拦截器”对象生效)
- 4. 拦截器的 “执行流程”
- “单个拦截器”的执行流程
- “多个拦截器”的执行流程
作者简介 :一只大皮卡丘,计算机专业学生,正在努力学习、努力敲代码中! 让我们一起继续努力学习!
该文章参考学习教材为:
《Java EE企业级应用开发教程 (Spring + Spring MVC +MyBatis)》 黑马程序员 / 编著
文章以课本知识点 + 代码为主线,结合自己看书学习过程中的理解和感悟 ,最终成就了该文章文章用于本人学习使用 , 同时希望能帮助大家。
欢迎大家点赞👍 收藏⭐ 关注💖哦!!!(侵权可联系我,进行删除,如果雷同,纯属巧合)
在实际项目中,拦截器 的 使用是非常普遍 的,例如在购物网站中通过 拦截器 可以 拦截未登录的用户 ,禁止其购买商品,或者 使用拦截器 来 验证已登录用户是否有相应 的 操作权限 等。在Struts2框架中,拦截器是其重要的组成部分,而 Spring MVC 中 也提供了拦截器功能,通过配置即可对请求进行拦截处理。
拦截器 :
1. 拦截器的 “概述”
SpringMVC 中的 拦截器( Interceptor ) 类似于 Servlet中的过滤器( Filter),它主要用于拦截用户请求并做相应的处理。例如通过拦截器可以进行 权限验证、记录请求信息的日志 、判断用户是否登录 等。
2. 拦截器的 “定义” (创建“拦截器”对象)
要使用 SpringMVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过 两种方式来定义。
- 一种是通过 实现 HandlerInterceptor接口,或 继承 HandlerInterceptor接口的实现类 : HandlerInterceptorAdapter 来定义;
- 另一种是通过 实现 WebRequestInterceptor接口,或 继承 WebRequestInterceptor接口 的 实现类 来定义。
例子如 :(实现HandlerInterceptor接口的方式来实现SpringMVC拦截器) :
//通过实现HandlerInterceptor接口的方式来实现SPringMVC拦截器 public class CustomerInterceptor implements HandlerInterceptor { //该方法在“控制器方法”之前执行,其返回值表示“是否中断后续操作” @Override public boolean preHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o) throws Exception { return false; } //该方法在“控制器方法”之后执行,且“解析视图”之前执行(可通过该方法对“模型和视图”进一步修改) @Override public void postHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } //该方法在“整个请求”完成之后执行,即“视图渲染结束”之后执行(通过该方法可进行“资源清理、记录日志信息等”) @Override public void afterCompletion(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
从上述代码可以看出,自定义的拦截器类实现了HandlerInterceptor接口,并实现了 接口中的三个方法 。 关于这 三个方法 的 具体描述 如下 :
方法 描述 preHandler()方法 该方法会在 控制器方法 之前执行,其 返回值 表示 是否中断后续操作。
当其返回值为 true 时,表示 继续向下执行;
当其返回值为 false 时,会 中断后续的所有操作 (包括调用下一个拦截器和控制器类中的方法执行等)。postHandle()方法 该方法会在 控制器方法 之后执行,且 解析视图 之前执行。可以通过此方法对请求域中的 模型和视图 做出 进一步的修改。 afterCompletion()方法 该方法在 “整个请求完成” 之后执行,即 视图渲染结束 之后执行。可以通过此方法实现一些资源清理、记录日志信息等。
要想让刚创建好的 “拦截器”生效,就要在 springmvc-config.xml中进行配置,让“拦截器”生效。
3. 拦截器的 “配置” (让“拦截器”对象生效)
要 使自定义的拦截器生效,还需要在SpringMVC的配置文件 : springmvc-config.xml 中进行配置。
SpringMVC拦截器“配置元素图” 如下所示 :
SpringMVC拦截器“在==springmvc-config.xml”== 中==配置代码== 如下所示 :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置拦截器 --> <mvc:interceptors> <!-- 配置“全局拦截器”,拦截所有请求 --> <bean class="com.myh.interceptor.CustomerInterceptor"/> <!-- 配置“普通拦截器1”,拦截“指定路径”/“指定请求” --> <mvc:interceptor> <!-- 需要拦截的路径 --> <mvc:mapping path="/**"/> <bean class="com.myh.interceptor.CustomerInterceptor1"/> </mvc:interceptor> <!-- 配置“普通拦截器2” --> <mvc:interceptor> <!-- 需要拦截的路径 --> <!-- 拦截所有以 /hello 结尾的路径 --> <mvc:mapping path="/hello"/> <bean class="com.myh.interceptor.CustomerInterceptor2"/> </mvc:interceptor> ..... </mvc:interceptors> </beans>
在 上述配置代码中,<mvc:interceptors>元素用于配置一组拦截器,其子元素<bean>中定义的
是全局拦截器,它会拦截所有的请求;而 <mvc:interceptor>元素 中定义的是指定路径的拦截器,
它会对指定路径下的请求生效。<mvc:interceptor> 元素的子元素<mvc:mapping>用于配置拦截
器作用的路径,该路径在其属性path中定义。如上述代码中path的属性值“/”** 表示拦截所有路径,“hello"表示拦截所有以"hello" 结尾的路径。如果在请求路径中包含不需要拦截的内容,还可以通过 <mvc:exclude- mapping>元素进行配置。注意点 :
需要注意的是,<mvc:interceptor>中的子元素必须按照上述代码的配置顺序进行编写,即 <mvc:mapping> —> <mvc:exclude-mapping> —> <bean> 的顺序,否则文件会报错。
4. 拦截器的 “执行流程”
“单个拦截器”的执行流程
在 运行程序 时,拦截器的执行 是 有一定顺序 的,该 顺序 与配置文件中所定义的 拦截器的顺序 相关。如果在项目中只定义了一个拦截器,那么该拦截器在程序中的 执行流程如图 如下图所示 :
从 上图 可以看出,程序首先 会 执行拦截器类 中的 preHandle( )方法,如果该方法的 返回值为 true ,则程序会 继续向下执行 处理器类中的方法 ,否则不会向下执行 ,后执行 控制器类中方法,
执行完“控制器类中方法”后,会执行“拦截器类”中的 postHandle( )方法,然后会通过DispatcherServlet 向 各户端返回响应;在DispatcherServlet处理完请求后,才会执行
afterCompletion( )方法。“单个拦截器”的执行流程 例子如 :
第一步、创建项目,导入依赖 :
Spring MVC所需JAR (百度网盘)第二步 :配置 SpringMVC拦截器 的 相关文件 :
web.xml :
<?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_4_0.xsd" version="4.0"> <!-- 配置"前端过滤器"--> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置springmvc-config.xml配置文件的位置 (上下文配置位置) --> <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的Mapper映射 --> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
springmvc-config.xml :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置组件扫描,进行根包扫描,让注解生效 --> <context:component-scan base-package="com.myh.controller"/> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/"/> <!-- 后缀 --> <property name="suffix" value=".jsp"/> </bean> <!-- 配置SpringMVC 拦截器 --> <mvc:interceptors> <!-- 全局拦截器,会拦截所有请求 --> <bean class="com.myh.interceptor.CustomerInterceptor"/> </mvc:interceptors> </beans>
HelloController.java (控制器类) :
package com.myh.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller //标记该类为控制器类 public class HelloController { /** * 页面跳转 */ @RequestMapping("/hello") public String Hello() { System.out.println("HelloController...Hello()"); return "success"; //响应一个页面给前端 } }
CustomerInterceptor.java (拦截器对象) :
package com.myh.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class CustomerInterceptor implements HandlerInterceptor { //通过实现HandlerInterceptor接口的方式来实现SPringMVC拦截器 //该方法在“控制器方法”之前执行,其返回值表示“是否中断后续操作” @Override public boolean preHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object handler) throws Exception { //对拦截的请求放行 return true; } //该方法在“控制器方法”之后执行,且“解析视图”之前执行(可通过该方法对“模型和视图”进一步修改) @Override public void postHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("CustomerInterceptor...postHandle()"); } //该方法在“整个请求”完成之后执行,即“视图渲染结束”之后执行(通过该方法可进行“资源清理、记录日志信息等”) @Override public void afterCompletion(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object handler, Exception e) throws Exception { System.out.println("CustomerInterceptor...afterCompletion()"); } }
success.jsp :
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>success.jsp页面</title> </head> <body> ok </body> </html>
启动服务器,前端访问 /hello ,控制台打印内容为 :
从上图可以看出,程序先执行了拦截器类中的==preHandle( )方法,然后执行了控制器中的Hello( )方法,最后分别执行了拦截器类中的postHandle( )方法和afterCompletion( )方法。这与上文所描述的单个拦截器的执行顺序是一致的==。
“多个拦截器”的执行流程
在 大型的企业级项目 中,通常 不会只有一个拦截器,开发人员可能会定义 多个拦截器 来实现不同的功能。
多个拦截器的执行顺序 如下图:
从上图可以看出,当有 "多个拦截器"同时工作 时,它们的 preHandle( )方法 会按照配置文件中 拦截器 的 "配置顺序"执行,而它们的 postHandle( )方法 和 afterCompletion( )方法 则会按照 配置顺序 的 “反序执行”。
“多个拦截器”的执行流程 例子如 :
第一步、创建项目,导入依赖 :
Spring MVC所需JAR (百度网盘)第二步 :配置 SpringMVC拦截器 的 相关文件 :
web.xml :
<?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_4_0.xsd" version="4.0"> <!-- 配置"前端过滤器"--> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置springmvc-config.xml配置文件的位置 (上下文配置位置) --> <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的Mapper映射 --> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
springmvc-config.xml :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置组件扫描,进行根包扫描,让注解生效 --> <context:component-scan base-package="com.myh.controller"/> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/"/> <!-- 后缀 --> <property name="suffix" value=".jsp"/> </bean> <!-- 定义两个拦截器 --> <mvc:interceptors> <!-- 拦截器1 --> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.myh.interceptor.Interceptor1"/> </mvc:interceptor> <!-- 拦截器2 --> <mvc:interceptor> <mvc:mapping path="/hello"/> <bean class="com.myh.interceptor.Interceptor2"/> </mvc:interceptor> </mvc:interceptors> </beans>
在上述拦截器的配置代码中,第一个拦截器会作用于所有路径下的请求,而 第二个拦截器 会作用于以 “hello" 结尾的请求。
HelloController.java (控制器类) :
package com.myh.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller //标记该类为控制器类 public class HelloController { /** * 页面跳转 */ @RequestMapping("/hello") public String Hello() { System.out.println("HelloController...Hello()"); return "success"; //响应一个页面给前端 } }
Interceptor1.java (拦截器对象1) :
package com.myh.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; /** * 如果有多个拦截器,preHandle()方法按照拦截器的“顺序执行”, * postHandle()方法 和 afterCompletion()方法按照拦截器的“逆序执行” */ public class Interceptor1 implements HandlerInterceptor {//以实现HandlerInterceptor接口的方式定义拦截器 @Override public boolean preHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o) throws Exception { System.out.println("Interceptor1...preHandle()"); return true; //对拦截的请求放行 } @Override public void postHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("Interceptor1...postHandle()"); } @Override public void afterCompletion(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { System.out.println("Interceptor1...afterCompletion()"); } }
Interceptor2.java (拦截器对象2) :
package com.myh.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; /** * 如果有多个拦截器,preHandle()方法按照拦截器的“顺序执行”, * postHandle()方法 和 afterCompletion()方法按照拦截器的“逆序执行” */ public class Interceptor2 implements HandlerInterceptor {//以实现HandlerInterceptor接口的方式定义拦截器 @Override public boolean preHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o) throws Exception { System.out.println("Interceptor2...preHandle()"); return true; //对拦截的请求放行 } @Override public void postHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("Interceptor2...postHandle()"); } @Override public void afterCompletion(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { System.out.println("Interceptor2...afterCompletion()"); } }
success.jsp :
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>success.jsp页面</title> </head> <body> ok </body> </html>
启动服务器,前端访问 /hello ,控制台打印内容为 :
从控制体输出信息可以看出,程序 先执行 了 前两个拦截器类 中的 preHandle( )方法,这 两个方法的执行顺序 与 配置文件中定义 的 顺序相同;然后执行了控制器类中的 Hello( )方法; 最后执行了两个拦截器类中的 postHandle( )方法 和 afterCompletion( )方法 ,且这两个方法的 执行顺序 与配置文件中所 定义 的拦截器 顺序相反。