Spring Reactive 使用 ServerRequest 获取正文 JSONObject

Posted

技术标签:

【中文标题】Spring Reactive 使用 ServerRequest 获取正文 JSONObject【英文标题】:Spring Reactive get body JSONObject using ServerRequest 【发布时间】:2019-03-23 01:20:45 【问题描述】:

我是 Spring 响应式新手。

我正在尝试使用邮递员从服务器获取请求信息。

首先,postman 使用 post 方法向服务器发送信息。 其次,我们一直在使用相关代码在服务器端工作并获取请求信息。

在下面的代码sn-p中

不知能不能得到ServerRequest函数的JSONObject。

邮递员正文(应用程序/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(处理程序)

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();

【问题讨论】:

【参考方案1】:

谢谢。 Alexander Terekhov

您的回答对解决问题有很大帮助。

我的测试代码。

RouterFunction = 与现有代码相同。

处理程序

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();

控制台中的结果如下所示:-

==========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======

编码愉快,谢谢。


已更新。

谢谢。 @Zon 评论。 toProcessor 现在已弃用 - 更喜欢 share() 共享父订阅,或使用接收器 https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#toProcessor--也请参考这个网址。

【讨论】:

请告诉我JSONObject类的导入路径是什么。 @Nick 嗨,我使用 org.json.simple.JSONObject 类。在 Maven 设置中。像这样。 com.googlecode.json-simplejson-simple1.1 toProcessor 现已弃用 - 首选 share() 共享父订阅,或使用 Sinks @Zon 谢谢。 projectreactor.io/docs/core/release/api/reactor/core/publisher/…也请参考这个网址。【参考方案2】:

我认为您可以尝试通过以下方式注册一种“回调”:

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

另外,我注意到您将ServerResponse.ok() 转换为Mono&lt;ServerResponse&gt;。我认为它不会投。使用ServerResponse.ok().build() 制作Mono&lt;ServerResponse&gt;

【讨论】:

我尝试了这种方法,但我观察到然后在 doOnNext 之前被调用,因为我正在更改 doOnNext 中的响应,我的要求是等到 doOnNext 完成 一些数据库调用 同步与否?【参考方案3】:

@oddeveloper 我发现 Mono.toProcessor() 已被弃用。

最简单的方法就是拥有这样的POJO

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 + '';
    

然后提取Person person = serverRequest.bodyToMono(Person.class).toFuture().get()

get() 函数

如有必要,等待这个未来完成,然后返回它的 结果。

@terekhov你的解决方案对我不起作用,我不知道为什么

如果这对你不起作用并且你必须有一个 JSONObject 然后像这样创建一个 JSONObjectBodyExtractor

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");
                

            );
        );
    


然后在您的反应式处理程序中像这样提取

    Mono<JSONObject> jsonObjectMono = (Mono<JSONObject>) request.body(jsonObjectBodyExtractor);
JSONObject jsonObject=jsonObjectMono.toFuture().get();

【讨论】:

谢谢。 projectreactor.io/docs/core/release/api/reactor/core/publisher/…也请参考这个网址。

以上是关于Spring Reactive 使用 ServerRequest 获取正文 JSONObject的主要内容,如果未能解决你的问题,请参考以下文章

Reactive Spring 不支持 ServerHttpRequest 作为 REST 端点测试中的参数?

Spring 5:使用 Spring Webflux 开发 Reactive 应用

Spring 5 Reactive - WebExceptionHandler 没有被调用

使用 Spring Reactive 时如何验证 Mono

@Tailable(spring-data-reactive-mongodb) 等效于 spring-data-r2dbc

Reactive Spring实战 -- 响应式Kafka交互