Отправьте данные html формы в webflux HandlerFunction - PullRequest
0 голосов
/ 25 октября 2018

У меня есть HTML-форма, отправляющая запрос в функцию HandlerFunction.Но я получаю сообщение об ошибке: «Произошла непредвиденная ошибка (type = Unsupported Media Type, status = 415). Тип содержимого« application / x-www-form-urlencoded »не поддерживается для bodyType = com.reactive.ui.component.SearchQuery

Вот форма.

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

А вот и функция Handler.

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());, но не знаю, как использовать его в моем случае.

Я думаю, что я где-то рядом с решением. Это код, который я написалНо теперь я получаю «Разрешено подписчику только одно соединение». Где я иду не так?

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

    };

1 Ответ

0 голосов
/ 25 октября 2018

Наконец я понял.Все это время я использовал request.body (BodyExtractors.toFormData ()), Бог знает почему !!, но то, что требовалось, было просто request.formData ().Размещаем код здесь, чтобы кто-то там получил пользу.Небольшое объяснение.request.formData () возвращает Mono<MultiValueMap<String, String>>.Сначала я сопоставляю его для создания экземпляра SearchQuery из значения, переданного через POST, затем отправляю его по плоской карте, где я вызываю другой микросервис, чтобы получить Flux<Flight>, затем помещаю его в java.util.Map и возвращаю ServerResponse.На самом деле вы можете сделать это в одном 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);
                });

    };
...