1. 程式人生 > >spring mvc 異常處理(轉)

spring mvc 異常處理(轉)

連結:http://gaojiewyh.iteye.com/blog/1297746 (附原始碼) 
連結:http://zywang.iteye.com/blog/983801  
連結:http://www.cnblogs.com/xguo/p/3163519.html  
連結:http://fuliang.iteye.com/blog/947191  
連結:http://blog.csdn.net/FansUnion/article/details/17038103

連結:http://cgs1999.iteye.com/blog/1547197(附原始碼)

      Spring3.0對異常的處理通過HandlerExceptionResolver來實現。HandlerExceptionResolver有4個實現類DefaultHandlerExceptionResolver、AnnotationMethodExceptionResolver、ResponseStatusExceptionResolver、SimpleMappingExceptionResolver。 
      Spring3.0對異常的處理主要可通過這兩種方式:一種是使用HandlerExceptionResolver介面;一種是在@Controller處理器內部使用@ExceptionHandler註解。使用第一種方式可以實現全域性異常控制,並且Spring已經提供了一個預設的實現類SimpleMappingExceptionResolver;使用第二種方式可以在Controller內部實現更個性化異常處理方式。 

---方式一:HandlerExceptionResolver介面,複寫resolveException()方法 
      springmvc通過HandlerExceptionResolver處理程式的異常,該介面僅有一個方法ModelAndView  resolveException(HttpServletRequest request,              HttpServletResponse response, Object handler, Exception ex)。我們可複寫該方法實現全域性異常的處理。 
      當發生異常時,springmvc會呼叫resolveException()方法,並返回一個ModelAndView物件。如果該方法返回了null,Spring會搜尋所有註冊在其環境中的實現了HandlerExceptionResolver介面的Bean,逐個執行,直到返回一個ModelAndView物件,最後轉到ModelAndView對應的檢視作為一個異常報告頁面! 

  1. /** 
  2.  * 基於HandlerExceptionResolver介面的異常處理類 
  3.  * 這個類必須宣告到Spring中去,讓Spring管理它,你可以使用@Component標籤: 
  4.  *   <context:component-scan base-package="test.*" /> 
  5.  * 或者使用在配置檔案通過<bean/>節點配置: 
  6.  *   <bean id="exceptionResolver" class="test.CustomExceptionHandler "/> 
  7.  */  
  8. @Component  
  9. public class CustomExceptionHandler implements HandlerExceptionResolver {  
  10.     @Override  
  11.     public ModelAndView resolveException(HttpServletRequest request,  
  12.             HttpServletResponse response, Object object, Exception exception) {  
  13.         if(exception instanceof IOException){  
  14.             return new ModelAndView("ioexp");  
  15.         }else if(exception instanceof SQLException){  
  16.             return new ModelAndView("sqlexp");  
  17.         }  
  18.         return null;  
  19.     }  
  20. }  

---區分ajax請求和普通http請求進行異常處理返回:

  1. /** 
  2.  * 程式碼2: 
  3.  * 說明:當在系統應用中出現普通異常時,根據是系統異常還是應用異常,跳到相應的介面, 
  4.  * 當ajax異常時,在ajax的error中可直接獲得異常。普通的異常我們都配置好了介面,系統會自動跳轉。 
  5.  */  
  6. public class CustomSimpleMappingExceptionResolver extends SimpleMappingExceptionResolver {  
  7.     @Override  
  8.     protected ModelAndView doResolveException(HttpServletRequest request,  
  9.             HttpServletResponse response, Object handler, Exception ex) {  
  10.         // Expose ModelAndView for chosen error view.  
  11.         String viewName = determineViewName(ex, request);  
  12.         if (viewName != null) {// JSP格式返回  
  13.             if (!(request.getHeader("accept").indexOf("application/json") > -1 || (request  
  14.                     .getHeader("X-Requested-With")!= null && request  
  15.                     .getHeader("X-Requested-With").indexOf("XMLHttpRequest") > -1))) {  
  16.                 // 如果不是非同步請求  
  17.                 // Apply HTTP status code for error views, if specified.  
  18.                 // Only apply it if we're processing a top-level request.  
  19.                 Integer statusCode = determineStatusCode(request, viewName);  
  20.                 if (statusCode != null) {  
  21.                     applyStatusCodeIfPossible(request, response, statusCode);  
  22.                 }  
  23.                 return getModelAndView(viewName, ex, request);  
  24.             } else {// JSON格式返回  
  25.                 try {  
  26.                     PrintWriter writer = response.getWriter();  
  27.                     writer.write(ex.getMessage());  
  28.                     writer.flush();  
  29.                 } catch (IOException e) {  
  30.                     e.printStackTrace();  
  31.                 }  
  32.                 return null;  
  33.             }  
  34.         } else {  
  35.             return null;  
  36.         }  
  37.     }  
  38. }  


