Spring ControllerAdvice(Exception Handling)

Spring ControllerAdvice Usage。

我們在寫AP程式時, 有時候會因為一些流程上的規劃,需要在一些特定情況下拋出例外條件並做處理(eg. 跳警告視窗、導頁)。

本次將會使用 Ajax 從前端送出 request 給 Spring 後台後拋出 Exception 進行導頁。

1. 首先先自訂一個 Exception 的 class,以利模擬之後丟出 Exception 使用。

public class AppException extends RuntimeException {

	private static final long serialVersionUID = 1L;
	private String redirectUrl;

	public AppException() {
		super();
	}

	public AppException(String message, Throwable cause) {
		super(message, cause);
	}

	public AppException(String message) {
		super(message);
	}

	public String getRedirectUrl() {
		return redirectUrl;
	}

	public void setRedirectUrl(String redirectUrl) {
		this.redirectUrl = redirectUrl;
	}
}

2. 撰寫起始頁面與導向頁面,步驟如下:

a. 撰寫 exception.jsp,設定利用 viewController 直接導向,於頁面onload完成後利用 /spring_ryuichi/exceptionCatcher導向controller。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<script src="${pageContext.request.contextPath}/static/js/jquery-ui/external/jquery/jquery.js"></script>
<script src="${pageContext.request.contextPath}/static/js/jquery-ui/jquery-ui.js"></script>
<script src="${pageContext.request.contextPath}/static/js/exception.js"></script>
</head>
<body onload="onReady()">
準備導頁
</body>
</html>
@Override
public void addViewControllers(ViewControllerRegistry registry) {
	/**
	* we can register view controllers that create a direct mapping between the URL and the view name using the ViewControllerRegistry.
	* This way, there’s no need for any Controller between the two
	* 意即, 在此註冊路徑mapping, 於畫面上要取改jsp頁面時, 不需要額外寫controller去控制導向該頁
	*/

	//eg. 設定此行, 要access WEB-INF/view下的index.jsp, 於畫面上打 http://localhost:8080/spring_ryuichi/
	//他就會自動導向該頁面 index.jsp
	registry.addViewController("/exception").setViewName("exception");
}
function onReady() {
	
	alert("準備導頁");
	
	$.ajax({
		url:'/spring_ryuichi/exceptionCatcher', //導向controller準備丟出Appexception
		type:"post",
		//dataType (default: Intelligent Guess (xml, json, script, or html))
		processData:false,
		contentType:false,
		success:function(data) {
			alert("success " + data);
			//導向指定的jsp
			if(data.redirectUrl != null) {
				//導頁
				location.replace(data.redirectUrl);
			}
		},
		error:function(data) {
			alert("error " + data);
			alert(data.redirectUrl)
			//導向指定的jsp
			if(data.redirectUrl != null) {
				//導頁
				location.replace(data.redirectUrl);
			}
		}
	});
}

b.controller準備丟出Appexception。

@Controller
@ComponentScan("com.spring.tku")
public class TkuController {

	private static Logger logger = Logger.getLogger(TkuController.class);

	@RequestMapping("/sample")
	public String sample() {

		logger.info("進入Sample Controller");
		return "sample";
	}

	@RequestMapping("/exceptionCatcher")
	public String exceptionCatcher() throws AppException {

		AppException app = new AppException("例外接收測試");
		app.setRedirectUrl("/spring_ryuichi/sample");//設定丟出exception後要導向的頁面
		throw app;
		//return "exceptionCatcher";
	}
}

3. 定義 controlleraDvice,接收拋出的 AppException。

@ControllerAdvice
//GlobalExceptionHandler:處理Controller中的異常
public class GlobalExceptionHandler {

	/**
     * Method handles the AppException
     * 
     * @param ex
     * @return Map<String, Object>
     */
    @ExceptionHandler(AppException.class) //// 攔截所有AppException,value可設定攔截條件
    public @ResponseBody Map<String, Object> handleAppException(AppException ex) {

    	Map<String, Object> map = new HashMap<String, Object>();
    	map.put("exception", ex.getMessage());
    	map.put("redirectUrl", ex.getRedirectUrl());
    	
        return map;

    }
}

於 Ajax 呼叫完後判斷 redirectUrl 是否有值,若有則進行導頁,這邊順帶一提,經過Spring controllerAdvice處理回傳過後。

若想要從 Ajax 的 success 執行,則須在方法名前面加上@ResponseBody,讓 Spring 將你所回傳的內容轉成JSON格式,讓 Ajax 可以認得出格式來。

Ajax 若沒指定 datatype,預設接收格式會去猜 xml、json、script or html。

認不出格式的話,會導向error的區塊,反之,則進入success區塊。

4. 範例結果如下,輸入 http://localhost:8080/spring_ryuichi/exception 後的頁面變化。