Java異常有很多問題需要處理。如是拋RuntimeException,還是拋CheckedException ? 異常處理能不能Reuse 等等。本文要探討的是在Web領域倆個常見問題:
如何避免重復打印異常&如何友好的顯示錯誤信息給終端用戶。
由於Java EE 編程模型是N-TIEr 結構,而很多模式,無論是設計模式,還是JavaEE模式,都傾向於分層,如下面一個列子,系統將用戶數據通過WebService導出到另外一系統:
UserDataExprotServlet.Java
public void doPost(HttpServlet request,HttpServletResponse response){
try{
String userId = request.getParameter("userId");
UserDataManager manager = new UserDataManager();
manager.exportToSCRT(userId);
}catch(MyApplicationException ex{
ex.pirntStackTrace();
//........
}
}
UserDataManager 作為一個Facade類,會通過userId獲取User對象,然後依次調用WebServiceClIEnt的login方法以及export方法,如下:
UserDataManager.Java
public void exportToSCRT(String userId) throws MyApplicationException
{
User user = null;
UserDao userDao = new UserDao();
WebServiceClient client = WebServiceClIEnt.instance();
try{
User user = userDao.getUser(userId)
}catch(SomeDaoApplicationException ex{
ex.pirntStackTrace();
//........
throw new MyApplicationException(...)
}
try{
clIEnt.login(AppProp.getAdminId(),AppProp.getAdminPassWord());
clinet.export(user)
}catch(WebServiceApplicationException ex{
ex.pirntStackTrace();
//........
throw new MyApplicationException(...)
}
}
WebServiceClIEnt.Java
public void login(id,passWord)
{
try{
String sessionId = soapBinding.login(id,passWord);
soapBinding.setHeader(sessionId);
}catch(SoapFault fault{
ex.pirntStackTrace(); //........
throw new MyApplicationException(...)
}
}
public void export(User user)
{
soapBinding.export(user);
}
我們已經看到了servlet和facade和WebServiceClIEnt這三層,servlet負責處理web請求,並給予響應,它會調用Facade這一層,這層封裝了多個業務調用,也許接下來還有更多的層去處理具體業務, 到此為止,我們已經發現同一個異常被多次打印。檢查日志文件,你就能看到滿屏重復的異常。
因此,異常只能被打印一次。在哪兒打異常最好呢?。原則就是自定義異常在拋出前打印一下,其他各層對自定義異常不作任何打印。甚至不用Catch.
對於上面WebServiceClIEnt.login,在這打印是對的,還可以加上自己的一些log信息,如log.fatal("can not log in the XXX system");至於在其他層,就不在需要打印,處理這個異常了。這樣的異常處理沒有什麼技術含量,只是個異常處理原則,如果人人都遵循(看到自定義不處理,拋自定義異常前處理)這個原則,就能避免重復打印異常日志
再考慮如何把友好的異常信息給終端用戶呢,所謂友好,不能總是提示“系統錯誤,請稍後再試”,因為這樣能讓使用者對系統沒有信心。好比領導交給你的任務,你沒有完成,你總不能每次都說“這是我的問題,以後改正”吧。對異常進行稍微詳細的說明,是必要的。另外,也不能總是把異常的stacktrace原封不動的現實給使用者,如Java.io.IOExcepiton:File can not be found .這樣會被認為你的程序質量不夠高。
可以通過異常指定類型來在Web層解釋並轉化為友好的異常。如上列子,可以如下定義MyApplicationExceptoin
public class MyApplicationExcepion extends Exception
{
public MyApplicationExcepion(int errorCode,Excetpion ex,Object... para){...}
}
errorCode 指示了異常代碼,如Web_Service_CanNot_Connect,Duplicate_Export_Error等等,Web層的Servlet可以通過分析errorCode來同一決定來決定輸出何種友好信息。 如下代碼:
public void doPost(HttpServlet request,HttpServletResponse response){
try{
String userId = request.getParameter("userId");
UserDataManager manager = new UserDataManager();
manager.exportToSCRT(userId);
}catch(MyApplicationException ex{
int code = ex.getErrorCode();
String msg = null;
switch(code){
case Web_Service_CanNot_Connect:{msg="無法登錄XXX系統,請聯系管理員";break;}
case Duplicate_Export_Error:{{msg="重復數據倒入";break;}}
default:msg="系統錯誤,請稍後再試"
}
......
}
}