自定义拦截器
2023年11月15日大约 8 分钟约 1515 字
什么是拦截器
说明
- Spring MVC 也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能。
- 自定义的拦截器必须实现 HandlerInterceptor 接口。
自定义拦截器的三个方法
- preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。
- postHandle():这个方法在目标方法处理完请求后执行。
- afterCompletion():这个方法在完全处理完请求后被调用,可以在该方法中进行一些资源 清理的操作。
自定义拦截器执行流程分析图

- 如果 preHandle 方法 返回 false,则不再执行目标方法,可以在此指定返回页面。
- postHandle 在目标方法被执行后执行。可以在方法中访问到目标方法返回的 ModelAndView 对象。
- 若 preHandle 返回 true,则 afterCompletion 方法 在渲染视图之后被执行。
- 若 preHandle 返回 false,则 afterCompletion 方法不会被调用。
- 在配置拦截器时,可以指定该拦截器对哪些请求生效,哪些请求不生效。
自定义拦截器应用实例
快速入门
创建 MyInterceptor01.java
package com.lzw.web.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author LiAng
*/
@Component
public class MyInterceptor01 implements HandlerInterceptor {
/**
* 1. preHandle() 在目标方法执行前被执行
* 2. 如果preHandle() 返回false , 不再执行目标方法
* 3. 该方法可以获取到request, response, handler
* 4. 这里根据业务,可以进行拦截,并指定跳转到哪个页面
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("--MyInterceptor01--preHandle()--");
return true;
}
/**
* 1. 在目标方法执行后,会执行postHandle
* 2. 该方法可以获取到 目标方法,返回的ModelAndView对象
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("--MyInterceptor01--postHandle()--");
}
/**
* afterCompletion() 在视图渲染后被执行, 这里可以进行资源清理工作
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("--MyInterceptor01--afterCompletion()--");
}
}
修改 springDispatcherServlet-servlet.xml
<!--配置自定义拦截器-spring配置文件-->
<mvc:interceptors>
<!--
1. 第一种配置方式
2. 使用ref 引用到对应的myInterceptor01
3. 这种方式,会拦截所有的目标方法
-->
<ref bean="myInterceptor01"/>
</mvc:interceptors>
创建 FurnHandler.java
package com.lzw.web.interceptor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author LiAng
*/
@Controller
public class FurnHandler {
@RequestMapping(value = "/hi")
public String hi(){
System.out.println("--FurnHandler--hi()--");
return "success";
}
@RequestMapping(value = "/hello")
public String hello(){
System.out.println("--FurnHandler--hello()--");
return "success";
}
}
创建 web/interceptor.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>测试自定义拦截器</title>
</head>
<body>
<h1>测试自定义拦截器</h1>
<a href="<%=request.getContextPath()%>/hi">测试自定义拦截器-hi</a><br/>
<a href="<%=request.getContextPath()%>/hello">测试自定义拦截器-hello</a><br/>
</body>
</html>
完成测试
注意事项和细节说明
- 默认配置是都所有的目标方法都进行拦截,也可以指定拦截目标方法,比如只是拦截 hi
<mvc:interceptors>
<!--
1. 第二种配置方式
2. mvc:mapping path="/hi" 指定要拦截的路径
3. ref bean="myInterceptor01" 指定对哪个拦截器进行配置
-->
<mvc:interceptor>
<mvc:mapping path="/hi"/>
<ref bean="myInterceptor01"/>
</mvc:interceptor>
</mvc:interceptors>

- mvc:mapping 支持通配符,同时指定不对哪些目标方法进行拦截
<mvc:interceptors>
<!--
1. 第三种配置方式
2. mvc:mapping path="/h*" 通配符方式 表示拦截 /h 打头的路径
3. mvc:exclude-mapping path="/hello" /hello不拦截
4. ref bean="myInterceptor01" 指定对哪个拦截器配置
-->
<mvc:interceptor>
<mvc:mapping path="/h*"/>
<mvc:exclude-mapping path="/hello"/>
<ref bean="myInterceptor01"/>
</mvc:interceptor>
</mvc:interceptors>

拦截器需要配置才生效,不配置是不生效的。
如果 preHandler() 方法返回了 false,就不会执行目标方法(前提是你的目标方法被拦截了),程序员可以在这里根据业务需要指定跳转页面。
多个拦截器
执行流程


应用实例1
创建 MyInterceptor02.java
package com.lzw.web.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author LiAng
*/
@Component
public class MyInterceptor02 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("--MyInterceptor02--preHandle()--");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("--MyInterceptor02--postHandle()--");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("--MyInterceptor02--afterCompletion()--");
}
}
修改 springDispatcherServlet-servlet.xml
<!--配置自定义拦截器-spring配置文件-->
<mvc:interceptors>
<!--
1. 第3种配置方式
2. mvc:mapping path="/h*" 通配符方式 表示拦截 /h 打头的路径
3. mvc:exclude-mapping path="/hello" /hello不拦截
4. ref bean="myInterceptor01" 指定对哪个拦截器配置
-->
<mvc:interceptor>
<mvc:mapping path="/h*"/>
<mvc:exclude-mapping path="/hello"/>
<ref bean="myInterceptor01"/>
</mvc:interceptor>
<!--
1.配置的第二个拦截器
2.多个拦截器在执行时,是顺序执行
-->
<mvc:interceptor>
<mvc:mapping path="/h*"/>
<ref bean="myInterceptor02"/>
</mvc:interceptor>
</mvc:interceptors>
完成测试

注意事项和细节说明
- 如果第1个拦截器的 preHandle() 返回 false,后面都不在执行。
- 如果第2个拦截器的 preHandle() 返回 false,就直接执行第1个拦截器的afterCompletion()方法,如果拦截器更多,规则类似。
- 前面说的规则,都是目标方法被拦截的前提。
应用实例2
如果用户提交的数据有禁用词(比如 病毒),则在第 1 个拦截器就返回,不执行目标方法。
创建 web\WEB-INF\pages\waring.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>警告</title>
</head>
<body>
<h1>不要乱讲话~</h1>
</body>
</html>
修改 MyInterceptor01.java
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("--MyInterceptor01--preHandle()--");
//获取到用户提交的关键字
String keyword = request.getParameter("keyword");
if("病毒".equals(keyword)){
//请求转发到 warning.jsp
request.getRequestDispatcher("/WEB-INF/pages/warning.jsp").forward(request,response);
return false;
}
System.out.println("keyword:" + keyword);
return true;
}