我有一个自定义验证器,需要包含消息参数来动态构造错误消息。
public class DescriptionLengthValidator
implements ConstraintValidator<ValidTypeDescriptionLength, RequestDto> {
@Override
public boolean isValid(RequestDto request, ConstraintValidatorContext context) {
int maxSize = request.getType().equals("Category1") ? 50 : 250;
boolean isValid = request.getDescription().length() <= maxSize;
if (!isValid) {
HibernateConstraintValidatorContext hibernateContext =
context.unwrap(HibernateConstraintValidatorContext.class);
hibernateContext.disableDefaultConstraintViolation();
hibernateContext.addMessageParameter("0", "0").addMessageParameter("1", maxSize)
.buildConstraintViolationWithTemplate("error.Size").addPropertyNode("description")
.addConstraintViolation();
return false;
}
return true;
}
}
注解定义如下。
@Constraint(validatedBy = DescriptionLengthValidator.class)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidTypeDescriptionLength {
String message() default "error.Size";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
控制器建议如下。
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
Map<String, String> fieldErrors = ex.getBindingResult().getFieldErrors().stream().collect(
Collectors.toMap(FieldError::getField, fe -> getFieldErrorMessage(fe,
String.format("Invalid value [%s]", fe.getRejectedValue()))));
return handleFieldValidationErrors(ex, status, request, fieldErrors);
}
private String getFieldErrorMessage(FieldError error, String defaultMessage) {
Object[] args = error.getArguments();
if (args != null && args.length > 0 && args[0] instanceof MessageSourceResolvable) {
args = Arrays.copyOfRange(args, 1, args.length);
}
List<String> errorCodes = new ArrayList<>();
if (error.getCodes() != null) {
Arrays.stream(error.getCodes()).map(s -> "error." + s).forEach(errorCodes::add);
}
if (error.getDefaultMessage() != null) {
errorCodes.add(error.getDefaultMessage());
}
return service.getMessage(args, defaultMessage);
}
}
通过调用 error.getArguments() 访问参数时,消息参数不可用。如何修改自定义验证器/控制器建议以访问按摩参数?
错误
error.getArguments()
的论据不是你想的那样。他们告诉你 MethodArgumentNotValidException
的哪些论点是无效的。不是消息的参数。
error.getDefaultMessage()
应该已经返回带有注入参数的完整消息。这就是它应该如何工作,这就是 hibernate 为自己的验证器实现它的方式。
例如,请参见 here(messages.properties)和 there(注释)。您还可以使用标准 @Min
和 @Max
,您将看到该值自动注入到消息中 error.getDefaultMessage()
我认为你的错误是默认消息缺少大括号
@Constraint(validatedBy = DescriptionLengthValidator.class)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidTypeDescriptionLength {
String message() default "{error.Size}"; // here
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
那么请在您的
messages.properties
中检查一下。错误消息中应该包含您使用的参数化占位符名称 addMessageParameter(name, value)
error.Size=Error size. Should be between {0} and {1}
此时
error.getDefaultMessage()
应返回 Error size. Should be between 0 and 250
或 Error size. Should be between 0 and 50