2024.10月11日--- SpringMVC拦截器

拦截器

1 回顾过滤器:

Servlet规范中的三大接口:==Servlet接口,Filter接口、Listener接口。==

过滤器接口,是Servlet2.3版本以来,定义的一种小型的,可插拔的Web组件,可以用来拦截和处理Servlet容器的请求和响应过程。以便查看,提取或以某种方式操作正在客户端与服务器端之间交换的数据。

过滤器的配置比较简单,直接实现Filter 接口即可,也可以通过@WebFilter注解实现对特定URL拦截。Filter 接口中定义了三个方法。

  • init() :该方法在容器启动初始化过滤器时被调用,它在 Filter 的整个生命周期只会被调用一次。「注意」:这个方法必须执行成功,否则过滤器会不起作用。

  • doFilter() :容器中的每一次请求都会调用该方法, FilterChain 用来调用下一个过滤器 Filter。

  • destroy(): 当容器销毁 过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次。

2 拦截器的简介

SpringMVC里的拦截器是面向切面编程AOP的一个具体实现,用于对请求做预处理。

1)什么是拦截器:

在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略

2)为什么需要拦截器:

在做身份认证或者是进行日志的记录时,我们需要通过拦截器达到我们的目的。最常用的登录拦截、或是权限校验、或是防重复提交、或是根据业务像12306去校验购票时间,总之可以去做很多的事情

3 拦截器的应用

步骤1):自定义一个类,实现HandlerInterceptor接口,或者继承HandlerInterceptorAdapter抽象类

步骤2):根据自己的需求,重写方法

方法1:boolean preHandle()
      - 想要在执行Controller之前执行拦截,就重写该方法。
      - 存在多个interceptor时,它们基于链式方式调用,按照注册的先后顺序依次执行。
      - 方法返回true时,后续有拦截器,就继续执行拦截器,没有就执行controller.
      - 方法返回false时,后续任何内容都不执行了,直接返回浏览器
​
​
方法2:void postHandle():
        会在Controller执行后,视图渲染之前调用该方法。因此可以在这个阶段,对将要返回给客户端的ModelAndView进行处理。
​
方法3:void afterCompletion:
        - 该方法会在视图渲染后被调用,主要是用来进行资源清理工作。
        - 多个拦截器时,依旧是先执行先注册的拦截器的afterCompletion方法
        - 不管处理器是否抛出异常,该方法都将执行。

步骤3)在spring的配置文件中配置拦截器(或者配置类中也可以)

4 拦截器执行流程

4.1 拦截器的执行时机

4.2 拦截器和过滤器一起应用时的执行时机

5 拦截器的应用场景

日志记录:记录请求信息的日志,以便进行信息监控、信息统计等;

权限检查:如登录校验,在处理器处理之前先判断是否已经登录;

性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。

通用行为:读取 Cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用。还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的都可以用拦截器来实现。

6 当前路径绑定权限拦截器

package com.ssm.netctoss.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 步骤1):自定义一个类,实现HandlerInterceptor接口,或者继承HandlerInterceptorAdapter抽象类
 * 步骤2):根据自己的需求,重写方法
 * 步骤3)在spring的配置文件中配置拦截器(或者配置类中也可以)
 */
