簡體   English   中英

自定義注解可以拋出自定義異常,而不是 MethodArgumentNotValidException?

[英]A custom annotation can throw a custom exception, rather than MethodArgumentNotValidException?

我有一個 @ExceptionHandler(MethodArgumentNotValidException.class) 在驗證失敗時返回 HTTP 代碼 400。 我創建了一個自定義注釋,我需要將 HTTP 代碼更改為 422。但是,由於異常處理程序已經用 @ResponseStatus(code = HttpStatus.BAD_REQUEST) 進行了注釋,我該怎么做?

我認為也許可以使我的自定義注釋引發自定義異常然后捕獲它。 那可能嗎? 如何?

我的 RestControllerAdvice:

@RestControllerAdvice
public class ManipuladorDeExcecoes {

  @Autowired
  MessageSource messageSource;

  @ResponseStatus(code = HttpStatus.BAD_REQUEST)
  @ExceptionHandler(MethodArgumentNotValidException.class)
  public List<ErroPadrao> handle(MethodArgumentNotValidException exception) {
    List<ErroPadrao> listaDeErros = new ArrayList<>();
    List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();

    fieldErrors.forEach(e -> {
      String mensagem = messageSource.getMessage(e, LocaleContextHolder.getLocale());
      ErroPadrao erro = new ErroPadrao(e.getField(), mensagem);
      listaDeErros.add(erro);
    });

    return listaDeErros;
  }
}

我的自定義注釋:

@Constraint(validatedBy = ValorUnicoValidator.class )
@Target({ FIELD })
@Retention(RUNTIME)
public @interface ValorUnico {
  String message() default "O valor informado já existe no banco de dados";

  String campo();
  Class<?> tabela();
  boolean removeStrings() default false;

  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() default {};
}

我的驗證器:

public class ValorUnicoValidator implements ConstraintValidator<ValorUnico, Object> {

  @PersistenceContext
  EntityManager entityManager;

  private String campo;
  private Class<?> tabela;
  private boolean removeStrings;

  @Override
  public void initialize(ValorUnico constraintAnnotation) {
    this.campo = constraintAnnotation.campo();
    this.tabela = constraintAnnotation.tabela();
    this.removeStrings = constraintAnnotation.removeStrings();
  }

  @Override
  public boolean isValid(Object value, ConstraintValidatorContext context) {
    if (removeStrings) {
      value = value.toString().replaceAll("[^0-9]", "");
    }

    Boolean valorJaExiste = entityManager
            .createQuery("SELECT COUNT(t) < 1 FROM " + tabela.getName() + " t WHERE "
                    + campo + " = :pValor", Boolean.class)
            .setParameter("pValor", value)
            .getSingleResult();

    return valorJaExiste;
  }
}

我不知道有什么方法可以讓驗證器拋出自定義異常。 在這里,有人通過手動拋出自定義異常來解決這個問題(在每個具有相關類型參數的請求映射中); 您可以做他們所做的,然后為您的自定義異常 class 編寫一個@ExceptionHandler 不過,我認為還有更好的方法。

您可以檢查@ExceptionHandler中失敗的約束的消息,並基於此返回不同的狀態代碼。 (您需要刪除@ResponseStatus注釋並更改方法的返回類型,但@ExceptionHandler方法有許多允許的返回類型 - 包括ResponseEntity ,您可以將其狀態設置為您喜歡的任何內容。)所以,有些東西喜歡

@ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Void> handleInvalid(MethodArgumentNotValidException e) {
        for (FieldError err: e.getFieldErrors()) {
            if (err.getDefaultMessage().equals("O valor informado já existe no banco de dados")) {
                return ResponseEntity.unprocessableEntity().build();
            }
        }

        return ResponseEntity.badRequest().build();
    }

顯然,您需要將該消息字符串轉換為常量,因為您不需要記住在@ExceptionHandler方法和注釋本身中都更改它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM