ControllerAdvice攔截器

Spring3.2開始提供的新註解,控制器加強(AOP),最主要的應用是作統一的異常處理。 @ControllerAdvice(當作spring mvc提供的一個特殊的攔截器)。
@ControllerAdvice是一個 @Component,用於定義 @ExceptionHandler(最主要用途), @InitBinder@ModelAttribute方法,適用於全部使用 @RequestMapping方法(攔截)。

引伸:@interface 元註解
@Target(ElementType.TYPE) :該註解應用到什麼地方。
@Retention(RetentionPolicy.RUNTIME):何時應用。html

@ExceptionHandler:爲全部controller封裝統一異常處理代碼。
@ModelAttribute:爲全部controller設置全局變量。
@InitBinder:用於爲全部controller設置某個類型的數據轉換器。java

準備:搭建好Spring Boot,頁面使用thymeleafspring

1.全局異常捕捉處理

ControllerAdviceTest.java瀏覽器

/**
 * 啓動應用後,被 @ExceptionHandler、@InitBinder、@ModelAttribute 註解的方法,
 * 都會做用在 被 @RequestMapping 註解的方法上
 */
@ControllerAdvice
public class ControllerAdviceTest {
    /**
     * 全局異常捕捉處理
     * @ExceptionHandler 用來定義函數針對的異常類型
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Map errorHandler(Exception ex){
        Map map = new HashMap();
        map.put("code","0000");
        map.put("msg",ex.getMessage());
        return map;
    }
}

ExceptionController.java服務器

@RestController
public class ExceptionController {
    @RequestMapping("exception1")
    public String exception1() throws IOException {
        return "攔截器測試";
    }
}

瀏覽器訪問:localhost:8080/exception1mvc

瀏覽器顯示:攔截器測試app

@RestController
public class ExceptionController {
    @RequestMapping("exception2")
    public String exception2() throws IOException {
        int i = 1/0;
        return "攔截器測試";
    }
}

瀏覽器訪問:localhost:8080/exception2編輯器

瀏覽器顯示:{"msg":"/ by zero","code":"0000"}函數

@RestController
public class ExceptionController {
    @RequestMapping("exception3")
    public String exception3() throws IOException {
        throw new NullPointerException("服務器到非洲去了");
    }
}

瀏覽器訪問:localhost:8080/exception3測試

瀏覽器顯示:{"msg":"服務器到非洲去了","code":"0000"}

2.攔截捕捉自定義異常

MyException.java

public class MyException extends RuntimeException {
    private String code;
    private String msg;
    //Get、Set方法略……
    public MyException(String code,String msg) {
        this.code = code;
        this.msg = msg;
    }
}

ControllerAdviceTest.java

@ControllerAdvice
public class ControllerAdviceTest {
    /**
     * 攔截捕捉自定義異常 MyException.class
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = MyException.class)
    public Map myErrorHandler(MyException ex) {
        Map map = new HashMap();
        map.put("code", ex.getCode());
        map.put("msg", ex.getMsg());
        return map;
    }
}

ExceptionController.java

@RestController
public class ExceptionController {
    @RequestMapping("myException")
    public String myException(){
        throw new MyException("1111","This is my Exception!");
    }
}

瀏覽器訪問:localhost:8080/myException

瀏覽器顯示:{"msg":"This is my Exception!","code":"1111"}


跳轉到一個單獨的異常顯示頁面

ControllerAdviceTest.java

@ControllerAdvice
public class ControllerAdviceTest {
    /**
     * 跳轉視圖顯示異常
     * @param ex
     * @return
     */
    @ExceptionHandler(value = MyException.class)
    public ModelAndView myErrorHandlerToView(MyException ex) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("myGlobalExceptionPage");
        modelAndView.addObject("code", ex.getCode());
        modelAndView.addObject("msg", ex.getMsg());
        return modelAndView;
    }
}

myGlobalExceptionPage.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>myGlobalExceptionPage</title>
</head>
<body>
    <p th:text="${code}"></p>
    <p th:text="${msg}"></p>
</body>
</html>

瀏覽器訪問:localhost:8080/myException

瀏覽器顯示:1111 This is my Exception!

3.綁定值到Model中

ControllerAdviceTest.java

@ControllerAdvice
public class ControllerAdviceTest {
    /**
     * 把值綁定到Model中,使全局@RequestMapping能夠獲取到該值
     * @param model
     */
    @ModelAttribute
    public void addAttributes(Model model) {
        System.out.println("添加全局變量");
        model.addAttribute("userName", "Jack");
    }
}

ExceptionController.java

@RestController
public class ExceptionController {
    /**
     * 使用注入的ModelMap來取變量
     * @param modelMap
     * @return
     */
    @RequestMapping("modelMapTest1")
    public Object modelMapTest1(ModelMap modelMap){
        Object globalVal = modelMap.get("userName");
        System.out.println("全局變量爲:"+globalVal);
        return globalVal;
    }
}

瀏覽器訪問:localhost:8080/modelMapTest1

控制檯輸出:添加全局變量 全局變量爲:Jack

瀏覽器顯示:Jack


ExceptionController.java

@RestController
public class ExceptionController {
    /**
     * 也能夠使用@ModelAttribute註解來取變量
     * @param globalVal
     * @return
     */
    @RequestMapping("/modelMapTest2")
    public Object modelMapTest2(@ModelAttribute("userName") String globalVal) {
        System.out.println("全局變量爲:"+globalVal);
        return globalVal;
    }
}

瀏覽器訪問:localhost:8080/modelMapTest2

控制檯輸出:添加全局變量 全局變量爲:Jack

瀏覽器顯示:Jack

4.轉換日期格式

ControllerAdviceTest.java

@ControllerAdvice
public class ControllerAdviceTest {
    /**
     * 應用到全部@RequestMapping註解方法,在其執行以前初始化數據綁定器
     * WebDataBinder是用來綁定請求參數到指定的屬性編輯器
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        System.out.println("initBinder執行");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);  //日期格式是否寬容(只能判斷是否須要跳到下個月去)

        /*
         * spring mvc在綁定表單以前,都會先註冊這些編輯器,
         * Spring本身提供了大量的實現類,諸如CustomDateEditor,CustomBooleanEditor,CustomNumberEditor等
         * 使用時候調用WebDataBinder的registerCustomEditor方法註冊
         */
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat,false));
    }
}

ExceptionController.java

@RestController
public class ExceptionController {
    @RequestMapping("/date")
    public Date index(Date date){
        System.out.println("date="+date);
        return date;
    }
}

瀏覽器訪問:localhost:8080/date?date=2019-3-20

控制檯輸出:initBinder執行 date=2019-3-20

瀏覽器顯示:"2019-3-20"

相關文章
相關標籤/搜索