自定义注释可以抛出自定义异常,而不是 MethodArgumentNotValidException?
A custom annotation can throw a custom exception, rather than MethodArgumentNotValidException?
我有一个@ExceptionHandler(MethodArgumentNotValidException.class),当验证失败时returns 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
中失败的约束的消息,以及基于此的 return 不同的状态代码。 (您需要删除 @ResponseStatus
注释并更改方法的 return 类型,但是 @ExceptionHandler
方法有许多允许的 return 类型——包括 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
方法和注释本身中更改它。
我有一个@ExceptionHandler(MethodArgumentNotValidException.class),当验证失败时returns 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;
}
}
我不知道有什么方法可以让验证器抛出自定义异常。 @ExceptionHandler
。不过,我认为还有更好的方法。
您可以检查 @ExceptionHandler
中失败的约束的消息,以及基于此的 return 不同的状态代码。 (您需要删除 @ResponseStatus
注释并更改方法的 return 类型,但是 @ExceptionHandler
方法有许多允许的 return 类型——包括 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
方法和注释本身中更改它。