優雅的處理 SpringBoot 全局異常

先贊後看,養成習慣 🌹 歡迎微信關注[Java編程之道],每天進步一點點,沉澱技術分享知識。

Spring Boot中Web應用的統一異常處理

大家在日常開發中常常遇到系統爆出各種不友好的異常,導致整個系統交互體驗極差甚至是系統崩潰,今天我們就聊一下SpringBoot中如果開發一個統一的異常處理中心。

這部分內容比較基礎,只是很多同學很少去設計或者參與到需要全局異常處理的開發中來…以下介紹幾種常用的處理方式。

友好的異常處理方式

SpringBoot默認的已經提供了一套處理異常的機制。一旦程序中出現了異常SpringBoot會像/error的url發送請求。在springBoot中提供了一個叫BasicExceptionController來處理/error請求,然後跳轉到默認顯示異常的頁面來展示異常信息。

也就是你們常常看到的這個錯誤界面,在一個完善的系統中出現這種界面你是會被祭天的!

定義錯誤頁面

如果我們需要將所有的異常統一跳轉到自定義的錯誤頁面,需要在src/main/resources/templates目錄下創建error.html頁面,注意:名稱必須叫error

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>錯誤提示頁面</title>
</head>
<body>
	出錯了,請與管理員聯繫。。。
	<span th:text="${exception}"></span>
</body>
</html>

該方式可以較好的把各種錯誤統一跳轉到自己的頁面上,這個頁面你就可以自由發揮寫的漂漂亮亮的避免被祭天了。

使用@ExceptionHandle註解處理異常


@Controller
public class DemoController {
	
	@RequestMapping("/show")
	public String showInfo(){
		String str = null;
		str.length();
		return "index";
	}
	
	@RequestMapping("/show2")
	public String showInfo2(){
		int a = 10/0;
		return "index";
	}
	
	/**
	 * java.lang.ArithmeticException
	 * 該方法需要返回一個ModelAndView:目的是可以讓我們封裝異常信息以及視圖的指定
	 * 參數Exception e:會將產生異常對象注入到方法中
	 */
	@ExceptionHandler(value={java.lang.ArithmeticException.class})
	public ModelAndView arithmeticExceptionHandler(Exception e){
		ModelAndView mv = new ModelAndView();
		mv.addObject("error", e.toString());
		mv.setViewName("error1");
		return mv;
	}
	
	/**
	 * java.lang.NullPointerException
	 * 該方法需要返回一個ModelAndView:目的是可以讓我們封裝異常信息以及視圖的指定
	 * 參數Exception e:會將產生異常對象注入到方法中
	 */
	@ExceptionHandler(value={java.lang.NullPointerException.class})
	public ModelAndView nullPointerExceptionHandler(Exception e){
		ModelAndView mv = new ModelAndView();
		mv.addObject("error", e.toString());
		mv.setViewName("error2");
		return mv;
	}	
}

以下兩個頁面分別是error1和error2。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>錯誤提示頁面-ArithmeticException</title>
</head>
<body>
	出錯了,請與管理員聯繫。。。
	<span th:text="${error}"></span>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>錯誤提示頁面-NullPointerException</title>
</head>
<body>
	出錯了,請與管理員聯繫。。。
	<span th:text="${error}"></span>
</body>
</html>

瀏覽器訪問show1便會出現以下圖片。

這種方式可以實現針對不同的異常跳轉到不同的頁面如404或者403、401等…針對不同報錯實現個性化的異常處理纔是正確的做法。

@ControllerAdvice+@ExceptionHandler

這種方式只是把ExceptionHandler處理類給單獨提了出來減少了Controller的代碼冗餘,提高了對異常統一管理的能力。

/**
 * 全局異常處理類
 *
 *
 */
@ControllerAdvice
public class GlobalException {
	/**
	 * java.lang.ArithmeticException
	 * 該方法需要返回一個ModelAndView:目的是可以讓我們封裝異常信息以及視圖的指定
	 * 參數Exception e:會將產生異常對象注入到方法中
	 */
	@ExceptionHandler(value={java.lang.ArithmeticException.class})
	public ModelAndView arithmeticExceptionHandler(Exception e){
		ModelAndView mv = new ModelAndView();
		mv.addObject("error", e.toString());
		mv.setViewName("error1");
		return mv;
	}
	/**
	 * java.lang.NullPointerException
	 * 該方法需要返回一個ModelAndView:目的是可以讓我們封裝異常信息以及視圖的指定
	 * 參數Exception e:會將產生異常對象注入到方法中
	 */
	@ExceptionHandler(value={java.lang.NullPointerException.class})
	public ModelAndView nullPointerExceptionHandler(Exception e){
		ModelAndView mv = new ModelAndView();
		mv.addObject("error", e.toString());
		mv.setViewName("error2");
		return mv;
	}	
}

配置SimpleMappingExceptionResolver處理異常解析器

這種方式的自由度更大

/**
 * 通過SimpleMappingExceptionResolver做全局異常處理
 *
 *
 */
@Configuration
public class GlobalException {
	
	/**
	 * 該方法必須要有返回值。返回值類型必須是:SimpleMappingExceptionResolver
	 */
	@Bean
	public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
		SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
		
		Properties mappings = new Properties();	
		/**
		 * 參數一:異常的類型,注意必須是異常類型的全名
		 * 參數二:視圖名稱
		 */
		mappings.put("java.lang.ArithmeticException", "error1");
		mappings.put("java.lang.NullPointerException","error2");
		//設置異常與視圖映射信息的
		resolver.setExceptionMappings(mappings);
		return resolver;
	}
	
}

/**
 * 通過實現HandlerExceptionResolver接口做全局異常處理
 *
 *
 */
@Configuration
public class GlobalException implements HandlerExceptionResolver {

	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
			Exception ex) {
		ModelAndView mv = new ModelAndView();
		//判斷不同異常類型,做不同視圖跳轉
		if(ex instanceof ArithmeticException){
			mv.setViewName("error1");
		}
		
		if(ex instanceof NullPointerException){
			mv.setViewName("error2");
		}
		mv.addObject("error", ex.toString());
		
		return mv;
	}
}

最後再說

現在基本上已經是前後端分離了,對於前後端分離的情況下我們做統一的異常處理則是實現一個同一個的Json返回。

  • @RestControllerAdvice = ControllerAdvice + @ResponseBody
@RestControllerAdvice
class GlobalExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    public Error defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        Error<String> stringError = new Error<String>();
        stringError.setCode(500);
        stringError.setMessage(e.getMessage());
        stringError.setUrl(req.getPathInfo());
        return stringError;
    }

    @ExceptionHandler(value = MyException.class)
    public Error myException(HttpServletRequest req, Exception e) throws Exception {
        Error<String> stringError = new Error<String>();
        stringError.setCode(500);
        stringError.setMessage(e.getMessage());
        stringError.setUrl(req.getPathInfo());
        return stringError;
    }
}

至此,已完成在Spring Boot中創建統一的異常處理,實際實現還是依靠Spring MVC的註解,更多更深入的使用可參考Spring MVC的文檔。


更多精彩好文盡在:Java編程之道 🎁

歡迎各位好友前去關注!🌹

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章