Grz*_*rek 5 spring-mvc project-reactor spring-webflux
我正在尝试使用 Spring Webflux 和 Spring MVC,遇到了一个有趣的案例。
从一个简单的控制器开始:
@GetMapping
public Mono<String> list(final Model model) {
Flux<User> users = this.userRepository.findAll();
model.addAttribute("users", users);
return Mono.just("users/list");
}
Run Code Online (Sandbox Code Playgroud)
这userReposutory是一个ConcurrentHashMap基于自定义的实现。在这里你可以找到findAll方法:
@Override
public Flux<User> findAll() {
return Flux.fromIterable(this.users.values());
}
Run Code Online (Sandbox Code Playgroud)
每当我尝试返回访问“用户/列表”视图时,一切似乎都正常工作。
但是,如果我尝试使用惯用的反应式方法重写控制器,问题就会开始出现:
@GetMapping
public Mono<String> list(final Model model) {
return this.userRepository.findAll()
.collectList()
.doOnEach(users -> model.addAttribute("users", users.get()))
.map(u -> "users/list");
}
Run Code Online (Sandbox Code Playgroud)
如果我到达终点,我会在日志中得到这个:
java.lang.IllegalArgumentException: ConcurrentModel does not support null attribute value
at org.springframework.util.Assert.notNull(Assert.java:193)
at org.springframework.ui.ConcurrentModel.addAttribute(ConcurrentModel.java:75)
at org.springframework.ui.ConcurrentModel.addAttribute(ConcurrentModel.java:39)
at com.baeldung.lss.web.controller.UserController.lambda$list$0(UserController.java:37)
at reactor.core.publisher.FluxDoOnEach$DoOnEachSubscriber.onError(FluxDoOnEach.java:132)
Run Code Online (Sandbox Code Playgroud)
显然,一些流浪者null正在那里。让我们急切地过滤掉所有这些:
@RequestMapping
public Mono<String> list(final Model model) {
return this.userRepository.findAll()
.filter(Objects::nonNull)
.collectList()
.filter(Objects::nonNull)
.doOnEach(users -> model.addAttribute("users", users.get()))
.map(u -> "users/list");
}
Run Code Online (Sandbox Code Playgroud)
同样的问题,但是......如果我在map()通话中压缩所有内容,一切都会再次正常:
@GetMapping
public Mono<String> list(final Model model) {
return this.userRepository.findAll()
.collectList()
.map(users -> {
model.addAttribute("users", users);
return "users/list";
});
}
Run Code Online (Sandbox Code Playgroud)
虽然,放置副作用map不是最佳的。
任何想法doOnEach()这里有什么问题?
非常好的问题。让我们看看JavaDocs讲述了什么doOnEach:
public final Mono<T> doOnEach(Consumer<? super Signal<T>> signalConsumer)添加当 Mono 发出项目、因错误而失败或成功完成时触发的行为。所有这些事件都表示为
Signal传递给副作用回调的 a
好奇的。该users 中doOnEach(users -> ...)不是一个List<User>而是一个Signal<List<User>>。这个Signal<T>对象不会为空,这就解释了为什么filter第二个版本中的方法不起作用。
在为JavaDocs中Signal<T>说,该get()法明确标记为@Nullable将返回只有一个项目到达一个非空值。如果生成完成或错误信号,则它将返回null。
解决方案:
doOnNext改为使用:您对下一个值感兴趣,而不是来自源流的任何信号。doOnEachlambda 中进行空检查:这也可以,但由于您对其他事件不感兴趣,因此是多余的。| 归档时间: |
|
| 查看次数: |
1211 次 |
| 最近记录: |