public class CurrentPathPrivilegeInterceptor implements HandlerInterceptor {
    /**
     *
     * @param request   请求对象
     * @param response  响应对象
     * @param handler   请求路径对应的Controller里的方法对象(反射机制)
     *                   /fee/findByPage
     *                  public String findByPage(){
     *                      ........
     *                  }
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("----------preHandle------------");
        System.out.println("-------注意:需要给每个用户添加0,8,9权限,在数据库中-----------");
        System.out.println("-------注意:需要给每个用户添加0,8,9权限,在数据库中-----------");
        System.out.println("-------注意:需要给每个用户添加0,8,9权限,在数据库中-----------");
        //获取请求路径:
        String uri = request.getRequestURI();
        int currentPrivilege = -1;
        if(uri.contains("/toIndex")){
            currentPrivilege = 0;
        }else if(uri.contains("/role/")){
            currentPrivilege = 1;
        }else if(uri.contains("/admin/")){
            currentPrivilege = 2;
        }else if(uri.contains("/fee/")) {
            currentPrivilege = 3;
        }else if(uri.contains("/account/")) {
            currentPrivilege = 4;
        }else if(uri.contains("/service/")) {
            currentPrivilege = 5;
        }else if(uri.contains("/bill/")) {
            currentPrivilege = 6;
        }else if(uri.contains("/report/")) {
            currentPrivilege = 7;
        }else if(uri.contains("/user/show")) {
            currentPrivilege = 8;
        }else if(uri.contains("/user/toUpdate")) {
            currentPrivilege = 9;
        }
        request.getSession().setAttribute("currentPrivilege", currentPrivilege);

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("----------postHandle------------");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("----------afterCompletion------------");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

 编写导航高亮提示

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<div id="navi">
   <ul id="menu">
      <li><a href="../index/toIndex" class="<c:choose><c:when test="${currentPrivilege==0}">index_on</c:when><c:otherwise>index_off</c:otherwise></c:choose>"></a></li>
      <li><a href="../role/findByPage" class="<c:choose><c:when test="${currentPrivilege==1}">role_on</c:when><c:otherwise>role_off</c:otherwise></c:choose>"></a></li>
      <li><a href="../admin/findByPage" class="<c:choose><c:when test="${currentPrivilege==2}">admin_on</c:when><c:otherwise>admin_off</c:otherwise></c:choose>"></a></li>
      <li><a href="../fee/findByPage" class="<c:choose><c:when test="${currentPrivilege==3}">fee_on</c:when><c:otherwise>fee_off</c:otherwise></c:choose>"></a></li>
      <li><a href="../account/findByPage" class="<c:choose><c:when test="${currentPrivilege==4}">account_on</c:when><c:otherwise>account_off</c:otherwise></c:choose>"></a></li>
      <li><a href="../service/searchService" class="<c:choose><c:when test="${currentPrivilege==5}">service_on</c:when><c:otherwise>service_off</c:otherwise></c:choose>"></a></li>
      <li><a href="../bill/bill_list.html" class="bill_off"></a></li>
      <li><a href="../report/report_list.html" class="report_off"></a></li>
      <li><a href="../user/showUserInfo" class="<c:choose><c:when test="${currentPrivilege==8}">information_on</c:when><c:otherwise>information_off</c:otherwise></c:choose>"></a></li>
      <li><a href="../user/toUpdatePwd" class="<c:choose><c:when test="${currentPrivilege==9}">password_on</c:when><c:otherwise>password_off</c:otherwise></c:choose>"></a></li>
   </ul>
</div>

 7 登录拦截

package com.ssm.netctoss.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 使用拦截器,来完成用户是否登录过。  如果没有登录,应该跳转到登录页面,强制其登录
 *
 * 返回值:
 *  false:  不执行后续的代码,包括Controller
 *  true:  执行后续的代码,如果有下一个拦截器,就执行下一个拦截器的preHandle。如果没有拦截器,执行Controller
 */
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("----------LoginInterceptor的preHandle-----------");
        //获取session,从中获取绑定的信息
        Object loginAdmin = request.getSession().getAttribute("LOGINADMIN");
        if (loginAdmin == null) {
            //没有登录过,就跳转
            response.sendRedirect(request.getContextPath()+"/login/toLogin");
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("----------LoginInterceptor的postHandle----------");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("----------LoginInterceptor的afterCompletion----------");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

 8 权限验证拦截器

package com.ssm.netctoss.interceptor;

import com.ssm.netctoss.pojo.Admin;
import com.ssm.netctoss.pojo.Privilege;
import com.ssm.netctoss.pojo.Role;
import com.ssm.netctoss.service.AdminService;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 登录用户的权限校验拦截:
 *      比如:登录用户,只能访问管理员,资费,账务,没有其他权限,那么相应的导航栏,有的能访问,有的不能访问
 *
 *
 *      admin_info ----> admin_role---->role_info--->role_privilege-->privilege_info
 *      caocao                           管理员1 100                   1 2 3
 *                                       营业员  200                   3 4 5 6
 *                                       经理    300                   7
 */
public class PrivilegeInterceptor extends HandlerInterceptorAdapter {
   /**
     * 因为拦截器是运行在Spring容器中维护的。(Bean),因此可以使用DI注入其他业务层/控制层的各种类型属性
     */
   //    @Resource
   //    private AdminService adminService;
   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      //获取当前登录用户的所有权限
      Admin admin = (Admin) request.getSession().getAttribute("LOGINADMIN");
      //创建一个Set集合,用于存储该用户的所有权限(privilegeId,name)
      Set<Privilege> privileges = new HashSet<Privilege>();  // Privileges实体类要重新hashCode和equals方法
      List<Role> roles = admin.getRoles();
      for (Role role : roles) {
         //添加进集合,并去重
         privileges.addAll(role.getPrivileges());
      }
      /*从当前的请求路径上获取对应的绑定权限*/
      int currentPrivilege = (Integer)(request.getSession().getAttribute("currentPrivilege"));
      /*查看当前路径的绑定权限是否在当前用户的权限集合里,如果没有,就跳转进行提示*/
      for (Privilege privilege : privileges) {
         if(privilege.getPrivilegeId()==currentPrivilege){
            return true;
         }
      }
      //如果在循序期间,没有遇到return true,说明要访问的路径用户是没有该权限的。因此要做一个跳转
      response.sendRedirect(request.getContextPath()+"/login/nopower");
      return false;
   }
}

注册拦截器

