使用 Spring WebFlux 路由器功能时如何获取模型属性?
How to get model attributes when using Spring WebFlux router functions?
Spring WebFlux 提供了两个编程选项的选择:Annotated Controllers 和 Functional Endpoints。对于第一个,我们可以使用 @ModelAttribute
注释将模型属性从控制器传输到视图(例如 Thymeleaf html-template),反之亦然。然而,当谈到路由器功能时,到目前为止,我只是想出了如何将模型属性附加到 ServerResponse
,但找不到将它们取回的方法。考虑以下代码片段:
@Configuration
public class StudentsRouterFunctions {
// inject repository
private final StudentsCrudRepository repo;
public StudentsRouterFunctions(StudentsCrudRepository repo) {
this.repo = repo;
}
@Bean
RouterFunction<?> routs() {
return RouterFunctions.route()
.GET("/students", this::showStudents)
.POST("/students", this::saveStudent)
.build();
}
// #1: GET-handler
private Mono<ServerResponse> showStudents(ServerRequest request) {
// set model attributes
Map<String, Object> model = new HashMap<>();
Mono<Student> studentsList = repo.findAll().collectList();
Mono<Student> newStudent = Mono.just(new Student());
model.put("students", studentsList);
model.put("studentForm", newStudent);
// render the view
return ServerResponse.ok()
.contentType(MediaType.TEXT_HTML)
.render("students-template", model);
}
// #2: POST-handler
private Mono<ServerResponse> saveStudent(ServerRequest request) {
// and here I somehow need to get my new student object
// back from the view via "studentForm" model attribute
// Student newStudent = request.getModel().get("studentForm");
// !!! however, ServerRequest.getModel() method doesn't exist
return repo.save(newStudent)
.then(ServerResponse.status(HttpStatus.PERMANENT_REDIRECT)
.render("redirect:/students", new Object()));
}
没有 ServerRequest::getModel
方法,但是 ServerRequest::bodyToMono(Class)
可以将模型所在的主体提取到 Mono<T>
。
然后利用 return 类型的反应式存储库方法的优势 ReactiveCrudRepository::save
returning Mono<T>
using Mono::flatMap
。
我还没有测试过,但应该可以。
private Mono<ServerResponse> saveStudent(ServerRequest request) {
return request.bodyToMono(Student.class) // Mono<Student> (a new one)
.flatMap(repo::save) // Mono<Student> (a saved one)
.then(ServerResponse // redirect sequence
.status(HttpStatus.PERMANENT_REDIRECT)
.render("redirect:/students", new Object()));
}
// .flatMap(repo::save) is the same as .flatMap(newStudent -> repo.save(newStudent))
请注意,方法 Mono::then
丢弃了源中的元素,因此重定向的对象仍然是 new Object()
,因此您想使用 Mono::map
.
private Mono<ServerResponse> saveStudent(ServerRequest request) {
return request.bodyToMono(Student.class) // Mono<Student> (a new one)
.flatMap(repo::save) // Mono<Student> (a saved one)
.map(savedStudent -> ServerResponse // redirect sequence
.status(HttpStatus.PERMANENT_REDIRECT)
.render("redirect:/students", savedStudent));
}
Spring WebFlux 提供了两个编程选项的选择:Annotated Controllers 和 Functional Endpoints。对于第一个,我们可以使用 @ModelAttribute
注释将模型属性从控制器传输到视图(例如 Thymeleaf html-template),反之亦然。然而,当谈到路由器功能时,到目前为止,我只是想出了如何将模型属性附加到 ServerResponse
,但找不到将它们取回的方法。考虑以下代码片段:
@Configuration
public class StudentsRouterFunctions {
// inject repository
private final StudentsCrudRepository repo;
public StudentsRouterFunctions(StudentsCrudRepository repo) {
this.repo = repo;
}
@Bean
RouterFunction<?> routs() {
return RouterFunctions.route()
.GET("/students", this::showStudents)
.POST("/students", this::saveStudent)
.build();
}
// #1: GET-handler
private Mono<ServerResponse> showStudents(ServerRequest request) {
// set model attributes
Map<String, Object> model = new HashMap<>();
Mono<Student> studentsList = repo.findAll().collectList();
Mono<Student> newStudent = Mono.just(new Student());
model.put("students", studentsList);
model.put("studentForm", newStudent);
// render the view
return ServerResponse.ok()
.contentType(MediaType.TEXT_HTML)
.render("students-template", model);
}
// #2: POST-handler
private Mono<ServerResponse> saveStudent(ServerRequest request) {
// and here I somehow need to get my new student object
// back from the view via "studentForm" model attribute
// Student newStudent = request.getModel().get("studentForm");
// !!! however, ServerRequest.getModel() method doesn't exist
return repo.save(newStudent)
.then(ServerResponse.status(HttpStatus.PERMANENT_REDIRECT)
.render("redirect:/students", new Object()));
}
没有 ServerRequest::getModel
方法,但是 ServerRequest::bodyToMono(Class)
可以将模型所在的主体提取到 Mono<T>
。
然后利用 return 类型的反应式存储库方法的优势 ReactiveCrudRepository::save
returning Mono<T>
using Mono::flatMap
。
我还没有测试过,但应该可以。
private Mono<ServerResponse> saveStudent(ServerRequest request) {
return request.bodyToMono(Student.class) // Mono<Student> (a new one)
.flatMap(repo::save) // Mono<Student> (a saved one)
.then(ServerResponse // redirect sequence
.status(HttpStatus.PERMANENT_REDIRECT)
.render("redirect:/students", new Object()));
}
// .flatMap(repo::save) is the same as .flatMap(newStudent -> repo.save(newStudent))
请注意,方法 Mono::then
丢弃了源中的元素,因此重定向的对象仍然是 new Object()
,因此您想使用 Mono::map
.
private Mono<ServerResponse> saveStudent(ServerRequest request) {
return request.bodyToMono(Student.class) // Mono<Student> (a new one)
.flatMap(repo::save) // Mono<Student> (a saved one)
.map(savedStudent -> ServerResponse // redirect sequence
.status(HttpStatus.PERMANENT_REDIRECT)
.render("redirect:/students", savedStudent));
}