9

i'm spring reactive newbie.

I am trying to use postman to get request information from the server.

First, postman sends information to the server using the post method. Second, we've been working on the server side with the relevant code and getting the request information.

In the following code snippet

I wonder if I can get the JSONObject of the ServerRequest function.

postman body(application/json)

{
    "name": "aaaa",
    "name_order": ["aa", "bb", "cc"],
    "type": "12",
    "query": ""
}

java (RouterFunction)

import com.ntels.io.input.handler.RestInHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.springframework.web.reactive.function.server.*;

import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
import static org.springframework.web.reactive.function.server.RequestPredicates.PUT;
import static org.springframework.web.reactive.function.server.RequestPredicates.DELETE;

@Configuration
@EnableWebFlux
public class RestConfig implements WebFluxConfigurer {

    @Bean
    public RouterFunction<ServerResponse> routes(RestInHandler restInHandler){
        return RouterFunctions.route(POST("/input/event").
        and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), restInHandler::toRESTInVerticle);
    }
}

java (Handler)

public Mono<ServerResponse> toRESTInVerticle(ServerRequest serverRequest) {
    String serverRequestUrl = serverRequest.uri().toString();

    System.out.println("RestInHandler test in");
    System.out.println(serverRequest.method());
    System.out.println(serverRequest.headers());
    System.out.println(serverRequest.uri().toString());

    // how can i get the jsonbody using serverrequest

    // testing..

    // Mono<JSONObject> jsonObjectMono = serverRequest.bodyToMono(JSONObject.class);
    // Flux<JSONObject> jsonObjectFlux = serverRequest.bodyToFlux(JSONObject.class);
-> MonoOnErrorResume

    return (Mono<ServerResponse>) ServerResponse.ok();
}
oddeveloper
  • 173
  • 1
  • 2
  • 10

3 Answers3

7

thank you. Alexander Terekhov

Your answer has been a lot of help in solving the problem.

My Test Code.

RouterFunction = Same as existing code.

Handler

public Mono<ServerResponse> toRESTInVerticle(ServerRequest serverRequest) {
    String uri = serverRequest.uri().toString();
    String method = serverRequest.methodName();
    String contentType = serverRequest.headers().contentType().get().toString();
    String characterSet = serverRequest.headers().acceptCharset().get(0).toString();
    JSONObject bodyData = serverRequest.bodyToMono(JSONObject.class).toProcessor().peek();

    System.out.println("==========toRESTInVerticle Data Check==========");
    System.out.println(uri);
    System.out.println(method);
    System.out.println(contentType);
    System.out.println(characterSet);
    System.out.println(bodyData);
    System.out.println("======toRESTInVerticle Data Check Complete======");

    return Mono.empty();
}

and the result in console as provided below :-

==========toRESTInVerticle Data Check==========
http://localhost:8082/input/event/check
POST
application/json
UTF-8
{"event_type":"12","event_name_order":["aa","bb","cc"],"event_query":"","event_name":"aaaa","init_value":"","init_value_yn":"N","event_descp":"ddd"}
======toRESTInVerticle Data Check Complete======

Happy Coding Thank you.


Updated.

Thank you. @Zon Comments. toProcessor is deprecated now - prefer share() to share a parent subscription, or use Sinks https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#toProcessor-- Please refer to this url as well.

oddeveloper
  • 173
  • 1
  • 2
  • 10
  • Please tell me what the import path of JSONObject class is. – Nick Jun 17 '20 at 01:28
  • @Nick Hi, I use the org.json.simple.JSONObject class. in maven settings. like this. com.googlecode.json-simple json-simple 1.1 – oddeveloper Jun 18 '20 at 02:12
  • `toProcessor` is deprecated now - prefer `share()` to share a parent subscription, or use `Sinks` – Zon Oct 13 '21 at 14:55
  • @Zon Thank you. https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#toProcessor-- Please refer to this url as well. – oddeveloper Oct 14 '21 at 05:58
5

I think you can try to register a kind of 'callback' in the next way:

        return request.bodyToMono(JSONObject.class)
                  .doOnNext(jsonObject -> // testing..)
                  .then(ServerResponse.ok().build());

Also, I noticed that you are casting ServerResponse.ok() to Mono<ServerResponse>. I think it will not cast. Use ServerResponse.ok().build() to make Mono<ServerResponse>.

0

@oddeveloper I find that Mono.toProcessor() is deprecated.

The easiest way is to have a POJO like this

import java.util.List;
import java.util.Objects;
import java.util.logging.Logger;

public class Person {
    
    private String name;
    
    private List<String> nameOrder;
    
    private String type;
    
    private String query;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<String> getNameOrder() {
        return nameOrder;
    }

    public void setNameOrder(List<String> nameOrder) {
        this.nameOrder = nameOrder;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getQuery() {
        return query;
    }

    public void setQuery(String query) {
        this.query = query;
    }
    
    
    @Override
    public String toString() {
        return "Person{" + "name=" + name + ", nameOrder=" + nameOrder + ", type=" + type + ", query=" + query + '}';
    }
}

then extract Person person = serverRequest.bodyToMono(Person.class).toFuture().get().

get() function

Waits if necessary for this future to complete, and then returns its result.

@terekhov your solution did not work for me I don't know why

If that doesn't work for you and you have to have a JSONObject then create a JSONObjectBodyExtractor like this

import java.nio.charset.StandardCharsets;
import org.json.JSONObject;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.springframework.http.ReactiveHttpInputMessage;
import org.springframework.web.reactive.function.BodyExtractor;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.core.io.buffer.DataBuffer;
import reactor.core.publisher.Mono;

/**
 *
 * @author timot
 * @param <T>
 * @param <M>
 */
public class JSONObjectBodyExtractor<T extends Mono<JSONObject>, M extends ReactiveHttpInputMessage> implements BodyExtractor {

    private static final Logger LOG = Logger.getLogger(JSONObjectBodyExtractor.class.getName());

    @Override
    public Mono<JSONObject> extract(ReactiveHttpInputMessage inputMessage, Context context) {

        return Mono.<JSONObject>create(sink -> {
            inputMessage.getBody().subscribe(new Subscriber() {

                @Override
                public void onSubscribe(Subscription s) {
                    s.request(1);
                }

                @Override
                public void onNext(Object t) {
                    
                    DataBuffer dataBuffer=(DataBuffer) t;
                    
                    sink.success(new JSONObject(dataBuffer.toString(StandardCharsets.UTF_8)));
                }

                @Override
                public void onError(Throwable thrwbl) {
                    LOG.log(Level.SEVERE, "jsonobjectbodyextractor onerror", thrwbl);
                }

                @Override
                public void onComplete() {
                    LOG.log(Level.INFO, "jsonobjectbodyextractor oncomplete");
                }

            });
        });
    }

}

Then in your reactive handler extract like this

    Mono<JSONObject> jsonObjectMono = (Mono<JSONObject>) request.body(jsonObjectBodyExtractor);
JSONObject jsonObject=jsonObjectMono.toFuture().get();
  • Thank you. https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#toProcessor-- Please refer to this url as well. – oddeveloper Oct 14 '21 at 05:59
  • This solution does assume that the incoming Flux has just one item, doesn't it? I see two problems: We could be missing further DataBuffer items + there is no guarantee that the first DataBuffer item has the bytes of a complete JSON. So, basically, this example only works if the incoming Flux has exactly one item, right? – Manuel Schmidt Feb 07 '23 at 13:21