不管作什麼項目,進行異常處理都是很是有必要的,並且你不能把一些只有程序員才能看懂的錯誤代碼拋給用戶去看,因此這時候進行統一的異常處理,展示一個比較友好的錯誤頁面就顯得頗有必要了。跟其餘MVC框架同樣,springMVC也有本身的異常處理機制。
springMVC提供的異常處理主要有兩種方式,一種是直接實現本身的HandlerExceptionResolver,固然這也包括使用Spring已經爲咱們提供好的SimpleMappingExceptionResolver和DefaultHandlerExceptionResolver,另外一種是使用註解的方式實現一個專門用於處理異常的Controller——ExceptionHandler。 css
一、實現本身的HandlerExceptionResolver,HandlerExceptionResolver是一個接口,springMVC自己已經對其有了一個自身的實現——DefaultHandlerExceptionResolver,該解析器只是對其中的一些比較典型的異常進行了攔截,而後返回對應的錯誤碼,固然你也能夠繼承DefaultHandlerExceptionResolver類,而後重寫其中的一些異常處理方法來實現本身的異常處理。 html
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; public class ExceptionHandler implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { // TODO Auto-generated method stub return new ModelAndView("exception"); } }
上述的resolveException的第4個參數表示對哪一種類型的異常進行處理。由於Exception類是全部異常類的基類,因此若是想根據異常類型的不一樣來進行不一樣的處理的話,能夠在resolveException方法裏面根據不一樣的異常類型進行不一樣的處理,返回不一樣的異常視圖。如: java
public class ExceptionHandler implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { // TODO Auto-generated method stub if (ex instanceof NumberFormatException) { //doSomething... return new ModelAndView("number"); } else if (ex instanceof NullPointerException) { //doSomething... return new ModelAndView("null"); } return new ModelAndView("exception"); } }
定義了這樣一個異常處理器以後就要在applicationContext中定義這樣一個bean對象,如: 程序員
<bean id="exceptionResolver" class="com.tiantian.xxx.web.handler.ExceptionHandler"/>
Spring除了實現了一個DefaultHandlerExceptionResolver以外,還實現了一個SimpleMappingExceptionResolver,這二者都是繼承自抽象類AbstractHandlerExceptionResolver,而AbstractHandlerExceptionResolver是實現了HandlerExceptionResolver接口的resolveException方法的,並由此抽取出兩個抽象方法,一個是在進行異常處理以前執行的方法prepareResponse(exception, response),一個是進行異常解析的doResolveException(request, response, handler, exception)方法。SimpleMappingExceptionResolver,顧名思義就是經過簡單的映射關係來決定由哪一個視圖來處理當前的錯誤信息。SimpleMappingExceptionResolver提供了經過異常類型exceptionMappings來進行異常與視圖之間的映射關係,提供了在發生異常時經過statusCodes來映射異常返回的視圖名稱和對應的HttpServletResponse的返回碼。並且能夠經過defaultErrorView和defaultErrorCode來指定默認值,defaultErrorView表示當沒有在exceptionMappings裏面找到對應的異常類型時就返回defaultErrorView定義的視圖,defaultErrorCode表示在發生異常時當沒有在視圖與返回碼的映射關係statusCodes裏面找到對應的映射時默認返回的返回碼。在使用SimpleMappingExceptionResolver時,當發生異常的時候,SimpleMappingExceptionResolver將會把當前的異常對象放到自身屬性exceptionAttribute中,當沒有指定exceptionAttribute時,exceptionAttribute就是用默認值exception。 web
如下是一個簡單的例子: spring
(1)SpringMVC的servlet配置文件中申明一個SimpleMappingExceptionResolver bean,並經過配置屬性exceptionMappings和defaultExceptionView來指定異常和視圖的對應關係。 app
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="NumberFormatException">number</prop><!-- 表示當拋出NumberFormatException的時候就返回名叫number的視圖 --> <prop key="NullPointerException">null</prop> </props> </property> <property name="defaultErrorView" value="exception"/><!-- 表示當拋出異常但沒有在exceptionMappings裏面找到對應的異常時 返回名叫exception的視圖--> <property name="statusCodes"><!-- 定義在發生異常時視圖跟返回碼的對應關係 --> <props> <prop key="number">500</prop><!-- 表示在發生NumberFormatException時返回視圖number,而後這裏定義發生異常時視圖number對應的HttpServletResponse的返回碼是500 --> <prop key="null">503</prop> </props> </property> <property name="defaultStatusCode" value="404"/><!-- 表示在發生異常時默認的HttpServletResponse的返回碼是多少,默認是200 --> </bean>
(2)以下訪問: 框架
@Controller @RequestMapping("/test") public class TestController { @RequestMapping("/null") public void testNullPointerException() { Blog blog = null; //這裏就會發生空指針異常,而後就會返回定義在SpringMVC配置文件中的null視圖 System.out.println(blog.getId()); } @RequestMapping("/number") public void testNumberFormatException() { //這裏就會發生NumberFormatException,而後就會返回定義在SpringMVC配置文件中的number視圖 Integer.parseInt("abc"); } @RequestMapping("/default") public void testDefaultException() { if (1==1) //因爲該異常類型在SpringMVC的配置文件中沒有指定,因此就會返回默認的exception視圖 throw new RuntimeException("Error!"); } }
(3)Jsp頁面中能夠訪問到的異常對象,這裏以NumberFormatException的返回視圖number.jsp做爲示例: jsp
<%@ page language="java" import="java.util.*" pageEncoding="GB18030" isErrorPage="true"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'number.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> NumberFormatException. <br> <%=exception.getMessage() %><br/> <%=exception %><br/><!-- 這是JSP中的內置對象exception --> <%=request.getAttribute("ex") %><br><!-- 這是SpringMVC放在返回的Model中的異常對象 --> <%=request.getAttribute("javax.servlet.error.status_code") %><!-- HttpServletResponse返回的錯誤碼信息,由於前面已經配置了NumberFormatException的錯誤碼返回值爲888,因此這裏應該顯示888 --> </body> </html>
(4)當請求/test/number.do的時候會返回定義好的number視圖,返回結果以下: ide
二、使用@ExceptionHandler進行處理
使用@ExceptionHandler進行處理有一個很差的地方是進行異常處理的方法必須與出錯的方法在同一個Controller裏面
如:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; import com.tiantian.blog.web.servlet.MyException; @Controller public class GlobalController { /** * 用於處理異常的 * @return */ @ExceptionHandler({MyException.class}) public String exception(MyException e) { System.out.println(e.getMessage()); e.printStackTrace(); return "exception"; } @RequestMapping("test") public void test() { throw new MyException("出錯了!"); } }
這裏在頁面上訪問test方法的時候就會報錯,而擁有該test方法的Controller又擁有一個處理該異常的方法,這個時候處理異常的方法就會被調用
優先級
既然在SpringMVC中有兩種處理異常的方式,那麼就存在一個優先級的問題:
當發生異常的時候,SpringMVC會以下處理:
(1)SpringMVC會先從配置文件找異常解析器HandlerExceptionResolver
(2)若是找到了異常異常解析器,那麼接下來就會判斷該異常解析器可否處理當前發生的異常
(3)若是能夠處理的話,那麼就進行處理,而後給前臺返回對應的異常視圖
(4)若是沒有找到對應的異常解析器或者是找到的異常解析器不能處理當前的異常的時候,就看當前的Controller中有沒有提供對應的異常處理器,若是提供了就由Controller本身進行處理並返回對應的視圖
(5)若是配置文件裏面沒有定義對應的異常解析器,而當前Controller中也沒有定義的話,那麼該異常就會被拋出來。