• SpringMVC拦截器


    1 拦截器概述

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

    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配置文件
    
    • 1
    
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    (2)拦截器类
    
    • 1
    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"));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    (3)控制器类
    
    • 1
    @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;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    (4)index.jsp请求页
    
    • 1
    <%@ 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>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    (5)view.jsp展示页面代码
    
    • 1
    <%@ 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>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

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

    (6)前端输入界面
    
    • 1

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

    控制台输出
    
    • 1

    在这里插入图片描述

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

    在这里插入图片描述
    (图源:动力节点)

    3 多个拦截器的执行

    再定义一个拦截器
    
    • 1
    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()");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    注册第二个拦截器
    
    • 1
    
    
    
        <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    执行程序,运行结果
    
    • 1

    在这里插入图片描述

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

    在这里插入图片描述
    图源:动力节点

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

  • 相关阅读:
    逻辑漏洞----任意账号注册
    【2023复旦微电子提前批笔试题】~ 题目及参考答案
    分布式锁选型+缓存db一致性
    练习接口测试详细步骤
    FullCalendarDemo5 控件的实例讲解—拖拽实现值班排班(三)
    cola架构:cola源码中访问者模式应用浅析
    Leetcode 219. Contains Duplicate II (hashmap 和 sliding window)
    【电子书赠送福利】蘇小沐电子数据取证实务教程!风吹哪页读哪页,哪页不会撕哪页!
    Linux MMC子系统 - 2.eMMC 5.1总线协议浅析
    最新开源ThinkPHP6框架云梦卡社区系统源码/亲测可用(全新开发)
  • 原文地址:https://blog.csdn.net/qq_63524487/article/details/132946198