定义
在实际应用中,会将拦截器(interceptor)按一定顺序联结成一条链,该链被称为拦截器链(Interceptor Chain)
拦截器(Interceptor)和过滤器(Filter)的区别
区别 | 过滤器 | 拦截器 |
---|---|---|
适用范围 | 是servlet规范中的一部分,任何JavaWeb工程都可以使用 | 是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用 |
拦截范围 | 在url-pattern中配置了/* 后,会对所有要访问的资源进行拦截 |
在<mvc:mapping path=""/> 中配置了/** 之后,也会对所有资源进行拦截,但是可以通过<mvc:exclude-mapping path=""/> 标签排除不需要拦截的资源 |
流程

步骤
HandlerInterceptor
接口的实现类,并重写它的三个方法注意:
此处仅弄一个简单环境来测试拦截器,所以准备工作均省略,可详见快速入门以及SpringMVC数据响应部分内容,完整框架如图所示
<img alt="image-20241127154532718">
以上图中还未配置拦截器,所以运行后前面能接收到响应如图所示,现要求进行拦截器配置
<img alt="image-20241127161120181">
Step1: 创建一个与三层架构包同级的interceptor
包并在该包下创建一个实现HandlerInterceptor
接口的拦截器类,代码如下
package at.guigu.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
// 在原始方法(即目标方法)执行之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle Running...");
return false;
}
// 在原始方法(即目标方法)执行之后,视图对象返回之前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle Running...");
}
// 在整个请求完成之后执行(即在原始方法执行完并且视图对象也以返回之后执行)
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion Running...");
}
}
Step2: 在SpringMVC的核心配置文件中配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--定义拦截器的作用范围:此处表示拦截所有请求路径-->
<mvc:mapping path="/**"/>
<!--定义拦截器的具体实现类,class属性值为对应实现类的全限定名-->
<bean class="at.guigu.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
SpringMVC核心配置文件完整代码如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--mvc的注解驱动-->
<mvc:annotation-driven/>
<!--配置Controller层的注解的组件扫描-->
<context:component-scan base-package="at.guigu.controller"></context:component-scan>
<!--等同于
<context:component-scan base-package="at.guigu">
type指定要扫描的内容为注解,expression指定要扫描的对应注解的全限定名
只扫描at.guigu包下有@Controller注解的类
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
-->
<!--配置内部资源视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--将InternalResourceViewResolver类中的视图名称前缀属性prefix的值设为/jsp/-->
<property name="prefix" value="/jsp/"></property>
<!--将InternalResourceViewResolver类中的视图名称后缀属性suffix的值设为.jsp-->
<property name="suffix" value=".jsp"></property>
</bean>
<!--配置静态资源的路径映射,让 Spring MVC 可以处理静态文件-->
<mvc:default-servlet-handler/>
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--定义拦截器的作用范围:此处表示拦截所有请求路径-->
<mvc:mapping path="/**"/>
<!--定义拦截器的具体实现类,class属性值为对应实现类的全限定名-->
<bean class="at.guigu.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
运行后截图如下
<img alt="image-20241127161337767">
Step3: 测试拦截器拦截效果
在以上运行截图中,只执行了preHandle
方法是因为它的返回值为true
表示请求可以交给Controller来执行原始方法;反之则请求被拦截
此时若将其返回值改true,代码如下
package at.guigu.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
// 在原始方法(即目标方法)执行之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle Running...");
return true;
}
// 在原始方法(即目标方法)执行之后,视图对象返回之前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle Running...");
}
// 在整个请求完成之后执行(即在原始方法执行完并且视图对象也以返回之后执行)
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion Running...");
}
}
此时的运行截图如下
<img alt="image-20241127162013217">
HandlerInterceptor
接口详解HandlerInterceptor
接口方法
HandlerInterceptor 接口方法 |
解释 |
---|---|
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception |
在请求到达Controller之前执行(即在在原始方法(即目标方法)执行之前执行),用于执行预处理逻辑。 |
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception |
在Controller处理完请求之后,视图渲染之前执行(即在原始方法(目标方法)执行之后,视图对象返回之前执行) |
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception |
在整个请求完成之后执行(即在原始方法执行完并且视图对象也以返回之后执行)。注意:即使在Controller或视图渲染过程中抛出异常,该方法也会执行 |
方法对应参数及返回值详解(相同参数不在重复解释)
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
——前置处理方法
HttpServletRequest
:请求对象HttpServletResponse
:响应对象handler
:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装return true
:表示请求可以交给Controller来执行原始方法。(当为拦截链环境时,会将请求交给下一个Interceptor的前置处理方法,直到所有前置处理方法均通过后,会交给Controller来执行原始方法)return false
:表示请求被拦截,Controller控制器和拦截链上后续的Interceptor
都不会继续执行postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView)
——后置处理方法
ModelAndView
:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行跳转afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex)
——完成后处理方法
Exception
: 如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理preHandle
方法经常用于执行预处理逻辑,比如:
验证用户身份或权限。
检查请求参数是否合法。
记录日志或统计请求次数。
当返回值为false
时请求被拦截,后续逻辑(如Controller处理或postHandle
、afterCompletion
方法)不会执行(可详见快速入门)。此时可以直接设置响应,例如返回一个错误状态码或转发或重定向到其他页面。示例如下
webapp
)下的jsp文件夹中创建error.jsp页面,代码如下,用于拦截示例<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Error...</h1>
</body>
</html>
MyInterceptor
类的代码更改如下
package at.guigu.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
// 在原始方法(即目标方法)执行之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle Running...");
String str = request.getParameter("param");
if ("yes".equals(str)) {
return true;
} else {
request.getRequestDispatcher("/jsp/error.jsp").forward(request, response);
return false;
}
}
// 在原始方法(即目标方法)执行之后,视图对象返回之前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle Running...");
}
// 在整个请求完成之后执行(即在原始方法执行完并且视图对象也以返回之后执行)
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion Running...");
}
}
当param请求参数值不是yes
<img alt="image-20241127163734877">
当param请求参数值是yes
<img alt="image-20241127163949308">
postHandle
方法用于对ModelAndView
进行修改,例如:
添加全局数据到视图中(如页面标题、用户信息)。
根据Controller的处理结果动态调整视图数据。
注意:如果Controller方法没有返回
ModelAndView
(如使用@ResponseBody
或RestController
),则此方法可能不会被调用。
MyInterceptor
类的代码更改如下
package at.guigu.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
// 在原始方法(即目标方法)执行之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle Running...");
String str = request.getParameter("param");
if ("yes".equals(str)) {
return true;
} else {
request.getRequestDispatcher("/jsp/error.jsp").forward(request, response);
return false;
}
}
// 在原始方法(即目标方法)执行之后,视图对象返回之前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
modelAndView.addObject("username", "李四");
System.out.println("postHandle Running...");
}
// 在整个请求完成之后执行(即在原始方法执行完并且视图对象也以返回之后执行)
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion Running...");
}
}
<img alt="image-20241127164527813">
在快速入门中配置的是单个拦截器,在SpringMVC的核心配置文件中对应的代码如下
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--定义拦截器的作用范围:此处表示拦截所有请求路径-->
<mvc:mapping path="/**"/>
<!--定义拦截器的具体实现类,class属性值为对应实现类的全限定名-->
<bean class="at.guigu.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
用到的标签
标签 | 解释 |
---|---|
<mvc:interceptors> |
配置拦截器 |
<mvc:interceptors> 内嵌标签 |
解释 |
<mvc:interceptor> |
配置单个拦截器 |
<mvc:interceptor> 内嵌标签 |
解释 |
<mvc:mapping path/> |
定义拦截器的作用范围。当path 属性为/** 时,代表拦截所有请求路径;当为/xxx/** 时,代表拦截xxx下的所有资源 |
<bean class/> |
定义拦截器的具体实现类,class 属性值为对应实现类的全限定名 |
环境准备等工作可见快速入门,此处以配置两个拦截器为例
Step1: 在interceptor
包下创建第二个实现HandlerInterceptor
接口的拦截器类,并重写其中的方法,代码如下
package at.guigu.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptorTwo implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle Running222...");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle Running222...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion Running222...");
}
}
Step2:
在SpringMVC的核心配置文件中配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<!--配置第一个拦截器实现类-->
<mvc:interceptor>
<!--定义拦截器的作用范围:此处表示拦截所有请求路径-->
<mvc:mapping path="/**"/>
<!--定义拦截器的具体实现类,class属性值为对应实现类的全限定名-->
<bean class="at.guigu.interceptor.MyInterceptor"/>
</mvc:interceptor>
<!--配置第二个拦截器实现类-->
<mvc:interceptor>
<!--定义拦截器的作用范围:此处表示拦截所有请求路径-->
<mvc:mapping path="/**"/>
<!--定义拦截器的具体实现类,class属性值为对应实现类的全限定名-->
<bean class="at.guigu.interceptor.MyInterceptorTwo"/>
</mvc:interceptor>
</mvc:interceptors>
SpringMVC核心配置文件完整代码如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--mvc的注解驱动-->
<mvc:annotation-driven/>
<!--配置Controller层的注解的组件扫描-->
<context:component-scan base-package="at.guigu.controller"></context:component-scan>
<!--等同于
<context:component-scan base-package="at.guigu">
type指定要扫描的内容为注解,expression指定要扫描的对应注解的全限定名
只扫描at.guigu包下有@Controller注解的类
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
-->
<!--配置内部资源视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--将InternalResourceViewResolver类中的视图名称前缀属性prefix的值设为/jsp/-->
<property name="prefix" value="/jsp/"></property>
<!--将InternalResourceViewResolver类中的视图名称后缀属性suffix的值设为.jsp-->
<property name="suffix" value=".jsp"></property>
</bean>
<!--配置静态资源的路径映射,让 Spring MVC 可以处理静态文件-->
<mvc:default-servlet-handler/>
<!--配置拦截器-->
<mvc:interceptors>
<!--配置第一个拦截器实现类-->
<mvc:interceptor>
<!--定义拦截器的作用范围:此处表示拦截所有请求路径-->
<mvc:mapping path="/**"/>
<!--定义拦截器的具体实现类,class属性值为对应实现类的全限定名-->
<bean class="at.guigu.interceptor.MyInterceptor"/>
</mvc:interceptor>
<!--配置第二个拦截器实现类-->
<mvc:interceptor>
<!--定义拦截器的作用范围:此处表示拦截所有请求路径-->
<mvc:mapping path="/**"/>
<!--定义拦截器的具体实现类,class属性值为对应实现类的全限定名-->
<bean class="at.guigu.interceptor.MyInterceptorTwo"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
<img alt="image-20241127171146964">
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。