---方式二:@ExceptionHandler

AnnotationMethodExceptionResolver:springmvc也預設配置了AnnotationMethodExceptionResolver,它允許通過@ExceptionHandler指定處理特定異常的方法。@ExceptionHandler:處理同一個類內觸發的區域性異常(如果要讓其處理多個需攔截異常的處理器,則可另其他類繼承此類!)

  1. @Controller  
  2. //可以被其他處理器繼承  
  3. public class MyExceptionFilter {  
  4.     ...  
  5.     //該處理器類中的所有方法丟擲的異常都可由此方法捕獲並處理  
  6.     //該註解也可制定多個異常類,如@ExceptionHandler(value={IOException.class,SQLException.class})    
  7.     @ExceptionHandler(Exception.class)  
  8.     public String handleException(Exception e, HttpServletRequest req) {          
  9.         System.out.println("exception name: " + e.getClass().toString());//異常名  
  10.         System.out.println("exception cause: " + e.getCause());  
  11.         System.out.println("exception msg: " + e.getLocalizedMessage());  
  12.         //e.printStackTrace();   
  13.         StackTraceElement[] ste = e.getStackTrace();  
  14.         StringBuffer sb_e = new StringBuffer();  
  15.         for(int j=0;j<ste.length;j++){  
  16.             if(ste[j].toString().contains("xxxx")) {  
  17.                 sb_e.append(ste[j].toString()+",  ");  
  18.             }  
  19.         }     
  20.         System.out.println("Exception detail: ");//異常詳細資訊  
  21.         System.out.println(sb_e.toString());  
  22.         StringBuffer sbUrl = new StringBuffer();//拼url  
  23.         System.out.println("request method: "+req.getMethod());//get,post  
  24.         System.out.println("request encode: " + req.getCharacterEncoding());//編碼  
  25.         System.out.println("request mapping: "+req.getRequestURL().toString());//請求url方法  
  26.         sbUrl.append(req.getRequestURL().toString());  
  27.         Enumeration en = req.getParameterNames();//請求引數-值  
  28.         for(int i=0; en.hasMoreElements(); i++){  
  29.             String arg = en.nextElement().toString();  
  30.             if(i==0){  
  31.                 sbUrl.append("?");  
  32.             }else{  
  33.                 sbUrl.append("&");  
  34.             }  
  35.             sbUrl.append(arg + "=" + req.getParameterValues(arg)[0]);  
  36.         }  
  37.         System.out.println("request url: " + sbUrl.toString());       
  38. //      if(ex instanceof BusinessException) {    
  39. //          return "error-business";    
  40. //      }else if(ex instanceof ParameterException) {    
  41. //          return "error-parameter";    
  42. //      } else {    
  43. //          return "error";    
  44. //      }    
  45.         return "forward:error.jsp";  
  46.     }  
  47. }  


---方式三:SimpleMappingExceptionResolver

SimpleMappingExceptionResolver:可對全域性異常進行統一處理。

  1. <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
  2.     <!--設定日誌輸出級別,不定義則預設不輸出警告等錯誤日誌資訊。連結:http://elf8848.iteye.com/blog/875830 -->      
  3.     <property name="warnLogCategory" value="WARN" />    
  4.     <!-- 預設錯誤頁面,就是不在exceptionMappings指定範圍內 -->  
  5.     <property name="defaultErrorView" value="error"></property>  
  6.     <!-- 定義需要特殊處理的異常,如當發生IOException異常時跳轉到error/ioexp檢視-->  
  7.     <property name="exceptionMappings"><span style="font-family: Arial, Helvetica, sans-serif;"><!—key為異常類,可以是全路徑,錯誤頁面或Controller路徑!會自動跳轉到對應url --></span>        
  8.         <props>  
  9.             <prop key="IOException">redirect:/login</prop>  
  10.             <prop key="java.sql.SQLException">error/sqlexp</prop>  
  11.         </props>  
  12.     </property>  
  13. </bean>  


