繁体   English   中英

Spring bean验证消息解析

[英]Spring bean validation messages resolution

我想做一个非常具体的任务,获取Object每个字段的所有验证消息。 第一项任务很容易,也已经递归地获取了Object所有字段的Annotations (来自thymeleaf的html5val方言的修改代码)

private List<Annotation> fieldAnnotations() {
    Field field = this.fieldFinder.findField(this.targetClass, this.targetFieldName);
    if (field != null) {
        List<Annotation> annotations = Arrays.asList(field.getAnnotations());
        List<Annotation> toAdd = new ArrayList<>();
        for(Annotation a:annotations)
            if(a.annotationType().isAssignableFrom(Valid.class)){
                toAdd.addAll(new AnnotationExtractor(field.getType()).getAnnotationsForField(this.targetFieldName));
            }
            else
                toAdd.add(a);
        return toAdd;
    }
    return Collections.emptyList();
}

现在,我试图通过国际化为每个注释获取消息。

    BeanPropertyBindingResult binding = new BeanPropertyBindingResult(realObject, root);
    for (Annotation constraint : constraints) {
        String message = AnnotationExtractor.getDefaultMessage(constraint);
        binding.rejectValue(fieldName, constraint.annotationType().getSimpleName(), message); 
    }
    List<ObjectError> errors = binding.getAllErrors();
    RequestContext requestContext = (RequestContext) arguments.getContext().getVariables().get(SpringContextVariableNames.SPRING_REQUEST_CONTEXT);
    for(ObjectError e:errors){
        String s =requestContext.getMessage(e, true);
    }

我正在收到国际化的消息,如果MessageSource可以解决某些问题,那就太好了! 令人遗憾的是,但是我无法获取默认消息的消息,例如org.hibernate.validator.constraints.Length.message ,但这并不是问题(我总是可以通过MessageSource提供这些消息)。

为了使此任务完全起作用,我错过了一件事,消息的参数。 因此,已解决的消息如下所示。 Alias length must be between {2} and {1} BeanPropertyBindingResult有一种方法可以拒绝带有参数的值,但是我不知道如何从注释中获取它。 这可能是由Validator实现完成的,对吧?

与Spring DataBinder处理无效字段的工作相同,但是我想在HTML5表单验证中获取此消息以用于自定义验证消息。 有谁知道如何通过Spring内部使用对象推送bean来获取这些消息?

还有一件重要的事,一切都在百里香的背景下(这是我对html5val方言的修改)

解决方案很丑。 完整的解决方案在我的HTML5验证方言的分支中https://bitbucket.org/globalbus/html5-validator-dialect-fork/commits/85da11b2c13dfbd90ff05a55014d792cb453d5e2

首先,我需要SpringValidatorAdapter.getArgumentsForConstraints()公开。

public class MyValidationAdapter extends SpringValidatorAdapter{
public MyValidationAdapter(Validator targetValidator) {
    super(targetValidator);
}
@Override
public Object[] getArgumentsForConstraint(String objectName,
        String field, ConstraintDescriptor<?> descriptor) {
    return super.getArgumentsForConstraint(objectName, field, descriptor);
}
@Override
public void processConstraintViolations(
        Set<ConstraintViolation<Object>> violations, Errors errors) {
    super.processConstraintViolations(violations, errors);
}
}

我们需要为构造Validator提供一个Validator对象。 我们可以从传递给方言的org.thymeleaf.Arguments获取它

this.requestContext = (RequestContext) this.arguments.getContext().getVariables().get(SpringContextVariableNames.SPRING_REQUEST_CONTEXT);

this.validatorFactory = this.requestContext.getWebApplicationContext().getBean(ValidatorFactory.class);

this.validator = new MyValidationAdapter(this.validatorFactory.getValidator());

现在,代码非常混乱

public void processField(Element fieldElement, String fieldName){
    BeanPropertyBindingResult binding = new BeanPropertyBindingResult(
            this.realObject, this.root);
    PropertyDescriptor rootProp = this.beanDescriptor
            .getConstraintsForProperty(fieldName);
    List<PropertyDescriptor> finalProp = new LinkedList<PropertyDescriptor>();
    if (rootProp.isCascaded())// if it's nested, scan all properties for
                            // annotation
        finalProp.addAll(this.validator.getConstraintsForClass(
                rootProp.getElementClass()).getConstrainedProperties());
    else
        finalProp.add(rootProp);
    for (PropertyDescriptor prop : finalProp)
        for (final ConstraintDescriptor<?> desc : prop
                .getConstraintDescriptors()) {
            Annotation constraint = desc.getAnnotation();
            String className = this.beanDescriptor.getElementClass()
                    .getSimpleName();
            className = Character.toLowerCase(className.charAt(0))
                    + className.substring(1);
            String field = className + "." + prop.getPropertyName();
            String errorCode = constraint.annotationType().getSimpleName();
            Object[] errorArgs = this.validator.getArgumentsForConstraint(
                    this.root, field, desc);
            String message = (String) desc.getAttributes().get(ANNOTATION_MESSAGE);
            if (INTERNAL.matcher(message).find())
                message = this.validatorFactory.getMessageInterpolator().interpolate(
                        message, new Context() {

                            public Object getValidatedValue() {
                                return null;
                            }

                            public ConstraintDescriptor<?> getConstraintDescriptor() {
                                return desc;
                            }
                        });
            String[] errorCodes = binding.resolveMessageCodes(errorCode,
                    field);
            binding.addError(new FieldError(binding.getObjectName(), prop
                    .getPropertyName(), null, false, errorCodes, errorArgs,
                    message));
        }

    List<ObjectError> errors = binding.getAllErrors();
    StringBuilder customValidation = new StringBuilder();
    for (ObjectError e : errors) {
        String s = this.requestContext.getMessage(e, true);
        customValidation.append(s);
        if (!s.endsWith("."))
            customValidation.append(". ");

    }
    String onInvalid = String.format("this.setCustomValidity('%s')",
            customValidation.toString());
    fieldElement.setAttribute(ONINVALID_ATTR, onInvalid);
    fieldElement.setAttribute(ONCHANGE_ATTR, "this.setCustomValidity('')");
}

线索位于SpringValidatorAdapter.getArgumentsForConstraints() ,带有有效参数,可以提供用于消息解析的参数。 内部Hibernate消息可由MessageInterpolator.interpolate()提供。最终解决方案由RequestContext.getMessage()

这不是“干净的解决方案”,我必须在更多用例中对其进行测试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM