在将@ControllerAdvice之前,先介绍Spring的@ExceptionHandler,它可以用来统一处理方法抛出的异常。
1.@ExceptionHandler介绍
@ExceptionHandler的作用主要在于声明一个或多个类型的异常,当在Controller中有方法抛出这些指定的异常之后,则会对这些异常进行捕捉,然后按照其标注的方法进行逻辑的处理。以下是@ExceptionHandler属性结构:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionHandler {
/**
* 指定需要捕获的异常类型,默认为Exception
*/
Class<? extends Throwable>[] value() default {};
}
2.@ExceptionHandler简单的使用例子
创建一个处理异常的房并用@ExceptionHandler修饰。@ExceptionHandler注解中可以添加参数,参数是某个异常类的class,代表这个方法专门处理该类异常,比如这样
@ExceptionHandler(NullPointerException.class)
public String nullPointerExceptionRun(Exception exception) {
exception.printStackTrace();
String message = "此类中发生了控制正异常,请在此处理";
System.out.println(message);
return message;
}
上面得方法中添加了 @ExceptionHandler注解,且参数为NullPointerException.class。代表当有方法抛出空指针异常时,该方法才会执行。其中参数exception为抛出的异常对象
整体的Controller代码如下:
@RestController
@RequestMapping("/test")
@Api(tags = "测试")
@CrossOrigin
public class ExceptionHandlerController {
/*
*@ExceptionHandler注解中可以添加参数,
*参数是某个异常类的class,代表这个方法专门处理该类异常,比如这样:
*/
@ExceptionHandler(NullPointerException.class)
public String nullPointerExceptionRun(Exception exception) {
exception.printStackTrace();
String message = "此类中发生了控制正异常,请在此处理";
System.out.println(message);
return message;
}
@GetMapping("nullPointerExceptionRun")
public Result test() {
String s=null;
System.out.println(s.toString()); //代码执行到这里时会产生空指针异常
return Result.ok();
}
}
运行后在Swagger中进行测试调用test方法:
前端页面显示结构如下
可以看到返回了错误信息message
后端显示如下:
3.使用@ExceptionHandler不优雅的地方
@ExceptionHandler可以接收请求处理方法抛出的异常。但是他们与产生异常的请求放在Controller中,作用范围是仅限于本Controller中。如果你有几百个控制器,在每个控制器里都加上类似的代码,不免有点冗余和费劲儿。因此Spring框架提供了@ControllerAdvice
注解,帮助你将其应用到所有的控制器上。
4.@ControllerAdvice
你可以将 @ExceptionHandler标记的方法提取出来,放到一个类中,并加上@ControllerAdvice注解,这样就可以使得所有的控制器使用。注意@ControllerAdvice也被@Component标记,因此也可以被加入到Spring容器中进行管理。以下是Controller源码
当如果只想对一部分的控制器(Controller)添加控制的话,有如下几种方式:
a.对某个包下的控制器添加通知
@ControllerAdvice("com.xxx")// 对位于com.xxx下的所有控制器进行同一通知
public class ControllerHandler{
.....
......
}
如果不写,则默认对所有的控制器添加通知
b.对包里的某个控制器添加通知
@ControllerAdvice(basePackageClasses = XxxController.class)
// 对位于包里某个类添加通知
public class ControllerHandler{
.....
......
}
c.对某几个控制器添加通知
@ControllerAdvice(assignableTypes= XxxController.class YyyController.class)
// 对位于包里某个类添加通知
public class ControllerHandler{
.....
......
}
5.@ControllerAdvice实例
@ControllerAdvice()
@Slf4j
public class GlobalException {
@ExceptionHandler(Exception.class)
@ResponseBody
public Result error(Exception e){
e.printStackTrace();
return Result.error().message("执行了全局异常处理");
}
@ExceptionHandler(ArithmeticException.class)
@ResponseBody()
public Result error(ArithmeticException e){
e.printStackTrace();
return Result.error().message("执行了ArithmeticException异常");
}
/*
* 当检测到抛出该异常后 比如
* throw new ChenException(xx,xx)
* 则会执行该方法 并直接将错误的异常信息返回给请求方接口
* */
@ExceptionHandler(ChenException.class)
@ResponseBody
public Result error(ChenException e){
e.printStackTrace();
log.error(e.getMsg());
return Result.error().message(e.getMsg()).code(e.getCode());
}
}
总结
@ControllerAdvice+@ExceptionHandle可以优雅的统一管理异常处理