一、異常解析器應該具有的功能:
1、既然使用異常解析器,那麼就不必在Controller中對異常進行處理,拋出即可,簡化開發,異常統一控制。
2、ajax請求(有@ResponseBody的Controller)發生錯誤,輸出JSON。
3、頁面請求(無@ResponseBody的Controller)發生錯誤,輸出錯誤頁面。
4、 它需要與AnnotationMethodHandlerAdapter使用同一個messageConverters
5、異常處理細節可控制。
二、SpringMVC異常機制總體思想:
(1)普通頁面出錯後可以跳到統一的錯誤處理頁面,但是ajax就不行了,ajax的本意就是不讓當前頁面發生跳轉,僅局部刷新,從而改善用戶體驗,基本思路是:把異常轉換成json數據返回,這樣ajax的回調函數,就能解析出錯誤原因。(對於僅僅提供json接口發生異常,可以輸出異常json信息)
(2)普通界面與json數據出錯跳入錯誤界面,需要重寫異常解析器。
(3)單地統一配置異常,使得發生普通錯誤指定到固定的頁面,ajax發生錯直接通過js獲取,展現給用戶。
三、SpringMVC框架中常用的異常處理辦法:
(1)
Dao層:直接拋出異常即可
Service層:直接拋出異常即可
Controller層: 訪問頁面時出現異常即可跳入錯誤頁面
Ajax請求:出現異常時提醒異常,不跳出界面
(2)在項目中Controller中的異常配置:
Web.xml:
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500.html</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
Spring-servlet.xml:
<!-- 覆蓋org.springframework.web.servlet.handler.SimpleMappingExceptionResolver,實現普通請求和ajax請求的異常處理 -->
<bean id="exceptionResolver" class="xyt.first.web.exception.CustomSimpleMappingExceptionResolver">
<!-- 異常信息變量名
配置異常的屬性值爲ex,那麼在錯誤頁面中可以通過 ${ex} 來獲取異常的信息
如果不配置這個屬性,它的默認值爲exception-->
<property name="exceptionAttribute" value="ex"></property>
<!--需要做特殊處理的異常,用類名或者完全路徑作爲key,異常頁面作爲值 -->
<property name="exceptionMappings">
<props>
<!-- 表示當拋出NumberFormatException異常時,會跳入commons/number界面 -->
<prop key="NumberFormatException">commons/number</prop>
<prop key="NullPointerException">commons/null</prop>
<prop key="java.lang.ArrayIndexOutOfBoundsException">commons/error</prop>
</props>
</property>
<!-- 定義發生異常時 視圖與返回碼對應關係 -->
<property name="statusCodes">
<props>
<!-- 表示在發生NumberFormatException時返回視圖number,然後這裏定義發生異常時視圖number對應的HttpServletResponse的返回碼是500 -->
<prop key="commons/number">500</prop>
<prop key="commons/null">503</prop>
</props>
</property>
<!-- 設置日誌輸出級別,不定義則默認不輸出警告等錯誤日誌信息 -->
<property name="warnLogCategory" value="WARN"></property>
<!-- 發生異常時默認返回碼404 -->
<property name="defaultStatusCode" value="500"/>
<!-- 表示拋出異常時沒有在exceptionMappings找到對應的異常時返回error視圖 -->
<property name="defaultErrorView" value="commons/error"/>
</bean>
實現普通異常和ajax異常的處理
觀察SimpleMappingExceptionResolver,我們可以複寫其doResolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)方法,通過修改該方法實現普通異常和ajax異常的處理,代碼如下:
public class CustomSimpleMappingExceptionResolver extends
SimpleMappingExceptionResolver {
@Override
protected ModelAndView doResolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
// Expose ModelAndView for chosen error view.
String viewName = determineViewName(ex, request);
if (viewName != null) {// JSP格式返回
if (!(request.getHeader("accept").indexOf("application/json") > -1 || (request
.getHeader("X-Requested-With")!= null && request
.getHeader("X-Requested-With").indexOf("XMLHttpRequest") > -1))) {
// 如果不是異步請求
Integer statusCode = determineStatusCode(request, viewName);
if (statusCode != null) {
applyStatusCodeIfPossible(request, response, statusCode);
}
return getModelAndView(viewName, ex, request);
} else {// JSON格式返回
try {
PrintWriter writer = response.getWriter();
writer.write(ex.getMessage());
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
} else {
return null;
}
}