目录
一、SpringMVC 拦截器_拦截器简介
二、SpringMVC 拦截器_拦截器使用
三、SpringMVC 拦截器_拦截器作用域
四、SpringMVC 拦截器_拦截器链与执行顺序
五、SpringMVC 拦截器_拦截器过滤敏感词案例
六、知识点整理:
一、SpringMVC 拦截器_拦截器简介
SpringMVC的拦截器(Interceptor)也是AOP思想的一种实现方式。它与Servlet的过滤器(Filter)功能类似,主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。
拦截器和过滤器的区别:
1.拦截器是SpringMVC组件,而过滤器是Servlet组件。
2.拦截器不依赖Web容器,过滤器依赖Web容器。
3.拦截器只能对控制器请求起作用,而过滤器可以对所有的请求起作用。
4.拦截器可以直接获取IOC容器中的对象,而过滤器不太方便获取。
二、SpringMVC 拦截器_拦截器使用
项目结构:
1.使用Maven创建SpringMVC的Web项目
2.创建控制器方法MyController1
@Controller
public class MyController1 {
@RequestMapping("/m1")
public String m1(){
System.out.println("控制器方法m1");
return "result";
}
}
3.创建拦截器类MyInterceptor,该类实现HandlerInterceptor接口,需要重写三个方法:
(1)preHandle:请求到达Controller前执行的方法,返回值为true时,请求可以通过拦截器,返回值为false时,请求不能通过拦截器,即被拦截器拦截
(2)postHandle:跳转到JSP前执行的方法
(3)afterCompletion:跳转到JSP执行后的方法
public class MyInterceptor implements HandlerInterceptor {
//请求到达Controller前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器1:请求到达Controller前");
return false;
}
//跳转到JSP页面前执行,此时可以向request域添加数据,也就是这里的name可以传到request域中
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器1:跳转到JSP页面前");
request.setAttribute("name","坏蛋");
}
//跳转到JSP页面后执行,此时不能向request域添加数据,也就是这里的age传不到request域中
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("拦截器1:跳转到JSP页面后");
request.setAttribute("age",10);
}
}
4.编写JSP页面 result.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>结果</title>
</head>
<body>
<h3>name:${requestScope.name}</h3>
<h3>age:${requestScope.age}</h3>
</body>
</html>
5.在SpringMVC核心配置文件springmvc.xml中配置拦截器
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置拦截器的作用路径,/**表示作用于所有控制器-->
<mvc:mapping path="/**"/>
<!-- 配置拦截器对象,指定用哪个拦截器-->
<bean class="com.itbaizhan.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
6.请求结果:
1.当 preHandle方法返回值为false时 :
当preHandle方法返回值为false时,请求会被拦截器拦截,不会到达Controller控制器。
2.当 preHandle方法返回值为true时 :
由结果可以看出,当preHandle方法返回值为true时,请求可以通过拦截器,不会被拦截器拦截,所以先执行preHandle方法,然后到达Controller层执行方法,再跳转到JSP页面,在跳转到JSP页面前先执行postHandle,等到JSP页面执行完毕再执行afterCompletion方法。同时,PostHandle方法在JSP页面前执行,所以可以向request域中添加数据,而afterCompletion方法在JSP页面执行后执行,所以不能向request域中添加数据。
三、SpringMVC 拦截器_拦截器作用域
1.全局拦截器
全局拦截器可以拦截所有控制器处理的URL,作用等于/**, 配置方式如下:
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 全局拦截器-->
<bean class="com.itbaizhan.interceptor.MyInterceptor"></bean>
</mvc:interceptors>
==
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置拦截器的作用路径,/**表示作用于所有控制器-->
<mvc:mapping path="/**"/>
<!-- 配置拦截器对象,指定用哪个拦截器-->
<bean class="com.itbaizhan.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
2.局部拦截器
如下代码中,在<mvc:mapping path="">标签中配置指定的区域
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置拦截器的作用路径,/**表示作用于所有控制器-->
<mvc:mapping path="/Student/MyController"/>
<!-- 配置拦截器对象,指定用哪个拦截器-->
<bean class="com.itbaizhan.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
四、SpringMVC 拦截器_拦截器链与执行顺序
如果一个URL能够被多个拦截器所拦截,全局拦截器最先执行,其他拦截器根据配置文件中配置的从上到下执行,如上图,先执行拦截器1,再执行拦截器2,再执行Handler控制器,然后返回去先执行postHandle2-->postHandle1-->afterCompletion2-->afterCompletion1
1.编写拦截器类MyInterceptor2
public class MyInterceptor implements HandlerInterceptor {
//请求到达Controller前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器1:请求到达Controller前");
return true;
}
//跳转到JSP页面前执行,此时可以向request域添加数据,也就是这里的name可以传到request域中
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器1:跳转到JSP页面前");
// request.setAttribute("name","坏蛋");
}
//跳转到JSP页面后执行,此时不能向request域添加数据,也就是这里的age传不到request域中
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("拦截器1:跳转到JSP页面后");
// request.setAttribute("age",10);
}
}
public class MyInterceptor implements HandlerInterceptor {
//请求到达Controller前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器1:请求到达Controller前");
return true;
}
//跳转到JSP页面前执行,此时可以向request域添加数据,也就是这里的name可以传到request域中
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器1:跳转到JSP页面前");
// request.setAttribute("name","坏蛋");
}
//跳转到JSP页面后执行,此时不能向request域添加数据,也就是这里的age传不到request域中
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("拦截器1:跳转到JSP页面后");
// request.setAttribute("age",10);
}
}
2.在springmvc核心配置文件springmvc.xml中配置拦截器链
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 拦截器1 -->
<mvc:interceptor>
<!-- 配置拦截器的作用路径,/**表示作用于所有控制器-->
<mvc:mapping path="/**"/>
<!-- 配置拦截器对象,指定用哪个拦截器-->
<bean class="com.itbaizhan.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
<!-- 拦截器2 -->
<mvc:interceptor>
<!-- 配置拦截器的作用路径,/**表示作用于所有控制器-->
<mvc:mapping path="/**"/>
<!-- 配置拦截器对象,指定用哪个拦截器-->
<bean class="com.itbaizhan.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
3.请求结果:
1.当MyInterceptor、MyInterceptor2中的preHandle方法返回值同时为true时,preHandle()方法顺序执行,postHandle()、afterCompletion()方法逆序执行。
拦截器执行顺序:
preHandle1()-->preHandle2()-->Handler-->postHandle1()-->postHandle2()-->afterCompletion1()-->afterCompletion2()
2. 当MyInterceptor中的preHandle方法返回值为false,MyInterceptor2中的preHandle方法返回值为true时, 在preHandle1()后面的preHandle()、postHandle()都不会执行。
拦截器执行顺序:
preHandle1()拦截,无后续;
3.当MyInterceptor中的preHandle方法返回值为true,MyInterceptor2中的preHandle方法返回值为false时,拦截器1、拦截器2的preHandle()都会执行,但Handler和postHandle()不会执行,同时afterCompletion()只执行对应preHandle()方法返回值为true拦截器。
拦截器执行顺序:
preHandle1()-->preHandle2()-->afterCompletion1()
结论:
当有多个拦截器对同一个作用域进行拦截时:
1.preHandle()方法顺序执行,postHandle()、afterCompletion()方法逆序执行。
2.只要有一个preHandle()拦截,在它之后的preHandle()、postHandle()都不会执行。
3.只要相应的preHandle()放行,对应的afterCompletion()就会执行。
五、SpringMVC 拦截器_拦截器过滤敏感词案例
在系统中,我们需要将所有响应中的一些敏感词替换为 *** ,此时可以使用拦截器达到要求:
1.编写控制器方法MyController2
@Controller
public class MyController2 {
@RequestMapping("/m2")
public String m2(Model model){
model.addAttribute("name","大笨蛋");
return "result";
}
}
2.编写敏感词拦截器SensitiveWordInterceptor
//敏感词拦截器
public class SensitiveWordInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//定义敏感词列表
String[] sensitiveWords = {"坏人","笨蛋","暴力"};
//获取Model中的所有数据
Map<String, Object> model = modelAndView.getModel();
Set<Map.Entry<String, Object>> entries = model.entrySet();
//遍历model,替换敏感词
for (Map.Entry<String, Object> entry : entries) {
String key = entry.getKey();
String value = entry.getValue().toString();
//将model值和敏感词列表遍历比对
for (String sensitiveWord:sensitiveWords){
//只要数据模型的值包含敏感词,替换
if (value.contains(sensitiveWord)){
String newStr = value.replaceAll(sensitiveWord,"***");
model.put(key,newStr);
}
}
}
}
}
3.在springmvc核心配置文件springmvc.xml中配置拦截器链
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 敏感词拦截器-->
<!-- 配置拦截器的作用路径,/**表示作用于所有控制器-->
<mvc:mapping path="/**"/>
<!-- 配置拦截器对象,指定用哪个拦截器-->
<bean class="com.itbaizhan.interceptor.SensitiveWordInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
4.请求结果:
拦截之前:
拦截之后:
六、知识点整理:
1.在SpringMVC中,定义拦截器需要实现“HandlerInterceptor ”接口
2.在SpringMVC配置文件中,配置拦截器的标签为“<mvc:interceptor>”
3.在SpringMVC中,全局拦截器会拦截“所有控制器处理的URL”
4.在SpringMVC中,拦截器链的执行顺序为“preHandle() 顺序执行, postHandle() 、afterCompletion()逆序执行。”
5.在SpringMVC中,只要相应的 preHandle() 放行,“afterComletion() 就会执行。”