Spring3.2开始提供的新注解,控制器增强(AOP),最主要的应用是做统一的异常处理。
@ControllerAdvice
(看成spring mvc提供的一个特殊的拦截器)。
@ControllerAdvice
是一个
@Component
,用于定义
@ExceptionHandler
(最主要用途),
@InitBinder
和
@ModelAttribute
方法,适用于所有使用
@RequestMapping
方法(拦截)。
引申:@interface
元注解@Target(ElementType.TYPE)
:该注解应用到什么地方。@Retention(RetentionPolicy.RUNTIME)
:什么时候应用。
@ExceptionHandler
:为所有controller封装统一异常处理代码。@ModelAttribute
:为所有controller设置全局变量。@InitBinder
:用于为所有controller设置某个类型的数据转换器。
准备:搭建好Spring Boot,页面使用thymeleaf
1.全局异常捕捉处理
ControllerAdviceTest.java
/**
* 启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,
* 都会作用在 被 @RequestMapping 注解的方法上
*/
@ControllerAdvice
public class ControllerAdviceTest {
/**
* 全局异常捕捉处理
* @ExceptionHandler 用来定义函数针对的异常类型
* @param ex
* @return
*/
@ResponseBody
@ExceptionHandler(value = Exception.class)
public Map errorHandler(Exception ex){
Map map = new HashMap();
map.put("code","0000");
map.put("msg",ex.getMessage());
return map;
}
}
ExceptionController.java
@RestController
public class ExceptionController {
@RequestMapping("exception1")
public String exception1() throws IOException {
return "拦截器测试";
}
}
浏览器访问:localhost:8080/exception1
浏览器显示:拦截器测试
@RestController
public class ExceptionController {
@RequestMapping("exception2")
public String exception2() throws IOException {
int i = 1/0;
return "拦截器测试";
}
}
浏览器访问:localhost:8080/exception2
浏览器显示:{“msg”:”/ by zero”,”code”:”0000″}
@RestController
public class ExceptionController {
@RequestMapping("exception3")
public String exception3() throws IOException {
throw new NullPointerException("服务器到非洲去了");
}
}
浏览器访问:localhost:8080/exception3
浏览器显示:{“msg”:”服务器到非洲去了”,”code”:”0000″}
2.拦截捕捉自定义异常
MyException.java
public class MyException extends RuntimeException {
private String code;
private String msg;
//Get、Set方法略……
public MyException(String code,String msg) {
this.code = code;
this.msg = msg;
}
}
ControllerAdviceTest.java
@ControllerAdvice
public class ControllerAdviceTest {
/**
* 拦截捕捉自定义异常 MyException.class
* @param ex
* @return
*/
@ResponseBody
@ExceptionHandler(value = MyException.class)
public Map myErrorHandler(MyException ex) {
Map map = new HashMap();
map.put("code", ex.getCode());
map.put("msg", ex.getMsg());
return map;
}
}
ExceptionController.java
@RestController
public class ExceptionController {
@RequestMapping("myException")
public String myException(){
throw new MyException("1111","This is my Exception!");
}
}
浏览器访问:localhost:8080/myException
浏览器显示:{“msg”:”This is my Exception!”,”code”:”1111″}
跳转到一个单独的异常显示页面
ControllerAdviceTest.java
@ControllerAdvice
public class ControllerAdviceTest {
/**
* 跳转视图显示异常
* @param ex
* @return
*/
@ExceptionHandler(value = MyException.class)
public ModelAndView myErrorHandlerToView(MyException ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("myGlobalExceptionPage");
modelAndView.addObject("code", ex.getCode());
modelAndView.addObject("msg", ex.getMsg());
return modelAndView;
}
}
myGlobalExceptionPage.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>myGlobalExceptionPage</title>
</head>
<body>
<p th:text="${code}"></p>
<p th:text="${msg}"></p>
</body>
</html>
浏览器访问:localhost:8080/myException
浏览器显示:1111 This is my Exception!
3.绑定值到Model中
ControllerAdviceTest.java
@ControllerAdvice
public class ControllerAdviceTest {
/**
* 把值绑定到Model中,使全局@RequestMapping可以获取到该值
* @param model
*/
@ModelAttribute
public void addAttributes(Model model) {
System.out.println("添加全局变量");
model.addAttribute("userName", "Jack");
}
}
ExceptionController.java
@RestController
public class ExceptionController {
/**
* 使用注入的ModelMap来取变量
* @param modelMap
* @return
*/
@RequestMapping("modelMapTest1")
public Object modelMapTest1(ModelMap modelMap){
Object globalVal = modelMap.get("userName");
System.out.println("全局变量为:"+globalVal);
return globalVal;
}
}
浏览器访问:localhost:8080/modelMapTest1
控制台输出:添加全局变量 全局变量为:Jack
浏览器显示:Jack
ExceptionController.java
@RestController
public class ExceptionController {
/**
* 也可以使用@ModelAttribute注解来取变量
* @param globalVal
* @return
*/
@RequestMapping("/modelMapTest2")
public Object modelMapTest2(@ModelAttribute("userName") String globalVal) {
System.out.println("全局变量为:"+globalVal);
return globalVal;
}
}
浏览器访问:localhost:8080/modelMapTest2
控制台输出:添加全局变量 全局变量为:Jack
浏览器显示:Jack
4.转换日期格式
ControllerAdviceTest.java
@ControllerAdvice
public class ControllerAdviceTest {
/**
* 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
* WebDataBinder是用来绑定请求参数到指定的属性编辑器
* @param binder
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
System.out.println("initBinder执行");
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false); //日期格式是否宽容(只能判断是否需要跳到下个月去)
/*
* spring mvc在绑定表单之前,都会先注册这些编辑器,
* Spring自己提供了大量的实现类,诸如CustomDateEditor,CustomBooleanEditor,CustomNumberEditor等
* 使用时候调用WebDataBinder的registerCustomEditor方法注册
*/
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat,false));
}
}
ExceptionController.java
@RestController
public class ExceptionController {
@RequestMapping("/date")
public Date index(Date date){
System.out.println("date="+date);
return date;
}
}
浏览器访问:localhost:8080/date?date=2019-3-20
控制台输出:initBinder执行 date=2019-3-20
浏览器显示:”2019-3-20″