使用WebFlux的HandlerFilterFunction实现过滤器

JAVA herman 41浏览

前面我们花了两篇的时间来写 webflux 的 WebFilter,大家应该都明白了它的具体用法。但是最终你会发现,WebFilter 这种过滤器没有servlet filter中的url pattern功能。也就是说它会对所有的 URL 请求进行链接,所以效率就比较低。

而 HandlerFilterFunction 这种用法更加专注具体的过滤细节,更符合 WebFlux 的特点。下面我们一起来学习它!

使用WebFlux的HandlerFilterFunction实现过滤器

先来段代码:

@Configuration
public class XttblogWebFlux {

    @Bean
    public RouterFunction<ServerResponse> helloXttblog() {
        return RouterFunctions.route(
                RequestPredicates.GET("/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                request -> ServerResponse.ok().body(BodyInserters.fromObject("Hello www.xttblog")))
                .filter((serverRequest, handlerFunction) -> {
                    // 针对/hello 的请求进行过滤,然后在响应中添加一个Content-Type属性
                    return ServerResponse.status(HttpStatus.OK).header("Content-Type","text/plain; charset=utf-8").build();
                });
    }
}

Router Functions是Spring 5新引入的一套Reactive风格(基于Flux和Mono)的函数式接口,主要包括RouterFunction,HandlerFunction和HandlerFilterFunction,分别对应Spring MVC中的@RequestMapping,@Controller和HandlerInterceptor(或者Servlet规范中的Filter)。

RouterFunctions.route 对针具体 url 进行映射,可以是多个url,多种请求方式:get、post等。匹配到对应的 url 就会路由,否则不会执行路由。

路由器功能映射的路由可以通过调用RouterFunction.filter(HandlerFilterFunction)进行过滤,其中HandlerFilterFunction本质上是一个占用ServerRequest和HandlerFunction的函数,并返回一个ServerResponse。

如果要被多个 HandlerFilterFunction 进行拦截,可以链式调用多次 .filter 方法,具体做法如下:

@Configuration
public class XttblogWebFlux {

    @Bean
    public RouterFunction<ServerResponse> helloXttblog() {
        return RouterFunctions.route(
                RequestPredicates.GET("/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                request -> {
                    System.out.println("url: " + request.attribute("url"));
                    return ServerResponse.ok().body(BodyInserters.fromObject("Hello www.xttblog"));
                })
                .filter((serverRequest, handlerFunction) -> {
                    // 针对/hello 的请求进行过滤,然后在响应中添加一个Content-Type属性
                    return ServerResponse.status(HttpStatus.OK)
                            .header("Content-Type","text/plain; charset=utf-8")
                            .body(BodyInserters.fromObject("Hello www.xttblog.com"));
                });
    }

    @Bean
    public RouterFunction<ServerResponse> xttblog() {
        return RouterFunctions.route(
                RequestPredicates.GET("/xttblog").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                request -> {
                    System.out.println("url: " + request.attribute("url"));
                    return ServerResponse.ok().body(BodyInserters.fromObject("Hello www.xttblog"));
                })
                .filter((serverRequest, handlerFunction) -> {
                    // 这里可以判断是否登录,进行拦截。我这里写个业余草,打个广告
                    if("业余草".equals(serverRequest.path())){
                        return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
                    }

                    //在request 中放一个url参数
                    serverRequest.attributes().put("url", "www.xttblog.com");
                    // 针对/hello 的请求进行过滤,然后在响应中添加一个Content-Type属性
                    return handlerFunction.handle(serverRequest);
                });
    }

    @Bean
    public RouterFunction<ServerResponse> xttblog_com() {
        return RouterFunctions.route(
                RequestPredicates.GET("/xttblogWebFlux").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                request -> {
                    System.out.println("url: " + request.attribute("url") + ", wexin: " + request.attribute("wexin"));
                    return ServerResponse.ok().body(BodyInserters.fromObject("Hello www.xttblog.com xttblogWebFlux"));
                })
                .filter((serverRequest, handlerFunction) -> {
                    // 这里可以判断是否登录,进行拦截。我这里写个业余草,打个广告
                    if("业余草".equals(serverRequest.path())){
                        return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
                    }

                    //在request 中放一个url参数
                    serverRequest.attributes().put("url", "www.xttblog.com");
                    // 针对/hello 的请求进行过滤,然后在响应中添加一个Content-Type属性
                    return handlerFunction.handle(serverRequest);
                })
                .filter((serverRequest, handlerFunction) -> {
                    // 这里可以判断是否登录,进行拦截。我这里写个业余草,打个广告
                    if("业余草".equals(serverRequest.path())){
                        return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
                    }

                    //在request 中放一个url参数
                    serverRequest.attributes().put("wexin", "公众号:业余草[yyucao]");
                    // 针对/hello 的请求进行过滤,然后在响应中添加一个Content-Type属性
                    return handlerFunction.handle(serverRequest);
                });
    }
}

过滤器除了 WebFilter 和 HanderFilterFunction 之外,还可以使用 @ControllerAdvice 或 ServletFilter实现类似的功能。

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847,QQ3群:187424846。QQ群进群密码:xttblog,想加微信群的朋友,可以微信搜索:xmtxtt,备注:“xttblog”,添加助理微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » 使用WebFlux的HandlerFilterFunction实现过滤器