出自:https://blog.csdn.net/goodyuedandan/article/details/62420120
一、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配置文件如下:
<!-- shiro異常處理 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.apache.shiro.authz.AuthorizationException">/unauthor</prop> <prop key="java.lang.Throwable">error/500</prop> </props> </property> </bean>
DefaultHandlerExceptionResolver將SpringMVC的異常分發到不同的錯誤代碼上,下面是錯誤代碼和異常的對應關系:
(2) 實現HandlerExceptionResolver 接口自定義異常處理器,HandlerExceptionResolver是一個接口,只有一個方法,我們只需要實現這個接口;
在springMvc-content.xml配置文件如下:
<!--然后通過 Spring的HandlerExceptionResolver去進行全局捕獲,不論你在系統哪里去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()); } }
頁面代碼
<!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>