Новое в WebFlux, реактиве и обработчиках. У меня все «работает», но я не понимаю, почему следующий код возвращает «хорошо» с пустым телом, а «не найден».
Разъяснение: проблема заключается в заключительном операторе возврата DemoPOJOHandler.getById () . Код «короткого замыкания» работает должным образом (т. Е. Возвращает состояние «Неверный запрос»), но путь «switchIfEmpty» в последнем операторе возврата не выполняется, если DemoPOJORepo.getById (int) возвращает Mono.empty () .
(Примечание: я взломал «репо» на основе списка, чтобы избежать работы с базой данных при выяснении обработчиков и типов возврата http.)
Реализация маршрутизатора ("/ 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)));
}
}
Реализация обработчика была "урезана" только до рассматриваемого кода. У меня есть ощущение, что большая часть стиля «все еще обязательна», но я попытался поставить реактивные вещи там, где они «наиболее разумны».
Если я предоставлю неверное значение в URI (то есть, "foo"), тогда я получу http "неверный запрос". Но, похоже, никогда не получит «not found», которое должно быть сгенерировано « switchIfEmpty », если указано правильно отформатированное значение int, но оно не отображается на запись в репо.
@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()));
}
}
Хак репозитория на основе списка, чтобы избежать работы с данными / API при работе с обработчиками и типами возврата http.
// 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();
}
}