#spring-boot #spring-data-mongodb #project-reactor #spring-data-mongodb-reactive
#весенняя загрузка #spring-data-mongodb #проект-реактор #spring-data-mongodb-реактивный
Вопрос:
Я совершенно новичок в реактивном коде, и после ряда руководств и видеороликов YouTube я пытаюсь настроить крошечное тестовое приложение, используя функциональные конечные точки; простая функция RouterFunction, RouterHandler и репозиторий. Проблема в том, как вернуть объект в ServerResponse из respository вызывающему, не вызывая ненужной блокировки?
Я использую Postman для тестирования. Вот интересные части моего тестового приложения:
@Configuration
public class BookRouter {
@Autowired
BookRepositoryImpl bookRepository;
@Bean
public RouterFunction<ServerResponse> bookRoutes() {
BookHandler bookHandler = new BookHandler(bookRepository);
return RouterFunctions
.nest(path("/api/books"),
route(GET("/{group}/{name}").and(accept(ALL)), bookHandler::getBook)
);
}
}
@Repository
public class BookRepositoryImpl implements BookRepository {
private final ReactiveMongoTemplate mongoTemplate;
@Autowired
public BookRepositoryImpl(ReactiveMongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
@Override
public Mono<Book> findByName(String group, String name) {
Query query = new Query(Criteria.where("group").is(group).and("name").is(name));
return mongoTemplate.findOne(query, Book.class);
}
}
public class BookHandler {
public Mono<ServerResponse> getBook(ServerRequest request) {
String group = request.pathVariable("group");
String name = request.pathVariable("name");
bookRepository
.findByName(group, name)
.subscribe(
ok -> System.out.println("findByName " ok),
error -> System.err.println("Error: " error));
return ServerResponse
.accepted()
.contentType(MediaType.TEXT_PLAIN)
.bodyValue("Request queued");
}
}
Когда у меня есть код, как показано выше, ожидаемые данные распечатываются в subscribe(ok -> ...)
, но я не понял, как вернуть эти данные в ServerResponse.
Если я изменю код в getBook()
на
return setting
.flatMap(s -> ServerResponse
.ok()
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(s))
.switchIfEmpty(NOT_FOUND);
возвращенный bodyValue
пустой, хотя я вижу, что он был извлечен из базы данных.
Любой совет о том, чего мне не хватает, наиболее ценен.
Обновить
Я использую MongoDB Compass для просмотра и проверки содержимого базы данных.
Ведение журнала отладки включено в application.properties
с logging.level.root=DEBUG
, поэтому классы Spring записывают некоторую информацию в окне терминала. Части несколько анонимизированного журнала выглядят следующим образом:
2020-09-05 21:37:02.688 DEBUG 32720 --- [ctor-http-nio-3] o.s.w.r.f.s.s.RouterFunctionMapping : [96ef6152-1] Mapped to com.sample.book.BookRouter$$Lambda$586/0x0000000800540040@3b0bf8e0
2020-09-05 21:37:02.717 DEBUG 32720 --- [ctor-http-nio-3] o.s.d.m.core.ReactiveMongoTemplate : findOne using query: { "group" : "Thriller", "name" : "The Shining"} fields: Document{{}} for class: class com.sample.book.Book in collection: book
2020-09-05 21:37:02.734 DEBUG 32720 --- [ctor-http-nio-3] o.s.d.m.core.ReactiveMongoTemplate : findOne using query: { "group" : "Thriller", "name" : "The Shining"} fields: {} in db.collection: book.book
2020-09-05 21:37:02.751 DEBUG 32720 --- [ctor-http-nio-3] org.mongodb.driver.protocol.command : Sending command '{"find": "book", "filter": {"group": "Thriller", "name": "The Shining"}, "limit": 1, "singleBatch": true, "$db": "book"}' with request id 7 to database book on connection [connectionId{localValue:2, serverValue:217}] to server localhost:27017
2020-09-05 21:37:02.766 DEBUG 32720 --- [ntLoopGroup-3-2] org.mongodb.driver.protocol.command : Execution of command with request id 7 completed successfully in 16.24 ms on connection [connectionId{localValue:2, serverValue:217}] to server localhost:27017
2020-09-05 21:37:02.837 DEBUG 32720 --- [ntLoopGroup-3-2] o.s.http.codec.json.Jackson2JsonEncoder : [96ef6152-1] Encoding [_id=5f53692af0a02d3af8a7fed9, group=Thriller, name=The Shining, value=in]]
2020-09-05 21:37:02.853 DEBUG 32720 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations : [id: 0x96ef6152, L:/0:0:0:0:0:0:0:1:8088 - R:/0:0:0:0:0:0:0:1:50248] Decreasing pending responses, now 0
2020-09-05 21:37:02.879 DEBUG 32720 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter : [96ef6152-1] Completed 200 OK
2020-09-05 21:37:02.905 DEBUG 32720 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations : [id: 0x96ef6152, L:/0:0:0:0:0:0:0:1:8088 - R:/0:0:0:0:0:0:0:1:50248] Last HTTP response frame
2020-09-05 21:37:02.931 DEBUG 32720 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations : [id: 0x96ef6152, L:/0:0:0:0:0:0:0:1:8088 - R:/0:0:0:0:0:0:0:1:50248] Last HTTP packet was sent, terminating the channel
Комментарии:
1. Последний фрагмент кода кажется правильным. Вы уверены, что значение, которое вы извлекаете из базы данных, существует? Что вы подразумеваете под «возвращенным
bodyValue
пустым»2. @caco3 Значение, полученное из базы данных, можно увидеть в распечатке отладки терминала. Запрос выполнен успешно, а затем напечатан как
2020-09-05 21:37:02.837 DEBUG 32720 --- [ntLoopGroup-3-2] o.s.http.codec.json.Jackson2JsonEncoder : [96ef6152-1] Encoding [_id=5f53692af0a02d3af8a7fed9, group=Thrillers, name=The Shining, value=in]]
я предполагаю, чтоbodyValue(s)
он не содержит никаких данных, поскольку Postman выводит ответ как «200 OK» и «{}». Я ожидал, что найденная запись будет в формате JSON. Может быть, я что-то неправильно интерпретирую?3. Звучит интересно. Не могли бы вы опубликовать полный
BookHandler
код (который выдает вывод на уровне отладки)?4. Я обновил и добавил журналы в исходном сообщении выше.
5. О, извините! Полный обработчик книг был довольно длинным (POST / PUT / DELETE / несколько вариантов GET, много закомментированного кода), поэтому я только скопировал приведенный выше код. Ваши комментарии мне очень помогли и заставили меня снова (в пятидесятый раз) просмотреть код новыми глазами, чтобы найти проблему. Большое спасибо!
Ответ №1:
Я нашел проблему. Я забыл реализовать getters в Book
классе, содержащем @Document
. Я удивлен, что не было сообщения об ошибке или предупреждения, когда они отсутствовали.
Как только я вставил их, результат был возвращен, как и ожидалось от этого кода:
return setting
.flatMap(s -> ServerResponse
.ok()
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(s))
.switchIfEmpty(NOT_FOUND);
Вот данные, возвращенные Postman после исправления:
{
"_id": "5f53692af0a02d3af8a7fed9",
"group": "Thrillers",
"name": "The Shining",
"value": "in"
}
Спасибо @caco3 за помощь в поиске проблемы!
Вот мой обновленный Book.java
.
@Document
@CompoundIndex(name = "group-name", def = "{'group':1, 'name':1}", unique = true) // Requires auto-index-creation in application.properties
public class Book {
@Id
private String _id;
private String group;
private String name;
private String value;
public Book() {
}
public Book(String group, String name, String value) {
this.group = group;
this.name = name;
this.value = value;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder('[');
s.append("_id=").append(_id);
s.append(", group=").append(group);
s.append(", name=").append(name);
s.append(", value=").append(value);
s.append(']');
return s.toString();
}
public String get_id() {
return _id;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}