共计 4819 个字符,预计需要花费 13 分钟才能阅读完成。
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”