使用 Spring WebFlux 路由器功能时如何获取模型属性?
Posted
技术标签:
【中文标题】使用 Spring WebFlux 路由器功能时如何获取模型属性?【英文标题】:How to get model attributes when using Spring WebFlux router functions? 【发布时间】:2020-08-12 03:30:19 【问题描述】:Spring WebFlux 提供两种编程选项可供选择:带注释的控制器和功能端点。对于第一个,我们可以使用@ModelAttribute
注解将模型属性从控制器传递到视图(例如 Thymeleaf html-template),反之亦然。但是,当涉及到路由器功能时,到目前为止,我只是想出了如何将模型属性附加到ServerResponse
,但找不到将它们取回的方法。考虑以下代码 sn-p:
@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()));
【问题讨论】:
【参考方案1】:没有ServerRequest::getModel
方法,但ServerRequest::bodyToMono(Class)
可以将模型所在的主体提取到Mono<T>
。
然后利用响应式存储库方法ReactiveCrudRepository::save
的返回类型的优势,使用Mono::flatMap
返回Mono<T>
。
我还没有测试过,但它应该可以工作。
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));
【讨论】:
当我使用你的组合bodyToMono.flatMap.map
时,我得到一个错误:不兼容的类型:推理变量 R 具有不兼容的边界等式约束:ServerResponse 下限:MonobodyToMono.flatMap.flatMap
的组合。
另外,bodyToMono()
在我的情况下不起作用,因为“studentForm”对象在视图中绑定到 Thymeleaf 的表单 th:object="$studentForm"
属性,所以当提交表单时,我得到错误:bodyType=Student 不支持内容类型“application/x-www-form-urlencoded”。为了解决这个问题,我必须使用ServerRequest.formData()
方法而不是ServerRequest.bodyToMono()
,然后手动将 MultiValueMap以上是关于使用 Spring WebFlux 路由器功能时如何获取模型属性?的主要内容,如果未能解决你的问题,请参考以下文章
在 Spring Boot WebFlux 上检索路径变量(功能方法)
为啥使用 webflux 进行 spring boot 测试会忽略自定义 jackson 模块