把 @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/