SpringMVC 拦截器(Interceptor)

news2025/4/3 3:35:06

一.拦截器

假设有这么一个场景,一个系统需要用户登录才能进入,在检验完用户的信息后对页面进行了跳转。但是如果我们直接输入跳转的url,可以绕过用户信息校验(用户登录),直接进入系统。

因此我们引入了使用session检验,我们在用户登录的时候创建session,并将这个用户的信息存入session中(setAttribute),这样我们跳转其他的url时就可以对session进行检验。

HttpSession httpSession=httpServletRequest.getSession(false);
if(httpSession==null){
    System.out.println("没有创建会话");
    return new User();
}
User user=(User) httpSession.getAttribute("user");
if(user==null){
    System.out.println("没有该用户");
    return new User();
}

但是这种方法每写一个接口就要重复一遍,有没有什么办法能不写这些重复的内容。这就是拦截器的内容了。

拦截器属于SpringMVC框架,是 Spring 生态的核心组件之一。拦截器主要用来拦截用户请求,在指定方法前后执行业务代码。总的来说,拦截器是 Spring 送给 Web 开发者的 “定制化关卡”,只在 Spring 的世界里生效。

使用拦截器的方法:

1)定义拦截器;2)注册配置拦截器。

二.实现流程

1.定义拦截器

自定义一个拦截器,实现 HandlerInterceptor 接口,并重写其方法。

1)preHandle()方法:在目标方法执行前执行,返回true继续执行后续操作,返回false拦截后续操作;

2)postHandle()方法:在目标方法执行后执行,无返回值

3)afterCompletion()方法:视图渲染完毕后执行。

我们可以将我们的业务逻辑写在这些方法中。比如上面的例子,我们的目的就是为了拦截用户在没有登录的时候就访问系统内部的url,所以我们可以写一个拦截器:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    HttpSession session=request.getSession(false);
    if(!checkUser(session)){
        response.setContentType("text/html;charset=utf-8");
        response.setStatus(401);
        String msg="用户未登录哦";
        response.getOutputStream().write(msg.getBytes("UTF-8"));
        return false;
    }
    return true;
}
private boolean checkUser(HttpSession session){
    if(session==null){
        log.warn("用户未登录,session==null");
        return false;
    }
    UserInfo userInfo=(UserInfo)session.getAttribute("userInfo");
    if(userInfo==null){
        log.warn("用户未登录,userInfo==null");
        return false;
    }
    log.info("用户已登录");
    return true;
}

最后不要忘记将我们定义实现 HandlerInterceptor 接口的类注入到Spring容器中。

这样我们的拦截器就定义完了。

2.注册配置拦截器

我们要实现 WebMvcConfigurer 接口,并重写其中 addInterceptors 方法。

 举例实现:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Resource
    LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**");
    }
}

我们通过addPathPatterns来指定要拦截的路径,也可以使用excludePathPatterns来指定不要拦截的路径。像上面的代码,我们一次性拦截了所有请求,用户登录请求也被拦截了,这是不行的。因此我们可以改一下上面的代码,使用excludePathPatterns来指定用户登录的请求不要拦截。

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Resource
    LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/uer/login");
    }
}

下面是一些常见的拦截配置:

