@ExceptionHandler注解的作用和示例

@ExceptionHandler 注解用于在 Spring MVC 应用程序中处理特定异常类型的方法。

通常,当 Spring MVC 应用程序在处理 HTTP 请求时出现错误或异常时,它将返回一个默认的 HTTP 500 错误页面或 JSON 响应。使用 @ExceptionHandler 注解,我们可以将控制权转移到自己定义的方法中,以提供自定义异常处理行为。

@ExceptionHandler 注解可以放置在类或方法上,用于处理在处理请求期间抛出的指定异常类型。在处理异常时,Spring MVC 将查找与请求的异常类型匹配的异常处理程序方法,并在发现匹配项时调用该方法来处理异常。

以下是一个使用 @ExceptionHandler 注解处理特定异常的示例:

@ControllerAdvice
public class GlobalExceptionHandler {

  @ExceptionHandler(RuntimeException.class)
  public ResponseEntity<ErrorResponse> handleRuntimeException(RuntimeException ex) {
    ErrorResponse error = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage());
    return new ResponseEntity<>(error, error.getStatus());
  }

  @ExceptionHandler(ResourceNotFoundException.class)
  public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
    ErrorResponse error = new ErrorResponse(HttpStatus.NOT_FOUND, ex.getMessage());
    return new ResponseEntity<>(error, error.getStatus());
  }

  @ExceptionHandler(MethodArgumentNotValidException.class)
  public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
    BindingResult result = ex.getBindingResult();
    ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST, "Validation error");
    error.addValidationErrors(result.getFieldErrors());
    error.addValidationError(result.getGlobalErrors());
    return new ResponseEntity<>(error, error.getStatus());
  }
}

在上面的示例中,GlobalExceptionHandler 类使用 @ControllerAdvice 注解标记,以指示该类是全局异常处理程序。

GlobalExceptionHandler 类包含三个方法,每个方法使用 @ExceptionHandler 注解来处理特定的异常类型。如果在处理请求期间抛出任何 RuntimeException 类型的异常,则会调用 handleRuntimeException() 方法。类似地,如果抛出 ResourceNotFoundException 异常,则会调用 handleResourceNotFoundException() 方法,并且如果抛出 MethodArgumentNotValidException 异常,则会调用 handleMethodArgumentNotValidException() 方法。

每个方法都返回一个 ResponseEntity 对象,其中包含一个自定义的 ErrorResponse 对象和一个 HTTP 状态代码。ErrorResponse 类用于构造 JSON 格式的错误响应,其中包含有关错误的详细信息。在上面的示例中,ErrorResponse 对象包含一个 HTTP 状态代码和一个消息。如果发生验证错误,则还会添加验证错误和字段错误列表。

在UserController类上加上@ControllerAdvice注解:

@ControllerAdvice
public class UserControllerAdvice {

    @ExceptionHandler(CustomException.class)
    public ResponseEntity<ErrorResponse> handleException(CustomException ex) {
        ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    }
}

这个类会在UserController抛出CustomException的时候捕获这个异常并处理。@ExceptionHandler注解用于定义异常处理方法,指定处理的异常类型为CustomException,方法名可以随意取。方法返回ResponseEntity,表示响应一个错误信息,这个错误信息包括状态码和错误消息,状态码为HttpStatus.BAD_REQUEST.value(),错误消息为ex.getMessage(),ex即为抛出的CustomException对象。ResponseEntity是Spring的一个响应实体类,可以通过它设置响应的头部、状态码等信息,以及设置响应的主体内容。

这样,当UserController抛出CustomException的时候,就会被UserControllerAdvice中的handleException方法捕获,并返回一个错误响应。

我们继续实现一个 GlobalExceptionHandler 类,来处理全局异常,并使用 @ExceptionHandler 注解来指定不同类型的异常处理方法,示例如下:

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
        ErrorResponse error = new ErrorResponse();
        error.setStatus(HttpStatus.NOT_FOUND.value());
        error.setMessage(ex.getMessage());
        error.setTimeStamp(System.currentTimeMillis());
        return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(Exception ex) {
        ErrorResponse error = new ErrorResponse();
        error.setStatus(HttpStatus.BAD_REQUEST.value());
        error.setMessage(ex.getMessage());
        error.setTimeStamp(System.currentTimeMillis());
        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    }
}

上面的代码中,我们使用 @ControllerAdvice 注解来声明 GlobalExceptionHandler 为全局异常处理类。该类中包含两个异常处理方法,一个用于处理 ResourceNotFoundException 类型的异常,另一个用于处理其他类型的异常。@ExceptionHandler 注解指定了具体的异常类型,当发生该类型的异常时,Spring 会调用对应的异常处理方法来处理异常。在方法中,我们创建一个 ErrorResponse 对象,设置错误信息并返回一个 ResponseEntity 对象。

这里的 ResourceNotFoundException 类是自定义的异常类型,继承了 RuntimeException 类。当我们需要在代码中抛出该异常时,可以像这样:

throw new ResourceNotFoundException("Resource not found with id " + id);

这样,当发生这种异常时,Spring 会调用 handleResourceNotFoundException 方法来处理异常,并返回一个包含错误信息的响应对象。如果发生其他类型的异常,Spring 会调用 handleException 方法来处理异常。