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包裹住拦截器。
相关文章:
2024.10月11日--- SpringMVC拦截器
拦截器 1 回顾过滤器: Servlet规范中的三大接口:Servlet接口,Filter接口、Listener接口。 过滤器接口,是Servlet2.3版本以来,定义的一种小型的,可插拔的Web组件,可以用来拦截和处理Servlet容…...
uniapp 锁屏显示插件 Ba-LockShow(可让vue直接具备锁屏显示能力)
简介 Ba-LockShow 是一款可以直接使uniapp的vue界面在锁屏页展示的插件。 支持使vue直接具备锁屏显示能力支持设置锁屏显示和不显示支持唤醒屏幕 截图展示(仅参考) 支持定制、本地包、源码等,有建议和需要,请点击文章结尾“Unia…...
CSS计数器
CSS 中的计数器类似于变量,可以实现简单的计数功能,并将结果显示在页面上,在早期的网站上应用比较广泛。要实现计数器需要用到以下几个属性: counter-reset:创建或者重置计数器;counter-increment…...
嵌入式Linux:信号集
目录 1、信号集初始化 2、向信号集中添加或删除信号 3、测试信号是否在信号集中 在 Linux 系统中,处理多个信号时常用到一种数据结构:信号集(sigset_t)。信号集允许我们将多个信号组织在一起,以便在系统调用中传递和…...
Linux 外设驱动 应用 1 IO口输出
从这里开始外设驱动介绍,这里使用的IMX8的芯片作为驱动介绍 开发流程: 修改设备树,配置 GPIO1_IO07 为 GPIO 输出。使用 sysfs 接口或编写驱动程序控制 GPIO 引脚。编译并测试。 这里假设设备树,已经配置好了。不在论述这个问题…...
基于SpringBoot+Vue+MySQL的留守儿童爱心网站
系统展示 用户前台界面 管理员后台界面 系统背景 随着现代社会的发展,留守儿童问题日益受到关注。传统的纸质管理方式已经无法满足现代人们对留守儿童爱心信息的需求。为了提高留守儿童爱心信息的管理效率,增加用户信息的安全性,并方便及时反…...
调用第三方接口
目录 一、分析给出的接口文档 二、请求体格式之间的区别 三、示例代码 一、分析给出的接口文档 一般的接口文档包括以下几大部分: 1、请求URL:http://{ip}:{port}/api/ec/dev/message/sendCustomMessageSingle 2、请求方式:POST、GET等 3、…...
JAVA 多线程入门例子:CountDownLatch
首先确定线程数量。如果数据集合的大小小于50,就只使用一个线程;否则使用5个线程。计算每个线程平均处理的数据数量sizePerThread以及余数remainder。在划分数据子集合时,对于每个线程的处理范围进行计算。如果有余数,就将余数依次…...
k8s jenkins 动态创建slave
k8s jenkins 动态创建slave 简述使用jenkins动态slave的优势:配置jenkins动态slave配置 Pod Template配置容器模板挂载卷 测试 简述 持续构建与发布是我们日常工作中必不可少的一个步骤,目前大多公司都采用 Jenkins 集群来搭建符合需求的 CI/CD 流程&am…...
MVS海康工业相机达不到标称最大帧率
文章目录 一、相机参数设置1、取消相机帧率限制2、修改相机图像格式3、调整相机曝光时间4、检查相机数据包大小(网口相机特有参数)5、 恢复相机默认参数6、 相机 ADC 输出位深调整 二、系统环境设置1、 网口相机设置2、 USB 相机设置 一、相机参数设置 …...
数据结构:用双栈实现一个队列
要用两个栈实现一个队列,可以利用“栈”的后进先出 (LIFO) 特性来模拟“队列”的先进先出 (FIFO) 操作。具体做法是使用两个栈:一个作为入栈栈,另一个作为出栈栈。 算法步骤 入队操作(enqueue): 将元素压…...
QScroller Class
Header:#include < QScroller > qmake:QT += widgets Since:Qt 5.0 Inherits:QObject This class was introduced in Qt 5.0. Public Types enum Input {InputPress, InputMove, InputRelease } enum ScrollerGestureType {TouchGesture, LeftMouseButtonGesture,…...
React高阶组件详解
React高阶组件(HOC)详解 定义 React高阶组件(HOC)是一个函数,该函数接受一个组件作为参数并返回一个新的组件。高阶组件本身不是一个组件,而是一个函数,它利用React的组合特性,对传入…...
TextView把其它控件挤出屏幕的处理办法
1.如果TextView后面的控件是紧挨着TextView的,可以给TextView添加maxWidth限制其最大长度 上有问题的布局代码 <?xml version"1.0" encoding"utf-8"?> <layout xmlns:android"http://schemas.android.com/apk/res/android&qu…...
长度为 K 的重复字符子串数目
长度为 K 的重复字符子串 给你一个由小写字母组成的长度为n的字符串 S ,找出所有长度为 k 且包含重复字符的子串,请你返回全部满足要求的子串的数目。 数据范围: 2≤k≤400 , 5≤n≤900 进阶: 时间复杂度O(n),空间复杂…...
html+css+js实现轮播图
实现效果: HTML部分 <div class"carousel"><div class"carousel-wrapper"><img src"./image/1.png" alt""></div><ul class"carousel-indictor"><li class"active"…...
Boost集成模型异同
一、常见Boost集成模型 AdaBoost、GBDT和XGBoost都是集成学习中的提升(Boosting)算法,它们通过组合多个弱学习器来构建一个强学习器。从经验上来说,XGBoost是诸多竞赛的大杀器,在实际业务工作中可能需要用到集成模型的…...
【系统架构设计师】案例专题四:嵌入式系统考点梳理
更多内容请见: 备考系统架构设计师-核心总结目录 摘要:本文主要梳理系统架构设计师 - 嵌入式系统 案例考点 ,主要包括嵌入式相关概念、软件和硬件可靠性、冗余技术、软件容错、集群技术、负载均衡、可维护性的评价指标、软件维护的分类等。 文章目录 一、相关概念二、软件可…...
Ngin入门套餐
快速了解Nginx 一、代理1.1 正向代理1.2 反向代理1.3 正向代理和反向代理的区别 二、Nginx负载均衡策略2.1 轮询(Round Robin)2.2 加权轮询(Weighted Round Robin)2.3 IP 哈希(IP Hash)2.4 最少连接&#x…...
使用linux编译main.cpp文件
1、首先创建一个简单的test.cpp,使用终端命令形式: touch test.cpp 创建结束,记得ls一下,如下: 2、找到创建结束的test.cpp文件,然后右键编辑,输入一个简单的代码,如下 #include …...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
