Struts2攔截器實現異常處理機制

Struts2攔截器實現異常處理機制  
在j2ee項目中,系統內部難免會出現一些異常,如果把異常放任不管直接打印到瀏覽器可能會讓用戶感覺莫名其妙,也有可能讓某些用戶找到破解系統的方法。 所以不要在頁面上輸出錯誤信息,使用log日誌的方式處理異常並記錄異常。
就拿struts2+hibernate+spring項目說明:通常一個頁面請求到後臺以後,首先是到action(也就是所謂mvc的controller),在action層會調用業務邏輯service,servce層會調用持久層dao獲取數據。最後執行結果會彙總到action,然後通過action控制轉發到指定頁面,執行流程如下圖所示:

而這三層其實都有可能發生異常,比如dao層可能會有SQLException,service可能會有NullPointException,action可能會有IOException,一但發生異常並且程序員未做處理,那麼該層不會再往下執行,而是向調用自己的方法拋出異常,如果dao、service、action層都未處理異常的話,異常信息會拋到服務器,然後服務器會把異常直接打印到頁面,結果就會如下圖所示:

     

其實這種錯誤對於客戶來說毫無意義,因爲他們通常是看不懂這是什麼意思的。
剛學java的時候,我們處理異常通常兩種方法:
①   直接throws,放任不管;
②    寫try...catch,在catch塊中不作任何操作,或者僅僅printStackTrace()把異常打印到控制檯。
第一種方法最後就造就了上圖的結果(不符合操作);而第二種方法更不好:頁面不報錯,但是也不執行用戶的請求,簡單的說,其實這就是bug。
那麼發生異常到底應該怎麼辦呢?我想在大家對java異常有一定了解以後,會知道:異常應該在action控制轉發之前儘量處理,同時記錄log日誌,然後在頁面以友好的錯誤提示告訴用戶出錯了,如。

然後我們回到剛纔處理異常的地方,如果大家積累了一些項目經驗以後會發現使用上面那種處理異常的方式可能還不夠靈活:
①因爲spring把大多數非運行時異常都轉換成運行時異常(RuntimeException)最後導致程序員根本不知道什麼地方應該進行try...catch操作
②每個方法都重複寫try...catch,而且catch塊內的代碼都很相似,這明顯做了很多重複工作而且還很容易出錯。
使用truts2攔截器定義異常攔截器用來解決上述問題,如下圖所示:

  
首先我的action類、service類和dao類如果有必要捕獲異常,我都會try...catch,catch塊內不記錄log,通常是拋出一個新異常,並且註明錯誤信息,有攔截器來拋出異常信息,並寫入log日誌文件:
  1. Java代碼
  2. //action層執行數據添加操作   
  3. public String save(){   
  4.    try{   
  5.          //調用service的save方法   
  6.          service.save(obj);   
  7.    }catch(Exception e){   
  8.       throw new RuntimeException("添加數據時發生錯誤!",e);   
  9.   }   
  10.    return "success";   
  11. }  

複製代碼
Struts2自定義攔截器的操作:
在struts2的配置文件<package>下添加:
   
  1. <interceptors>
  2.                    <!-- 聲明攔截器 -->
  3.                    <interceptor name="errorInterceptor" class="cn.itcast.elec.util.ErrorInterceptor" />
  4.                    <!-- 配置攔截器棧 -->
  5.                    <interceptor-stack name="myErrorInterceptor">
  6.                                <interceptor-ref name="defaultStack" />
  7.                                <interceptor-ref name="errorInterceptor" />
  8.                    </interceptor-stack>
  9. </interceptors>
  10. <!-- 覆蓋底層的攔截器棧 對包中的所有action都有效 -->
  11. <default-interceptor-ref name="myErrorInterceptor"/>
  12.             
  13.             <global-results>
  14.                     <result name="errorMsg">/errorMsg.jsp</result>
  15.             </global-results>
  16.             <global-exception-mappings>
  17.                     <exception-mapping result="errorMsg" exception="java.lang.Exception"></exception-mapping>
  18.         </global-exception-mappings>

複製代碼
然後在異常攔截器對異常進行處理,看下面的代碼:

攔截器的Java代碼
  1. public class ErrorInterceptor implements Interceptor {

  2.         public void init() {

  3.         }

  4.         public String intercept(ActionInvocation actioninvocation) {

  5.                 String result = null; // Action的返回值   
  6.                 try {
  7.                         // 運行被攔截的Action,期間如果發生異常會被catch住   
  8.                         result = actioninvocation.invoke();
  9.                         return result;
  10.                 } catch (Exception e) {
  11.                         /**  
  12.                          * 處理異常  
  13.                          */
  14.                         String errorMsg = "出現錯誤信息,請查看日誌!";
  15.                         //通過instanceof判斷到底是什麼異常類型   
  16.                         if (e instanceof RuntimeException) {
  17.                                 //未知的運行時異常   
  18.                                 RuntimeException re = (RuntimeException) e;
  19.                                 //re.printStackTrace();
  20.                                 errorMsg = re.getMessage().trim();
  21.                         }
  22.                         //把自定義錯誤信息   
  23.                         HttpServletRequest request = (HttpServletRequest) actioninvocation
  24.                                         .getInvocationContext().get(StrutsStatics.HTTP_REQUEST);
  25.                         /**  
  26.                          * 發送錯誤消息到頁面  
  27.                          */
  28.                         request.setAttribute("errorMsg", errorMsg);

  29.                         /**  
  30.                          * log4j記錄日誌  
  31.                          */
  32.                         Log log = LogFactory
  33.                                         .getLog(actioninvocation.getAction().getClass());
  34.                         log.error(errorMsg, e);
  35.                         return "errorMsg";
  36.                 }// ...end of catch   
  37.         }

  38.         public void destroy() {

  39.         }
  40. }

複製代碼
最後在errorMsg.JSP頁面顯示具體的錯誤消息即可:
   
  1. <body>   
  2. <s:if test="%{#request.errorMsg==null}">   
  3.     <p>對不起,系統發生了未知的錯誤,請查看日誌</p>   
  4. </s:if>   
  5. <s:else>   
  6.     <p>${requestScope.errorMsg}</p>   
  7. </s:else>   
  8. </body>  

複製代碼
以上方式可以攔截後臺代碼所有的異常,但如果出現數據庫連接異常時不能被捕獲的,大家可以使用struts2的全局異常處理機制來處理:

Struts2配置文件代碼
  1. <global-results>
  2.             <result name="errorMsg">/errorMsg.jsp</result>
  3. </global-results>
  4. <global-exception-mappings>
  5.                     <exception-mapping result="errorMsg" exception="java.lang.Exception"></exception-mapping>
  6. </global-exception-mappings>
複製代碼
上面這是一個很簡單的異常攔截器,大家可以使用自定義異常,那樣會更靈活一些。
以上異常攔截器可以使用其它很多技術替換:比如spring aop,servlet filter等,根據項目實際情況處理。
發佈了0 篇原創文章 · 獲贊 4 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章