一、Modeljava
你能够使用@ModelAttribute注解:react
在@RequestMapping方法中的方法参数上建立或访问模型中的对象,并经过WebDataBinder将其绑定到请求。typescript
做为@Controller或@ControllerAdvice类中的方法级注解,有助于在调用任何@RequestMapping方法以前初始化模型。微信
将@RequestMapping方法返回值标记为 model attribute。cookie
讨论@ModelAttribute方法,或前面列表中的第二项(上一篇Spring 5.2.2 WebFlux 之带注解的控制器(方法参数、返回值等详细内容))。一个控制器能够有任意数量的@ModelAttribute方法。全部这些方法都在同一个控制器中的@RequestMapping方法以前调用。@ModelAttribute方法也能够经过@ControllerAdvice在控制器之间共享。app
@ModelAttribute方法具备灵活的方法签名。它们支持许多与@RequestMapping方法相同的参数(除了@ModelAttribute自己和任何与请求正文相关的参数)。框架
如下示例使用@ModelAttribute方法:异步
public void populateModel( String number, Model model) { model.addAttribute(accountRepository.findAccount(number)); // 更多 ...}
如下示例仅添加一个属性:性能
public Account addAccount( String number) { return accountRepository.findAccount(number);}
若是没有明显指定名称,则根据类型选择默认名称。始终能够经过使用重载的addAttribute
方法或经过@ModelAttribute
上的name属性(用于返回值)来指定显式名称。ui
Spring WebFlux与Spring MVC不一样,它在模型中明确支持reactive 类型(例如Mono<Account>或io.reactivex.Single<Account>)。若是不使用封装声明@ModelAttribute参数,则能够透明地将此类异步模型属性解析(并更新模型)为其在@RequestMapping调用时的实际值,以下例所示:
public void addAccount( String number) { Mono<Account> accountMono = accountRepository.findAccount(number); model.addAttribute("account", accountMono);}
"/accounts") (public String handle( Account account, BindingResult errors) { // ...}
此外,任何具备reactive 类型封装的模型属性都会在视图呈现以前解析为其实际值(以及更新的模型)。
你还能够将@ModelAttribute用做@RequestMapping方法的方法级注解,在这种状况下,@RequestMapping方法的返回值将解释为模型属性。这一般不是必需的,由于这是HTML控制器中的默认行为,除非返回值是一个字符串,不然会被解释为视图名称。@ModelAttribute还能够帮助自定义模型属性名称,以下例所示:
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
注解:
public class FormController {
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
程序实例,以下例所示:
public class FormController {
protected void initBinder(WebDataBinder binder) { binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); }
// ...}
三、管理异常
@Controller和@ControllerAdvice类能够有@ExceptionHandler方法来处理来自控制器方法的异常。如下示例包括这样一个处理程序方法:
public class SimpleController {
// ...
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注解的全部控制器为目标public class ExampleAdvice1 {}
// 针对特定包中的全部控制器public class ExampleAdvice2 {}
// 将全部可分配给特定类的控制器做为目标public class ExampleAdvice3 {}
上例中的选择器是在运行时评估的,若是普遍使用,可能会对性能产生负面影响。
欢迎关注和转发Spring中文社区(加微信群,能够关注后加我微信):
本文分享自微信公众号 - Spring中文社区(gh_81d233bb13a4)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。