---方式四:<error-page> 
DefaultHandlerExceptionResolver:Springmvc預設裝配了DefaultHandlerExceptionResolver,它會將springmvc的異常轉換成對應的響應狀態碼(500,404等)。對於Unchecked Exception而言,由於程式碼不強制捕獲,往往被忽略,如果執行期產生了Unchecked Exception,而程式碼中又沒有進行相應的捕獲和處理,則我們可能不得不面對尷尬的404、500……等伺服器內部錯誤提示頁面。  
      我們需要一個全面而有效的異常處理機制。目前大多數伺服器也都支援在web.xml中通過<error-page>(Websphere/Weblogic)或者<error-code>(Tomcat)節點配置特定異常情況的顯示頁面。(springmvc)操作如下: 
1.在web.xml中配置響應狀態碼對應的頁面,如:

  1. <error-page>    
  2.     <error-code>500</error-code>    
  3.     <location>/WEB-INF/pages/error/500.jsp</location>    
  4. </error-page>   
  5. <!-- 未捕獲的錯誤,同樣可指定其它異常類,或自定義異常類 -->  
  6. <error-page>  
  7.     <exception-type>java.lang.Exception</exception-type>  
  8.     <location>/uncaughtException</location>  
  9. </error-page>  

2. applicationContext.xml中配置

  1. <!-- 錯誤路徑和錯誤頁面,注意指定viewResolver -->  
  2. <mvc:view-controller path="/404" view-name="404"/>  
  3. <mvc:view-controller path="/500" view-name="500"/>  
  4. <mvc:view-controller path="/uncaughtException" view-name="uncaughtException"/>  

附:https://www.google.com.hk/search?newwindow=1&safe=strict&espv=210&es_sm=93&q=error+page%E4%B8%8D%E8%B5%B7%E4%BD%9C%E7%94%A8&revid=601630396&sa=X&ei=ORwOU7K_INKbiQeTjIG4BA&ved=0CIcBENUCKAE&biw=1440&bih=737  

---方式五:Spring3.2新註解@ControllerAdvice 
連結:http://jinnianshilongnian.iteye.com/blog/1866350   
        @ControllerAdvice,是spring3.2提供的新註解。會把@ControllerAdvice註解內部使用@ExceptionHandler、@InitBinder、@ModelAttribute註解的方法應用到所有的 @RequestMapping註解的方法(全域性的)

      有一次發現springmvc3.2.x的@ControllerAdvice註解不起作用,參考連結http://www.07net01.com/linux/spring3_2_mvc__ControllerAdvice_buqizuoyong_554229_1375786240.html加上@EnableWebMvc後就可以了。但是,後來又發現會導致這個原因是因為專案的springmvc配置檔案中沒有配置<mvc:annotation-driven />,於是將其配置上。但是配置上<mvc:annotation-driven />後問題就來了,啟動的時候就報異常,看了下原因,感覺是@EnableWebMvc註解導致的,於是將該註解刪除掉,果然就正常啟動了。不過,至於其中的原理還是理解不深刻,不知道內部是怎麼呼叫的,只是發現當配置上<mvc:annotation-driven />的時候不應該用@EnableWebMvc修飾@ControllerAdvice。(待研究)附連結:http://hahalq.iteye.com/blog/1738599。http://www.yulezhandian.com/?p=196。

      測試後發現,當全域性異常和區域性異常都存在時,全域性異常處理會被區域性異常處理覆蓋。

  1. /** 
  2.  * 全域性異常 
  3.  */  
  4. //@EnableWebMvc  
  5. @ControllerAdvice  
  6. public class MyExceptionHandler {  
  7.     @ExceptionHandler(Exception.class)  
  8.     public String handleException(Exception re, HttpServletRequest request) {  
  9.         System.out.println("error.......");  
  10.         return "forward:error.jsp";  
  11.     }  
  12. }