重写webFlux中的webFilter,随意跳转到指定的过滤器,其实很简单
背景:由于webFlux中的webFilter没有对指定请求路径进行分流功能,因为过滤器就像一根管道,默认情况下过滤器执行的顺序是已经固定好了的,谁也不能插队,所以我希望过滤器可以通过我的请求来分发到不同的过滤器来执行。
原理:重写 webFlux中 的 DefaultWebFilterChain.java实现类 与 WebFilterChain.java接口
DefaultWebFilterChain.java代码如下:
/** Copyright 2002-2017 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package org.springframework.web.server.handler;import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects;import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Mono;import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import org.springframework.web.server.WebHandler;/*** Default implementation of {@link WebFilterChain}.** @author Rossen Stoyanchev* @since 5.0*/ @Slf4j public class DefaultWebFilterChain implements WebFilterChain {private final List<WebFilter> filters;private final WebHandler handler;private final int index;public DefaultWebFilterChain(WebHandler handler, WebFilter... filters) {Assert.notNull(handler, "WebHandler is required");this.filters = ObjectUtils.isEmpty(filters) ? Collections.emptyList() : Arrays.asList(filters);this.handler = handler;this.index = 0;}private DefaultWebFilterChain(DefaultWebFilterChain parent, int index) {this.filters = parent.getFilters();this.handler = parent.getHandler();this.index = index;}public List<WebFilter> getFilters() {return this.filters;}public WebHandler getHandler() {return this.handler;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange) {return Mono.defer(() -> {if (this.index < this.filters.size()) {WebFilter filter = this.filters.get(this.index);WebFilterChain chain = new DefaultWebFilterChain(this, this.index + 1);return filter.filter(exchange, chain);} else {return this.handler.handle(exchange);}});}/*** 通过索引确定过滤器* @param exchange the current server exchange* @param index the filter index,you can choose filter to execute* @return*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, int index) {return Mono.defer(() -> {if (index < this.filters.size()) {WebFilter filter = this.filters.get(index);WebFilterChain chain = new DefaultWebFilterChain(this, index + 1);return filter.filter(exchange, chain);} else {return this.handler.handle(exchange);}});}/*** 通过指定过滤器执行* @param exchange the current server exchange* @param cls appoint one filter to execute* @return*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, Class cls) {WebFilter filter = null;int index = 0;try {for (int i = 0; i < this.filters.size(); i++) {Class targetCls = Class.forName(this.filters.get(i).getClass().getName());if (cls.isAssignableFrom(targetCls)) {filter = this.filters.get(i);index = i;}}} catch (Exception e) {log.error("get filter is error,please contact with administrator!");}if (Objects.nonNull(filter)) {WebFilterChain chain = new DefaultWebFilterChain(this, index + 1);return filter.filter(exchange, chain);} else {return this.handler.handle(exchange);}} }
WebFilterChain.java代码如下:
/** Copyright 2002-2015 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package org.springframework.web.server;import reactor.core.publisher.Mono;/*** Contract to allow a {@link WebFilter} to delegate to the next in the chain.** @author Rossen Stoyanchev* @since 5.0*/ public interface WebFilterChain {/*** Delegate to the next {@code WebFilter} in the chain.* @param exchange the current server exchange* @return {@code Mono<Void>} to indicate when request handling is complete*/Mono<Void> filter(ServerWebExchange exchange);/*** Delegate to the next {@code WebFilter} in the chain.* @param exchange the current server exchange* @param index the filter index,you can choose filter to execute* @return {@code Mono<Void>} to indicate when request handling is complete*/Mono<Void> filter(ServerWebExchange exchange,int index);/*** Delegate to the next {@code WebFilter} in the chain.* @param exchange the current server exchange* @param cls appoint one filter to execute* @return {@code Mono<Void>} to indicate when request handling is complete*/Mono<Void> filter(ServerWebExchange exchange, Class cls);}
接下来,编写自己的过滤器,主要包括三部分:
1、入口的过滤器(DispatcherFilter.java) ,主要用于分发到不同的过滤器
2、业务过滤器(checkFilter.java,自己随意编写)
3、底层过滤器(BaseFilter.java)
一、BaseFilter.java代码如下:
package com.test.filter;
import io.netty.buffer.ByteBufAllocator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.net.URI;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;/**
*
*/
@Slf4j
@Component
public abstract class BaseFilter implements WebFilter, Ordered {protected String bodyData="";
protected void readRequestData(ServerHttpRequest serverHttpRequest)
{
String method = serverHttpRequest.getMethodValue();
if ("POST".equals(method)) {
bodyData=resolveBodyFromRequest(serverHttpRequest);
}
else if("GET".equals(method))
{
bodyData=getContentByGetRequest(serverHttpRequest);
}
}public void after(ServerWebExchange exchange) {
}@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
System.out.println("BaseFilter is comming");
ServerHttpRequest serverHttpRequest = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();String method = serverHttpRequest.getMethodValue();
if ("POST".equals(method)) {
//下面的将请求体再次封装写回到request里,传到下一级,否则,由于请求体已被消费,后续的服务将取不到值
URI uri = serverHttpRequest.getURI();
ServerHttpRequest request = serverHttpRequest.mutate().uri(uri).build();
DataBuffer bodyDataBuffer = stringBuffer(bodyData);
Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
request = new ServerHttpRequestDecorator(request) {
@Override
public Flux<DataBuffer> getBody() {
return bodyFlux;
}
};
//封装request,传给下一级
return chain.filter(exchange.mutate().request(request).build());
} else if ("GET".equals(method)) {
return chain.filter(exchange);
}
return chain.filter(exchange);
}private String getContentByGetRequest(ServerHttpRequest serverHttpRequest) {
Map requestQueryParams = serverHttpRequest.getQueryParams().toSingleValueMap();
StringBuffer s = new StringBuffer();
String content = "";
requestQueryParams.forEach((k, v) -> {
System.out.println(k + " v:" + v);
s.append(k + "=" + v + "&");
});
if (StringUtils.isNotEmpty(s.toString())) {
content = s.toString().substring(0, s.toString().lastIndexOf('&'));
}
return content;
}/**
* 从Flux<DataBuffer>中获取字符串的方法
*
* @return 请求体
*/
private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
//获取请求体
Flux<DataBuffer> body = serverHttpRequest.getBody();AtomicReference<String> bodyRef = new AtomicReference<>();
body.subscribe(buffer -> {
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
DataBufferUtils.release(buffer);
bodyRef.set(charBuffer.toString());
});
//获取request body
return bodyRef.get();
}private DataBuffer stringBuffer(String value) {
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
buffer.write(bytes);
return buffer;
}@Override
public int getOrder() {
return 0;
}}
二,DispatcherFilter.java分流过滤器
package org.test.filter import lombok.extern.slf4j.Slf4j; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono;@Slf4j @Component public class DispatcherFilter extends BaseFilter {@Overridepublic int getOrder() {//数值越小,优先级越高return Integer.MIN_VALUE;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {super.readRequestData(exchange.getRequest());List<String> signUrls = cantaloupeConfig.getCheckSignWhiteUrls();List<String> cacheUrls = cantaloupeConfig.getUpdateCacheWhiteUrls();//根据不同的请求分流到不同的过滤器if (checkUrl(exchange,signUrls)) {return chain.filter(exchange,CheckSignFilter.class);}else if (checkUrl(exchange,cacheUrls)){return chain.filter(exchange,UpdateCacheFilter.class);}return super.filter(exchange,chain);}}
三,各业务过滤器,举个栗子,CheckSignFilter.java
package com.test.filter;import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono;import java.util.List;/*** 验证签名过滤器*/ @Slf4j @Component public class CheckSignFilter extends BaseFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {//to doreturn super.filter(exchange,chain);}@Overridepublic void after(ServerWebExchange exchange) {}@Overridepublic int getOrder() {return -100;} }
是不是很简单的就可以让过滤器听你的话,亲测无误,如有问题,请留言 !
重写webFlux中的webFilter,随意跳转到指定的过滤器,其实很简单相关推荐
- STM32 之十 供电系统及内部参照电压(VREFINT)使用及改善ADC参考电压,内部参照电压的具体方法,只有在STM32F0x芯片的参考手册中才能找到,其他MCU的参考手册都是很简单的说明
STM32 之十 供电系统及内部参照电压(VREFINT)使用及改善ADC参考电压 ZCShouEXP 2018-12-21 10:50:33 16404 收藏 32 展开 问题 今天在使用 ...
- Linux 中 vim编辑器如何跳转到指定的列、如何跳转到行首或者行尾、左右跳转
1.跳转到首行(文件的第一行第一列) gg # 输入两个小写gg 2.跳转到末行(文件的最后一行第一列) G #输入一个大写G 3.跳转到指定的第n行 66gg 66G # 输入 ngg 或 nG, ...
- vim 如何根据文本中的路径,跳转到指定文件 gf
1. 把光标放到指定路径上,按gf,就可以跳转了gf means go to fileVim has to determine where the file name starts and ends. ...
- 如何提取视频中的音频,这个方法真的很简单
如何提取视频中的音频,很多小伙伴再工作中会遇到类似的问题,要根据视频做一些纪要或文字记录,比如会议视频很长,又有很多类似的视频需要保存或处理,这样就比较占用磁盘空间,将他转换成音频之后,能大大减少磁盘 ...
- java实现日期让随动变_java工具类(四)之实现日期随意跳转
Java实现日期随意跳转 项目开发过程中.须要进行订单提醒日期的设置.主要包含设置每月指定的日期或者指定的天数,代码例如以下: public static String DateOperation(S ...
- 浏览器中唤起native app || 跳转到应用商城下载(二) 之universal links
上一篇文章 在ios9出来以后,我们发现越来越多的应用能够直接绕过微信的屏蔽,从其内置浏览器中直接唤起app.相比于通过弹窗提示让用户到浏览器中操作的方式,这无疑是极大的提高了用户体验与流量导入.因此 ...
- ASP.NET MVC中如何实现页面跳转
1,最简单的方式:超链接 以下分别是连接到HomeController控制器下的SharpL动作方法,以及百度首页.代码如下: 1 <a href="Home\SharpL" ...
- SQLAlchemy中模糊查询;JS中POST带参数跳转;JS获取url参数
SQLAlchemy中模糊查询,如何like多个关键字 JS中POST带参数跳转 一个项目中要跳转到另外一个项目,还需要带参数 考虑到安全性的问题,最好是用POST跳转,不能再URL中拼参 所以找到了 ...
- 在jQuery和JavaScript中,实现转跳
在jQuery和JavaScript中,实现转跳 隐藏转跳,浏览器不产生历史记录(replace).代码片段: window.location.replace("http://insus.c ...
最新文章
- 杭电多校(二)2019.7.24--暑假集训
- Java的三种代理模式完整源码分析
- 访问 JSON 对象的值
- vue ---- webpack扩展
- java 静态扫描_静态代码扫描工具 – (八)- 扫描Java项目
- mysql 5.1 1067,mysql服务1067错误多种解决方案汇总
- 8.cisco思科模拟器无线路由器设备实训练习
- 云南省工信厅洪正华一行莅临红谷滩区·高通中国·影创联合创新中心考察调研
- c++快速傅里叶变换、反变换(FFT、IFFT)
- 基于表情分析的智能语音陪伴机器人
- 目标检测概述-VOC COCO数据集 IOU AP NMS
- 桑佛德大学计算机科学,桑佛德大学
- 从几个简单例子聊聊Verilog的参数化设计(parameter、localparam和`define)
- 2021年十大网络用语发布
- 为何在网络上很难赚到钱?网络副业赚钱真的很难做吗?
- 努比亚手机安装linux,努比亚红魔5G电竞手机将发布;Linux版荣耀MagicBook降价促销...
- 玩游戏掉帧严重?看过来!
- 微信扫码登录功能实现
- 十万部冷知识:足球赛中进三个球为什么叫帽子戏法?
- Python 英文分词
热门文章
- simulink电力电子仿真(3)单相桥式全控整流电路
- excel表格打开灰色,没有内容
- 阿里巴巴王坚:不理解在线,就没有真懂互联网
- 京东平台研发朱志国:领域驱动设计(DDD)理论启示
- Android布局动画之animateLayoutChanges与LayoutTransition
- TMS320C6455入门实践(六)——编写boot程序
- 十一届蓝桥杯 100阶乘的约数-python
- 面试项目2:基于Spark2.x的电商大数据统计分析平台
- [PsTools]psexec.exe使用范例-执行远程电脑程序(exe、bat等)
- 疯狂的大柚柚带你玩转MSP-ESP430G2(基础篇)----(十)定时计数器