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"
}