spring boot 异常处理:
在spring 3.2中,新增了@ControllerAdvice 注解,这个注解注释的类实现控制器增强的功能,在其中可以定义@ExceptionHandler、@InitBinder、@ModelAttribute并应用到所有@RequestMapping注释的方法中。
1.@ExceptionHandler实现全局异常处理
1)在启动类所在的包或其子包中定义全局异常处理类:
@ControllerAdvice //"控制器增强"注解
public class ExceptionHander {
@ExceptionHandler(Exception.class) //用于注释异常处理类,value属性指定需要拦截的异常类型
@ResponseBody //和controller方法上的用法一样,会将方法中的返回值转json后返回给客户端
public Map<String, Object> errorHandler(Exception e) { //捕获异常并获取异常处理对象
Map<String, Object> result = new HashMap<String, Object>();
result.put("code", "0");
result.put("msg", e.getMessage()); //获取异常信息
return result; //将异常信息响应给浏览器
}
}
上面的errorHandler()会捕获到所有被@RequestMapping注释的方法中所抛出的异常,并获取到异常处理对象,异常对象会被赋值给参数e。在此方法中处理异常并将处理结果响应给客户端
2)如在controller中:
@RequestMapping("/hello")
public String sayHello() {
int a=1/0; //程序在这里会出异常
return "hello,spring boot";
}
访问上面的controller时,会抛出/0 异常,这个异常将被全局异常处理类捕获和处理,并将结果响应,响应结果:
{"msg":"/ by zero","code":"0"}
2.@ExceptionHandler实现自定义全局异常处理类
在实际应用中,往往需要对程序中的异常进行自定义处理:
1)自定义异常类:
public class MyException extends RuntimeException { //继承RuntimeException
private String code;
private String msg;
public MyException(String code, String msg) {
super();
this.code = code;
this.msg = msg;
}
//getter & setter方法
...
}
2)在上面被@ControllerAdvice注释的类中添加方法:
@ControllerAdvice
public class ExceptionHander {
@ExceptionHandler(Exception.class)
@ResponseBody
public Map<String, Object> errorHandler(Exception e) { //--方法1
Map<String, Object> result = new HashMap<String, Object>();
result.put("code", "0");
result.put("msg", e.getMessage());
return result;
}
@ExceptionHandler(MyException.class) //在这里将value属性改为自定义的异常类,表示将拦截MyException异常
@ResponseBody
public Map<String, Object> errorHandler(MyException e) { //参数也改为自定义的异常类 --方法2
Map<String, Object> result = new HashMap<String, Object>();
result.put("code", e.getCode());
result.put("msg", e.getMsg());
return result;
}
}
当程序抛出自定义异常时,将会被方法2捕获并处理,如果是抛出其他异常,将被方法1捕获并处理
3)如,在Controller中抛出自定义异常和其他异常
1)抛出自定义异常
@RequestMapping("/hello")
public String sayHello() {
throw new MyException("0", "自定义全局异常"); //抛出自定义异常
}
程序运行时抛出自定义异常,会被捕获并处理,响应结果:
{"msg":"自定义全局异常","code":"0"}
2)抛出其他异常:
@RequestMapping("/hello")
public String sayHello() {
int a=1/0; //程序在这里会出异常
return "hello,spring boot";
}
抛出的异常不是自定义异常,将被@ExceptionHandler(Exception.class)注释的方法拦截并处理,响应结果:
{"msg":"/ by zero","code":"0"}
3.被@ControllerAdvice注释的类中@InitBinder、@ModelAttribute的作用
@InitBinder 在其执行之前初始化数据绑定器
@ModelAttribute
1)@ModelAttribute
1)在@ControllerAdvice注释的类中添加方法:
@ModelAttribute
public void addAtr(Model model){ //参数为model对象
model.addAttribute("globalAtt", "全局属性"); //添加属性
}
2)在controller中能获取到上面添加的属性,两种方法获取:
方法1:
@RequestMapping("/hello")
public String sayHello(@ModelAttribute("globalAtt") String author) {
return author;
}
方法2:
@RequestMapping("/hello")
public String sayHello(ModelMap modelMap) { //通过ModelMap获取
return (String) modelMap.get("globalAtt");
}
响应结果均为:
全局属性
2)@InitBinder
这个注解用于初始化数据绑定器。数据绑定器就是springMVC用于进行参数绑定的组件。
当请求中某些数据如日期数据不能实现自动绑定时,可以通过这个 注解对数据绑定器进行初始化:
如:
1)初始化数据绑定器
@ControllerAdvice
public class ExceptionHander {
@InitBinder //初始化数据绑定器
public void InitBinder(WebDataBinder binder){
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
CustomDateEditor editor=new CustomDateEditor(sdf, false); //定义日期编辑器,编辑器都是PropertyEditorSupport的子类
//可以根据需要定义其它的编辑器
binder.registerCustomEditor(Date.class, editor); //注册编辑器,这里的第一个参数为要绑定的参数类型
}
}
2)controller方法:
@RequestMapping("/hello")
public String sayHello(Date date) { //这里需要绑定一个日期参数,无法自动绑定,必须借助编辑器
return new SimpleDateFormat("yyyy-MM-dd").format(date);
}
3)访问路径:
http://localhost:8080/springboot/hello?date=1992-12-18 //这里传入一个日期 字符串
响应结果:
1992-12-18
流程:程序启动时会自动注册日期转化的编辑器。程序进行参数绑定时,如果发现要将参数绑定到一个Date对象,就会获取到我们初始化的编辑器CustomDateEditor,
通过这个编辑器将参数中的日期字符串转化为日期对象,并实现参数绑定。
注意,@initBinder注解也可以放在Controller类中使用。如果这样使用,这个编辑器的作用域只在当前的controller中
如:
@RestController
@RequestMapping("/springboot")
public class DemoController {
@RequestMapping("/hello")
public String sayHello( Date date) {
return new SimpleDateFormat("yyyy-MM-dd").format(date);
}
@InitBinder
public void initb(WebDataBinder binder){ //直接放在controller 类中,只作用于当前的controller
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
CustomDateEditor editor=new CustomDateEditor(sdf, false);
binder.registerCustomEditor(Date.class, editor);
}
}