統一異常處理@ExceptionHandler


轉自:

https://blog.csdn.net/liujia120103/article/details/75126124/

一、如何設置全局的異常處理
用@RequestBody,@ResponseBody,不費吹灰之力就解決了JSon自動綁定。
接着就發現,如果遇到RuntimeException,需要給出一個默認返回JSON,有以下三種方式:

1.當這個Controller中任何一個方法發生異常,一定會被這個方法攔截到。然后,輸出日志。封裝Map並返回,頁面上得到status為false。

代碼如下:

復制代碼
 1 @Controller  
 2 public class AccessController {  
 3   
 4     /** 
 5      * 異常頁面控制 
 6      *  
 7      * @param runtimeException 
 8      * @return 
 9      */  
10     @ExceptionHandler(RuntimeException.class)  
11     public @ResponseBody  
12     Map<String,Object> runtimeExceptionHandler(RuntimeException runtimeException) {  
13         logger.error(runtimeException.getLocalizedMessage());  
14   
15         Map model = new TreeMap();  
16         model.put("status", false);  
17         return model;  
18     }  
19   
20 } 
復制代碼

2.返回到錯誤界面

代碼如下:

復制代碼
 1     @Controller  
 2     public class AccessController {  
 3         /** 
 4          * 異常頁面控制 
 5          *  
 6          * @param runtimeException 
 7          * @return 
 8          */  
 9         @ExceptionHandler(RuntimeException.class)  
10         public String runtimeExceptionHandler(RuntimeException runtimeException,  
11                 ModelMap modelMap) {  
12             logger.error(runtimeException.getLocalizedMessage());  
13       
14             modelMap.put("status", IntegralConstant.FAIL_STATUS);  
15             return "exception";  
16         }  
17     }  
復制代碼

3.使用 @ControllerAdvice,不用任何的配置,只要把這個類放在項目中,Spring能掃描到的地方。就可以實現全局異常的回調。

代碼如下:

復制代碼
    @ControllerAdvice  
    public class SpringExceptionHandler{  
      /** 
         * 全局處理Exception 
         * 錯誤的情況下返回500 
         * @param ex 
         * @param req 
         * @return 
         */  
        @ExceptionHandler(value = {Exception.class})  
        public ResponseEntity<Object> handleOtherExceptions(final Exception ex, final WebRequest req) {  
            TResult tResult = new TResult();  
            tResult.setStatus(CodeType.V_500);  
            tResult.setErrorMessage(ex.getMessage());  
            return new ResponseEntity<Object>(tResult,HttpStatus.OK);  
        }  
      
    }  

二、@ExceptionHandler注解

 

直接在Controller里面加上用@ExceptionHandler標注一個處理異常的方法像下面這樣子

  1.  
    @ ExceptionHandler(MissingServletRequestParameterException.class)
  2.  
    @ResponseStatus(HttpStatus .BAD_REQUEST)
  3.  
    public void processMethod(MissingServletRequestParameterException ex,HttpServletRequest request ,HttpServletResponse response) throws IOException {
  4.  
    System.out.println("拋異常了!"+ex.getLocalizedMessage());
  5.  
    logger.error("拋異常了!"+ex.getLocalizedMessage());
  6.  
    response.getWriter().printf(ex.getMessage());
  7.  
    response.flushBuffer();
  8.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

這樣,Controller里面的方法拋出了MissingServletRequestParameterException異常就會執行上面的這個方法來進行異常處理。 
如下面的代碼:

  1.  
    @RequestMapping("/index")
  2.  
    public String index(@MyUser User user,@RequestParam String id,ModelMap modelMap){
  3.  
    return "login";
  4.  
    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

如果我沒有傳入id值,那么就會拋出MissingServletRequestParameterException的異常,就會被上面的異常處理方法處理。

上面的@ExceptionHandler(MissingServletRequestParameterException.class)這個注解的value的值是一個Class[]類型的,這里的ExceptionClass是你自己指定的,你也可以指定多個需要處理的異常類型,比如這樣@ExceptionHandler(value = {MissingServletRequestParameterException.class,BindException.class}),這樣就會處理多個異常了。

但這個只會是在當前的Controller里面起作用,如果想在所有的Controller里面統一處理異常的話,可以用@ControllerAdvice來創建一個專門處理的類。如一中的3所述。

三、@ControllerAdvice注解

 

@ControllerAdvice,是Spring3.2提供的新注解,從名字上可以看出大體意思是控制器增強。讓我們先看看@ControllerAdvice的實現:

這里寫圖片描述

沒什么特別之處,該注解使用@Component注解,這樣的話當我們使用<context:component-scan>掃描時也能掃描到。

再一起看看官方提供的comment。

這里寫圖片描述

大致意思是:

  • @ControllerAdvice是一個@Component,用於定義@ExceptionHandler,@InitBinder和@ModelAttribute方法,適用於所有使用@RequestMapping方法。

  • Spring4之前,@ControllerAdvice在同一調度的Servlet中協助所有控制器。Spring4已經改變:@ControllerAdvice支持配置控制器的子集,而默認的行為仍然可以利用。

  • 在Spring4中, @ControllerAdvice通過annotations(), basePackageClasses(), basePackages() 方法定制用於選擇控制器子集。

不過據經驗之談,只有配合@ExceptionHandler最有用,其它兩個不常用。

 

這里寫圖片描述

SpringMVC重要注解(一)@ExceptionHandler和@ResponseStatus我們提到,如果單使用@ExceptionHandler,只能在當前Controller中處理異常。但當配合@ControllerAdvice一起使用的時候,就可以擺脫那個限制了。

這里寫圖片描述

  1.  
    @Controller
  2.  
    @RequestMapping(value = "exception")
  3.  
    public class ExceptionHandlerController {
  4.  
     
  5.  
    @RequestMapping(value = "e2/{id}", method = { RequestMethod.GET })
  6.  
    @ResponseBody
  7.  
    public String testExceptionHandle2(@PathVariable(value = "id") Integer id) {
  8.  
    List<String> list = Arrays.asList( new String[]{"a","b","c","d"});
  9.  
    return list.get(id-1);
  10.  
    }
  11.  
     
  12.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

當我們訪問http://localhost:8080/SpringMVC/exception/e2/5的時候會拋出ArrayIndexOutOfBoundsException異常,這時候定義在@ControllerAdvice中的@ExceptionHandler就開始發揮作用了。

如果我們想定義一個處理全局的異常

這里寫圖片描述

乍一眼看上去毫無問題,但這里有一個紕漏,由於Exception是異常的父類,如果你的項目中出現過在自定義異常中使用@ResponseStatus的情況,你的初衷是碰到那個自定義異常響應對應的狀態碼,而這個控制器增強處理類,會首先進入,並直接返回,不會再有@ResponseStatus的事情了,這里為了解決這種紕漏,我提供了一種解決方式。

這里寫圖片描述

如果碰到了某個自定義異常加上了@ResponseStatus,就繼續拋出,這樣就不會讓自定義異常失去加上@ResponseStatus的初衷。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM