1. 程式人生 > >springMVC+shiro異常處理總結

springMVC+shiro異常處理總結

一、Spring MVC處理異常有3種方式:
(1)使用Spring-MVC提供的SimpleMappingExceptionResolver; 
(2)實現Spring的異常處理介面HandlerExceptionResolver 自定義自己的異常處理器; 

(3)使用@ExceptionHandler註解實現異常處理;

Spring HandlerExceptionResolver implementations deal with unexpected exceptions that occur during controller execution. A HandlerExceptionResolver somewhat resembles the exception mappings you can define in the web application descriptor web.xml. However, they provide a more flexible way to do so. For example they provide information about which handler was http://blog.csdn.net/frankcheng5143/article/details/50890118executing when the exception was thrown. Furthermore, a programmatic way of handling exceptions gives you more options for responding appropriately before the request is forwarded to another URL (the same end result as when you use the Servlet specific exception mappings).

Besides implementing the HandlerExceptionResolver interface, which is only a matter of implementing the resolveException(Exception, Handler) method and returning a ModelAndView, you may also use the provided SimpleMappingExceptionResolver or create @ExceptionHandler methods. The SimpleMappingExceptionResolver enables you to take the class name of any exception that might be thrown and map it to a view name. This is functionally equivalent to the exception mapping feature from the Servlet API, but it is also possible to implement more finely grained mappings of exceptions from different handlers. The @ExceptionHandler annotation on the other hand can be used on methods that should be invoked to handle an exception. Such methods may be defined locally within an @Controller or may apply to many @Controller classes when defined within an @ControllerAdvice class. The following sections explain this in more detail.

在Controller執行過程中發生的異常可以通過Spring的HandlerExceptionResolver實現類來處理異常,它有點像web.xml中你所能定義的那種錯誤頁面。然而,它提供的方式比web.xml更加靈活性。比如它能提供發生異常所在handler的資訊,而且通過程式設計處理異常在轉發請求的時候給開發者更多的選擇。除了通過實現HandlerExceptionRresolver介面來處理異常之外(它通常是實現resolveException(Exception, Handler)方法並返回一個ModelAndView)開發人員還可以使用SimpleMappingExceptionResolver 或者@ExceptionHandler來處理異常。開發者可以通過SimpleMappingExceptionResolver將異常的類名和一個檢視名對映起來,這等同於通過Servlet API的對映, 但是它可以實現更加細粒度的將異常對映到不同的handler上。 在Controller中,可以通過@ExceptionHandler註解來處理異常@ExceptionHandler註解在方法之上,將或者通過@ControllerAdvice定義在許多的Controller上。

(1)使用SimpleMappingExceptionResolver實現異常處理能夠輕鬆的將異常對映到對應的錯誤檢視上,在處理請求的時候Spring MVC可能丟擲很多異常,給客戶端返回資訊的時候需要和相關的錯誤碼匹配,根據錯誤給客戶的返回相關的錯誤代號;

 在springMvc-content.xml配置檔案如下:

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
   <property name="exceptionMappings">
      <props>
         <prop key="org.apache.shiro.authz.UnauthorizedException">error/403</prop>  
         <prop key="java.lang.Throwable">error/500</prop>
      </props>
   </property>
</bean>

DefaultHandlerExceptionResolver將SpringMVC的異常分發到不同的錯誤程式碼上,下面是錯誤程式碼和異常的對應關係:

這裡寫圖片描述這裡寫圖片描述

(2) 實現HandlerExceptionResolver 介面自定義異常處理器,HandlerExceptionResolver是一個介面,只有一個方法,我們只需要實現這個介面;

在springMvc-content.xml配置檔案如下:

<!--然後通過 SpringHandlerExceptionResolver去進行全域性捕獲,不論你在系統哪裡去throw,只要實現了 HandlerExceptionResovler這個介面,Spring都會攔截下異常進行處理  -->
<bean id="exceptionResolver" class="com.lf.resolver.MyExceptionResolver"></bean>

我的實現如下:

public class MyExceptionResolver implements HandlerExceptionResolver {

   public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
      System.out.println("==============異常開始=============");
ex.printStackTrace();
System.out.println("==============異常結束=============");
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex.toString().replaceAll("\n", "<br/>"));
      return mv;
}

}

(3)@ExceptionHandler註解實現異常處理

將@ExceptionHandler標註在Controller的方法上,該方法將處理由@RequestMapping方法丟擲的異常

