簡介
@ControllerAdvice
就是 @Controller 的增強版。主要用來處理全局數據,一般搭配 @InitBinder
、@ModelAttribute
、@ExceptionHandler
使用。在@ControllerAdvice註解類的內部使用以上三個註解的方法會應用到所有的@RequestMapping
註解的方法。
注:
- 如果這三個註解直接在@Controller類中使用,則只對當前控制器生效
- 如果@ControllerAdvice中不需要返回view,也可以使用
@RestControllerAdvice
,即@RestControllerAdvice = @ControllerAdvice + @ResponseBody
下面將分別介紹:
一、@InitBinder
作用:對HTTP請求參數進行預處理,再綁定到對應的接口。這裏我們就可以對參數做一些額外的處理,比如時間格式的轉換等。(注意:這裏對@RequestBody註解的參數無效,需要自行實現)
在Spring MVC的web項目中,相信小夥伴們經常會遇到一些前端給後端傳值比較棘手的問題:
比如後端Controller如何接收Date
日期類型的參數,業界比較通用的做法是用時間戳
或者用字符串
或者使用@DateTimeFormat
註解,但是這還需要我們自己做後續的處理轉換,或者每一個日期類型的參數都需要加註解處理,用起來麻煩而且不夠優雅,這裏看我們的@InitBinder是怎麼處理的:
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.util.Date;
@ControllerAdvice
public class GlobalHandler {
private static String[] patterns = {
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"
};
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) {
Date date = null;
try {
if (text != null) {
date = DateUtils.parseDate(text, patterns);
}
} catch (ParseException e) {
}
setValue(date);
}
});
}
}
這樣當前後端再需要傳日期類型的參數時,後端可以直接使用Date
進行接收了。
使用時:
二、@ModelAttribute
作用:綁定數據
這個註解大家應該很熟悉了,可以在進入接口前綁定一些數據
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;
import java.util.HashMap;
@ControllerAdvice
public class GlobalHandler {
@ModelAttribute
public void addAttributes(Model model) {
model.addAttribute("msg", "Hello World");
HashMap<String, Object> map = new HashMap<>();
map.put("name", "張三");
map.put("age", 20);
model.addAttribute("info", map);
}
}
使用時:
三、@ExceptionHandler
作用:統一異常處理
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ExceptionHandler;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalHandler.class);
@ExceptionHandler(Exception.class)
@ResponseBody
public Map<String, Object> handleException(Exception e) {
LOGGER.error(e.getMessage(), e);
HashMap<String, Object> map = new HashMap<>(3);
map.put("code", 500);
map.put("msg", "服務器內部錯誤");
return map;
}
}
使用時:
這樣,對於RequestMapping標記的方法,只要拋出了Exception異常,便會被此方法攔截,從而返回我們封裝標準的響應格式或者view,這裏我只處理了Exception異常,還可以指定其他自定義的業務異常等等。
當定義了多個異常處理器的時候,比如@ExceptionHandler(Exception.class)
、@ExceptionHandler(ParseException.class)
,如果程序中拋出了異常,那麼它將嘗試查找爲處理異常而註冊的最“特定”的異常處理程序。如果沒有這樣的處理程序,它將嘗試檢查異常的超類,如果它也沒有找到,它會更高級別等等等等,從最具體到一般。