SpringBoot 异常处理

之前在 SpringBoot 参数校验 中已经简单介绍了异常的处理,在这篇文章中再系统总结一下。

1. Controller 异常捕获

在一个类上面加 @ControllerAdvice 或者 @RestControllerAdvice 注解,就是定义该类为异常处理类。如果不带任何参数,那么这个类就是全局异常处理类,例如在 SpringBoot 参数校验 中我们创建的 GlobalExceptionHandler 。有时候如果不希望捕获全局异常,可以通过给注解传递参数,指定处理的 Controller 范围:

1. basePackages :指定一个或多个包,这些包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理

@ControllerAdvice(basePackages = {
     "com.tfjybj.intern.provider.controller"})
public class FaultBarrier{
     }

2. basePackageClasses :是 basePackages 的一种变形,指定一个或多个 Controller 类,这些类所属的包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理

@ControllerAdvice(basePackageClasses = {
     Test.class})
public class FaultBarrier{
     }

3. assignableTypes :指定一个或多个 Controller 类,这些类被该 @ControllerAdvice 管理

@ControllerAdvice(assignableTypes= {
     Test.class})
public class FaultBarrier{
     }

4. annotations :指定一个或多个注解,被这些注解所标记的 Controller 会被该 @ControllerAdvice 管理

@ControllerAdvice(annotations = {
     RestController.class})
public class FaultBarrier{
     }

另外还要注意下,{} 在 Java 中表示数组,例如我们想指定多个注解,可以这样用:

@ControllerAdvice(annotations = {
     RestController1.class, RestController2.class})
public class FaultBarrier{
     }

在异常处理类中,我们可以使用 @ExceptionHandler 注解定义异常处理方法,其中 value 为需要处理的异常类的 class :

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
     
	@ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseEntity<ServerResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
     
    	return ServerResponse.badRequest(Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());
    }
}

这边需要注意下, @ControllerAdvice 或者 @RestControllerAdvice 只能处理 Controller 层抛出的异常,对例如 Interceptor(拦截器)层的异常、定时任务中的异常、异步方法中的异常,不会进行处理。此外,404 的错误也是无法捕获的:

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
     
	@ExceptionHandler(value = NoHandlerFoundException.class)
	public ResponseEntity<ServerResponse> handleNoHandlerFoundException(NoHandlerFoundException e) {
     
        // @RestControllerAdvice 只能捕获 Controller 抛出的异常
        // NoHandlerFoundException 实际上是捕获不到的
        log.error("======not found 异常======");
        log.error(e.getMessage());
        return ServerResponse.notFound();
    }
}

例如我们访问一个不存在的地址,可以看到异常并没有捕获到:
SpringBoot 异常处理_第1张图片

2. 非 Controller 异常捕获

对于上面这种不是通过 Controller 抛出的异常,使用 @ControllerAdvice@RestControllerAdvice 异常处理类无法捕获到,那么如何处理 404 异常呢?本人找到了一种方案,创建一个类并实现 ErrorController 接口,就可以处理非 Controller 抛出的异常:

@RestController
@Slf4j
public class ServerErrorController implements ErrorController {
     
	@Override
    public String getErrorPath() {
     
        // 实现 ErrorController 接口必须要实现 getErrorPath 方法
        // getErrorPath 方法返回的 path,会映射到 handleError 方法
        return "/error";
    }

	@RequestMapping(value = "/error", produces = {
     MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<ServerResponse> handleError(HttpServletResponse response) {
     
    	if (response.getStatus() == 404) {
     
            return ServerResponse.notFound();
        } else if (response.getStatus() == 500){
     
            return ServerResponse.internalServerError();
        } else {
     
            return ServerResponse.ok(null);
        }
    }
}

在 SpringBoot 中的默认异常处理映射为 “/error”,BasicErrorController 已经默认实现了 “text/html” 的处理。如果想返回自定义 JSON 格式信息,则实现 ErrorController 接口,重写 getErrorPath 方法。这个方法返回一个 String ,也就是异常处理映射,然后增加一个 produces 为 “application/json” 的方法即可。

参考

SpringBoot中实现拦截器, 并实现对404和500等错误的拦截
Spring Boot 实现ErrorController接口处理404、500等错误页面

你可能感兴趣的:(Java,Spring)