首先要增加BaseController類,並在類中使用@ExceptionHandler註解宣告異常處理,程式碼如下:

public class BaseController {
   /** 基於@ExceptionHandler異常處理 */
@ExceptionHandler
   public String exp(HttpServletRequest request, Exception ex) {
      request.setAttribute("ex", ex);
// 根據不同錯誤轉向不同頁面  
if(ex instanceof BusinessException) {
         return "business_error";
}else if(ex instanceof ParameterException) {
         return "parameter_error";
} else {
         return "error";
}
   }
}

    然後需要修改現有程式碼,使所有需要異常處理的Controller都繼承該類,如下所示:

public class TestController extends BaseController

三、未捕獲異常的處理 :

        對於Unchecked Exception而言,由於程式碼不強制捕獲,往往被忽略,如果執行期產生了UncheckedException,而程式碼中又沒有進行相應的捕獲和處理,則我們可能不得不面對尷尬的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>

三、比較異常處理方式的優缺點:

        Spring MVC整合異常處理3種方式都可以達到統一異常處理的目標。從3種方式的優缺點比較,若只需要簡單的整合異常處理,推薦使用SimpleMappingExceptionResolver即可;若需要整合的異常處理能夠更具個性化,提供給使用者更詳細的異常資訊,推薦自定義實現HandlerExceptionResolver介面的方式;若不喜歡Spring配置檔案或要實現“零配置”,且能接受對原有程式碼的適當入侵,則建議使用@ExceptionHandler註解方式。 

在此補充個Ajax實現異常資訊無跳轉的處理方式:

   Java程式碼(Controller類)

@RequestMapping(value = "/ajaxAlert", method = RequestMethod.POST)
public void ajax(HttpServletResponse response, User user) throws Exception {

   if(user.getId()==null) {
      if(user.getUserName()==null || "".equals(user.getUserName())) {
         AjaxUtils.rendJson(response, false, "使用者名稱為空建立失敗");
} else {
         AjaxUtils.rendJson(response, true, "建立使用者成功");
}
   } else {
      AjaxUtils.rendJson(response, true, "修改使用者成功");
}
}

@RequestMapping(value = "/controllerAjax", method = RequestMethod.POST)
public void controllerAjax(HttpServletResponse response, Integer id) throws Exception {
   try {
      testService.daoTest();
AjaxUtils.rendJson(response, true, "操作成功");
} catch(Exception be) {
      AjaxUtils.rendJson(response, false, "Dao層異常");
}
}

Java程式碼(AjaxUtils類)

import java.io.IOException;
      import javax.servlet.http.HttpServletResponse;
      import net.sf.json.JSONObject;
public class AjaxUtils {

   public static void rendText(HttpServletResponse response, String content)
         throws IOException {
      response.setCharacterEncoding("UTF-8");
response.getWriter().write(content);
}

   public static void rendJson(HttpServletResponse response, boolean success,
String message) throws IOException{
      JSONObject json = new JSONObject();
json.put("isSuccess", success);
json.put("message", message);
rendText(response, json.toString());
}
}
   html程式碼(jQuery)
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Exception</title>
<script type="text/javascript" src="./jquery-1.10.2.min.js"></script>
<script type="text/javascript">
      $(function(){
      init();
});
function init(){
      $("#ajaxCreate").click(function(){
      doAjax({userName: "Candy", realName: "Carol"});
})
      $("#ajaxUpdate").click(function(){
      doAjax({id: 1, userName: "Candy", realName: "Carol"});
})
      $("#ajaxFail").click(function(){
      doAjax({realName: "Carol"});
})
      }
      function doAjax(data) {
      $.post("./ajax.do",data,function(t){
      if(!t.isSuccess){
      alert("操作失敗, 原因:" + t.message);
}else{
      alert("操作成功, 描述:" + t.message);
}
      },"json").error(function(){
      alert("未知錯誤");
});
}
</script>
</head>
<body>
<br />
<a id="ajaxCreate" href="#">建立使用者成功</a>
<br />
<a id="ajaxUpdate" href="#">修改使用者成功</a>
<br />
<a id="ajaxFail" href="#">使用者名稱為空建立失敗</a>
</body>
</html>

轉載自:

https://my.oschina.net/CandyDesire/blog/333340

http://blog.csdn.net/frankcheng5143/article/details/50890118