zoukankan      html  css  js  c++  java
  • springmvc拦截器

    在之前学习过滤器Filter,看到拦截器就想到了Filter

    Filter的作用:对请求和响应进行过滤

    Filter的生命周期:实例化----->初始化------>过滤-------->销毁

    原理:基于函数回调;

    只能在Web容器中使用,需要在服务器中使用,是一种Servlet规范;

    那么拦截器是什么呢?

    拦截器:针对处理器(Controller)的拦截器,是基于spring实现的

    实现原理:反射;是AOP思想的一种体现;

    拦截器的应用场景:

    1.权限验证

    2.日志记录

    3.通用行为

    4.性能监控

    拦截器的实现:

    1.实现HandlerInterceptor,接口源码如下:

    package org.springframework.web.servlet;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.lang.Nullable;
    import org.springframework.web.method.HandlerMethod;
    
    public interface HandlerInterceptor {
    
        //预处理,在控制器方法执行之前进行拦截
        default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
    
            return true;
        }
    
      //后处理,在控制器方法执行之后,视图渲染执行之前进行拦截
        default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                @Nullable ModelAndView modelAndView) throws Exception {
        }
    
        //在控制器方法执行之后进行处理,处理资源的释放
        default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                @Nullable Exception ex) throws Exception {
        }
    
    }

    可以看到,源码的接口中提供了三个default方法;在jdk8之后,提供了default,接口中的方法使用default修饰后,实现类不是必须实现该方法了,在使用拦截器时,创建类继承拦截器适配器;接口适配:接口A中包含很多的方法,不想全部实现,就提供一个抽象子类B,实现部分方法,继承部分方法;子类C继承子类B可以根据需要重写B中的方法;

    创建一个拦截器,进行登录身份验证:如果已经登录,就放行请求,如果没有登录,就拦截请求

    //创建一个拦截器,继承HandlerInterceptor适配器
    public class MyInterceptor extends HandlerInterceptorAdapter {
    //    登录验证是在请求之前进行验证,因此重写preHandle方法
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            Object user = request.getSession().getAttribute("user");
            if (user!=null)
                return true;//true表示该拦截器放行,false表示不放行
            return false;
        }
    }

    然后再mvc配置文件中注册该拦截器:

    <!--注册拦截器-->
        <mvc:interceptors>
            <!--可以写多个拦截器-->
            <mvc:interceptor>
                <!--设置拦截路径-->
                <mvc:mapping path="/**"/>
                <!--如果是第一次登录请求,要放行-->
                <mvc:exclude-mapping path="/user/login"/>
                <bean class="com.zs.interceptor.MyInterceptor"/>
            </mvc:interceptor>
        </mvc:interceptors>

    编写登录后台:

    @Controller
    @RequestMapping("/user")
    @SessionAttributes("user")
    public class UserController {
    
        @RequestMapping("/login")
        public String login(String username, String password, Model model) {
    //        验证登录信息
            if (username.equals("zhangsan") && password.equals("123456")) {
                model.addAttribute("user", username);
            }
            return "redirect:/view/index.jsp";
        }
    }

    编辑前端页面验证拦截器是否生效:

    模拟性能监控:

    package com.zs.interceptor;
    
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * 性能监控,需要计算方法执行的时间,因此要在方法执行前,获取时间,方法执行后再获取时间,两个时间相减
     */
    public class XingNengInterceptor extends HandlerInterceptorAdapter {
        //线程不同步? 
        // 本地线程局部变量:只能在当前线程中使用,Map, 实现线程同步
        ThreadLocal<Long> threadLocal = new ThreadLocal<>();
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            long start = System.currentTimeMillis();
            threadLocal.set(start);
            return true;
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            long end = System.currentTimeMillis();
            System.out.println(String.format("执行时间:%d",end-threadLocal.get()));
        }
    }

    注册拦截器,进行测试;

    因为再Web容器中运行时,拦截器是分线程的,每一个登录的用户就开启一个线程,如果直接使用变量,会导致不同线程公用同一个变量,竞争资源,线程不安全,一个线程调用了方法,给变量赋值,方法执行期间,又一个线程执行了方法,就又给变量赋值了,所以使用本地线程局部变量的方法

  • 相关阅读:
    C#实现仪器的自动化控制
    .Net FrameWork常用类
    编码:隐匿在计算机软硬件背后的语言(8)--自动操作(三)
    深入理解计算机系统(4)-- 整数和浮点数
    编码:隐匿在计算机软硬件背后的语言(8)--自动操作(二)
    C#中二进制、十进制和十六进制互相转换的方法
    深入理解计算机系统(3)-- 信息存储
    mysql-5.7.17-winx64免安装版环境配置 问题小记
    python生成随机数:uniform(), randint(), gauss(), expovariate()
    深度学习翻译 效果优于各类翻译器
  • 原文地址:https://www.cnblogs.com/Zs-book1/p/11329464.html
Copyright © 2011-2022 走看看