提交 html 表单数据到 webflux HandlerFunction

Submit html form data to webflux HandlerFunction

我有一个 html 表单向 HandlerFunction 提交请求。但我收到错误消息,“出现意外错误(类型=不支持的媒体类型,状态=415)。 bodyType=com.reactive.ui.component.SearchQuery

不支持内容类型 'application/x-www-form-urlencoded'

这是表格。

<form
            action="#"
            th:action="@{/search}"
            th:object="${searchQuery}"
            method="post">
            <table>
                <tr>
                    <td>traveling from</td>
                    <td><input
                        type="text"
                        th:field="*{origin}" /></td>
                </tr>
                <tr>
                    <td>going to</td>
                    <td><input
                        type="text"
                        th:field="*{destination}" /></td>
                </tr>
                <tr>
                    <td>planning on</td>
                    <td><input
                        type="text"
                        th:field="*{flightDate}" /></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input
                        type="submit"
                        value="Submit" /></td>
                </tr>
            </table>
        </form>

这里是 HandlerFunction。

public HandlerFunction<ServerResponse> postSearch = request ->
    {
        Mono<SearchQuery>         sq      = request.bodyToMono(SearchQuery.class);
        Flux<Flight>              flights = this.searchClient.post()
                .uri("/search/get/")
                .body(BodyInserters.fromPublisher(sq,
                                                  SearchQuery.class))
                .retrieve()
                .bodyToFlux(Flight.class);
        Map<String, Flux<Flight>> model   = new HashMap<>();
        model.put("flights",
                  flights);

        return ServerResponse.ok()
                .render("result",
                        model);
    };

这是路线。

@Bean
    RouterFunction<ServerResponse> search()
    {
        RouterFunction<ServerResponse> searchRoutes = RouterFunctions.route(GET("/"),
                                                                            uiHandler.search)
                .andRoute(POST("/search"),
                          uiHandler.postSearch);
        return searchRoutes;

    }

遇到这种情况怎么办?我看到了这样的代码 Mono<MultiValueMap<String, String> map = request.body(BodyExtractors.toFormData()); 但不知道如何在我的案例中使用它。

我想我已经接近解决方案了。这是我写的代码。但是现在我得到 "Only one connection receive subscriber allowed." 我哪里出错了?

public HandlerFunction<ServerResponse> postSearch = request ->
    {

        return request.body(BodyExtractors.toFormData())
                .map(value ->
                {
                    sq.setOrigin(value.getFirst("origin"));
                    sq.setDestination(value.getFirst("destination"));
                    sq.setFlightDate(value.getFirst("flightDate"));
                    System.out.println(sq);
                    Flux<Flight>      flights = this.searchClient.post()
                            .uri("/search/get/")
                            .body(BodyInserters.fromObject(sq))
                            .retrieve()
                            .bodyToFlux(Flight.class);
                    Map<String, Flux<Flight>> model = new HashMap<>();
                    model.put("flights",
                              flights);
                    return model;
                })
                .flatMap(model -> ServerResponse.ok()
                        .render("result",
                                model));

    };

终于明白了。一直以来我都在使用 request.body(BodyExtractors.toFormData()),天知道为什么!!但所需要的只是 request.formData()。将代码粘贴到此处以使其他人受益。 一点解释。 request.formData() returns Mono<MultiValueMap<String, String>>。首先,我将其映射为根据通过 POST 提交的值创建一个 SearchQuery 实例,然后将其平面映射到我调用另一个微服务的位置以获取 Flux<Flight>,然后将其放入 java.util.Map 和 return 服务器响应。实际上,您可以在单个 flatMap 中完成此操作,而不是先进行映射,然后再进行 flatMapping。

public HandlerFunction<ServerResponse> postSearch = request ->
    {
        return request.formData()
                .map(value ->
                {
                    SearchQuery sq = new SearchQuery();
                    sq.setOrigin(value.getFirst("origin"));
                    sq.setDestination(value.getFirst("destination"));
                    sq.setFlightDate(value.getFirst("flightDate"));
                    return sq;
                })
                .flatMap(sq ->
                {
                    Flux<Flight>      flights = this.searchClient.post()
                            .uri("/search/get/")
                            .body(BodyInserters.fromObject(sq))
                            .retrieve()
                            .bodyToFlux(Flight.class);
                    Map<String, Flux<Flight>> model = new HashMap<>();
                    model.put("flights",
                              flights);
                    return ServerResponse.ok()
                            .render("result",
                                    model);
                });

    };