 <!--注册拦截器:    拦截器的执行顺序与配置的先后有关系。  先配置的先执行-->
    <mvc:interceptors>
        <!--配置登录拦截器-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/login/login"/>
            <mvc:exclude-mapping path="/login/getCheckCode"/>
            <mvc:exclude-mapping path="/login/toLogin"/>
            <bean class="com.ssm.netctoss.interceptor.LoginInterceptor"></bean>
        </mvc:interceptor>
        <!--  当前路径的权限绑定拦截器      -->
        <mvc:interceptor>
            <!-- 需要拦截的各种路径:-->
            <mvc:mapping path="/**"/>
<!--            <mvc:mapping path="/login/toIndex"/>-->
<!--            <mvc:mapping path="/login/showUserInfo"/>-->
            <!-- 不需要拦截的路径:-->
            <mvc:exclude-mapping path="/login/toLogin"/>
            <mvc:exclude-mapping path="/login/login"/>
            <mvc:exclude-mapping path="/login/logout"/>
            <!-- 手动配置拦截器的Bean对象           -->
            <bean class="com.ssm.netctoss.interceptor.CurrentPathPrivilegeInterceptor"></bean>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/login/*"/>
            <bean class="com.ssm.netctoss.interceptor.PrivilegeInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

 9 拦截器与过滤器的比较

**①** 拦截器是基于java的反射机制的,而过滤器是基于函数回调。
  

**②** 拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
  

**③** 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
  

**④** 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
  

**⑤** 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

**⑥** 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

**⑦ **过滤器和拦截器触发时机、时间、地方不一样

**⑧**过滤器包裹住servlet,servlet包裹住拦截器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/894363.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

力扣 142.环形链表Ⅱ【详细解释】

一、题目 二、思路 三、代码 /*** Definition for singly-linked list.* class ListNode {* int val;* ListNode next;* ListNode(int x) {* val x;* next null;* }* }*/ public class Solution {public ListNode detectCycle(ListNode hea…

LSL常见应用场景及示例<一>

目录 往期推荐 场景1&#xff1a;如何在指定内存定义中定位一个函数&#xff1f; 场景2&#xff1a;如何在绝对内存偏移地址处定位一个函数&#xff1f; 场景3&#xff1a;如何在绝对地址处定位一个函数&#xff1f; 场景4&#xff1a;有多个函数必须位于特定的内存定义中。…

vue3+ts+vite--路由跳转,params传参好像丢失了?

前言 相信大家一定写过后台管理系统&#xff0c;有一个很普遍的功能&#xff0c;就是点击编辑&#xff0c;根据id&#xff0c;跳转到相对应的编辑页面&#xff0c;id是通过路由params传递过去了&#xff0c;但是还有一个需求是要将父组件的名称也传递过去 &#xff0c;过程特别…

从0到1封装一个image/pdf预览组件

iShot_2024-10-14_16.47.10 目录结构 content.vue <template><div class"no-content-block"><i class"iconfont icondocument large-file" /><div class"text-wrapper">{{ t(__ui__.siPreview.previewSupported) }}<…

Spring Cloud Sentinel配置

Spring Cloud Sentinel 文章目录 Spring Cloud Sentinel1. Sentinel Dashboard 启动2. Spring Cloud 客户端配置3. Sentinel Dashboard 限流配置流控模式直连关联链路 流控规则快速失败Warm Up排队等待 4. Sentinel Dashboard 熔断配置5. Sentinel Dashboard 热点配置 1. Senti…

MEMC功能详解

文章目录 MEMC的工作原理&#xff1a;优点&#xff1a;缺点&#xff1a;适用场景&#xff1a;1. Deblur&#xff08;去模糊&#xff09;2. Dejudder&#xff08;去抖动&#xff09;总结两者区别&#xff1a; MEMC&#xff08;Motion Estimation and Motion Compensation&#x…

打破“几何第五公设不可证明”的神话——黄氏平行定义使证明第五公设易如反掌

黄小宁 绿色图片中的直线平行的定义&#xff08;此定义可推广为相应的平面平行的定义&#xff09;使人能根据几何常识一下子证明第五公设从而表明“2000年都无人能解决的世界著名数学难题”其实是一个天大的笑话。

Linux 手撕线程池

前言 线程池 是 池化技术 中很典型的一个&#xff0c;它旨在高效的管理和复用线程资源&#xff01;在现在的计算机体系中&#xff0c;线程是执行任务&#xff08;调度&#xff09;的基本单位。然而&#xff0c;频繁的创建和销毁线程也会带来较大的开销&#xff0c;包括系统资源…

RISC-V笔记——Pipeline依赖

1. 前言 RISC-V的RVWMO模型主要包含了preserved program order、load value axiom、atomicity axiom、progress axiom和I/O Ordering。今天主要记录下preserved program order(保留程序顺序)中的Pipeline Dependencies(Pipeline依赖)。 2. Pipeline依赖 Pipeline依赖指的是&a…

ECCV‘24 | WTConv:小参数大感受野,基于小波变换的新型卷积

前言 近年来&#xff0c;人们尝试增加卷积神经网络&#xff08;CNN&#xff09;的卷积核大小&#xff0c;以模拟视觉Transformer&#xff08;ViTs&#xff09;自注意力模块的全局感受野。然而&#xff0c;这种方法很快就遇到了上限&#xff0c;并在实现全局感受野之前就达到了饱…

鸿蒙原生应用扬帆起航

就在2024年6月21日华为在开发者大会上发布了全新操作的系统HarmonyOS Next开发测试版&#xff0c;网友们把它称之为“称之为纯血鸿蒙”。因为在此之前鸿蒙系统底层式有两套基础架构的&#xff0c;一套是是Android的AOSP&#xff0c;一套是鸿蒙的Open Harmony&#xff0c;因为早…

一篇文章教你完成软件验收测试,项目结题不再难

在软件开发过程中&#xff0c;验收测试是项目结题前的最后一道关卡。能否顺利通过验收测试&#xff0c;直接关系到项目的成功与否。 了解软件验收测试的重要性 软件验收测试是项目开发周期中的关键环节&#xff0c;其主要目的是检验软件是否满足用户需求、设计规范和合同要求…

C Primer Plus 第9章——第一篇

你该逆袭了 文章目录 一、复习函数1、定义带形式参数的函数2、声明带形式参数函数的原型3、使用 return 从函数中返回值&#xff08;1&#xff09;、返回值不仅可以赋给变量&#xff0c;也可以被用作表达式的一部分。&#xff08;2&#xff09;、返回值不一定是变量的值&#x…

机器视觉入门基础相关概念一 ——单目相机模型

机器视觉入门基础相关概念 相机模型 引言介绍&#xff1a;如果只是希望获取图像上的一些信息&#xff08;例如特征提取、拟合等&#xff09;&#xff0c;那么我们不会对三维空间中相机的位置有所要求。但如果希望通过二维的图像去理解三维空间中摄像机的信息&#xff0c;或者是…

简单三步完成 Telegram 生态的 Web3 冷启动

在竞争激烈的 Web3 领域&#xff0c;强有力的启动往往能决定成败。Telegram 无疑当下最火热的流量池&#xff0c;是很多 Web3 项目冷启动阶段的必选项。 但眼看着好多项目在 Telegram 生态火速获取百万级甚至千万级别的用户&#xff0c;自己的项目要怎么开始做增长&#xff0c;…

【记录】Django数据库的基础操作

数据库连接 在Django中使用 mysqlclient 这个包用于数据库的连接&#xff0c;切换至 Django环境中直接 pip install mysqlclient 安装此包 1 数据库连接配置 在项目目录下的setting.py中配置 DATABASES {default: {ENGINE: django.db.backends.mysql,NAME: mini,#数据库名US…

nginx过滤模块怎么生效的

在nginx中&#xff0c;如果你要开发一个过滤模块&#xff0c;config中必须要加 HTTP_FILTER_MODULES$HTTP_FILTER_MODULES xxx 否则&#xff0c;即使在postconfiguration回调中加了ngx_http_top_header_filtermy_xxxx_filter_handle&#xff0c;最终my_xxxx_filter_handle也不…

PTA L1系列题解(C语言)(L1_081 -- L1_088)

L1-081 今天我要赢 题目内容&#xff1a; 2018 年我们曾经出过一题&#xff0c;是输出“2018 我们要赢”。今年是 2022 年&#xff0c;你要输出的句子变成了“我要赢&#xff01;就在今天&#xff01;”然后以比赛当天的日期落款。 输入格式&#xff1a; 本题没有输入。 输…

聊聊ASSERT处理在某些场景下的合理用法

先看看ASSERT的介绍&#xff1a; 编写代码时&#xff0c;我们总是会做出一些假设&#xff0c;ASSERT断言就是用于在代码中捕捉这些假设&#xff0c;可以将断言看作是异常处理的一种高级形式。断言表示为一些布尔表达式&#xff0c;程序员相信在程序中的某个特定点该表达式值为真…

数据结构编程实践20讲(Python版)—20并查集

本文目录 20 并查集&#xff08;Union-Find Set&#xff09;S1 说明并查集的定义并查集基本操作并查集优化并查集特点应用领域 S2 示例S3 问题1&#xff1a;朋友圈问题S4 问题2&#xff1a;网络连接恢复问题S5 问题3&#xff1a;随机生成迷宫 往期链接 01 数组02 链表03 栈04 …