Java 自定义注释可以引发自定义异常,而不是MethodArgumentNotValidException?

Java 自定义注释可以引发自定义异常,而不是MethodArgumentNotValidException?,java,spring,spring-validator,javax.validation,Java,Spring,Spring Validator,Javax.validation,我有一个@ExceptionHandler(MethodArgumentNotValidException.class),在验证失败时返回HTTP代码400。我创建了一个自定义注释,需要将HTTP代码更改为422。但是,由于异常处理程序已经用@ResponseStatus(code=HttpStatus.BAD_REQUEST)进行了注释,我该怎么做呢 我想也许可以让我的自定义注释抛出一个自定义异常,然后捕获它。可能吗?怎么做 我的建议: @RestControllerAdvice public

我有一个@ExceptionHandler(MethodArgumentNotValidException.class),在验证失败时返回HTTP代码400。我创建了一个自定义注释,需要将HTTP代码更改为422。但是,由于异常处理程序已经用@ResponseStatus(code=HttpStatus.BAD_REQUEST)进行了注释,我该怎么做呢

我想也许可以让我的自定义注释抛出一个自定义异常,然后捕获它。可能吗?怎么做

我的建议:

@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;
  }
}
@RestControllerAdvice
公共级操纵杆{
@自动连线
消息源消息源;
@ResponseStatus(代码=HttpStatus.BAD_请求)
@ExceptionHandler(MethodArgumentNotValidException.class)
公共列表句柄(MethodArgumentNotValidException异常){
List listaDeErros=新建ArrayList();
List fieldErrors=exception.getBindingResult().getFieldErrors();
字段错误。forEach(e->{
字符串mensage=messageSource.getMessage(e,LocaleContextHolder.getLocale());
ErroPadrao erro=新ErroPadrao(e.getField(),mensagem);
添加(erro);
});
返回列表错误;
}
}
我的自定义批注:

@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 {};
}
@约束(validatedBy=ValorUnicoValidator.class)
@目标({FIELD})
@保留(运行时)
public@interface ValorUnico{
String message()默认值“O valor informado jáexiste no banco de dados”;
字符串campo();
类tabela();
布尔removeStrings()默认值为false;
类[]组()默认值{};
塔贝拉类;
私有布尔重投资;
@凌驾
公共无效初始化(ValorUnico ConstraintAnotation){
this.campo=constraintanotation.campo();
this.tabela=constraintanotation.tabela();
this.removeStrings=constraintanotation.removeStrings();
}
@凌驾
公共布尔值有效(对象值、ConstraintValidatorContext上下文){
如果(重新投资){
value=value.toString().replaceAll([^0-9],”);
}
布尔值valorJaExiste=entityManager
.createQuery(“从“+tabela.getName()+”t其中选择计数(t)<1”
+campo+“=:pValor”,布尔类)
.setParameter(“pValor”,值)
.getSingleResult();
返回valorJaExiste;
}
}

我不知道有什么方法可以让验证器抛出自定义异常,有人通过手动抛出自定义异常来解决这个问题(在每个具有相关类型参数的请求映射中);您可以执行他们所做的操作,然后为自定义异常类编写一个
@ExceptionHandler
。不过,我认为还有更好的办法

您可以检查消息以查找在
@ExceptionHandler
中失败的约束,并基于此返回不同的状态代码。(您需要删除
@ResponseStatus
注释并更改该方法的返回类型,但是
@ExceptionHandler
方法有许多允许的返回类型,包括
ResponseEntity
,其状态可以设置为您喜欢的任何内容)

@ExceptionHandler(MethodArgumentNotValidException.class)
公共响应处理有效(方法论证无效){
for(FieldError错误:e.getFieldErrors()){
if(err.getDefaultMessage().equals(“O valor informado jáexiste no banco de dados”)){
返回ResponseEntity.unprocessableEntity().build();
}
}
返回ResponseEntity.badRequest().build();
}

显然,您需要将该消息字符串转换为常量,因为您不需要记住在
@ExceptionHandler
方法和注释本身中对其进行更改。

Hi@neofilis,感谢您的支持!你的解决方案非常适合我的问题。由于它不能回答我的问题,我将等待更多的答案,然后再将其标记为已回答。谢谢
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;
  }
}