一般SpringMVC對異常的配置都是返回某個jsp視圖給用戶,可是經過ajax方式發起請求,即便發生異常,前臺也沒法得到任何異常提示信息。所以須要對異常進行統一的處理,對於普通請求以及ajax請求的異常都有效。java
1.Spring MVC的異常處理機制web
Spring MVC 經過HandlerExceptionResolver處理程序的異常,包括處理器映射,數據綁定以及處理器執行時發生的異常。HandlerExceptionResolver僅有一個接口方法:ajax
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
當發生異常時,Spring MVC將調用resolveException()方法,並轉到ModelAndView對應的視圖,做爲一個異常報告頁面反饋給用戶。
HandlerExceptionResolver擁有4個實現類,分別是
DefaultHandlerExceptionResolver,
AnnotationMethodExceptionResolver,
ResponseStatusExceptionResolver,
SimpleMappingExceptionResolver.
(1)DefaultHandlerExceptionResolver
Spring MVC默認裝配了DefaultHandlerExceptionResolver,它會將Spring MVC框架的異常轉換爲相應的響應狀態碼。響應狀態碼以下:
500:Web服務內部錯誤
406:無和請求accept匹配的MIME類型
415:不支持的MIME類型
400:壞的請求
405:不支持的請求方法
404:找不到匹配的資源。
能夠在web.xml中經過以下配置爲響應狀態碼配置一個對應的頁面:
1: <error>
2: <error-code>404</error-code>
3: <location>/404.htm</location>
4: <error-page>
(2)AnnotationMethodHandlerExceptionResolverspring
Spring MVC已經默認註冊了AnnotationMethodHandlerExceptionResolver,它容許經過@ExceptionHandler的註解支持處理特定異常的方法。json
1: @Controller
2: public class UserController{
3:
4: @RequestMapping("/throwException")
5: public String throwException(){
6: if (2 > 1) {
7: throw new RuntimeException("ddd")
8: }
9: return "/success";
10: }
11:
12: @ExceptionHandler(RuntimeException.class)
13: public String handlerException(RuntimeException ex,HttpServletRequest request){
14: return "forward:/error.jsp";
15: }
16: }
當調用throwException方法時,會拋出RuntimeException,它會被出於同一個處理器類中的handlerException()方法捕獲。@ExceptionHandler能夠指定多個異常,可是標註@ExceptionHandler的異常處理方法只能對同一個處理器類中的其餘方法進行異常響應處理。app
(3)ResponseStatusHandlerExceptionResolver框架
ResponseStatusHandlerExceptionResolver和AnnotationMethodHandlerExceptionResolver相似,能夠經過@ResponseStatus註解標註一個方法,用於處理特定類型的響應狀態碼。異步
(4)SimpleMappingHandlerExceptionResolverjsp
SimpleMappingHandlerExceptionResolver將異常類名映射爲視圖名,即發生異常時使用對應的視圖報告異常。ide
1: <bean id="exceptionResolver"
2: class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
3: <property name="exceptionMappings">
4: <props>
5: <prop key="com.wbl.modal.exception.NoPermissionException">/error</prop>
6: <prop key="com.wbl.modal.exception.NotLoginException">/login</prop>
7: </props>
8: </property>
9: <property name="exceptionAttribute" value="ex"></property>
10: </bean>
咱們指定當發生NotLoginException異常,使用login視圖進行顯示,即用戶未登錄時,讓用戶到登錄頁面進行登錄。
2.Spring MVC 的異常統一處理
爲了可以對異常進行統一的處理,包括普通請求發生異常以及ajax請求發生異常時,咱們能夠覆寫SimpleMappingHandlerExceptionResolver中的doResolveException()方法,判斷是普通請求仍是ajax請求。
1: package com.wbl.modal.exception;
2:
3: import org.springframework.web.servlet.ModelAndView;
4: import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
5:
6: import javax.servlet.http.HttpServletRequest;
7: import javax.servlet.http.HttpServletResponse;
8: import java.io.IOException;
9: import java.io.PrintWriter;
10:
11: /**
12: * Created by Simple_love on 2015/9/10.
13: */
14: public class GlobalExceptionResolver extends SimpleMappingExceptionResolver {
15:
16: @Override
17: protected ModelAndView doResolveException(HttpServletRequest request,
18: HttpServletResponse response, Object handler, Exception ex){
19: String viewName = determineViewName(ex,request);
20: response.setCharacterEncoding("UTF-8");
21: if (viewName != null) {// JSP格式返回
22: if (!(request.getHeader("accept").contains("application/json") || (request.getHeader("X-Requested-With")!= null && request
23: .getHeader("X-Requested-With").contains("XMLHttpRequest") ))) {
24: // 若是不是異步請求
25: // Apply HTTP status code for error views, if specified.
26: // Only apply it if we're processing a top-level request.
27: Integer statusCode = determineStatusCode(request, viewName);
28: if (statusCode != null) {
29: applyStatusCodeIfPossible(request, response, statusCode);
30: }
31: System.out.println("JSP格式返回" + viewName);
32: return getModelAndView(viewName, ex, request);
33: } else {// JSON格式返回
34: try {
35: PrintWriter writer = response.getWriter();
36: writer.write(ex.getMessage());
37: writer.flush();
38: } catch (IOException e) {
39: e.printStackTrace();
40: }
41: System.out.println("JSON格式返回" + viewName);
42: return null;
43: }
44: } else {
45: return null;
46: }
47: }
48: }