異常

1         異常和日誌的做用

1.1.    異常的做用

Java異常機制是爲了對程序中可能出現的已知錯誤進行捕獲,並進行相應處理。從是否反饋給用戶來看,存在兩類異常: java

系統異常:這類異常由系統自己的低級異常引發,例如數據庫鏈接失敗、內存溢出、空指針異常等等,這類異常不須要出如今前臺,由於用戶看不懂也沒有必要看到這些異常信息。這類異常須要在日誌中進行完整記錄以供往後開發人員進行查看分析。 sql

應用異常:即自定義異常,這類異常須要經過前臺反饋給用戶,友好提示用戶當前操做異常。應用異常經過系統異常轉換而來,例如新建用戶時,發生「主鍵衝突異常」,則須要在UserinfoDao中將「主鍵衝突異常」捕獲,並轉換爲應用異常,異常提示信息設爲「該用戶名XXX已存在,請使用其它用戶名」,並將該異常信息反饋給前臺。只要系統異常影響到的用戶的當前操做,就必須給用戶提示信息,好比「系統後臺發生錯誤,請稍後再試」等。應用異常應按照提示方式的異常進行分類,對應不一樣的提示頁面。 數據庫

1.2.    日誌的做用

系統運行日誌:記錄系統的運行狀況,跟蹤代碼運行時軌跡; 編程

異常和錯誤日誌:記錄異常堆棧信息,以供開發人員查看分析; 架構

業務日誌:記錄業務信息和用戶操做,例如用戶登陸、刪除數據、更新數據等。 app

2.      異常的處理原則

1、避免過大的try塊,不要把不會出現異常的代碼放到try塊裏面,儘可能保持一個try塊對應一個或多個異常。 框架

2、細化異常的類型,不要無論什麼類型的異常都寫成Excetpion。catch語句表示咱們預期會出現某種異常,並且但願可以處理該異常。異常類的做用就是告訴Java編譯器咱們想要處理的是哪種異常,而後針對具體的異常類進行不一樣的處理。例如在DAO層中咱們應該只捕獲SQLExceptionDataAccessException(Spring自定義的數據訪問異常類)這些數據庫異常類,其餘的異常NullPointExceptionNumberFormatException等應經過檢測代碼增長其健壯性來解決,而不該該經過try..catch(Exception e)…語句捕獲全部的異常。 ide

3、不要把本身能處理的異常拋給別人,不要忽略捕獲的異常,捕獲到後要麼處理,要麼轉譯,要麼從新拋出新類型的異常。。處理方式包括: spa

Ø  處理異常。針對該異常採起一些行動,例如修正問題、提醒某我的或進行其餘一些處理,要根據具體的情形肯定應該採起的動做。再次說明,調用printStackTrace算不上已經處理好了異常指針

Ø  從新拋出異常。處理異常的代碼在分析異常以後,認爲本身不能處理它,從新拋出異常也不失爲一種選擇。

Ø  把該異常轉換成另外一種異常。大多數狀況下,這是指把一個低級的異常轉換成應用級的異常(其含義更容易被用戶瞭解的異常)。

4、若是對catch塊儘可能保持一個塊捕獲一類異常,在catch語句中儘量指定具體的異常類型,必要時使用多個catch

例:

      try {

      } catch (Exception e) {

           e.printStackTrace();

           log.error("UserinfoDao execute() failed");

}

這段代碼捕獲了異常,但實際上對異常並無進行處理,能夠算得上Java編程中的殺手。按照這個方式,在DAO層發生異常被忽略,Service層就認爲DAO層運行正確,就不會回滾,事務控制就沒有任何做用!!!

Ø  printStackTrace對調試程序有幫助,但程序調試階段結束以後,printStackTrace就不該再在異常處理模塊中擔負主要責任。

Ø  日誌儘可能在系統中的各個出口,例如Action、調度方法等處統一記錄,可減小工做量,何況日誌"UserinfoDao execute() failed」並無說明異常的詳細信息,沒有必要向日志輸出這句話。

Ø  即便catch中加入throw new RuntimeException(e);語句。若是捕獲的異常是RuntimeException,更沒有必要將異常再次轉化爲RuntimeException,這樣不只異常的自己的類型丟失,從新定義異常也形成必定消耗。

因此該處的處理原則應是:若是該處異常須要能轉化爲業務異常反饋給用戶,則須要捕捉低級異常並轉換成業務異常上拋,不然不作任何處理!!!

6、不要用try...catch參與控制程序流程,異常控制的根本目的是處理程序的非正常狀況。

3.      開發中異常的處理方式

本系統使用SSH框架,DAO+Service+Action三層架構,捕獲原則是隻有將低級系統異常轉化爲應用異常的須要才進行捕捉。

各層的處理方式以下:

DAO層:引起DAO異常的問題每每是不可恢復的,如數據鏈接失敗,SQL語句存在語法錯誤,強制捕捉的檢查型異常除了限制開發人員的自由度之外,並無提供什麼有意義的做用。所以,Spring的異常體系都是創建在運行期異常的基礎上,這些異常都繼承於DataAccessExceptionRuntimeException異常子類),因此,除了出於將低級系統異常轉化爲應用異常的須要,沒有必要捕獲異常,讓DAO類自動上拋異常便可。

Service層:只捕獲自定義應用異常,其餘異常上拋。

Action:只捕獲自定義應用異常,其餘異常上拋。Struts2提供了異常攔截器,攔截器會將定義的異常捕獲,記錄日誌,而後根據配置的異常的類型順序跳轉到相應的頁面。配置以下:

struts.xml配置文件

<interceptor-ref name="defaultStack">

       <param name="exception.logEnabled">true</param><!--開啓日誌記錄 -->

       <param name="exception.logLevel">error</param><!-- 日誌級別爲ERROR -->

</interceptor-ref>

<global-exception-mappings><!—異常類和跳轉頁面配置 -->

       <exception-mapping result="basicerror" exception="com.***.***.exception.BasicException"/>

       <exception-mapping result="error" exception="java.lang.Exception"/>

</global-exception-mappings>

com.***.***.exception.BasicException爲自定義應用異常,若是客戶端的請求執行過過程當中產生com.***.***.exception.BasicException異常,則會自動轉到basicerror頁面,從而給用戶相應的提示。

basicerror頁面

<%@ page language="java" contentType="text/xml; charset=UTF-8"       pageEncoding="UTF-8"%>${exception.message }

4.      自定義應用異常

 

異常名稱

說明

com.***.***.exception.BasicException

基礎異常類,本系統中全部的自定義異常類均需繼承本類

com.***.***.exception. DuplicateKeyException

主鍵衝突異常,繼承BasicException

 

Userinfo save方法異常處理

@Override

       public void save(Userinfo entity) {

              try {

                     super.save(entity);

              } catch (DataIntegrityViolationException e) {

                     if(e.getCause().getCause() instanceof SQLException){

                            SQLException sqlE = (SQLException)e.getCause().getCause();

                            if(sqlE.getErrorCode()==1){//ORACLE主鍵衝突異常代碼

                                   throw new DuplicateKeyException("用戶名:"+entity.getUserid()+"已存在,請使用其餘用戶名");

                            }

                     }

              }

       }

5.      日誌配置

系統中目前配置了三個日誌記錄器,一個爲異常記錄器,專門記錄異常信息,日誌文件到達必定大小後將產生新的日誌文件,文件名稱爲exception.log,另外一個爲系統運行記錄器,按照日期記錄全部的日誌信息。

相關文章
相關標籤/搜索