springMvc中@ControllerAdvice和ErrorController接口使用
一、簡介
springMvc中對全局的處理,可以使用aop。這裏介紹另外一種方式,藉助springMvc的ControllerAdvice註解和ErrorController接口。
二、ControllerAdvice註解
@ControllerAdvice(直接返回請求體,可以使用@RestControllerAdvice)可以對控制器進行全局處理,通常藉助@ExceptionHandler、@InitBinder、@ModelAttribute處理。
2.1 @ExceptionHandler
@ExceptionHandler用於全局處理控制器異常。示例如下:
2.1.1 使用
定義控制器異常捕獲類,類用@ControllerAdvice註解修飾,處理方法用@ExceptionHandler修飾。
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class ExceptionControllerAdvice {
//通過註解@ExceptionHandler捕獲所有異常
@ResponseBody
@ExceptionHandler(value = {Exception.class})
public Object exceptionDispose(Exception e, HttpServletRequest req, HttpServletResponse res) {
Map<String, Object> result = new HashMap<>();
result.put("exception", e.getClass().getName());
result.put("uri", req.getRequestURI());
return result;
}
}
定義會拋異常的控制器:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("ex")
public class ExceptionController {
//異常
@RequestMapping("exception")
public Object exception(String exClassName) throws Exception {
throw (Exception) Class.forName(exClassName).newInstance();
}
}
2.1.2 測試
請求:
### 空指針異常測試
GET http://localhost:9090/ex/exception?id=002&exClassName=java.lang.NullPointerException
Accept: application/json
響應:
{
"exception": "java.lang.NullPointerException",
"uri": "/ex/exception"
}
2.2 @ModelAttribute
@ModelAttribute用於全局參數綁定,可提前綁定參數到所有請求中。示例如下:
2.2.1 使用
定義綁定參數處理類,類用@ControllerAdvice註解修飾,處理方法用@ModelAttributer修飾。
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
@ControllerAdvice
public class ModelAttributeControllerAdvice {
//通過註解@ExceptionHandler捕獲所有異常
@ModelAttribute
public void modelAttributeDispose(Model model, HttpServletRequest req, HttpServletResponse res) {
model.addAttribute("token", UUID.randomUUID());
}
}
定義測試控制器:
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
@RestController
@RequestMapping("ma")
public class ModelAttributeController {
//參數綁定
@RequestMapping("modelAttribute")
public Object modelAttribute(Model model, HttpServletRequest req, HttpServletResponse res) throws Exception {
return new HashMap<>(model.asMap());
}
}
2.2.2 測試
請求:
### 全局參數測試
GET http://localhost:9090/ma/modelAttribute?id=003
Accept: application/json
響應:
{
"token": "9143f492-e501-4c4f-8c17-637ed7bd048a"
}
2.3 @InitBinder
@InitBinder用於參數綁定處理,可對參數進行轉換等處理。
2.3.1 使用
定義參數處理類,類用@ControllerAdvice註解修飾,處理方法用@InitBinder修飾。
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@ControllerAdvice
public class InitBinderControllerAdvice {
private DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
@InitBinder
public void initBinder(WebDataBinder wdb, HttpServletRequest req, HttpServletResponse res) {
CustomDateEditor cde = new CustomDateEditor(df, true);
wdb.registerCustomEditor(Date.class, cde);
}
}
定義參數綁定轉換測試控制器。
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
@RequestMapping("ib")
public class InitBinderController {
//參數轉換綁定
@RequestMapping("initBind")
public Object initBind(Date dt) throws Exception {
return DateFormatUtils.format(dt, "yyyy-MM-dd");
}
}
2.3.2 測試
請求:
### 全局參數測試
GET http://localhost:9090/ib/initBind?dt=2020-06-29
Accept: application/json
響應:
2020-06-29
三、ErrorController接口
ErrorController接口可以對尚未進入控制器的請求錯誤進行捕獲處理,使用中通過繼承ErrorController接口,實現getErrorPath方法,指定錯誤處理路徑,然後在錯誤路徑控制器方法中處理。示例如下:
3.1 使用示例
定義錯誤處理控制器類,繼承ErrorController,在實現方法getErrorPath中指定錯誤處理路徑。
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@RestController
public class JsonErrorController implements ErrorController {
@Override
public String getErrorPath() {
//指定錯誤處理路徑
return "/error";
}
//錯誤處理
@RequestMapping("error")
public Object errorDispose(HttpServletRequest req) {
Map<String, Object> result = new HashMap<>();
result.put("code", req.getAttribute("javax.servlet.error.status_code"));
result.put("uri", req.getRequestURI());
result.put("param", req.getParameterMap());
return result;
}
}
3.2 測試
請求:
### 測試輸入不存在地址的錯誤捕獲
GET http://localhost:9090/xx?id=001
Accept: application/json
響應:
{
"code": 404,
"param": {
"id": [
"001"
]
},
"uri": "/error"
}