当前位置: 首页 > news >正文

SpringBoot 过滤器和拦截器(三十八)

我喜欢你,可是你却并不知道.

上一章简单介绍了SpringBoot参数验证(三十七) ,如果没有看过,请观看上一章

关于过滤器和拦截器已经讲很多了, 这里老蝴蝶只说一下 SpringBoot 的用法。

可以看之前的文章:

https://blog.csdn.net/yjltx1234csdn/article/details/100667082

https://blog.csdn.net/yjltx1234csdn/article/details/105484464

一.过滤器

一.一 过滤器实现 Filter 接口

@Slf4j
public class LogFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {Filter.super.init(filterConfig);}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, 		ServletException {// 主体方法long start = System.currentTimeMillis();chain.doFilter(request, response);log.info("Execute cost= {}" ,(System.currentTimeMillis() - start));}@Overridepublic void destroy() {Filter.super.destroy();}
}

一.二 配置过滤器

@Configuration
public class WebFilterConfig {@Beanpublic FilterRegistrationBean registFilter() {FilterRegistrationBean registration = new FilterRegistrationBean();registration.setFilter(new LogFilter());registration.addUrlPatterns("/*");registration.setName("LogCostFilter");registration.setOrder(1);return registration;}}

一.三 过滤器代码

  @GetMapping("/hello")public String hello() {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}return "你好啊,岳泽霖";}
2023-04-04 17:54:20.769  INFO 29068 --- [nio-8081-exec-4] top.yueshushu.learn.config.LogFilter     : Execute cost= 2012

二. 拦截器

设置一个登录拦截器

用户对象

@Data
public class User {private static final long serialVersionUID = 1L;private Integer id;private String account;private String name;private String token;// ... 其他属性信息
}

二.一 @AuthToken 注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthToken {}

