JAVA:Filer过滤器+案例:请求IP访问限制和请求返回值修改

JAVA:Filer过滤器

介绍

Java中的Filter也被称为过滤器,它是Servlet技术的一部分,用于在web服务器上拦截请求和响应,以检查或转换其内容。
Filter的urlPatterns可以过滤特定地址http的请求,也可以利用Filter对访问请求的数据IP做限制。
文档为本人学习java过滤器过程中做的学习记录。

主要用途:

  • 认证过滤:检查用户请求并确定是否合法。
  • 登记日志:记录请求和响应的日志。
  • 改变请求和响应:可以修改请求头和响应头。
  • 数据压缩:在发送大数据前,可以压缩数据。
  • 加密:对请求和响应进行加密和解密。

使用说明

Spring项目中,创建类继承Filter,实现init、doFilter、destroy方法;

  • init:只在项目启动的时候运行,用来做数据的初始化
  • doFilter:数据过滤,每次http请求都会过滤;filterChain.doFilter(request, servletResponse)前面的程序程序是在执行目标程序前执行,后面的程序是在目标程序后执行,若doFilter程序没有执行filterChain.doFilter,请求将会被拦截。
  • destroy:项目结束时运行

多个过滤器执行顺序

注意:SpringBoot项目中,多个过滤器时,@Order + @WebFilter + @ServletComponentScan 是无法实现按顺序执行过滤器的,推荐使用FilterRegistrationBean实现过滤。

  • 原因详细分析见:https://blog.csdn.net/Zong_0915/article/details/126747302

案例(使用FilterRegistrationBean限制过滤器执行循序+限制IP+修改请求返回值)

案例:有两个过滤器:MyFilter01和MyFilter02,要求按先执行过滤器MyFilter01,再执行过滤器MyFilter02顺序。
MyFilter01实现对IP的白名单限制(限制127.0.0.1仅可以访问一次),以及请求返回值的更写。
MyFilter02仅用于体现执行顺序。

  • 案例参考地址:
    https://blog.csdn.net/zhanwuguo8346/article/details/120498756

创建过滤器:MyFilter01用于限制访问IP,修改请求返回值;