拦截路径含义举例
/*拦截一级路径能拦截 /user,/login,不能拦截 /user/login
/**拦截任意路径拦截所有
/user/*拦截/user的下一级路径能拦截 /user/getList,不能拦截 /user/getList/1 和 /user
/user/**拦截/user下的所有路径拦截/user下的所有路径,但是不能拦截 /book/getList

此外拦截器不仅可以拦截项目中的URL,还可以拦截静态资源(html,图片等)。

三.拦截器与前端的交互

最近做项目的时候突然意识到一个问题,我们确确实实拦截了一些请求,返回false了。但是前端没有处理,导致我们访问一些被拦截的请求,但是不知道为什么被拦截了。

简单来说,我想让拦截器返回false,并且浏览器给个 alert ,告诉用户为什么被拦截了。

因为拦截器返回 false 意味着请求被中断,后端不会继续执行控制器,所以传统的通过控制器返回数据的方式不可行。所有我们的核心方案是状态码 + 自定义头 + 响应体。

具体操作:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    HttpSession session=request.getSession(false);
    if(!checkUser(session)){
        // 1. 设置AJAX友好的响应格式
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401状态码
        // 2. 返回结构化的拦截信息(含提示语和跳转指令)
        String json = "{\"code\":401, \"msg\":\"用户未登录哦,请重新登录\",\"redirect\":\"login.html\"}";
        response.getOutputStream().write(json.getBytes("UTF-8"));
        return false;
    }
    return true;
}

后端设置好状态码等信息,前端接收状态码,并执行操作:

$.ajax({
    type: "GET",
    url: "/book/getListByPage" + location.search,
    xhrFields: { withCredentials: true }, // 携带Cookie(登录状态)
    statusCode: { // 关键:捕获特定状态码
        401: function(xhr) { // 拦截器返回的401状态
            const interceptData = JSON.parse(xhr.responseText);
            alert("用户没有登录"); 
            if (interceptData.redirect) {
                location.href = interceptData.redirect;
            }
        }
    },
    //success执行的是成功后的逻辑
    success: function (result) {}
});

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

03-SpringBoot3入门-配置文件(自定义配置及读取)

1、自定义配置 # 自定义配置 zbj:user:username: rootpassword: 123456# 自定义集合gfs:- a- b- c2、读取 1)User类 package com.sgu.pojo;import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.spring…

【蓝桥杯每日一题】3.28

🏝️专栏: 【蓝桥杯备篇】 🌅主页: f狐o狸x "今天熬的夜,会变成明天奖状的闪光点!" 目录 一、唯一的雪花 题目链接 题目描述 解题思路 解题代码 二、逛画展 题目链接 题目描述 解题思路 解题代…

万字长文详解Text-to-SQL

什么是Text-to-SQL 在各个企业数据量暴涨的现在,Text-to-SQL越来越重要了,所以今天就来聊聊Text-to-SQL。 Text-to-SQL是一种将自然语言查询转换为数据库查询的技术。它可以让用户通过自然语言来查询数据库,而不需要编写复杂的SQL语句。 T…

【Linux】动静态库的制作与使用

一.对软硬链接的补充 1、无法对目录进行硬链接 为什么呢? 首先,我们在访问文件时,每一个文件都会有自己的dentry结构,这些结构会在内存中维护一棵路径树,来快速进行路径查找。但是如果某个节点直接使用硬链接到了根节…

ubuntu22.04 如何安装 ch341 驱动

前言 本篇是介绍ubuntu22.04如何安装 ch341 驱动,并对其中遇到的问题进行整理。 一、流程 1.1 查看CH340驱动 首先是查看ubuntu22.04系统自带的驱动,用以下命令即可 ls /lib/modules/$(uname -r)/kernel/drivers/usb/serial 然后会跳出以下界面&…

个人博客网站从搭建到上线教程

步骤1:设计个人网站 设计个人博客网站的风格样式,可以在各个模板网站上多浏览浏览,以便有更多设计网站风格样式的经验。 设计个人博客网站的内容,你希望你的网站包含哪些内容如你的个人基本信息介绍、你想分享的项目、你想分享的技术文档等等。 步骤2:选择开发技术栈 因…

mac m4 Homebrew安装MySQL 8.0

1.使用Homebrew安装MySQL8 在终端中输入以下命令来安装MySQL8: brew install mysql8.0 安装完成后,您可以通过以下命令来验证MySQL是否已成功安装: 2.配置mysql环境变量 find / -name mysql 2>/dev/null #找到mysql的安装位置 cd /op…

UE5学习笔记 FPS游戏制作26 UE中的UI

文章目录 几个概念创建一个UI蓝图添加UI获取UI的引用 切换设计器和UI蓝图将UI添加到游戏场景锚点轴点slotSizeToContent三种UI数据更新方式(Text、Image)函数绑定属性绑定事件绑定 九宫格分割图片按钮设置图片绑定按下事件 下拉框创建添加数据修改样式常用函数 滚动框创建添加数…

Navicat导出mysql数据库表结构说明到excel、word,单表导出方式记录

目前只找到一张一张表导出的方式 使用information_schema传入表名查询 字段名根据需要自行删减,一般保留序号、字段名、类型、说明就行 SELECT COLUMNS.ORDINAL_POSITION AS 序号, COLUMNS.COLUMN_NAME AS 字段名, COLUMNS.COLUMN_TYPE AS 类型(长度), COLUMNS.N…

Linux驱动开发 中断处理

目录 序言 1.中断的概念 2.如何使用中断 中断处理流程 中断上下文限制 屏蔽中断/使能 关键区别与选择 上半部中断 下半部中断 软中断(SoftIRQ) 小任务(Tasklet) 工作队列(Workqueue) 线程 IRQ(Threaded IRQ…

Centos主机检查脚本

使用方法: 将脚本保存为 CentOS_syscheck.sh 添加执行权限: chmod x CentOS_syscheck.sh 执行脚本: ./CentOS_syscheck.sh #!/bin/bash# 设置颜色变量 RED\033[0;31m GREEN\033[0;32m YELLOW\033[0;33m BLUE\033[0;34m NC\033[0m # 重置…

python系统之综合案例:用python打造智能诗词生成助手

不为失败找理由,只为成功找方法。所有的不甘,因为还心存梦想,所以在你放弃之前,好好拼一把,只怕心老,不怕路长。 python系列之综合案例 前言一、项目描述二、项目需求三、 项目实现1、开发准备2、代码实现 …

23种设计模式-结构型模式-桥接器

文章目录 简介问题解决方案示例总结 简介 桥接器是一种结构型设计模式,可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构,从而能在开发时分别使用。 问题 假如你有一个几何形状Shape类,它有两个子类:圆形C…

K8S学习之基础五十八:部署nexus服务

部署nexus服务 Nexus服务器是一个代码包管理的服务器,可以理解 Nexus 服务器是一个巨大的 Library 仓库。Nexus 可以支持管理的工具包括 Maven , npm 等,对于 JAVA 开发来说,只要用到 Maven 管理就可以了。Nexus服务器作用&#x…

Docker Desktop 界面功能介绍

Docker Desktop 界面功能介绍 左侧导航栏 Containers(容器): 用于管理容器,包括查看运行中或已停止的容器,检查容器状态、日志,执行容器内命令,启动、停止、删除容器等操作。Images(镜像): 管理本地 Docker 镜像,可查看镜像列表、从 Docker Hub 拉取新镜像、删除镜…

C++ set map

1.set和map是什么 set和map是 C STL 提供的容器,用于高效的查找数据,底层采用红黑树实现,其中set是Key模型,map是Key-Value模型 set和map的基本使用较为简单,这里不再叙述,直接进入实现环节 2.set和map的…

Spring AI Alibaba 对话记忆使用

一、对话记忆 (ChatMemory)简介 1、对话记忆介绍 ”大模型的对话记忆”这一概念,根植于人工智能与自然语言处理领域,特别是针对具有深度学习能力的大型语言模型而言,它指的是模型在与用户进行交互式对话过程中,能够追踪、理解并利…

Ubuntu24.04 离线安装 MySQL8.0.41

一、环境准备 1.1 官方下载MySQL8.0.41 完整包 1.2 上传包 & 解压 上传包名称是:mysql-server_8.0.41-1ubuntu24.04_amd64.deb-bundle.tar # 切换到上传目录 cd /home/MySQL8 # 解压: tar -xvf mysql-server_8.0.41-1ubuntu24.04_amd64.deb-bundl…

SOME/IP-SD -- 协议英文原文讲解10

前言 SOME/IP协议越来越多的用于汽车电子行业中,关于协议详细完全的中文资料却没有,所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块: 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 5.1.5 Non…

Ubuntu上给AndroidStudio创建桌面图标

最近使用了Ubuntu开发了,默认的android studio没有桌面图标,还是很不方便,每次都要cd到bin目录启动studio.sh。 步骤1:cd /usr/share/applications linux系统里面,所有的应用启动入口都在 /usr/share/applications …