1. 程式人生 > >Spring的全域性異常處理

Spring的全域性異常處理

J2EE專案的開發中,不管是對底層的資料庫操作過程,還是業務層的處理過程,還是控制層的處理過程,都不可避免會遇到各種可預知的、不可預知的異常需要處理。每個過程都單獨處理異常,系統的程式碼耦合度高,工作量大且不好統一,維護的工作量也很大。那麼,能不能將所有型別的異常處理從各處理過程解耦出來,這樣既保證了相關處理過程的功能較單一,也實現了異常資訊的統一處理和維護?答案是肯定的。下面將介紹使用Spring MVC統一處理異常的解決和實現過程

  1. 使用Spring MVC提供的SimpleMappingExceptionResolver

    2.    實現Spring的異常處理介面HandlerExceptionResolver

自定義自己的異常處理器

    3.    使用@ExceptionHandler註解實現異常處理

()SimpleMappingExceptionResolver

使用這種方式具有整合簡單、有良好的擴充套件性、對已有程式碼沒有入侵性等優點,但該方法僅能獲取到異常資訊,若在出現異常時,對需要獲取除異常以外的資料的情況不適用。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

@Configuration

@EnableWebMvc

@ComponentScan(basePackages = {"com.balbala.mvc.web"})

publicclassWebMVCConfig extendsWebMvcConfigurerAdapter{

 @Bean

  publicSimpleMappingExceptionResolver simpleMappingExceptionResolver()

  {

    SimpleMappingExceptionResolver b = newSimpleMappingExceptionResolver();

    Properties mappings = new

Properties();

    mappings.put("org.springframework.web.servlet.PageNotFound", "page-404");

    mappings.put("org.springframework.dao.DataAccessException", "data-access");

    mappings.put("org.springframework.transaction.TransactionException", "transaction-Failure");

    b.setExceptionMappings(mappings);

    returnb;

  }

}

()HandlerExceptionResolver

相比第一種來說,HandlerExceptionResolver能準確顯示定義的異常處理頁面,達到了統一異常處理的目標

1.定義一個類實現HandlerExceptionResolver介面,這次貼一個自己以前的程式碼

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

31

32

33

34

35

packagecom.athena.common.handler;

importcom.athena.common.constants.ResponseCode;

importcom.athena.common.exception.AthenaException;

importcom.athena.common.http.RspMsg;

importorg.slf4j.Logger;

importorg.slf4j.LoggerFactory;

importorg.springframework.web.servlet.HandlerExceptionResolver;

importorg.springframework.web.servlet.ModelAndView;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importjava.io.IOException;

importjava.io.PrintWriter;

/**

 * Created by sam on 15/4/14.

 */

publicclassGlobalHandlerExceptionResolver implementsHandlerExceptionResolver { 

 privatestaticfinalLogger LOG = LoggerFactory.getLogger(GlobalHandlerExceptionResolver.class);        

  /**  

  * 在這裡處理所有得異常資訊  

  */

  @Override

  publicModelAndView resolveException(HttpServletRequest req,                     HttpServletResponse resp, Object o, Exception ex) { 

    ex.printStackTrace();  

    if(ex instanceofAthenaException) { 

      //AthenaException為一個自定義異常

      ex.printStackTrace();    

      printWrite(ex.toString(), resp);  

      returnnewModelAndView();

    } 

    //RspMsg為一個自定義處理異常資訊的類

    //ResponseCode為一個自定義錯誤碼的介面

    RspMsg unknownException = null;  

    if(ex instanceofNullPointerException) {   

      unknownException = newRspMsg(ResponseCode.CODE_UNKNOWN, "業務判空異常", null);

    } else{    

      unknownException = newRspMsg(ResponseCode.CODE_UNKNOWN, ex.getMessage(), null);    }  

      printWrite(unknownException.toString(), resp); 

      returnnewModelAndView(); 

  }

  /**  

  * 將錯誤資訊新增到response中  

  *  

  * @param msg  

  * @param response  

  * @throws IOException  

  */

  publicstaticvoidprintWrite(String msg, HttpServletResponse response) {  

     try{     

       PrintWriter pw = response.getWriter();   

       pw.write(msg);   

       pw.flush();   

       pw.close();  

     } catch(Exception e) {    

       e.printStackTrace();  

     } 

  }

}

2.加入spring的配置中,這裡只貼出了相關部分

1

2

3

4

5

6

7

8

9

10

11

1

importcom.athena.common.handler.GlobalHandlerExceptionResolver;

importorg.springframework.context.annotation.Bean;

importcom.athena.common.handler.GlobalHandlerExceptionResolver;