@Slf4j
public class MyFilter01 implements Filter {private Map<String, Integer> whiteIPMap;private List<String> alwaysIPList;public MyFilter01(Map<String, Integer> whiteIPMap, List<String> alwaysIPList) {this.alwaysIPList = alwaysIPList;this.whiteIPMap = whiteIPMap;}private final ObjectMapper objectMapper = new ObjectMapper();private static final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("/swagger-resources", "/v3/swagger-login", "/v2/api-docs")));private static Map<String, Integer> whiteIpMapDay = new HashMap<>();@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("(MyFilter01)项目开始时候执行:------->>>init");System.out.println("(MyFilter01)whiteIPMap:" + whiteIPMap);System.out.println("(MyFilter01)alwaysIPList:" + alwaysIPList);whiteIpMapDay.putAll(whiteIPMap);}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("(MyFilter01)项目每次http请求时候执行:------->>>doFilter.start");HttpServletRequest request = (HttpServletRequest) servletRequest;String ipAddr = getIpAddr(request);log.info("PermissionFilter 过滤器,请求ip为:{}", ipAddr);String path = request.getRequestURI().substring(request.getContextPath().length()).replaceAll("[/]+$", "");boolean contains = ALLOWED_PATHS.contains(path);servletResponse.setCharacterEncoding("utf-8");servletResponse.setContentType("text/html;charset=utf-8");if (alwaysIPList.contains(ipAddr) && contains) {filterChain.doFilter(request, servletResponse);} else {if (whiteIpMapDay.containsKey(ipAddr)) {Integer integer = whiteIpMapDay.get(ipAddr);if (integer > 0) {if (contains) {filterChain.doFilter(request, servletResponse);} else {whiteIpMapDay.put(ipAddr, (whiteIpMapDay.get(ipAddr) - 1));filterChain.doFilter(request, servletResponse);}} else {BaseResponse<Void> baseResponse = new BaseResponse<>();baseResponse.setCode(-1);baseResponse.setMessage("请求被拒绝,本IP:" + ipAddr + "每天只允许调用:" + whiteIPMap.get(ipAddr) + "次!");String response = objectMapper.writeValueAsString(baseResponse);setServletResponseMessage(servletResponse, response);}} else {BaseResponse<Void> baseResponse = new BaseResponse<>();baseResponse.setMessage("不支持本IP请求:" + ipAddr);baseResponse.setCode(-1);String response = objectMapper.writeValueAsString(baseResponse);setServletResponseMessage(servletResponse, response);}}System.out.println("(MyFilter01)项目每次http请求时候执行:------->>>doFilter.end");}@Overridepublic void destroy() {System.out.println("(MyFilter01)项目结束时候执行:------->>>destroy");}/*** 处理返回是getWriter()还是getOutputStream();* getWriter():out对象用于处理字符流数据。* getOutputStream():os用于输出字符流数据或者二进制的字节流数据都可以。*/private void setServletResponseMessage(ServletResponse servletResponse, String response) {try {servletResponse.getWriter().write(response);} catch (IOException e) {throw new RuntimeException(e);} catch (IllegalStateException e) {servletResponse.setContentType("text/plain;charset=UTF-8"); // 设置内容类型和编码try {ServletOutputStream outputStream = servletResponse.getOutputStream();outputStream.write(response.getBytes(StandardCharsets.UTF_8)); // 写入字节数组} catch (IOException ex) {throw new RuntimeException(ex);}}}public static String getIpAddr(HttpServletRequest request) {String ipAddress = request.getHeader("x-forwarded-for");if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("Proxy-Client-IP");}if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("WL-Proxy-Client-IP");}if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddr();if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {//根据网卡取本机配置的IPInetAddress inet = null;try {inet = InetAddress.getLocalHost();} catch (UnknownHostException e) {e.printStackTrace();}
//                ipAddress= inet.getHostAddress();ipAddress = "127.0.0.1";}}//对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割if (ipAddress.length() > 15) { //"***.***.***.***".length() = 15if (ipAddress.indexOf(",") > 0) {ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));}}return ipAddress;}}

过滤器:MyFilter02仅作日志记录。体现执行顺序

public class MyFilter02 implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("(MyFilter02)项目开始时候执行:------->>>init");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("(MyFilter02)项目每次http请求时候执行:------->>>doFilter.start");filterChain.doFilter(servletRequest, servletResponse);System.out.println("(MyFilter02)项目每次http请求时候执行:------->>>doFilter.end");}@Overridepublic void destroy() {System.out.println("(MyFilter02)项目结束时候执行:------->>>destroy");}}

application.yml中设置白名单访问次数,一直有权限访问的白名单。
127.0.0.1限制仅可以访问一次。

permission:white-ip: '{"127.0.0.1": 1, "192.168.16.30": 2}'always-ip: 127.0.0.1,127.0.0.1 

创建配置类:FilterConfig使用@Value读取配置文件值,注册FilterRegistrationBean到Spring容器中,并设置两个过滤器的执行顺序和过滤路径

@Configuration
public class FilterConfig { @Value("#{${permission.white-ip}}")private Map<String, Integer> whiteIPMap;@Value("#{'${permission.always-ip}'.split(',')}")private List<String> alwaysIPList;@Beanpublic FilterRegistrationBean<MyFilter01> myFilterRegistrationBean01() {FilterRegistrationBean<MyFilter01> bean = new FilterRegistrationBean<>();bean.setFilter(new MyFilter01(whiteIPMap, alwaysIPList));bean.addUrlPatterns("/api/*");bean.setOrder(1);return bean;}@Beanpublic FilterRegistrationBean<MyFilter02> myFilterRegistrationBean02() {FilterRegistrationBean<MyFilter02> bean = new FilterRegistrationBean<>();bean.setFilter(new MyFilter02());bean.addUrlPatterns("/*");bean.setOrder(2);return bean;}
}

程序中用到的BaseResponse类:

@Data
public class BaseResponse<T> implements Serializable {private int code;private T data;private String message;private String description;public BaseResponse() {}public BaseResponse(int code, T data, String message, String description) {this.code = code;this.data = data;this.message = message;this.description = description;}public BaseResponse(int code, T data, String message) {this(code, data, message, "");}public BaseResponse(int code, T data) {this(code, data, "", "");}public BaseResponse(ErrorCodeEnum errorCode) {this(errorCode.getCode(), null, errorCode.getMessage(), errorCode.getDescription());}
}

测试结果:

第一次执行接口ApiPost(127.0.0.1)接口返回:数据正常创建
在这里插入图片描述

第二次执行接口ApiPost(127.0.0.1)接口返回:提示IP只能每天访问一次(这里没有提供更新:MyFilter01.whiteIpMapDay来实现每天可反问一次,可以使用@Schedule每天定时对静态变态做充值)。
在这里插入图片描述

执行日志:可以看出过滤器按照顺序执行
在这里插入图片描述

参考网址

https://blog.csdn.net/zhanwuguo8346/article/details/120498756
https://blog.csdn.net/Zong_0915/article/details/126747302

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

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

相关文章

鸿蒙语言基础类库:【@system.sensor (传感器)】

传感器 说明&#xff1a; 从API Version 8开始&#xff0c;该接口不再维护&#xff0c;推荐使用新接口[ohos.sensor]。本模块首批接口从API version 4开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。该功能使用需要对应硬件支持&#xff0c;仅支持…

地图项目涉及知识点总结

序&#xff1a;最近做了一个在地图上标记点的项目&#xff0c;用户要求是在地图上显示百万量级的标记点&#xff0c;并且地图仍要可用&#xff08;能拖拽&#xff0c;能缩放&#xff09;。调研了不少方法和方案&#xff0c;最终实现了相对流畅的地图系统&#xff0c;加载耗时用…

2024可信数据库发展大会:TDengine CEO 陶建辉谈“做难而正确的事情”

在当前数字经济快速发展的背景下&#xff0c;可信数据库技术日益成为各行业信息化建设的关键支撑点。金融、电信、能源和政务等领域对数据处理和管理的需求不断增加&#xff0c;推动了数据库技术的创新与进步。与此同时&#xff0c;人工智能与数据库的深度融合、搜索与分析型数…

【Git】(基础篇四)—— GitHub使用

GitHub使用 经过上一篇的文章&#xff0c;相信大家已经对git的基本操作熟悉了&#xff0c;但哪些使用git的方法只是在本地仓库进行&#xff0c;本文介绍如何使用git和远程仓库进行连接使用。 Github和Gitee 主要用到的两个远程仓库在线平台是github和gitee GitHub GitHub …

Adobe XD中文设置指南:专业设计师的现场解答

Adobe XD是世界领先的在线合作UI设计工具。它摆脱了Sketch、Figma等传统设计软件对设备的依赖&#xff0c;使设计师可以随时随地使用任何设备打开网页浏览器&#xff0c;轻松实现跨平台、跨时空的设计合作。然后&#xff0c;为了提高国内设计师的使用体验&#xff0c;Adobe XD如…

2024-07-18 Unity插件 Odin Inspector8 —— Type Specific Attributes

文章目录 1 说明2 特定类型特性2.1 AssetList2.2 AssetSelector2.3 ChildGameObjectsOnly2.4 ColorPalette2.5 DisplayAsString2.6 EnumPaging2.7 EnumToggleButtons2.8 FilePath2.9 FolderPath2.10 HideInInlineEditors2.11 HideInTables2.12 HideMonoScript2.13 HideReferenc…

DP(6) | 完全背包 | Java | LeetCode 322, 179, 139 做题总结

