SpringMVC拦截器

1 拦截器概述

	SpringMVC 中的 Interceptor 拦截器是非常重要和相当有用的,它的主要作用是拦截指定
的用户请求,并进行相应的预处理与后处理。其拦截的时间点在“处理器映射器根据用户提
交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器,
在处理器适配器执行处理器之前”。当然,在处理器映射器映射出所要执行的处理器类时,
已经将拦截器与处理器组合为了一个处理器执行链,并返回给了中央调度器。

2 一个拦截器的执行

自定义拦截器,需要实现 HandlerInterceptor 接口。而该接口中含有三个方法:
➢ preHandle(request,response, Object handler):
该方法在处理器方法执行之前执行。其返回值为 boolean,若为 true,则紧接着会执行处理器方
法,且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行。
➢ postHandle(request,response, Object handler,modelAndView):
该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。
由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修
改处理器方法的处理结果数据,且可以修改跳转方向。
➢ afterCompletion(request,response, Object handler, Exception ex):
当 preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有
工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此
时对 ModelAndView 再操作也对响应无济于事。
afterCompletion 最后执行的方法,清除资源,例如在 Controller 方法中加入数据

2.1 代码

(1)dispatvherServlet配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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.hkd.springmvc.controller"/>




    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.hkd.springmvc.interceptor.MyInterceptor"/>
        mvc:interceptor>
    mvc:interceptors>



beans>
(2)拦截器类
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("正在执行MyInterceptor的-------------preHandle()");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("正在执行MyInterceptor的-------------postHandle()");
        modelAndView.addObject("name","tim");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("正在执行MyInterceptor的-------------afterCompletion()");
        HttpSession session = request.getSession();
        Object attr = session.getAttribute("attr");
        System.out.println(attr);
        session.removeAttribute("attr");
        System.out.println(session.getAttribute("attr"));
    }
}

(3)控制器类
@Controller
public class MyController {

    @RequestMapping(value = "/some.do",method = RequestMethod.POST)
    public ModelAndView doSome(String name, Integer age, HttpSession session){
        System.out.println("正在执行myController的方法");
        ModelAndView mv = new ModelAndView();
        mv.addObject("name",name);
        mv.addObject("age",age);
        mv.setViewName("view.jsp");
        session.setAttribute("attr","session中的数据");
        return mv;
    }
}

(4)index.jsp请求页
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String path = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";
%>
<html>
<head>
    <title>主页title>
    <base href="<%=path%>">
head>
<body>
<form action="some.do" method="post">
    姓名:<input type="text" name="name"><br>
    年龄:<input type="text" name="age"><br>
    <input type="submit" value="提交">
form>
body>
html>

(5)view.jsp展示页面代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>viewtitle>
head>
<body>
${name}<br>
<hr>
${age}<br>
<hr>
${pageContext.session.getAttribute("attr")}
body>
html>

运行预期:
展示页面第一行是tim,虽然传入的是tom,但是MyInterceptor 的postHandle()方法将name更改为了tim。
第二行正常显示前端页面输入的年龄
第三行正常显示"session中的数据",因为afterCompletion()是在中央调度器渲染(数据填充)了响应页面之后执行的,因此上面代码中afterCompletion()的removeAttribute()还没有生效,控制台第一次正常显示"attr"中的内容,第二次为null;

(6)前端输入界面

在这里插入图片描述
运行结果
在这里插入图片描述

控制台输出

SpringMVC拦截器_第1张图片

(7)收获
	深刻理解
	afterCompletion(request,response, Object handler, Exception ex):
	当 preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有
	工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此
	时对 ModelAndView 再操作也对响应无济于事。

SpringMVC拦截器_第2张图片
(图源:动力节点)

3 多个拦截器的执行

再定义一个拦截器
public class MyInterceptor2 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("正在执行MyInterceptor222的-------------preHandle()");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("正在执行MyInterceptor222的-------------postHandle()");
        modelAndView.addObject("name","tim");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("正在执行MyInterceptor222的-------------afterCompletion()");
    }
}

注册第二个拦截器



    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.hkd.springmvc.interceptor.MyInterceptor"/>
        mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.hkd.springmvc.interceptor.MyInterceptor2"/>
        mvc:interceptor>
    mvc:interceptors>
执行程序,运行结果

SpringMVC拦截器_第3张图片

结论
当有多个拦截器时,形成拦截器链。拦截器链的执行顺序,与其注册顺序一致。需要再
次强调一点的是,当某一个拦截器的 preHandle()方法返回 true 并被执行到时,会向一个专
门的方法栈中放入该拦截器的 afterCompletion()方法。

SpringMVC拦截器_第4张图片
图源:动力节点

从图中可以看出,只要有一个 preHandle()方法返回 false,则上部的执行链将被断开,
其后续的处理器方法与 postHandle()方法将无法执行。但,无论执行链执行情况怎样,只要
方法栈中有方法,即执行链中只要有 preHandle()方法返回 true,就会执行方法栈中的
afterCompletion()方法。最终都会给出响应。

你可能感兴趣的:(SpringMVC,java,前端,servlet,mvc,spring)