一、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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。