322. 零钱兑换 我的错误答案 class Solution {public int coinChange(int[] coins, int amount) {int[][]dp new int [coins.length][amount1];for(int j0; j<amount; j) {if(coins[0] j){dp[0][coins[0]] 1;}}for(int i1; i<coins.length; i) {for(int j0; j<am…

带时间窗车辆路径问题丨论文复现:改进粒子群算法求解

路径优化相关文章 1、路径优化历史文章2、路径优化丨带时间窗和载重约束的CVRPTW问题-改进遗传算法&#xff1a;算例RC1083、路径优化丨带时间窗和载重约束的CVRPTW问题-改进和声搜索算法&#xff1a;算例RC1084、路径优化丨复现论文-网约拼车出行的乘客车辆匹配及路径优化5、…

[C/C++入门][进制原理]27、计算机种的进制

各种信息进入计算机&#xff0c;都要转换成“0”和“1”的二进制形式。 计算机 采用二进制的原因是&#xff1a; 物理上容易实现&#xff0c;可靠性高。&#xff08;电子元件的通电和不通电就可以表示1和0&#xff0c;所以非常方便&#xff09;运算简单&#xff0c;通用性强。…

ELK日志分析系统部署文档

一、ELK说明 ELK是Elasticsearch&#xff08;ES&#xff09; Logstash Kibana 这三个开源工具组成&#xff0c;官方网站: The Elastic Search AI Platform — Drive real-time insights | Elastic 简单的ELK架构 ES: 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它…

Java 网络编程(TCP编程 和 UDP编程)

1. Java 网络编程&#xff08;TCP编程 和 UDP编程&#xff09; 文章目录 1. Java 网络编程&#xff08;TCP编程 和 UDP编程&#xff09;2. 网络编程的概念3. IP 地址3.1 IP地址相关的&#xff1a;域名与DNS 4. 端口号&#xff08;port&#xff09;5. 通信协议5.1 通信协议相关的…

如何免费用java c#实现手机在网状态查询

今天分享手机在网状态查询接口&#xff0c;该接口适用的场景非常广泛&#xff01;首先我们先讲下什么是手机在网状态&#xff1f;简单来说&#xff0c;就是你得手机号是否还在正常使用中&#xff0c;是否能够及时接收和回复信息&#xff0c;是否能够随时接听和拨打电话。如果你…

小白新手搭建个人网盘

小白新手搭建个人网盘 序云服务器ECS重置密码远程连接ECS实例 安装OwnCloud安装Apache服务PHP运行环境NAS挂载挂载验证操作体验 序 阿里云文件存储NAS&#xff08;Apsara File Storage NAS&#xff09;是一个可大规模共享访问&#xff0c;弹性扩展的分布式文件系统。本文主要是…

Python面试宝典第15题:岛屿数量

题目 在二维网格地图上&#xff0c;1 表示陆地&#xff0c;0 表示水域。如果相邻的陆地可以水平或垂直连接&#xff0c;则它们属于同一块岛屿。请进行编码&#xff0c;统计地图上的岛屿数量。比如&#xff1a;下面的二维网格地图&#xff0c;其岛屿数量为3。 基础知识 解决这类…

简约的悬浮动态特效404单页源HTML码

源码介绍 简约的悬浮动态特效404单页源HTML码,页面简约美观,可以做网站错误页或者丢失页面,将下面的代码放到空白的HTML里面,然后上传到服务器里面,设置好重定向即可 效果预览 完整源码 <!DOCTYPE html> <html><head><meta charset="utf-8&q…

高性能、安全、低碳绿色的趋势下,锐捷网络发布三擎云办公解决方案 3.0

桌面虚拟化作为云时代的主流和热门技术&#xff0c;已经取得了广泛应用。随着生成式 AI 爆炸式发展&#xff0c;CSDN 看到&#xff0c;人工智能正在引发计算、开发、交互三大范式的全面升级&#xff0c;技术开发或将迎来一次全新的科技变革周期&#xff0c;因此 VDI 云桌面随之…

组队学习——支持向量机

本次学习支持向量机部分数据如下所示 IDmasswidthheightcolor_scorefruit_namekind 其中ID&#xff1a;1-59是对应训练集和验证集的数据&#xff0c;60-67是对应测试集的数据&#xff0c;其中水果类别一共有四类包括apple、lemon、orange、mandarin。要求根据1-59的数据集的自…

Day16_集合与迭代器

Day16-集合 Day16 集合与迭代器1.1 集合的概念 集合继承图1.2 Collection接口1、添加元素2、删除元素3、查询与获取元素不过当我们实际使用都是使用的他的子类Arraylist&#xff01;&#xff01;&#xff01; 1.3 API演示1、演示添加2、演示删除3、演示查询与获取元素 2 Iterat…

[数据分析]脑图像处理工具

###############ATTENTION&#xff01;############### 非常需要注意软件适配的操作系统&#xff01;有些仅适用于Linux&#xff0c;可以点进各自软件手册查看详情。 需要自行查看支持的影像模态。 代码库和软件我没有加以区分。 不是专门预处理的博客&#xff01;&#xf…

HDU1005——Number Sequence,HDU1006——Tick and Tick,HDU1007——Quoit Design

目录 HDU1005——Number Sequence 题目描述 超时代码 代码思路 正确代码 代码思路 HDU1006——Tick and Tick 题目描述 运行代码 代码思路 HDU1007——Quoit Design 题目描述 运行代码 代码思路 HDU1005——Number Sequence 题目描述 Problem - 1005 超时代码…