一網打盡 @ExceptionHandler、HandlerExceptionResolver、@controlleradvice 三兄弟!

一網打盡 @ExceptionHandler、HandlerExceptionResolver、@controlleradvice 三兄弟!

把 @ExceptionHandler、HandlerExceptionResolver、@controlleradvice 三兄弟放在一起來寫更有比較性。這三個東西都是用來處理異常的,但是它們使用的場景都不一樣。看本文給你詳細的講解,再也不怕面試被問到了!

這三個註解都是來自於 SpringMVC 的,都能進行異常處理。

Java 程序員都非常的痛恨異常,很多人討厭 Java 就是因爲它的異常處理機制。到處的 try-catch-finally,再不是就是到處拋出異常。

所以 Spring 深知 Java 的疼點,推出了:@ExceptionHandler、HandlerExceptionResolver、@controlleradvice 來方便我們處理一些異常!

@ExceptionHandler 註解

用於局部方法捕獲,與拋出異常的方法處於同一個 Controller 類。源碼如下:

1

2

3

4

5

6

@Target({ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface ExceptionHandler {

    Class<? extends Throwable>[] value() default {};

}

從源碼中可以看出,@ExceptionHandler 註解只能作用爲對象的方法上,並且在運行時有效,value() 可以指定異常類。由該註解註釋的方法可以具有靈活的輸入參數。

異常參數可以包括一般的異常或特定的異常(即自定義異常),如果註解沒有指定異常類,會默認進行映射。

用法代碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

@Controller

public class XttblogController {

    @ExceptionHandler({NullPointerException.class})

    public String exception(NullPointerException e) {

        System.out.println(e.getMessage());

        e.printStackTrace();

        return "null pointer exception";

    }

    @RequestMapping("test")

    public void test() {

        throw new NullPointerException("出錯了!");

    }

}

上面這段代碼只會捕獲 XttblogController 類中的 NullPointerException 異常。

HandlerExceptionResolver 接口

HandlerExceptionResolver 是 Spring 提供的一個接口。它可以用來處理全局異常!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

@Component

public class GlobalExceptionResolver implements HandlerExceptionResolver{

    private ObjectMapper objectMapper;

    public CustomMvcExceptionHandler() {

        objectMapper = new ObjectMapper();

    }

    @Override

    public ModelAndView resolveException(HttpServletRequest request, 

        HttpServletResponse response,Object o, Exception ex) {

        response.setStatus(200);

        response.setContentType(MediaType.APPLICATION_JSON_VALUE);

        response.setCharacterEncoding("UTF-8");

        response.setHeader("Cache-Control", "no-cache, must-revalidate");

        Map<String, Object> map = new HashMap<>();

        if (ex instanceof NullPointerException) {

            map.put("code", ResponseCode.NP_EXCEPTION);

        } else if (ex instanceof IndexOutOfBoundsException) {

            map.put("code", ResponseCode.INDEX_OUT_OF_BOUNDS_EXCEPTION);

        } else {

            map.put("code", ResponseCode.CATCH_EXCEPTION);

        }

        try {

            map.put("data", ex.getMessage());

            response.getWriter().write(objectMapper.writeValueAsString(map));

        } catch (Exception e) {

            e.printStackTrace();

        }

        return new ModelAndView();

    }

}

在 Spring 源碼中,我們可以看出它會獲取一個實現了 HandlerExceptionResolver 接口的列表 List<HandlerExceptionResolver> resolvers; 如果這個列表不爲空,則循環處理其中的異常。

HandlerExceptionResolve 雖然能夠處理全局異常,但是 Spring 官方不推薦使用它。

@controlleradvice 註解

另外一個能夠處理全局異常的就是 @controlleradvice 註解了。

@controlleradvice 註解根據它的源碼,我們知道它也只能作用在類上,並且作用於運行時。下面我們來看一個例子。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

@ControllerAdvice

public class ExceptionController {

    @ExceptionHandler(RuntimeException.class)

    public ModelAndView handlerRuntimeException(RuntimeException ex) {

        if (ex instanceof MaxUploadSizeExceededException) {

            return new ModelAndView("error").addObject("msg", "文件太大!");

        }

        return new ModelAndView("error").addObject("msg", "未知錯誤:" + ex);

    }

    @ExceptionHandler(Exception.class)

    public ModelAndView handlerMaxUploadSizeExceededException(Exception ex) {

        if (ex != null) {

            return new ModelAndView("error").addObject("msg", ex);

        }

        return new ModelAndView("error").addObject("msg", "未知錯誤:" + ex);

    }

}

需要注意的是,@ControllerAdvice 一般是和 @ExceptionHandler 組合在一起使用的。官方也推薦用這種方式處理統一全局異常。

博客地址:https://blog.csdn.net/xiang__liu,https://www.cnblogs.com/xiang--liu/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章