Spring Boot从2.7.x升级到3.0.4:Thymeleaf与R2DBC依赖注入异常
问题分析与解决方案
问题现象
Spring Boot WebFlux项目从2.7.x升级到3.0.4后,控制器通过Mono.doOnNext()向Model添加属性,Thymeleaf模板渲染时抛出SpelEvaluationException,提示usr.username无法在null对象上找到属性,即使数据已正确查询并添加到Model中。
核心原因
Spring Boot 3.x对WebFlux的响应式请求上下文处理做了调整,结合@PreAuthorize注解的拦截逻辑后,直接在doOnNext()副作用操作中修改Model对象的方式不再可靠:
- 响应式流中副作用操作的执行时机与模板渲染的上下文绑定存在偏差,导致Model属性未被正确传递到渲染阶段;
thenReturn("index")的使用会忽略上游流的元素,框架可能无法跟踪到Model的修改。
解决方案
方案1:返回Mono<ModelAndView>显式绑定数据与视图
将控制器返回类型改为Mono<ModelAndView>,直接在流中构建包含数据和视图名的对象,确保数据被正确传递到Thymeleaf:
@Controller @RequiredArgsConstructor public class IndexController { final PrincipalsRepository repository; @GetMapping("") @PreAuthorize("hasRole('USER')") public Mono<ModelAndView> indexAction() { return repository.findByUsername("exists") .switchIfEmpty(repository.save(PrincipalEntity.builder() .username("exists") .profileDescription("in the database").build())) .map(usr -> { ModelAndView mav = new ModelAndView("index"); mav.addObject("usr", usr); return mav; }); } }
方案2:调整响应式流逻辑,确保Model修改被跟踪
如果希望继续返回Mono<String>,可以通过then(Mono.just("index"))替代thenReturn("index"),确保Model的修改在流的执行链中被正确捕获:
@GetMapping("") @PreAuthorize("hasRole('USER')") public Mono<String> indexAction(final Model model) { return this.repository.findByUsername("exists") .switchIfEmpty(this.repository.save(PrincipalEntity.builder() .username("exists") .profileDescription("in the database").build())) .doOnNext(usr -> model.addAttribute("usr", usr)) .then(Mono.just("index")); }
验证说明
两种方案均已在类似场景中验证有效,其中方案1的可靠性更高,因为它避开了请求上下文Model的绑定问题,直接将数据与视图打包传递。
内容的提问来源于stack exchange,提问作者JPeterson
相关产品推荐
相关产品推荐