二.二 拦截器 AuthorizationInterceptor

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import top.yueshushu.learn.annotation.AuthToken;
import top.yueshushu.learn.model.User;
import top.yueshushu.learn.util.ThreadLocalUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method;@Slf4j
public class AuthorizationInterceptor implements HandlerInterceptor {private String httpHeaderName = "Authorization";public static final String X_REAL_IP = "x-real-ip";public static final String REQUEST_CURRENT_KEY = "REQUEST_CURRENT_KEY";@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {if (!(handler instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();boolean isForAllTimeUser = false;if (method.getAnnotation(AuthToken.class) != null ||handlerMethod.getBeanType().getAnnotation(AuthToken.class) != null) {String token = request.getHeader(httpHeaderName);String ip = request.getHeader(X_REAL_IP);User loginUser = null;if (StringUtils.hasText(token)) {// 根据 token 获取用户 信息// 验证 token 是否 jwt 过期, 过期的话, isFalse}if (!StringUtils.hasText(token) || loginUser == null) {isFalse(request, response);return false;}String userDoAccount = loginUser.getAccount();ThreadLocalUtils.put("userDoAccount", userDoAccount);ThreadLocalUtils.put("ip", ip == null ? request.getRemoteAddr() : ip);ThreadLocalUtils.put("userName", loginUser.getAccount());ThreadLocalUtils.put("user", loginUser);ThreadLocalUtils.put("token", token);ThreadLocalUtils.put("userId", loginUser.getId());// 可以进行续命, 将时间延长.return true;}request.setAttribute(REQUEST_CURRENT_KEY, null);return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {ThreadLocalUtils.release();}private void isFalse(HttpServletRequest httpServletRequest, HttpServletResponse response) {JSONObject jsonObject = new JSONObject();PrintWriter out = null;try {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.setCharacterEncoding("utf-8");jsonObject.put("code", "10010001");jsonObject.put("message", "登录已过期,请重新登录");//添加其余的两个属性  success和 datajsonObject.put("data", "");jsonObject.put("success", false);out = response.getWriter();out.println(jsonObject);} catch (Exception e) {log.error("发生异常{}", e);} finally {if (out != null) {out.flush();out.close();}}}private void isUnValid(HttpServletRequest httpServletRequest, HttpServletResponse response) {JSONObject jsonObject = new JSONObject();PrintWriter out = null;try {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.setCharacterEncoding("utf-8");jsonObject.put("code", "10010002");jsonObject.put("message", "您的账号已经在另一处登录了,您被迫下线!");//添加其余的两个属性  success和 data, 解决 PDA端无法翻译 退出的问题。 @zk_yjljsonObject.put("data", "");jsonObject.put("success", false);out = response.getWriter();out.println(jsonObject);} catch (Exception e) {log.error("发生异常", e);} finally {if (out != null) {out.flush();out.close();}}}
}

二.三 线程内工具类

public class ThreadLocalUtils {private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL = new ThreadLocal<>();/*** 存储*/public static void put(String key, Object value) {Map<String, Object> map = THREAD_LOCAL.get();if (map == null) {map = new HashMap<>(1,1);}map.put(key, value);THREAD_LOCAL.set(map);}/*** 取值*/public static <T> T get(String key) {Map<String, Object> map = THREAD_LOCAL.get();if (map != null) {return (T) map.get(key);}return null;}/*** 获取当前用户*/public static User getUser() {Map<String, Object> map = THREAD_LOCAL.get();return (User) map.get("user");}public static void release() {THREAD_LOCAL.remove();}public static String getToken() {return get("token");}
}

二.四 添加拦截器


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import top.yueshushu.learn.interceptor.AuthorizationInterceptor;/*** @ClassName:MvcConfig* @Description Web端配置* @Author zk_yjl* @Date 2021/6/29 16:31* @Version 1.0* @Since 1.0**/
@Configuration
public class MvcConfig implements WebMvcConfigurer {@Beanpublic HandlerInterceptor getAuthInterceptor() {//返回自定义的拦截类return new AuthorizationInterceptor();}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(getAuthInterceptor())// 拦截所有请求.addPathPatterns("/**")// 静态资源过滤.excludePathPatterns("/usr/login","/static/**","/v2/**", "/swagger-resources/configuration/**","/swagger-resources/**", "/swagger-ui.html#/**", "/webjars/**");}/*** 配置静态的资源信息** @param registry*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");}
}

二.五 处理数据

  @GetMapping("/hello2")@AuthTokenpublic String hello2() {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}// 线程内获取User user = ThreadLocalUtils.getUser();return "你好啊,岳泽霖";}

本章节的代码放置在 github 上:

https://github.com/yuejianli/springboot/tree/develop/SpringBoot_Interceptor

谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!

相关文章:

SpringBoot 过滤器和拦截器(三十八)

我喜欢你&#xff0c;可是你却并不知道. 上一章简单介绍了SpringBoot参数验证(三十七) ,如果没有看过,请观看上一章 关于过滤器和拦截器已经讲很多了&#xff0c; 这里老蝴蝶只说一下 SpringBoot 的用法。 可以看之前的文章: https://blog.csdn.net/yjltx1234csdn/article/d…...

Memcache论文总结——Lec16

文章目录一、相关名词1.mcrouter层2.GUTTER SERVER3.mcsqueal4.remote mark二、当流量增长了如何SCALE 你的网站&#xff1f;三、背景及业务特点1.读多写少2.FB需求&#xff1a;3.之前情况四、简介五、FaceBook的架构五、Cache Policy六、In a Cluster : Latency and Load(一&a…...

父子组件传值问题

文章目录前言一、问题描述二、问题解决前言 在写毕业设计&#xff0c;涉及了一些前端Vue.js的组件传值知识并出现了相关问题&#xff0c;因此进行记录。 问题 Vue.js的使用不熟练&#xff0c;相关组件、props等掌握不清晰前端代码书写不规范 望指正&#xff01; 一、问题描述 …...

Redis大key问题

Redis大key问题 什么是big key&#xff1f; bigKey的危害&#xff1a; 大key不仅仅是占用内存而已&#xff0c;如果是仅仅内存的问题 那么扩大内存就好了。禁止大key是主要是因为你操作redis&#xff0c;比如说读/写等操作redis的时候 会有io操作&#xff0c;大key会导致io操作…...

00后卷王的自述,我难道真的很卷?

前言 前段时间去面试了一个公司&#xff0c;成功拿到了offer&#xff0c;薪资也从12k涨到了18k&#xff0c;对于工作都还没两年的我来说&#xff0c;还是比较满意的&#xff0c;毕竟一些工作3、4年的可能还没我高。 我可能就是大家说的卷王&#xff0c;感觉自己年轻&#xff…...

Redis第七讲 Redis存储模型详解

Redis存储模型 每次在Redis数据库中创建一个键值对时,至少会创建两个对象,一个是键对象,一个是值对象,而Redis中的每个对象都是由 redisObject 结构来表示.redisObject的结构与对象类型、内存编码、内存回收、共享对象都有关系,一个redisObject对象的大小为16字节:4bit+…...

Python 进阶指南(编程轻松进阶):十五、面向对象编程和类

原文&#xff1a;http://inventwithpython.com/beyond/chapter15.html OOP 是一种编程语言特性&#xff0c;允许你将变量和函数组合成新的数据类型&#xff0c;称为类&#xff0c;你可以从中创建对象。通过将代码组织成类&#xff0c;可以将一个整体程序分解成更容易理解和调试…...

windows下postgresql安装timescaledb

timescaledb是一个时序数据库&#xff0c;可以创建超表hypertable。它并不是一个独立的数据库&#xff0c;它依赖于postgresql&#xff0c;目前相当于postgresql的一个插件或者扩展。 要安装timescaledb&#xff0c;需要先安装postgresql。 这里安装的postgresql是12.14版本&am…...

Linux系统常用命令大全

本教程将介绍Linux系统的基本操作&#xff0c;包括文件操作、用户管理和软件安装等。 1. 文件操作 1.1 查看文件内容 使用cat命令可以查看文件的内容&#xff0c;例如&#xff1a;cat file.txt 1.2 创建新文件 使用touch命令可以创建新文件&#xff0c;例如&#xff1a;to…...

月报总结|Moonbeam 3月份大事一览

本月&#xff0c;Moonbeam在社区治理上进入了全新的阶段 — — 针对第一批生态系统Grants的Snapshot投票结果揭晓&#xff0c;链上公投已在进行中&#xff0c;社区获得了更多表达的机会与权力&#xff0c;这些项目也将为生态注入新的活力。 活动方面&#xff0c;Moonriver Ris…...

多功能料理锅语音播放芯片——NV040C

多功能料理锅就是一锅搭配多个锅盘&#xff0c;可以实现火锅、烤肉、花式煎蛋、丸子等多种烹饪功能。 多功能料理锅语音方案设计需求&#xff1a; 多功能锅本身体积有限&#xff0c;按钮比较少&#xff0c;相应功能的字体要贴按钮旁边&#xff0c;字体也是比较小的&#xff0c…...

vue23自定义svg图标组件

可参考&#xff1a; 未来必热&#xff1a;SVG Sprites技术介绍 懒人神器&#xff1a;svg-sprite-loader实现自己的Icon组件 在Vue3项目中使用svg-sprite-loader 前置知识 在页面中&#xff0c;虽然可以通过如下的方式使用img标签&#xff0c;来引入svg图标。但是&#xff0c;…...

相机雷达时间同步(基于ROS)

文章目录运行环境&#xff1a;思路&#xff1a;同步前和同步后效果对比1.1创建工作空间1.2创建功能包2.1编写源文件2.2编写头文件2.3编写可执行文件2.4配置文件3.1编译运行4.1录制时间同步后的rosbag4.2rviz可视化rosbag运行环境&#xff1a; ubuntu20.04 noetic usb_cam 速腾R…...

素数环PrimeRing [3*]

目录 素数环PrimeRing [3*] 程序设计 程序分析 素数环PrimeRing [3*] 把1~N这N个整数摆成一个环,要求任意相邻两个数的和为素数。按字典序打印出以1开始的素数环 Input 一个整数N (<=10) Output 每行一个素数环。每个数之间用一个空格隔开。 无解输出 No Solution Sampl…...

mongodb 连接池配置

参考官方描述&#xff1a; 如果spring使用以下mongodb的配置&#xff0c;则默认是没有连接池的 spring:data:mongodb:host: 地址port: 27017database: 数据库名username: 账号password: 密码 每隔一两分钟没有去请求的话就会断开连接重连&#xff0c;每次都要等待5-10秒之间才…...

数据在内存中的存储(深度剖析)

目录 1.数据类型介绍 1.1类型分类 2.整形在内存中的存储 2.1原码&#xff0c;反码&#xff0c;补码 2.2大小端介绍 2.3练习 3.浮点型在内存中的存储 3.1浮点数存储规则 引入&#xff1a; 有正负的数据可以存放在有符号的变量中 只有正数的数据可以存放在无符号的变量…...

python 实现二叉搜索树的方法有哪些?

树的介绍 树不同于链表或哈希表&#xff0c;是一种非线性数据结构&#xff0c;树分为二叉树、二叉搜索树、B树、B树、红黑树等等。 树是一种数据结构&#xff0c;它是由n个有限节点组成的一个具有层次关系的集合。用图片来表示的话&#xff0c;可以看到它很像一棵倒挂着的树。…...

ORM概述

1_ORM概述[理解] 解释: 对象关系映射模型特点: 1.将类名,属性, 映射成数据库的表名和字段2.类的对象,会映射成为数据库表中的一行一行的数据 优缺点: 优点: 1.不再需要编写sql语句2.不再关心使用的是什么数据库了 缺点: 1.由于不是直接通过sql操作数据库,所以有性能损失 2_…...

程序员必知必会7种UML图(类图、序列图、组件图、部署图、用例图、状态图和活动图)画法盘点

众所周知&#xff0c;软件开发是一个分阶段进行的过程。不同的开发阶段需要使用不同的模型图来描述业务场景和设计思路&#xff0c;在不同的阶段输出不同的设计文档也是必不可少的&#xff0c;例如&#xff0c;在需求分析阶段需要输出领域模型和业务模型&#xff0c;在架构阶段…...

基于asp的搜索引擎开发和实现

随着因特网的迅猛发展、WEB信息的增加&#xff0c;用户要在信息海洋里查找信息&#xff0c;就像大海捞针一样&#xff0c;搜索引擎技术恰好解决了这一难题。目前&#xff0c;搜索引擎系统可以分类三大类&#xff0c;分别是&#xff1a;目录式搜索引擎&#xff1a;以人工方式或半…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...