访问从自定义验证器传递的控制器建议中的消息参数

问题描述 投票:0回答:1

我有一个自定义验证器,需要包含消息参数来动态构造错误消息。

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() 访问参数时,消息参数不可用。如何修改自定义验证器/控制器建议以访问按摩参数?

java spring spring-boot spring-annotations hibernate-validator
1个回答
0
投票

错误

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

© www.soinside.com 2019 - 2024. All rights reserved.