WebFlux 返回 http.okay 副 http.notFound

WebFlux returning http.okay vice http.notFound

WebFlux、反应式和处理程序的新手。我有东西 "working",但我不明白为什么下面的代码是 returning "okay" 空体,副 "not found".

澄清:关注的问题在DemoPOJOHandler.getById()的最后return声明中。 "short-circuit" 代码按预期工作(即 returns "Bad Request" 状态),但最终 return 语句的 "switchIfEmpty" 路径似乎没有得到执行如果 DemoPOJORepo.getById(int) returns Mono.empty().

(注意:我破解了一个基于列表的 "repo" 以避免在确定处理程序和 http return 类型时处理数据库。)

路由器实现(“/v1”是一组基于注释的 RESTful 端点)...

@Configuration
public class DemoPOJORouter {

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

处理程序实现已 "stripped down" 仅针对相关代码。我感觉大部分样式都是 "still imperative",但我试图将反应性内容放在 "makes the most sense".

的位置

如果我在 URI 上提供了错误的值(即 "foo"),那么我会得到 http "bad request" returned。但是,如果提供了有效格式的 int 值,似乎永远不会得到应该由“switchIfEmpty”生成的 "not found",但它不会映射到 repo 中的条目.

@Component
public class DemoPOJOHandler {

    public static final String PATH_VAR_ID = "id";

    private DemoPOJORepo repo = null;

    public Mono<ServerResponse> getById(ServerRequest request) {
        Mono<DemoPOJO>      monoDemoPOJO  = null;
        Map<String, String> pathVariables = request.pathVariables();
        int                 id            = -1;

        checkRepoRef(); // part of the list hack

        // short-circuit if request doesn't contain id (should never happen)
        if ((pathVariables == null)
         || (!pathVariables.containsKey(PATH_VAR_ID))) {
            return ServerResponse.badRequest().build();
        }

        // short-circuit if bad id value
        try {
            id = Integer.parseInt(pathVariables.get(PATH_VAR_ID));
        } catch(NumberFormatException e) {
            return ServerResponse.badRequest().build();
        }

        // get entity by keyValue
        monoDemoPOJO = repo.getById(id);

        return monoDemoPOJO
                   .flatMap(demoPOJO -> ServerResponse.ok()
                                                      .contentType(MediaType.APPLICATION_JSON)
                                                      .syncBody(demoPOJO)
                   .switchIfEmpty(ServerResponse.notFound().build()));
    }

}

破解基于列表的回购以避免在处理程序和 http return 类型时处理 data/APIs。

// local hack to avoid a database for testing
public class DemoPOJORepo {

    private static DemoPOJORepo fpRepo   = null;
    private static int          NUM_ROWS = 100;

    private Map<Integer, DemoPOJO> fooPOJOMap;

    private DemoPOJORepo() {
        initMap();
    }

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

    public Mono<DemoPOJO> getById(int id) {
        Mono<DemoPOJO> monoDP;

        if (fooPOJOMap.containsKey(id)) {
            monoDP = Mono.just(fooPOJOMap.get(id));
        } else {
            monoDP = Mono.empty();
        }
        return monoDP;
    }

    private Mono<Void> initMap() {
        fooPOJOMap = new TreeMap<Integer, DemoPOJO>();
        int offset = -1;

        for(int ndx=0; ndx<NUM_ROWS; ndx++) {
            offset = ndx + 1;
            fooPOJOMap.put(offset, new DemoPOJO(offset, "foo_" + offset, offset+100));
        }
        return Mono.empty();
    }
}

正如我所见,代码是正确的。响应代码是 Bad request,因为您正在尝试将 "foo" 转换为 Integer,当它抛出异常时您将返回 Bad 请求响应,所以我认为它工作得很好。 如果您使用数据库中不存在的整数 ID,则答案必须是未找到的响应

您的括号位置错误,导致 swithIfEmpy 应用于 ServerResponse.ok() 发布者而不是 monoDemoPOJO,将 return 替换为这个,它应该可以工作:

return monoDemoPOJO
                   .flatMap(demoPOJO -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).syncBody(demoPOJO))
                   .switchIfEmpty(ServerResponse.notFound().build());