RestController 中的 ControllerAdvice、ExceptionHandler 和 try catch 块

ControllerAdvice, ExceptionHandler and try catch block in RestController

我有关于 @ControllerAdvice@ExceptionHandler 的一般性问题。我有一个带有 2 个 API 的注释 @RestController 的休息控制器。如果参数验证失败,它会抛出 MethodArgumentNotValidException。我创建了 ExceptionHandler 来处理这个问题:

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public ResponseEntity<String> handleException(MethodArgumentNotValidException e) throws Exception {
        return new ResponseEntity<>(e.getBindingResult().getGlobalError().getDefaultMessage(), HttpStatus.BAD_REQUEST);
    }
}

如果我想在发生此异常时记录一些内容,我可以在 return 语句之前添加一行代码,例如:

LOG.info("something happened");

它会记录它然后 return BAD_REQUEST 返回给调用者吗?

If I want to log something when this exception happens, can I just add line of code before return statement like:

LOG.info("something happened");

Will it log it and then return BAD_REQUEST back to the caller?

是的。这就是使用 @ExceptionHandler 的目的。它们有助于减少用于处理项目中定义的多个剩余端点的异常的代码。这也可以作为记录异常的单点,从而避免这种反模式:

//BAD
class SomeService {
    public SomeEntity someMethod() {
        try {
            /* stuff... */
        } catch (Exception e) {
            //No need to log the exception here
            log.error("An exception happened", e);
            throw e;
        }
    }
}

不过,您仍然可以获得一些好处,例如包装异常并重新抛出它们:

//GOOD
class SomeService {
    public SomeEntity someMethod(String param) {
        try {
            /* stuff... */
        } catch (Exception e) {
            //You may use this to perform other logic like setting specific message or wrap your exception
            log.error("Unexpected behaviour with param {}", param);
            throw new MyCustomException("Some message", e);
        }
    }
}

您可以将 @ExceptionHandler 视为一个巨大的 catch 块,用于所有其余端点和特定类型的异常。

此外,您的 GlobalExceptionHandler class 成为具有关联逻辑的组件,用于处理后端抛出的每个异常并处理如何向客户端报告异常。