Spring異常處理——詳解(附源碼)

Spring異常處理——詳解

源碼文件鏈接在最後

背景

一個較爲常見的系統,會涉及控制層,服務(業務)層、緩存層、存儲層以及接口調用等,其中每一個環節都不可避免的會遇到各種不可預知的異常需要處理。如果每個步驟都單獨try…catch會使系統顯的很雜亂,可讀性差,維護成本高;常見的方式就是,實現統一的異常處理,從而將各類異常從各個模塊中解耦出來;

測試案例的製作

前端error.jsp代碼
文件名:/springmvc/src/main/webapp/views/error.jsp
代碼:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div align="center">
	<h2>ERROR PAGE</h2>
	<div>
		errorINof:${exception }
	</div>
</div>
</body>
</html>

先來個簡單的數組用來測試今天的異常處理
文件名:/springmvc/src/main/java/init/wuji/springboot/mvc/exception/action/SecondExceptionController.java
代碼

package init.wuji.springboot.mvc.exception.action;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class SecondExceptionController {

	@RequestMapping("/sectstException")
	public String sectstException(int nameIndex) {
		
		String[] userNames = {"張三", "Lisi", "小黑"};
		
		System.out.println("hello Exception! userName:"  + userNames[nameIndex]);
		
		return "success";
	}
}

那個視圖解析器就不說
別return success看不懂

	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>	

配置在了上下文
也就是我的error文件在views/error.jsp

1、在上下文在配置異常處理(較常見)

<bean id="exceptionResolver"   class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
		<property name="exceptionAttribute" value="myException"></property>
		<property name="exceptionMappings">
			<props>
				<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
			</props>
		</property>
	</bean>

exceptionAttribute是exception用來前端接收的名字,源碼中默認爲exception,如果要修改就定義成別的名字

2、@ControllerAdvice全局作用(較常見)

這裏雖說是ControllerAdvice註解,其實是其與ExceptionHandler的組合使用。在上文中可以看到,單獨使用@ExceptionHandler時,其必須在一個Controller中,然而當其與ControllerAdvice組合使用時就完全沒有了這個限制。換句話說,二者的組合達到的全局異常捕獲處理

文件名:/springmvc/src/main/java/init/wuji/springboot/mvc/exception/action/MyExceptionHandler.java
代碼:

package init.wuji.springboot.mvc.exception.action;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class MyExceptionHandler{

	@ExceptionHandler(Throwable.class)
	public ModelAndView handleException(Throwable e) {
		ModelAndView mav = new ModelAndView("error");
		System.out.println("=======MyhandleException=========");
		mav.addObject("exception", e);
		return mav;
	}

}

運行結果
在這裏插入圖片描述
在這裏插入圖片描述
一般來說全局註解比較常見使用

3、註解ExceptionHandler(局部)

註解ExceptionHandler作用對象爲方法,最簡單的使用方法就是放在controller文件中,詳細的註解定義不再介紹。如果項目中有多個controller文件,通常可以在baseController中實現ExceptionHandler的異常處理,而各個contoller繼承basecontroller從而達到統一異常處理的目的。因爲比較常見,簡單代碼如下:
文件名:/springmvc/src/main/java/init/wuji/springboot/mvc/exception/action/TestExceptionController.java
代碼:

package init.wuji.springboot.mvc.exception.action;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class TestExceptionController {
	@RequestMapping("/tstException")
	public String tstException(int nameIndex) {
		
		String[] userNames = {"張三", "Lisi", "小黑"};
		
		System.out.println("hello Exception! userName:"  + userNames[nameIndex]);
		
		return "success";
	}
	
	/**
	 * 
	 * 在使用@ExceptionHandler進行異常處理時,不可以將exception直接設置到方法參數中聲明的modle, 必須返回ModelAndView
	 * 
	 * @param e
	 * @param map
	 * @return
	 */
	@ExceptionHandler
	public ModelAndView handleException(Exception e) {
	
		ModelAndView mav = new ModelAndView("error");
		System.out.println("=======handleException=========");
		mav.addObject("exception", e);
		return mav;
	}
}

運行結果
在這裏插入圖片描述

=======handleException=========
17:06:20.458 [http-nio-8080-exec-11] DEBUG org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Resolved [java.lang.ArrayIndexOutOfBoundsException: 5] to ModelAndView [view="error"; model={exception=java.lang.ArrayIndexOutOfBoundsException: 5}]
17:06:20.458 [http-nio-8080-exec-11] DEBUG org.springframework.web.servlet.DispatcherServlet - Using resolved error view: ModelAndView [view="error"; model={exception=java.lang.ArrayIndexOutOfBoundsException: 5}]
17:06:20.459 [http-nio-8080-exec-11] DEBUG org.springframework.web.servlet.view.JstlView - View name 'error', model {exception=java.lang.ArrayIndexOutOfBoundsException: 5}
17:06:20.459 [http-nio-8080-exec-11] DEBUG org.springframework.web.servlet.view.JstlView - Forwarding to [/views/error.jsp]
17:06:20.461 [http-nio-8080-exec-11] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK


4、接口

實現HandlerExceptionResolver接口
HandlerExceptionResolver本身SpringMVC內部的接口,其內部只有resolveException一個方法,通過實現該接口我們可以達到全局異常處理的目的。
只需要將該Bean加入到Spring容器,可以通過Xml配置,也可以通過註解方式加入容器。

總結(異常處理順序)

三種都講完了,下面說一下,當有多個exception時的運行機制,
通過實踐可知,單獨@ExceptionHandle異常處理排在了首位,@ControllerAdvice排在了第二位,也就是優先選擇離異常近的

下課

發佈了21 篇原創文章 · 獲贊 29 · 訪問量 6301
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章