在web項目開發中,一個系統應該要考慮到異常情況的處理,並且應該當異常發生時應該需要記錄相應的異常日志,對於用戶而言則不能直接拋出異常,需要考慮到用戶的體驗:
以下就介紹基於spring框架的基礎上的異常處理:
1:如何將異常優雅地顯示給用戶?
如果將一連串的java報錯展示給用戶,對用戶而言是沒有意義的,並且也是危險的;
1)定義錯誤代碼:這里以一個枚舉類來封裝用戶錯誤代碼:ErrorCode:
public enum ErrorCode { NULL_OBJ("LUO001","對象為空"), ERROR_ADD_USER("LUO002","添加用戶失敗"), UNKNOWN_ERROR("LUO999","系統繁忙,請稍后再試...."), FILE_NOT_FOUND("FILE001","你要讀取的資源找不到"); private String value; private String desc; private ErrorCode(String value, String desc) { this.setValue(value); this.setDesc(desc); }
自定義項目的業務異常類:繼承 RuntimeException
public class BusinessException extends RuntimeException { private static final long serialVersionUID = 1L; public BusinessException(Object Obj) { super(Obj.toString()); } }
自定義異常處理類:實現 HandlerExceptionResolver 這個類是用來處理異常發生時做出的邏輯處理,和spring框架集成:
public class MySimpleMappingExceptionResolver implements HandlerExceptionResolver{ @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception) { // 判斷是否ajax請求 if (!(request.getHeader("accept").indexOf("application/json") > -1 || (request .getHeader("X-Requested-With") != null && request.getHeader( "X-Requested-With").indexOf("XMLHttpRequest") > -1))) { // 如果不是ajax,JSP格式返回 // 為安全起見,只有業務異常我們對前端可見,否則否則統一歸為系統異常 Map<String, Object> map = new HashMap<String, Object>(); map.put("success", false); if (exception instanceof BusinessException) { map.put("errorMsg", exception.getMessage()); } else { map.put("errorMsg", "系統異常!"); } //這里需要手動將異常打印出來,由於沒有配置log,實際生產環境應該打印到log里面 exception.printStackTrace(); //對於非ajax請求,我們都統一跳轉到error.jsp頁面 return new ModelAndView("/error", map); } else { // 如果是ajax請求,JSON格式返回 try { response.setContentType("application/json;charset=UTF-8"); PrintWriter writer = response.getWriter(); Map<String, Object> map = new HashMap<String, Object>(); map.put("success", false); // 為安全起見,只有業務異常我們對前端可見,否則統一歸為系統異常 if (exception instanceof BusinessException) { map.put("errorMsg", exception.getMessage()); } else { map.put("errorMsg", "系統異常!"); } JSONObject json =new JSONObject(); // writer.write(json.fromObject(map)); // writer.flush(); // writer.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } }
在spring容器中注冊這個異常處理類
<!-- 定義異常處理器 --> <bean id="exceptionResolver" class="bz.beppe.exception.MySimpleMappingExceptionResolver"></bean>
這樣,在項目拋出自定義的業務異常時,都或進入這個異常處理類進行處理,然后展示給用戶;
當然項目還有一些unchecked Exception,由於代碼不要求強制處理,當這些異常發生時,用戶就會面對 404 500等服務器內部的頁面,目前大多數服務器也都支持在Web.xml中通過<error-page>(Websphere/Weblogic)或者<error-code>(Tomcat)節點配置特定異常情況的顯示頁面。修改web.xml文件,增加以下內容:
<!-- 出錯頁面定義 --> <error-page> <exception-type>java.lang.Throwable</exception-type> <location>/500.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/500.jsp</location> </error-page> <error-page> <error-code>404</error-code> <location>/404.jsp</location> </error-page>
這樣一個健全的異常處理系統就好了;
以下是controller層對這些業務異常和系統異常 以及 unchecked exception 的測試代碼:
public class ExceptionController { @RequestMapping(value = "/controller", method = RequestMethod.GET) public void controller(Model model,String id) { throw new BusinessException(ErrorCode.NULL_OBJ.toString()); } @RequestMapping(value = "/service", method = RequestMethod.GET) public void service(Model model,String id) { // String str=null; // str.substring(10); // System.out.println("代碼運行了"); File file=new File("c:/a.txt"); try { FileReader reader = new FileReader(file); int i = reader.read(); System.out.println(i); } catch (FileNotFoundException e) { // TODO Auto-generated catch block System.out.println("文件找不到"); throw new BusinessException(ErrorCode.FILE_NOT_FOUND); // e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block System.out.println("讀取文件出錯"); e.printStackTrace(); } } }