Day133.異常處理 -SpringMVC

轉行一點成功發表於2020-12-15

異常處理

1.異常處理概述

  • Spring MVC 通過 HandlerExceptionResolver 處理程式的異常,包括 Handler 對映、資料繫結以及目標方法執行時發生的異常。

  • SpringMVC 提供的 HandlerExceptionResolver 的實現類

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-5FLWseSk-1608010743472)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201215130842533.png)]

2. HandlerExceptionResolver

DispatcherServlet 預設裝配的 HandlerExceptionResolver

沒有使用 < mvc:annotation-driven /> 配置:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-i7scG9lu-1608010743475)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201215130951367.png)]

使用了< mvc:annotation-driven /> 配置:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-xCanLa61-1608010743479)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201215131023355.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-brjz5rbK-1608010743482)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201215131034350.png)]

3. 實驗程式碼

①頁面連結

<a href="testExceptionHandlerExceptionResolver?i=1">testExceptionHandlerExceptionResolver</a>

②控制器方法

@Controller
public class ExceptionHandler {
@RequestMapping("/testExceptionHandlerExceptionResolver")
    public String testExceptionHandlerExceptionResolver(@RequestParam("i") int i){
    System.out.println("10/"+i+"="+(10/i));
    return "success";
    }
}

③測試,出現異常情況

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-xfe1ODSF-1608010743487)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201215131207172.png)]

處理異常,跳轉到error.jsp

④在控制器中增加處理異常的方法

@ExceptionHandler(value={java.lang.ArithmeticException.class})
public String handleException(Exception ex){
System.out.println("出現異常啦"+ex);
return "error";
}

⑤增加error.jsp

<h3>Error Page</h3>

4. 如何將異常物件從控制器攜帶給頁面,做異常資訊的獲取

① 異常物件不能通過Map集合方式傳遞給成功頁面。(Map不可以)

// @ExceptionHandler(value={java.lang.ArithmeticException.class})
public String handleException(Exception ex,Map<String,Object> map){
System.out.println("出現異常啦:"+ex);
map.put("exception",ex);
return "error";
}

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-K3nFWR1d-1608010743488)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201215131449225.png)]

②可以通過ModelAndView將異常物件傳遞給成功頁面上

@ExceptionHandler(value={java.lang.ArithmeticException.class})
public ModelAndView handleException(Exception ex){
System.out.println("出現異常啦:"+ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
return mv;
}

5. 匹配異常型別,執行順序問題

@ExceptionHandler(value={java.lang.ArithmeticException.class})
public ModelAndView handleException(Exception ex){
    System.out.println("出現異常啦:"+ex);
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("exception", ex);
    return mv;
}
 
@ExceptionHandler(value={java.lang.RuntimeException.class})
public ModelAndView handleException2(Exception ex){
    System.out.println("RuntimeException-出現異常啦:"+ex);
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("exception", ex);
    return mv;
}

6. 公共的處理異常的類@ControllerAdvice

① 定義公共的處理異常的類

@ControllerAdvice
public class ExceptionAdviceHandler {
 
    /*        
    @ExceptionHandler(value={java.lang.ArithmeticException.class})
    public ModelAndView handleException(Exception ex){

    System.out.println("出現異常啦:"+ex);
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("exception", ex);

    return mv; 
    }*/

    @ExceptionHandler(value={java.lang.RuntimeException.class})
    public ModelAndView handleException2(Exception ex){

    System.out.println("RuntimeException-出現異常啦:"+ex);
    ModelAndView mv = new ModelAndView("error");
    mv.addObject("exception", ex);

    return mv;
    }
}

7. ExceptionHandlerExceptionResolver

  • 主要處理 Handler 中用 @ExceptionHandler 註解定義的方法。

  • @ExceptionHandler 註解定義的方法優先順序問題:例如發生的是NullPointerException,但是宣告的異常有 RuntimeException 和 Exception,此候會根據異常的最近繼承關係找到繼承深度最淺的那個 @ExceptionHandler 註解方法,即標記了 RuntimeException 的方法

  • ExceptionHandlerMethodResolver 內部若找不到@ExceptionHandler 註解的話,會找 @ControllerAdvice 中的**@ExceptionHandler** 註解方法

8. 異常處理_ResponseStatusExceptionResolver

  • 在異常及異常父類中找到 @ResponseStatus 註解,然後使用這個註解的屬性進行處理。

  • 定義一個 @ResponseStatus 註解修飾的異常類

  • 若在處理器方法中丟擲了上述異常:若ExceptionHandlerExceptionResolver 不解析上述異常。由於觸發的異常 UnauthorizedException 帶有@ResponseStatus 註解。因此會被ResponseStatusExceptionResolver 解析到。最後響應HttpStatus.UNAUTHORIZED 程式碼給客戶端。HttpStatus.UNAUTHORIZED 代表響應碼401,無許可權。 關於其他的響應碼請參考 HttpStatus 列舉型別原始碼。

9. 實驗程式碼

① 頁面連結

<a href="testResponseStatusExceptionResolver?i=10">testResponseStatusExceptionResolver</a>

② 自定義異常類

/**
 * 自定義異常類
HttpStatus.FORBIDDEN 不允許的,禁用的
 */
@ResponseStatus(value=HttpStatus.FORBIDDEN,reason="使用者名稱稱和密碼不匹配")
public class UsernameNotMatchPasswordException extends RuntimeException{
}

③控制器方法

@RequestMapping(value="/testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
    if(i==13){
    	throw new UsernameNotMatchPasswordException();
    }
    System.out.println("testResponseStatusExceptionResolver...");
    return "success";
}

④ 出現的錯誤訊息

  • 沒使用註解時:**@ResponseStatus(value=HttpStatus.**FORBIDDEN,reason=“使用者名稱稱和密碼不匹配”)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-ljbCgYN8-1608010743491)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201215132118265.png)]

  • 用註解時:@ResponseStatus(value=HttpStatus.FORBIDDEN,reason=“使用者名稱稱和密碼不匹配”)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-lQTe4P9B-1608010743493)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201215132141157.png)]

  • 測試在方法上使用註解
