背景:由于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,随意跳转到指定的过滤器,其实很简单相关推荐

  1. STM32 之十 供电系统及内部参照电压(VREFINT)使用及改善ADC参考电压,内部参照电压的具体方法,只有在STM32F0x芯片的参考手册中才能找到,其他MCU的参考手册都是很简单的说明

    STM32 之十 供电系统及内部参照电压(VREFINT)使用及改善ADC参考电压 ZCShouEXP 2018-12-21 10:50:33  16404  收藏 32 展开 问题   今天在使用 ...

  2. Linux 中 vim编辑器如何跳转到指定的列、如何跳转到行首或者行尾、左右跳转

    1.跳转到首行(文件的第一行第一列) gg # 输入两个小写gg 2.跳转到末行(文件的最后一行第一列) G #输入一个大写G 3.跳转到指定的第n行 66gg 66G # 输入 ngg 或 nG, ...

  3. vim 如何根据文本中的路径,跳转到指定文件 gf

    1. 把光标放到指定路径上,按gf,就可以跳转了gf means go to fileVim has to determine where the file name starts and ends. ...

  4. 如何提取视频中的音频,这个方法真的很简单

    如何提取视频中的音频,很多小伙伴再工作中会遇到类似的问题,要根据视频做一些纪要或文字记录,比如会议视频很长,又有很多类似的视频需要保存或处理,这样就比较占用磁盘空间,将他转换成音频之后,能大大减少磁盘 ...

  5. java实现日期让随动变_java工具类(四)之实现日期随意跳转

    Java实现日期随意跳转 项目开发过程中.须要进行订单提醒日期的设置.主要包含设置每月指定的日期或者指定的天数,代码例如以下: public static String DateOperation(S ...

  6. 浏览器中唤起native app || 跳转到应用商城下载(二) 之universal links

    上一篇文章 在ios9出来以后,我们发现越来越多的应用能够直接绕过微信的屏蔽,从其内置浏览器中直接唤起app.相比于通过弹窗提示让用户到浏览器中操作的方式,这无疑是极大的提高了用户体验与流量导入.因此 ...

  7. ASP.NET MVC中如何实现页面跳转

    1,最简单的方式:超链接 以下分别是连接到HomeController控制器下的SharpL动作方法,以及百度首页.代码如下: 1 <a href="Home\SharpL" ...

  8. SQLAlchemy中模糊查询;JS中POST带参数跳转;JS获取url参数

    SQLAlchemy中模糊查询,如何like多个关键字 JS中POST带参数跳转 一个项目中要跳转到另外一个项目,还需要带参数 考虑到安全性的问题,最好是用POST跳转,不能再URL中拼参 所以找到了 ...

  9. 在jQuery和JavaScript中,实现转跳

    在jQuery和JavaScript中,实现转跳 隐藏转跳,浏览器不产生历史记录(replace).代码片段: window.location.replace("http://insus.c ...

最新文章

  1. 杭电多校(二)2019.7.24--暑假集训
  2. Java的三种代理模式完整源码分析
  3. 访问 JSON 对象的值
  4. vue ---- webpack扩展
  5. java 静态扫描_静态代码扫描工具 – (八)- 扫描Java项目
  6. mysql 5.1 1067,mysql服务1067错误多种解决方案汇总
  7. 8.cisco思科模拟器无线路由器设备实训练习
  8. 云南省工信厅洪正华一行莅临红谷滩区·高通中国·影创联合创新中心考察调研
  9. c++快速傅里叶变换、反变换(FFT、IFFT)
  10. 基于表情分析的智能语音陪伴机器人
  11. 目标检测概述-VOC COCO数据集 IOU AP NMS
  12. 桑佛德大学计算机科学,桑佛德大学
  13. 从几个简单例子聊聊Verilog的参数化设计(parameter、localparam和`define)
  14. 2021年十大网络用语发布
  15. 为何在网络上很难赚到钱?网络副业赚钱真的很难做吗?
  16. 努比亚手机安装linux,努比亚红魔5G电竞手机将发布;Linux版荣耀MagicBook降价促销...
  17. 玩游戏掉帧严重?看过来!
  18. 微信扫码登录功能实现
  19. 十万部冷知识:足球赛中进三个球为什么叫帽子戏法?
  20. Python 英文分词

热门文章

  1. simulink电力电子仿真(3)单相桥式全控整流电路
  2. excel表格打开灰色,没有内容
  3. 阿里巴巴王坚:不理解在线,就没有真懂互联网
  4. 京东平台研发朱志国:领域驱动设计(DDD)理论启示
  5. Android布局动画之animateLayoutChanges与LayoutTransition
  6. TMS320C6455入门实践(六)——编写boot程序
  7. 十一届蓝桥杯 100阶乘的约数-python
  8. 面试项目2:基于Spark2.x的电商大数据统计分析平台
  9. [PsTools]psexec.exe使用范例-执行远程电脑程序(exe、bat等)
  10. 疯狂的大柚柚带你玩转MSP-ESP430G2(基础篇)----(十)定时计数器