WebClient 未成功调用“POST”操作

问题描述 投票:0回答:1

我正在使用 Spring 的 WebClient。 REST 端点的主要实现(在 DemoPOJORouterDemoPOJOHandler 中)似乎可以工作。此外,DemoClientRouterDemoClientHandler中的http.Get端点似乎可以工作。

但是,DemoClient 实现的 http.Post “什么也不做”。它返回成功(200),但没有任何内容添加到虚拟存储库中。我有一种感觉,我需要在 DemoClient 中做一些事情来导致 DemoPOJOHandler 中的 http.Post 端点实际执行(即,我不相信 DemoPOJOService.add() 中的语句也不相信 DemoPOJORepo.add( ) 正在执行).

基于之前在 WebFlux/反应式/功能性工作中的失误,我有一种感觉,我没有成功订阅,因此永远不会调用这些语句。但是,我很难确定“为什么”。

测试代码如下...

DemoClient 路由器...

@Configuration
public class DemoClientRouter {

    @Bean
    public RouterFunction<ServerResponse> clientRoutes(DemoClientHandler requestHandler) {
        return nest(path("/v2"),
                nest(accept(APPLICATION_JSON),
                        RouterFunctions.route(RequestPredicates.GET("/DemoClient/{id}"), requestHandler::getById)
                                       .andRoute(RequestPredicates.POST("/DemoClient"), requestHandler::add)));
    }
}

DemoClient 处理程序...

@Component
public class DemoClientHandler {

    public static final String PATH_VAR_ID = "id";

    @Autowired
    DemoClient demoClient;

    public Mono<ServerResponse> getById(ServerRequest request) {
        Mono<DemoPOJO> monoDemoPOJO;
        int            id;

        // short-circuit if bad request or invalid value for id
        id = getIdFromServerRequest(request);
        if (id < 1) {
            return ServerResponse.badRequest().build();
        }

        // non-blocking mechanism for either returning the Mono<DemoPOJO>
        //  or an empty response if Mono<Void> was returned by repo.getById()
        return demoClient.getById(id).flatMap(demoPOJO -> ServerResponse.ok()
                                                                        .contentType(MediaType.APPLICATION_JSON)
                                                                        .body(Mono.just(demoPOJO), DemoPOJO.class))
                                                                        .switchIfEmpty(ServerResponse.notFound().build());
    }

    public Mono<ServerResponse> add(ServerRequest request) {
        return request.bodyToMono(DemoPOJO.class).doOnSuccess( demoPOJO -> demoClient.add(demoPOJO))
                                                     .then(ServerResponse.ok().build())
                                                 .onErrorResume(e -> simpleErrorReporter(e))
                                                 .switchIfEmpty(ServerResponse.badRequest().build());
    }

    private int getIdFromServerRequest(ServerRequest request) {
        Map<String, String> pathVariables = request.pathVariables();
        int                 id            = -1;

        // short-circuit if bad request
        //  should never happen, but if this method is ever called directly (vice via DemoPOJORouter)
        if ((pathVariables == null)
         || (!pathVariables.containsKey(PATH_VAR_ID))) {
            return id;
        }

        try {
            id = Integer.parseInt(pathVariables.get(PATH_VAR_ID));
        } catch (NumberFormatException e) {
            // swallow the error, return value <0 to signal error
            id = -1;
        }
        return id;
    }

    private Mono<ServerResponse> simpleErrorReporter(Throwable e) {
        return ServerResponse.badRequest()
                             .contentType(MediaType.TEXT_PLAIN)
                             .syncBody(e.getMessage());
    }
}

DemoClient 实现...

@Component
public class DemoClient {

    private final WebClient client;

    public DemoClient() {
        client = WebClient.create();
    }

    public Mono<DemoPOJO> getById(int id) {
        return client.get().uri("http://localhost:8080/v2/DemoPOJO/" + id)
                           .accept(MediaType.APPLICATION_JSON)
                           .exchange()
                           .flatMap(response -> response.bodyToMono(DemoPOJO.class));
    }

    public Mono<Boolean> add(DemoPOJO demoPOJO) {
        return client.post().uri("http://localhost:8080/v2/DemoPOJO")
                            .syncBody(demoPOJO)
                            .exchange()
                            .flatMap(response -> response.bodyToMono(Boolean.class));
    }
}

还有 DemoPOJO 的东西,从 DemoPOJORouter...

开始
@Configuration
public class DemoPOJORouter {

    @Bean
    public RouterFunction<ServerResponse> demoPOJORoute(DemoPOJOHandler requestHandler) {
        return nest(path("/v2"),
                nest(accept(APPLICATION_JSON),
                        RouterFunctions.route(RequestPredicates.GET("/DemoPOJO/{id}"), requestHandler::getById)
                                       .andRoute(RequestPredicates.POST("/DemoPOJO"), requestHandler::add)));
    }
}

演示POJOHandler...

@Component
public class DemoPOJOHandler {

    public static final String PATH_VAR_ID = "id";

    @Autowired
    private DemoPOJOService service;