importorg.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**

 * Created by sam on 15/4/14.

 */

publicclassWebSpringMvcConfig extendsWebMvcConfigurerAdapter {

  @Bean

  publicGlobalHandlerExceptionResolver globalHandlerExceptionResolver() {

   returnnewGlobalHandlerExceptionResolver();

  }

}

()@ExceptionHandler

這是筆者現在專案的使用方式,這裡也僅貼出了相關部分

1.首先定義一個父類,實現一些基礎的方法

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

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

packagecom.balabala.poet.base.spring;

importcom.google.common.base.Throwables;

importcom.raiyee.poet.base.exception.MessageException;

importcom.raiyee.poet.base.utils.Ajax;

importorg.slf4j.Logger;

importorg.slf4j.LoggerFactory;

importorg.springframework.core.annotation.AnnotationUtils;

importorg.springframework.http.HttpStatus;

importorg.springframework.web.bind.annotation.ResponseStatus;

importorg.springframework.web.servlet.ModelAndView;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importjava.io.IOException;

importjava.io.PrintWriter;

importjava.util.Date;

publicclassBaseGlobalExceptionHandler { 

   protectedstaticfinalLogger logger = null; 

   protectedstaticfinalString DEFAULT_ERROR_MESSAGE = "系統忙,請稍後再試";

   protectedModelAndView handleError(HttpServletRequest req, HttpServletResponse rsp, Exception e, String viewName, HttpStatus status) throwsException { 

     if(AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null)   

     throwe;  

     String errorMsg = e instanceofMessageException ? e.getMessage() : DEFAULT_ERROR_MESSAGE;   

     String errorStack = Throwables.getStackTraceAsString(e); 

     getLogger().error("Request: {} raised {}", req.getRequestURI(), errorStack);   

     if(Ajax.isAjax(req)) {   

       returnhandleAjaxError(rsp, errorMsg, status); 

     }   

     returnhandleViewError(req.getRequestURL().toString(), errorStack, errorMsg, viewName);

   } 

   protectedModelAndView handleViewError(String url, String errorStack, String errorMessage, String viewName) {   

     ModelAndView mav = newModelAndView();   

     mav.addObject("exception", errorStack);   

     mav.addObject("url", url);  

     mav.addObject("message", errorMessage);

     mav.addObject("timestamp", newDate());   

     mav.setViewName(viewName); 

     returnmav; 

    } 

   protectedModelAndView handleAjaxError(HttpServletResponse rsp, String errorMessage, HttpStatus status) throwsIOException {   

      rsp.setCharacterEncoding("UTF-8");   

      rsp.setStatus(status.value());  

      PrintWriter writer = rsp.getWriter();

      writer.write(errorMessage);   

      writer.flush();   

      returnnull; 

   } 

   publicLogger getLogger() {   

      returnLoggerFactory.getLogger(BaseGlobalExceptionHandler.class);

   }

}

2.針對你需要捕捉的異常實現相對應的處理方式

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

31

32

33

34

35

36

packagecom.balabala.poet.base.spring;

importorg.slf4j.Logger;

importorg.slf4j.LoggerFactory;

importorg.springframework.http.HttpStatus;

importorg.springframework.web.bind.annotation.ControllerAdvice;

importorg.springframework.web.bind.annotation.ExceptionHandler;

importorg.springframework.web.bind.annotation.ResponseStatus;

importorg.springframework.web.servlet.ModelAndView;

importorg.springframework.web.servlet.NoHandlerFoundException;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

@ControllerAdvice

publicclassGlobalExceptionHandler extendsBaseGlobalExceptionHandler { 

   //比如404的異常就會被這個方法捕獲

   @ExceptionHandler(NoHandlerFoundException.class) 

   @ResponseStatus(HttpStatus.NOT_FOUND) 

    publicModelAndView handle404Error(HttpServletRequest req, HttpServletResponse rsp, Exception e) throwsException { 

       returnhandleError(req, rsp, e, "error-front", HttpStatus.NOT_FOUND); 

    } 

   //500的異常會被這個方法捕獲

   @ExceptionHandler(Exception.class)  

   @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)

   publicModelAndView handleError(HttpServletRequest req, HttpServletResponse rsp, Exception e) throwsException {

       returnhandleError(req, rsp, e, "error-front", HttpStatus.INTERNAL_SERVER_ERROR);

   } 

   //TODO 你也可以再寫一個方法來捕獲你的自定義異常

   //TRY NOW!!!

   @Override

   publicLogger getLogger() {  

      returnLoggerFactory.getLogger(GlobalExceptionHandler.class); 

   }

 }