在spring 3.2中,新增了@ControllerAdvice 注解,并且配套有三个注解@ExceptionHandler、@InitBinder、@ModelAttribute,以此来对@RequestMapping注解下的方法进行“切面”环绕。参考:@ControllerAdvice 文档
- 全局异常处理@ExceptionHandler
- 全局数据绑定@ModelAttribute
- 全局数据预处理@InitBinder
一、最常用的全局异常处理
1、自定义异常类
package com.demo.demo.exception;@Data
public class MyException extends RuntimeException {public MyException(String msg) {this.msg = msg;}public MyException(String code, String msg) {this.code = code;this.msg = msg;}private String code;private String msg;}
2、自定义全局异常处理类
package com.demo.demo.controller;import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;/*** 如果全部异常处理返回json,那么可以使用 @RestControllerAdvice 代替 @ControllerAdvice ,这样在方法上就可以不需要添加 @ResponseBody*/
@ControllerAdvice
public class GlobalExceptionHandler {/*** 全局异常捕捉处理*/@ResponseBody@ExceptionHandler(value = Exception.class)public Map errorHandler(Exception ex) {Map map = new HashMap();map.put("code", 500);map.put("msg", ex.getMessage());return map;}/*** 拦截捕捉自定义异常 MyException.class*/@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;}/*** 捕捉到异常后,不是返回json而是返回某个渲染的页面*/@ExceptionHandler(value = MyException2.class)public ModelAndView myErrorHandler(MyException2 ex) {ModelAndView modelAndView = new ModelAndView();modelAndView.setViewName("error");modelAndView.addObject("code", ex.getCode());modelAndView.addObject("msg", ex.getMsg());return modelAndView;}
}
3、Controller拦截类
@RequestMapping("/getException")
public String getException() throws Exception {throw new MyException("500", "自定义异常错误");
//最后返回前端以下json信息
//{"msg":"自定义异常错误","code":"500"}
}
二、全局数据绑定
1、自定义全局数据绑定类
package com.demo.demo.controller;import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;@ControllerAdvice
public class GlobalController {/*** 把值绑定到Model中,使全局@RequestMapping可以获取到该值*/@ModelAttributepublic void addAttributes(Model model) {model.addAttribute("author", "Magical Sam");}@ModelAttribute(value = "message")public String globalModelAttribute() {System.out.println("global model attribute.");return "this is from model attribute";}}
2、在@RequestMapping下获取定义的值
@RequestMapping("/getValue")
public String getValue(ModelMap modelMap,) {System.out.println(modelMap.get("author"));//Magical Sam
}@RequestMapping("/getValue2")
public String getValue2(@ModelAttribute("message") String message/**感觉像是给一个全局方法返回值取的别名*/) {System.out.println(message);//global model attribute.this is from model attribute
}
三、全局数据预处理
解决两个实体类有相同属性名,从前端接收两个相同属性会拼接接收的问题
1、有相同属性的实体类
2、预处理类
package com.junya.areyouok;import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;@ControllerAdvice
public class GlobalData {@InitBinder("book")public void initA(WebDataBinder binder){binder.setFieldDefaultPrefix("book.");}@InitBinder("author")public void initB(WebDataBinder binder){binder.setFieldDefaultPrefix("author.");}
}
3、controller接收类
package com.junya.areyouok.controller;import com.junya.areyouok.entity.Author;
import com.junya.areyouok.entity.Book;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;@Controller
public class BookController {@PostMapping("/addBook")public void addBook(@ModelAttribute("book") Book book, @ModelAttribute("author") Author author) {System.out.println(book);System.out.println(author);}
}
4、从前端传入数据格式
处理前端传入的日期格式字符串到后台解析为Date格式
/*** 将前台传递过来的日期格式的字符串,自动转化为Date类型*/
@InitBinder
public void initBinder(WebDataBinder binder)
{//binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));// Date 类型转换binder.registerCustomEditor(Date.class, new PropertyEditorSupport(){@Overridepublic void setAsText(String text){setValue(DateUtils.parseDate(text));}});
}
四、 小结
本文首先讲解了@ControllerAdvice注解的作用,然后结合@ControllerAdvice讲解了能够与其结合的三个注解的使用方式。关于这三种使用方式,需要说明的是,这三种注解如果应用于@ControllerAdvice注解所标注的类中,那么它们表示会对@ControllerAdvice所指定的范围内的接口都有效;如果单纯的将这三种注解应用于某个Controller中,那么它们将只会对该Controller中所有的接口有效,并且此时是不需要在该Controller上标注@ControllerAdvice的。
最后,本文借鉴了一些其他前辈的文章,如果有侵权,请联系我删除哦。
欢迎大家留言交流、共同进步!