    public Mono<ServerResponse> getById(ServerRequest request) {
        Mono<DemoPOJO> monoDemoPOJO;
        int            id;

        // short-circuit if bad request or invalid value for id
        id = getIdFromServerRequest(request);
        if (id < 1) {
            return ServerResponse.badRequest().build();
        }

        // non-blocking mechanism for either returning the Mono<DemoPOJO>
        //  or an empty response if Mono<Void> was returned by repo.getById()
        return service.getById(id).flatMap(demoPOJO -> ServerResponse.ok()
                                                                     .contentType(MediaType.APPLICATION_JSON)
                                                                     .body(Mono.just(demoPOJO), DemoPOJO.class))
                                  .switchIfEmpty(ServerResponse.notFound().build());
    }

    public Mono<ServerResponse> add(ServerRequest request) {
        return request.bodyToMono(DemoPOJO.class).doOnSuccess( demoPOJO -> service.add(demoPOJO))
                                                     .then(ServerResponse.ok().build())
                                                 .onErrorResume(e -> simpleErrorReporter(e))
                                                 .switchIfEmpty(ServerResponse.badRequest().build());
    }

    private int getIdFromServerRequest(ServerRequest request) {
        Map<String, String> pathVariables = request.pathVariables();
        int                 id            = -1;

        // short-circuit if bad request
        //  should never happen, but if this method is ever called directly (vice via DemoPOJORouter)
        if ((pathVariables == null)
         || (!pathVariables.containsKey(PATH_VAR_ID))) {
            return id;
        }

        try {
            id = Integer.parseInt(pathVariables.get(PATH_VAR_ID));
        } catch (NumberFormatException e) {
            // swallow the exception, return illegal value to signal error
            id = -1;
        }
        return id;
    }

    private Mono<ServerResponse> simpleErrorReporter(Throwable e) {
        return ServerResponse.badRequest()
                             .contentType(MediaType.TEXT_PLAIN)
                             .syncBody(e.getMessage());
    }
}

演示POJOService...

@Component
public class DemoPOJOService {

    @Autowired
    private DemoPOJORepo demoPOJORepo;

    public Mono<DemoPOJO> getById(int id) {
        DemoPOJO demoPOJO = demoPOJORepo.getById(id);

        return (demoPOJO == null) ? Mono.empty()
                                  : Mono.just(demoPOJO);
    }

    public Mono<Boolean> add(DemoPOJO demoPOJO) {
        return Mono.just(demoPOJORepo.add(demoPOJO));
    }
}

演示POJORepo...

@Component
public class DemoPOJORepo {

    private static final int NUM_OBJS = 5;

    private static DemoPOJORepo demoRepo = null;

    private Map<Integer, DemoPOJO> demoPOJOMap;

    private DemoPOJORepo() {
        initMap();
    }

    public static DemoPOJORepo getInstance() {
        if (demoRepo == null) {
            demoRepo = new DemoPOJORepo();
        }
        return demoRepo;
    }

    public DemoPOJO getById(int id) {
        return demoPOJOMap.get(id);
    }

    public boolean add(DemoPOJO demoPOJO) throws InvalidParameterException {
        // short-circuit on null pointer or duplicate id
        if (demoPOJO == null) {
            throw new InvalidParameterException("Add failed, null object detected...");
        } else if (demoPOJOMap.containsKey(demoPOJO.getId())) {
            throw new InvalidParameterException("Add failed, duplicate id detected...");
        }

        demoPOJOMap.put(demoPOJO.getId(), demoPOJO);
        // if the return statement is reached, then the new demoPOJO was added
        return true;
    }
}

最后,演示POJO...

public class DemoPOJO {

    public static final String DEF_NAME = "DEFAULT NAME";
    public static final int DEF_VALUE = 99;

    private int id;
    private String name;
    private int value;

    public DemoPOJO(int id) {
        this(id, DEF_NAME, DEF_VALUE);
    }

    public DemoPOJO(@JsonProperty("id") int id, @JsonProperty("name") String name, @JsonProperty("value") int value) {
        this.id = id;
        this.name = name;
        this.value = value;
    }

    /*
     * setters and getters go here
     */

    public String toString() {
        StringBuilder builder = new StringBuilder();

        builder.append(id);
        builder.append(" :: ");
        builder.append(name);
        builder.append(" :: ");
        builder.append(value);
        return builder.toString();
    }
}
spring-boot spring-webflux project-reactor
1个回答
1
投票

这可能是您的问题。

演示POJOHandler.class

request.bodyToMono(DemoPOJO.class).doOnSuccess(demoPOJO -> service.add(demoPOJO))

演示POJOService.class

public Mono<Boolean> add(DemoPOJO demoPOJO) {
    return Mono.just(demoPOJORepo.add(demoPOJO));
}

doOnSuccess
返回
Void
,但您正在调用一个将“操作”包装在返回的
Mono
中的方法。所以
demoPOJORepo#add
函数永远不会被触发,因为你已经破坏了这里的事件链。最简单的解决方法是去掉包装
Mono
并返回void。

public void add(DemoPOJO demoPOJO) {
    demoPOJORepo.add(demoPOJO);
}
© www.soinside.com 2019 - 2024. All rights reserved.