@ResponseStatus(value=HttpStatus.NOT_FOUND,reason="測試方法上設定響應狀態碼")
@RequestMapping(value="/testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
    if(i==13){
 	   throw new UsernameNotMatchPasswordException();
    }
    System.out.println("testResponseStatusExceptionResolver...");
    return "success";
}

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-qoIgsIhL-1608010743495)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201215132233906.png)]

10. 異常處理_DefaultHandlerExceptionResolver

  • 對一些特殊的異常進行處理,比如:

NoSuchRequestHandlingMethodException、

HttpRequestMethodNotSupportedException

HttpMediaTypeNotSupportedException、

HttpMediaTypeNotAcceptableException等。

11. 實驗程式碼

① 增加頁面連結:GET請求

<a href="testDefaultHandlerExceptionResolver">testDefaultHandlerExceptionResolver</a>

增加處理器方法

//@RequestMapping(value="/testDefaultHandlerExceptionResolver")
@RequestMapping(value="/testDefaultHandlerExceptionResolver",method=RequestMethod.POST)  //不支援GET請求
public String testDefaultHandlerExceptionResolver(){
    System.out.println("testDefaultHandlerExceptionResolver...");
    return "success";
}

② 出現異常錯誤

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-pgpnskzV-1608010743497)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201215132359746.png)]

12. 異常處理_SimpleMappingExceptionResolver

  • 如果希望對所有異常進行統一處理,可以使用 SimpleMappingExceptionResolver,它將異常類名對映為檢視名,即發生異常時使用對應的檢視報告異常

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-wxYikW77-1608010743499)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201215132429949.png)]

1) 實驗程式碼

① 增加頁面連結

<a href="testSimpleMappingExceptionResolver?i=1">testSimpleMappingExceptionResolver</a>

② 增加控制器方法

@RequestMapping("/testSimpleMappingExceptionResolver")
public String testSimpleMappingExceptionResolver(@RequestParam("i") int i){
    System.out.println("testSimpleMappingExceptionResolver..."); 
    String[] s = new String[10]; 
    System.out.println(s[i]); 
    return "success";
}

③ 出現異常情況:引數i的值大於10

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-zYI6L42N-1608010743500)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201215132518567.png)]

① 配置異常解析器:自動將異常物件資訊,存放到request範圍內

<!-- 配置SimpleMappingExceptionResolver異常解析器 -->
<bean id="simpleMappingExceptionResolver"
 class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- exceptionAttribute預設值(通過ModelAndView傳遞給頁面):
exception   ->  ${requestScope.exception}
public static final String DEFAULT_EXCEPTION_ATTRIBUTE = "exception";
-->
<property name="exceptionAttribute" value="exception"></property>
    <property name="exceptionMappings">
        <props>
        	<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
        </props>
    </property>
</bean>

error.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body> 
<h3>Error Page</h3> 
${exception }
${requestScope.exception } 
</body>
</html>

相關文章