spring的@ControllerAdvice注解
@ControllerAdvice注解是Spring3.2中新增的注解,學(xué)名是Controller增強(qiáng)器,作用是給Controller控制器添加統(tǒng)一的操作或處理。
對(duì)于@ControllerAdvice,我們比較熟知的用法是結(jié)合@ExceptionHandler用于全局異常的處理,但其作用不止于此。ControllerAdvice拆開(kāi)來(lái)就是Controller Advice,關(guān)于Advice,在Spring的AOP中,是用來(lái)封裝一個(gè)切面所有屬性的,包括切入點(diǎn)和需要織入的切面邏輯。這里ControllerAdvice也可以這么理解,其抽象級(jí)別應(yīng)該是用于對(duì)Controller進(jìn)行切面環(huán)繞的,而具體的業(yè)務(wù)織入方式則是通過(guò)結(jié)合其他的注解來(lái)實(shí)現(xiàn)的。@ControllerAdvice是在類(lèi)上聲明的注解,其用法主要有三點(diǎn):
1.結(jié)合方法型注解@ExceptionHandler,用于捕獲Controller中拋出的指定類(lèi)型的異常,從而達(dá)到不同類(lèi)型的異常區(qū)別處理的目的。
2.結(jié)合方法型注解@InitBinder,用于request中自定義參數(shù)解析方式進(jìn)行注冊(cè),從而達(dá)到自定義指定格式參數(shù)的目的。
3.結(jié)合方法型注解@ModelAttribute,表示其注解的方法將會(huì)在目標(biāo)Controller方法執(zhí)行之前執(zhí)行。
從上面的講解可以看出,@ControllerAdvice的用法基本是將其聲明在某個(gè)bean上,然后在該bean的方法上使用其他的注解來(lái)指定不同的織入邏輯。不過(guò)這里@ControllerAdvice并不是使用AOP的方式來(lái)織入業(yè)務(wù)邏輯的,而是Spring內(nèi)置對(duì)其各個(gè)邏輯的織入方式進(jìn)行了內(nèi)置支持。
@ControllerAdvice注解的使用
@ControllerAdvice public class SpringControllerAdvice {/*** 應(yīng)用到所有被@RequestMapping注解的方法,在其執(zhí)行之前初始化數(shù)據(jù)綁定器* @param binder*/@InitBinderpublic void initBinder(WebDataBinder binder) {}/*** 把值綁定到Model中,使全局@RequestMapping可以獲取到該值* @param model*/@ModelAttributepublic void addAttributes(Model model) {model.addAttribute("words", "hello world");}/*** 全局異常捕捉處理* @param ex* @return*/@ResponseBody@ExceptionHandler(value = Exception.class)public Map errorHandler(Exception ex) {Map map = new HashMap();map.put("code", 100);map.put("msg", ex.getMessage());return map;}}在啟動(dòng)應(yīng)用之后,被@ExceptionHandler、@InitBinder和@ModelAttribute注解的方法都會(huì)作用在被@RequestMappping注解的方法上。比如上面的@ModelAttribute注解的方法參數(shù)model上設(shè)置的值,所有被@RequestMapping注解的方法中都可以通過(guò)ModelMap獲取。
@RequestMapping("/index") public String index(ModelMap modelMap) {System.out.println(modelMap.get("words")); }// 也可以通過(guò)@ModelAttribute獲取 @RequestMapping("/index") public String index(@ModelAttribute("words") String words) {System.out.println(words); }下面對(duì)@ControllerAdvice三種使用方式進(jìn)行分別講解。
@ExceptionHandler攔截異常并統(tǒng)一處理
@ExceptionHandler的作用主要在于聲明一個(gè)或多個(gè)類(lèi)型的異常,當(dāng)符合條件的Controller拋出這些異常之后將會(huì)對(duì)這些異常進(jìn)行捕獲,然后按照其標(biāo)注的方法的邏輯進(jìn)行處理,從而改變返回的視圖信息。
@ExceptionHandler的屬性結(jié)構(gòu)
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ExceptionHandler {// 指定需要捕獲的異常的Class類(lèi)型Class<? extends Throwable>[] value() default {}; }使用@ExceptionHandler捕獲RuntimeException異常的例子
@ControllerAdvice public class SpringControllerAdvice {@ExceptionHandler(RuntimeException.class)public ModelAndView runtimeExceptionHandler(RuntimeException e) {e.printStackTrace();return new ModelAndView("error");} } @Controller public class UserController {@RequestMapping(value = "/users", method = RequestMethod.GET)public void users() {throw new RuntimeException("沒(méi)有任何用戶。");} }這樣,當(dāng)訪問(wèn)/users的時(shí)候,因?yàn)樵谠摲椒ㄖ袙伋隽薘untimeException,那么理論上這里的異常捕獲器就會(huì)捕獲該異常,然后返回我們定義的異常視圖(默認(rèn)的error視圖)。
使用@InitBinder綁定一些自定義參數(shù)
對(duì)于@InitBinder,該注解的主要作用是綁定一些自定義的參數(shù)。一般情況下我們使用的參數(shù)通過(guò)@RequestParam,@RequestBody或者@ModelAttribute等注解就可以進(jìn)行綁定了,但對(duì)于一些特殊類(lèi)型參數(shù),比如Date,它們的綁定Spring是沒(méi)有提供直接的支持的,我們只能為其聲明一個(gè)轉(zhuǎn)換器,將request中字符串類(lèi)型的參數(shù)通過(guò)轉(zhuǎn)換器轉(zhuǎn)換為Date類(lèi)型的參數(shù),從而供給@RequestMapping標(biāo)注的方法使用。
@InitBinder的屬性結(jié)構(gòu)
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface InitBinder {// 這里value參數(shù)用于指定需要綁定的參數(shù)名稱,如果不指定,則會(huì)對(duì)所有的參數(shù)進(jìn)行適配,// 只有是其指定的類(lèi)型的參數(shù)才會(huì)被轉(zhuǎn)換String[] value() default {}; }使用@InitBinder注冊(cè)Date類(lèi)型參數(shù)轉(zhuǎn)換器的實(shí)現(xiàn)
@ControllerAdvice public class SpringControllerAdvice {@InitBinderpublic void globalInitBinder(WebDataBinder binder) {binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));} } @Controller public class UserController {@RequestMapping(value = "/users", method = RequestMethod.GET)public void users(Date date) {System.out.println(date); // Tue May 02 00:00:00 CST 2019} }這里@InitBinder標(biāo)注的方法注冊(cè)的Formatter在每次request請(qǐng)求進(jìn)行參數(shù)轉(zhuǎn)換時(shí)都會(huì)調(diào)用,用于判斷指定的參數(shù)是否為其可以轉(zhuǎn)換的參數(shù)。可以看到當(dāng)訪問(wèn)/users的時(shí)候,對(duì)request參數(shù)進(jìn)行了轉(zhuǎn)換,并且在接口方法中成功接收了該參數(shù),并在控制臺(tái)打印出日期格式的結(jié)果。
使用@ModelAttribute在方法執(zhí)行前進(jìn)行一些操作
關(guān)于@ModelAttribute的用法,除了用于方法參數(shù)時(shí)可以用于轉(zhuǎn)換對(duì)象類(lèi)型的屬性之外,其還可以用來(lái)進(jìn)行方法的聲明。如果聲明在方法上,并且結(jié)合@ControllerAdvice,該方法將會(huì)在@ControllerAdvice所指定的范圍內(nèi)的所有接口方法執(zhí)行之前執(zhí)行,并且@ModelAttribute標(biāo)注的方法的返回值還可以供給后續(xù)會(huì)調(diào)用的接口方法使用。
@ModelAttribute的屬性結(jié)構(gòu)
@Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ModelAttribute {// 該屬性與name屬性的作用一致,用于指定目標(biāo)參數(shù)的名稱@AliasFor("name")String value() default "";@AliasFor("value")String name() default "";// 與name屬性一起使用,如果指定了binding為false,那么name屬性指定名稱的屬性將不會(huì)被處理boolean binding() default true; }這里@ModelAttribute的各個(gè)屬性值主要是用于其在接口方法參數(shù)上進(jìn)行標(biāo)注時(shí)使用的,如果是作為方法注解,其name或value屬性則指定的是返回值的名稱。
使用@ModelAttribute注解進(jìn)行方法標(biāo)注的一個(gè)例子
@ControllerAdvice public class SpringControllerAdvice {@ModelAttribute(value = "message")public String globalModelAttribute() {System.out.println("添加了message全局屬性。");return "輸出了message全局屬性。";} } @Controller public class UserController {@RequestMapping(value = "/users", method = RequestMethod.GET)public void users(@ModelAttribute("message") String message) {System.out.println(message);} }這里@ModelAttribute注解的方法提供了一個(gè)String類(lèi)型的返回值,而@ModelAttribute注解中指定了該屬性的名稱是message,這樣在Controller層就可以通過(guò)@ModelAttribute注解接收名稱為message的參數(shù),從而獲取到前面綁定的參數(shù)了。
添加了message全局屬性。 輸出了message全局屬性。從輸出結(jié)果上看,使用@ModelAttribute注解標(biāo)注的方法確實(shí)在目標(biāo)方法執(zhí)行之前執(zhí)行了。需要說(shuō)明的是,@ModelAttribute標(biāo)注的方法的執(zhí)行是在所有的攔截器的preHandle()方法執(zhí)行之后才會(huì)執(zhí)行。
小結(jié)
關(guān)于@ControllerAdvice注解的三種使用方式對(duì)應(yīng)的注解,這三種注解如果應(yīng)用于@ControllerAdvice注解所標(biāo)注的類(lèi)中,那么它們表示會(huì)對(duì)@ControllerAdvice所指定的范圍內(nèi)的方法都有效;如果單純地將這三種注解應(yīng)用于某個(gè)Controller中,那么它們將只會(huì)對(duì)該Controller類(lèi)中的所有接口有效,并且此時(shí)是不需要在該Controller上標(biāo)注@ControllerAdvice注解的。
另外的還有@RestControllerAdvice注解,用法和@ControllerAdvice注解類(lèi)似,只是當(dāng)需要返回值到響應(yīng)頭的時(shí)候就不用在方法上添加@ResponseBody注解了。
總結(jié)
以上是生活随笔為你收集整理的spring的@ControllerAdvice注解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java基础day5
- 下一篇: Controller层使用@value注