Spring 5.2.2 WebFlux 之 注解控制器(Model)

一、Modeljava

    你能够使用@ModelAttribute注解:react

  • @RequestMapping方法中的方法参数上建立或访问模型中的对象,并经过WebDataBinder将其绑定到请求。typescript

  • 做为@Controller@ControllerAdvice类中的方法级注解,有助于在调用任何@RequestMapping方法以前初始化模型。微信

  • @RequestMapping方法返回值标记为 model attributecookie

    

    讨论@ModelAttribute方法,或前面列表中的第二项(上一篇Spring 5.2.2 WebFlux 之带注解的控制器(方法参数、返回值等详细内容))。一个控制器能够有任意数量的@ModelAttribute方法。全部这些方法都在同一个控制器中的@RequestMapping方法以前调用。@ModelAttribute方法也能够经过@ControllerAdvice在控制器之间共享。app

    @ModelAttribute方法具备灵活的方法签名。它们支持许多与@RequestMapping方法相同的参数(除了@ModelAttribute自己和任何与请求正文相关的参数)。框架

如下示例使用@ModelAttribute方法:异步

@ModelAttributepublic void populateModel(@RequestParam String number, Model model) { model.addAttribute(accountRepository.findAccount(number));    // 更多 ...}

如下示例仅添加一个属性:性能

@ModelAttributepublic Account addAccount(@RequestParam String number) { return accountRepository.findAccount(number);}

   若是没有明显指定名称,则根据类型选择默认名称。始终能够经过使用重载的addAttribute 方法或经过@ModelAttribute上的name属性(用于返回值)来指定显式名称。ui

   Spring WebFluxSpring MVC不一样,它在模型中明确支持reactive 类型(例如Mono<Account>io.reactivex.Single<Account>)。若是不使用封装声明@ModelAttribute参数,则能够透明地将此类异步模型属性解析(并更新模型)为其在@RequestMapping调用时的实际值,以下例所示:

@ModelAttributepublic void addAccount(@RequestParam String number) { Mono<Account> accountMono = accountRepository.findAccount(number); model.addAttribute("account", accountMono);}
@PostMapping("/accounts")public String handle(@ModelAttribute Account account, BindingResult errors) { // ...}

     此外,任何具备reactive 类型封装的模型属性都会在视图呈现以前解析为其实际值(以及更新的模型)。

     你还能够将@ModelAttribute用做@RequestMapping方法的方法级注解,在这种状况下,@RequestMapping方法的返回值将解释为模型属性。这一般不是必需的,由于这是HTML控制器中的默认行为,除非返回值是一个字符串,不然会被解释为视图名称。@ModelAttribute还能够帮助自定义模型属性名称,以下例所示:

@GetMapping("/accounts/{id}")@ModelAttribute("myAccount")public Account handle() { // ... return account;}

二、DataBinder

    @Controller@ControllerAdvice类能够有@InitBinder方法来初始化WebDataBinder的实例。这些反过来又用于:

  • 将请求参数(即表单数据或查询)绑定到模型对象。

  • 将基于String 的请求值(如请求参数、路径变量、头、cookie等)转换为控制器方法参数的目标类型。

  • 呈现HTML表单时,将模型对象值格式化为String 值。

@InitBinder方法能够注册特定于控制器的java.bean.PropertyEditor或Spring  Converter Formatter 程序组件。此外,你能够使用WebFlux Java配置在全局共享的FormattingConversionService中注册Converter Formatter 程序类型。

       @InitBinder方法支持许多与@RequestMapping方法相同的参数,但@ModelAttribute(command object)参数除外。一般,它们是用WebDataBinder参数声明的,用于注册和void返回值。如下示例使用@InitBinder注解:

@Controllerpublic class FormController {
@InitBinder public void initBinder(WebDataBinder binder) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); }
// ...}

或者,当经过共享FormattingConversionService使用基于Formatter程序的设置时,能够重用相同的方法并注册特定于控制器的Formatter 程序实例,以下例所示:

@Controllerpublic class FormController {
@InitBinder protected void initBinder(WebDataBinder binder) { binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); }
// ...}

三、管理异常

    @Controller@ControllerAdvice类能够有@ExceptionHandler方法来处理来自控制器方法的异常。如下示例包括这样一个处理程序方法:

@Controllerpublic class SimpleController {
// ...
@ExceptionHandler public ResponseEntity<String> handle(IOException ex) { // ... }}

    异常能够与正在传播的顶级异常(即引起的直接IOException )匹配,也能够与顶级封装异常中的直接缘由匹配(例如,IllegalStateException中封装的IOException )。

     为了匹配异常类型,最好将目标异常声明为方法参数,如前面的示例所示。或者,注解声明能够缩小异常类型以匹配。咱们一般建议在参数签名中尽量具体,并在@ControllerAdvice上声明主顶级异常映射,并按相应的顺序进行优先级排序。

      WebFlux中的@ExceptionHandler方法支持与@RequestMapping方法相同的方法参数和返回值,但与请求正文和@ModelAttribute相关的方法参数除外。

   Spring WebFlux中对@ExceptionHandler方法的支持是由@RequestMapping方法的HandlerAdapter 提供的。

REST API异常

     REST服务的一个常见需求是在响应主体中包含错误详细信息。Spring框架不会自动这样作,由于响应体中错误详细信息的表示是特定于应用程序的。可是,@RestController能够使用带有ResponseEntity返回值的@ExceptionHandler方法来设置响应的状态和主体。这些方法也能够在@ControllerAdvice类中声明以全局应用它们。

   请注意,Spring WebFlux没有Spring MVC ResponseEntityExceptionHandler,由于WebFlux只引起ResponseStatusException (或其子类),这些不须要转换为HTTP状态代码。

四、Controller Advice

     一般,@ExceptionHandler@InitBinder@ModelAttribute方法应用于声明它们的@Controller类(或类层次结构)中。若是你但愿这样的方法更全局地(跨控制器)应用,能够在一个用@ControllerAdvice@RestControllerAdvice注解的类中声明它们。

     @ControllerAdvice@Component注解,这意味着能够经过组件扫描将这些类注册为Spring bean@RestControllerAdvice是一个组合注解,它同时使用@ControllerAdvice@ResponseBody进行注解,这实际上意味着@ExceptionHandler方法经过消息转换(相对于视图解析或模板呈现)呈现到响应体。

    启动时,@RequestMapping@ExceptionHandler方法的基础结构类检测用@ControllerAdvice注解的Spring bean,而后在运行时应用它们的方法。全局@ExceptionHandler方法(来自@ControllerAdvice)应用于本地方法(来自@Controller)以后。相比之下,全局@ModelAttribute@InitBinder方法应用于本地方法以前。

    默认状况下,@ControllerAdvice方法应用于每一个请求(即,全部控制器),但能够经过使用注解上的属性将其缩小到控制器的子集,以下例所示:

// 以@RestController注解的全部控制器为目标@ControllerAdvice(annotations = RestController.class)public class ExampleAdvice1 {}
// 针对特定包中的全部控制器@ControllerAdvice("org.example.controllers")public class ExampleAdvice2 {}
// 将全部可分配给特定类的控制器做为目标@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})public class ExampleAdvice3 {}

     上例中的选择器是在运行时评估的,若是普遍使用,可能会对性能产生负面影响。

欢迎关注和转发Spring中文社区(加微信群,能够关注后加我微信):
















本文分享自微信公众号 - Spring中文社区(gh_81d233bb13a4)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索