Avatar
0
anaconda875 Beginner
anaconda875 Beginner
Spring weblux how to share data from Controller to Filter using Context

In controller I need to share some data to WebFilter (I don't want to use ServerWebExchange.getAttributes().put("KEY", "VALUE"), and my boss either), this is my current implemetation:

<code><span>@Component</span>
<span>public</span> <span>class</span> <span>RequestFilter</span> <span>implements</span> <span>WebFilter</span> {

  <span>@Override</span>
  <span>public</span> Mono<Void> <span>filter</span><span>(ServerWebExchange exchange, WebFilterChain chain)</span> {
    exchange.getResponse().beforeCommit(() -> Mono.deferWithContext(c -> {
      <span>//I CHECK WHETHER DATA SHARED FROM CONTROLLER EXIST OR NOT</span>
      System.out.println(c.hasKey(<span>"abc"</span>));
      <span>Context</span> <span>innerContext</span> <span>=</span> c.get(<span>"CONTEXT"</span>);
      System.out.println(innerContext.hasKey(<span>"abc"</span>));
      <span>return</span> Mono.empty();
    }));

    <span>ServerHttpRequest</span> <span>request</span> <span>=</span> exchange.getRequest();
    <span>BodyCaptureExchange</span> <span>bodyCaptureExchange</span> <span>=</span> <span>new</span> <span>BodyCaptureExchange</span>(exchange);

    <span>return</span> chain.filter(bodyCaptureExchange).subscriberContext(context -> {
      <span>//HERE I PUT CONTEXT TO ITSELF</span>
      context = context.put(<span>"CONTEXT"</span>, context);
      <span>return</span> context;
    });
  }
}</code>

Here is my controller method:
<code><span>public</span> Mono<ResponseEntity<Response>> <span>post</span><span>(<span>@RequestBody</span> Mono<Request> request)</span> {
    Mono<ResponseEntity<Response>> responseEntityMono = request.flatMap(
            rq -> service.requestProcess(rq).map(res -> ResponseEntity.ok().body(res))
        ).subscriberContext(c -> {
            <span>//HERE I GET THE INNER CONTEXT FROM ABOVE FILTER</span>
            <span>Context</span> <span>innerContext</span> <span>=</span> c.get(<span>"CONTEXT"</span>);
            <span>//PUT DATA TO IT</span>
            c = c.put(<span>"CONTEXT"</span>, innerContext.put(<span>"abc"</span>, <span>"abc"</span>));
            <span>//ALSO PUT DATA TO PARENT</span>
            c = c.put(<span>"abc"</span>, <span>"abc"</span>);
            <span>return</span> c;
        });
        
    <span>return</span> responseEntityMono;
}</code>


The System.out.println in RequestFilter print:

<code><span>false</span>
<span>false</span>
</code>

Means that data I put from controller are lost when it come to Filter.  Please correct me if I'm wrong somewhere. I really need your help

Reactor version: 3.3.14

Spring boot stater webflux: 2.3.9.RELEASE

  • Answer
spring webflux
Remain: 5
1 Answer
Avatar
monkey Beginner
monkey Beginner
The Best Answer
Thằng Context này là đối tượng của spring và em không nên dùng nó, nếu em đặt breakpoint hoặc xem source code vào các lớp Context0, Context1 em sẽ thấy mỗi khi gọi hàm put nó lại sinh ra 1 context mới chứ không phải là đưa dữ liệu vào context đâu,

Vậy nên thay vì dùng context em có thể dùng map của java nhé:

// RequestFilter</span>
<span>// exchange.getResponse().beforeCommit</span>
<span>Map</span><<span>Object</span>, <span>Object</span>> innerContext = c.<span>get</span>(<span>"CONTEXT"</span>);

<span>// return chain.filter(exchange)</span>
<span>Map</span><<span>Object</span>, <span>Object</span>> innerContext = <span>new</span> HashMap<>();
context = context.put(<span>"CONTEXT"</span>, innerContext);
<span>return</span> context;

<span>// controller</span>
 <span>Map</span><<span>Object</span>, <span>Object</span>> innerContext = c.<span>get</span>(<span>"CONTEXT"</span>);
innerContext.put(<span>"abc"</span>, <span>"abc"</span>);
<span>//PUT DATA TO IT</span>
c = c.put(<span>"abc"</span>, <span>"abc"</span>);
<span>return</span> c;
  • 1
  • Reply