Spring MVC 異常處理
Spring MVC處理異常有3種方式: (1)使用@ExceptionHandler注解實現異常處理; (2)使用Spring MVC提供的簡單異常處理器SimpleMappingExceptionResolver; (3)實現Spring的異常處理接口HandlerExceptionResolver 自定義自己的異常處理器;
一、使用@ExceptionHandler進行處理
1.創建異常基類,使用@ExceptionHandler聲明異常處理
BusinessException和SystemException為自定義異常類,代碼如下:
package com.twosnail.exception;import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ExceptionHandler;
@Controller public class BasicExController { /* 基于@ExceptionHandler異常處理基類 @return / @ExceptionHandler public String exception( HttpServletRequest request , Exception ex ) {
// 根據不同錯誤轉向不同頁面
if( ex instanceof BusinessException ) { return "business-error"; }else if( ex instanceof SystemException ) { return "system-error"; } else { return "error"; } } }</pre>
2、使所有需要異常處理的Controller都繼承該類,如下所示:
public class DemoController extends BasicExController {}
然而,Dao層、Service層、Controller層拋出的異常(BusinessException、SystemException和其它異常)都能準確顯示定義的異常處理頁面,達到了統一異常處理的目標。
總結:使用@ExceptionHandler注解實現異常處理,具有集成簡單、有擴展性好(只需要將要異常處理的Controller類繼承于BasicExController即可)、不需要附加Spring配置等優點,但該方法對已有代碼存在入侵性(需要修改已有代碼,使繼承于BasicExController),在異常處理時不能獲取除異常以外的數據。
二、SimpleMappingExceptionResolver簡單異常處理器
SimpleMappingExceptionResolver有兩種配置方式,可以按自己需求而定,配置代碼如下:
1、第一種,在Spring的配置文件中,增加以下內容:
在這里,可以設置跳轉相應頁面。
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 定義默認的異常處理頁面,當該異常類型的注冊時使用 --> <property name="defaultErrorView" value="error"></property> <!-- 定義異常處理頁面用來獲取異常信息的變量名,默認名為exception --> <property name="exceptionAttribute" value="ex"></property> <!-- 定義需要特殊處理的異常,用類名或完全路徑名作為key,異常也頁名作為值 --> <property name="exceptionMappings"> <props> <prop key="com.twosnail.exception.BusinessException">business-error</prop> <prop key="com.twosnail.exception.SystemException">system-error</prop> </props> </property><!-- 相關狀態碼對應的錯誤頁面 --> <property name="statusCodes"> <props> <prop key="errors/500">500</prop> <prop key="errors/404">404</prop> </props> </property> <!-- 設置日志輸出級別,不定義則默認不輸出警告等錯誤日志信息 --> <property name="warnLogCategory" value="WARN" /> <!-- 默認HTTP狀態碼 --> <property name="defaultStatusCode" value="500" />
</bean></pre>
2、第二種,通過自定義java類,繼承SimpleMappingExceptionResolver
然后在Spring的配置。代碼如下:
<bean id="exceptionResolver" class="com.twosnail.exception.MyselfSimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="com.twosnail.exception.SystemException">error/500</prop> <prop key="com.twosnail.exception.BusinessException">error/errorpage</prop> <prop key="java.lang.exception">error/500</prop> </props> </property> </bean>
java類代碼如下,在這里可以處理相應邏輯,如下,分別處理了jsp頁面和json數據:
package com.twosnail.exception;import java.io.IOException; import java.io.PrintWriter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
public class MyselfSimpleMappingExceptionResolver 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))) { // 如果不是異步請求 // Apply HTTP status code for error views, if specified. // Only apply it if we're processing a top-level request. 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; } }
}</pre>
總結:使用SimpleMappingExceptionResolver進行異常處理,具有集成簡單、有良好的擴展性、對已有代碼沒有入侵性等優點,但方法1僅能獲取到異常信息,若在出現異常時,對需要獲取除異常以外的數據的情況不適用。
三、HandlerExceptionResolver自定義異常
1.在Spring的配置文件中,增加以下內容:
<bean id="exceptionHandler" class="com.twosnail.exception.MyExceptionHandler"/>
2.添加自定義的MyExceptionHandler類,代碼如下:
在這里,單獨打印出了異常路徑,便于在日志中查看,在對SystemException異常進行了特殊處理:
package com.twosnail.exception;import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.View; import org.springframework.web.servlet.view.RedirectView;
public class MyExceptionHandler implements HandlerExceptionResolver {
public ModelAndView resolveException( HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception ) { System.out.println( "【拋出異常】--異常路徑為:" + request.getServletPath() + "\n【異常信息】--" + exception.getMessage() ) ; //如果不是拋出的action業務異常則不處理 if( !( exception instanceof SystemException ) ) { return null; } final SystemException actionE = (SystemException) exception; ModelAndView model = null; if( actionE.getForwardType() == SystemException.FORWARD ) { //進入頁面渲染 model = new ModelAndView( actionE.getModelPath(), actionE.getAttributes()); } else if( actionE.getForwardType() == SystemException.REDIRECT ) { model = new ModelAndView( new RedirectView( actionE.getModelPath(), true)); } else { //直接返回頁面內容 model = new ModelAndView( new View() { @Override public void render(Map<String, ?> arg0, HttpServletRequest arg1, HttpServletResponse arg2) throws Exception { arg2.setContentType( "text/html" ); arg2.setCharacterEncoding( actionE.getEncode() ); if( actionE.getResponseBody() != null ) { arg2.getWriter().print( actionE.getResponseBody() ); } } @Override public String getContentType() { return "text/html; charset=utf-8"; } } ); } return model; }
}</pre>
總結:從上面的集成過程可知,使用實現HandlerExceptionResolver接口的異常處理器進行異常處理,具有集成簡單、有良好的擴展性、對已有代碼沒有入侵性等優點。在異常處理時能獲取導致出現異常的對象,有利于提供更詳細的異常處理信息。而SimpleMappingExceptionResolver就是HandlerExceptionResolver的默認實現類。
四、項目截圖
![]()
代碼地址:twosnail源碼地址
參考資料:使用Spring MVC統一異常處理實戰
原創作者:兩只蝸牛