Spring Webflux is the new reactive web framework available as part of Spring 5+. The way filters were written in a traditional Spring MVC based application(Servlet Filter, HandlerInterceptor) is very different from the way a filter is written in a Spring Webflux based application and this post will briefly go over the WebFlux approach to Filters.
The WebFilter adds a request attribute with the value being a collection where the filter is just putting in a message that it has intercepted the request.
The second approach is more focused and covers only endpoints written using functional style. Here specific RouterFunctions can be hooked up with a filter, along these lines:
Consider a Spring Webflux endpoint defined the following way:
A HandlerFilterFunction which intercepts these API's alone can be added in a highly focused way along these lines:
Note that there is no need to be explicit about the types in Kotlin, I have added it just to be clear about the types in some of the lambda expressions
Approach 1 - WebFilter
The first approach using WebFilter affects all endpoints broadly and covers Webflux endpoints written in a functional style as well the endpoints that are written using an annotation style. A WebFilter in Kotlin look like this:
@Bean
fun sampleWebFilter(): WebFilter {
return WebFilter { e: ServerWebExchange, c: WebFilterChain ->
val l: MutableList<String> = e.getAttributeOrDefault(KEY, mutableListOf())
l.add("From WebFilter")
e.attributes.put(KEY, l)
c.filter(e)
}
}
The WebFilter adds a request attribute with the value being a collection where the filter is just putting in a message that it has intercepted the request.
Approach 2 - HandlerFilterFunction
The second approach is more focused and covers only endpoints written using functional style. Here specific RouterFunctions can be hooked up with a filter, along these lines:
Consider a Spring Webflux endpoint defined the following way:
@Bean
fun route(): RouterFunction<*> = router {
GET("/react/hello", { r ->
ok().body(fromObject(
Greeting("${r.attribute(KEY).orElse("[Fallback]: ")}: Hello")
))
POST("/another/endpoint", TODO())
PUT("/another/endpoint", TODO())
})
}
A HandlerFilterFunction which intercepts these API's alone can be added in a highly focused way along these lines:
fun route(): RouterFunction<*> = router {
GET("/react/hello", { r ->
ok().body(fromObject(
Greeting("${r.attribute(KEY).orElse("[Fallback]: ")}: Hello")
))
})
POST("/another/endpoint", TODO())
PUT("/another/endpoint", TODO())
}.filter({ r: ServerRequest, n: HandlerFunction<ServerResponse> ->
val greetings: MutableList<String> = r.attribute(KEY)
.map { v ->
v as MutableList<String>
}.orElse(mutableListOf())
greetings.add("From HandlerFilterFunction")
r.attributes().put(KEY, greetings)
n.handle(r)
})
Note that there is no need to be explicit about the types in Kotlin, I have added it just to be clear about the types in some of the lambda expressions