Java springbean验证消息解析

Java springbean验证消息解析,java,spring,bean-validation,thymeleaf,Java,Spring,Bean Validation,Thymeleaf,我想做一个非常具体的任务,获取对象中每个字段的所有验证消息。 第一个任务很简单,获取对象中字段的所有注释,同样是递归的,已经完成了。 (修改了html5val方言中用于thymeleaf的代码) 私有列表字段注释(){ Field Field=this.fieldFinder.findField(this.targetClass,this.targetFieldName); 如果(字段!=null){ List annotations=Arrays.asList(field.getAnnotat

我想做一个非常具体的任务,获取
对象中每个字段的所有验证消息。
第一个任务很简单,获取
对象
中字段的所有
注释
,同样是递归的,已经完成了。 (修改了html5val方言中用于thymeleaf的代码)

私有列表字段注释(){
Field Field=this.fieldFinder.findField(this.targetClass,this.targetFieldName);
如果(字段!=null){
List annotations=Arrays.asList(field.getAnnotations());
List toAdd=new ArrayList();
对于(注释a:注释)
if(a.annotationType().isAssignableFrom(Valid.class)){
toAdd.addAll(新的AnnotationExtractor(field.getType()).getAnnotationsForField(this.targetFieldName));
}
其他的
添加(a);
返回添加;
}
返回集合。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);
    }
BeanPropertyBindingResult绑定=新的BeanPropertyBindingResult(realObject,root);
用于(注释约束:约束){
字符串消息=AnnotationExtractor.getDefaultMessage(约束);
binding.rejectValue(字段名,约束。注释类型()。getSimpleName(),消息);
}
列表错误=binding.getAllErrors();
RequestContext RequestContext=(RequestContext)参数.getContext().getVariables().get(SpringContextVariableNames.SPRING_请求_上下文);
for(ObjectError e:errors){
字符串s=requestContext.getMessage(e,true);
}
我收到的是国际化的消息,如果有什么问题可以通过
MessageSource
解决,那就太好了! 遗憾的是,我无法获取默认消息的消息,如
org.hibernate.validator.constraints.Length.message
,但问题并不大(我总是可以通过
MessageSource
提供这些消息)

为了使这项任务完全工作,我错过了一件事,消息的参数。所以,解析的消息如下所示。
别名长度必须介于{2}和{1}
BeanPropertyBindingResult
有一个拒绝带有参数的值的方法,但我不知道如何从注释中获取它。它可能是由
验证程序
实现完成的,对吗

这与SpringDataBinder对无效字段所做的工作相同,但我希望在HTML5表单验证中为自定义验证消息获取这些消息。有人知道如何通过Spring内部使用对象推送bean来获取这些消息吗

还有一件重要的事,一切都是在thymeleaf上下文中(这是我对html5val方言的修改)

解决方案很难看。 完整的解决方案在我的HTML5验证方言中

首先,我需要
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);
}
}
现在,真是乱七八糟的代码

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('')");
}
public void processField(元素fieldElement,字符串fieldName){
BeanPropertyBindingResult绑定=新的BeanPropertyBindingResult(
this.realObject、this.root);
PropertyDescriptor rootProp=this.beanDescriptor
.getConstraintsForProperty(字段名);
List finalProp=newlinkedlist();
if(rootProp.isCascaded())//如果它是嵌套的,请扫描所有属性以查找
//注释
finalProp.addAll(this.validator.getConstraintsForClass(
getElementClass()).getConstrainedProperties());
其他的
finalProp.add(rootProp);
对于(PropertyDescriptor属性:finalProp)
对于(最终约束描述者描述:道具
.getConstraintDescriptors()){
注释约束=desc.getAnnotation();
String className=this.beandDescriptor.getElementClass()
.getSimpleName();
className=Character.toLowerCase(className.charAt(0))
+子字符串(1);
字符串字段=className+“+prop.getPropertyName();
String errorCode=constraint.annotationType().getSimpleName();
Object[]errorArgs=this.validator.getArgumentsForConstraint(
这是(根、字段、描述);
字符串消息=(字符串)desc.getAttributes().get(注释消息);
if(内部.matcher(message.find())
message=this.validatorFactory.getMessageInterpolator().interpolate(
消息,新上下文(){
公共对象getValidatedValue(){
返回null;
}
public ConstraintDescriptor getConstraintDescriptor(){
返回描述;
}
});
String[]errorCodes=binding.resolveMessageCodes(errorCode,
字段);
binding.addError(新字段错误)(binding.getObjectName(),prop
.getPropertyName(),null,false,errorCodes,errorArgs,
讯息);;
}
列表错误=binding.getAllErrors();
StringBuilder customValidation=新建StringBuilder();
for(ObjectError e:errors){
字符串s=this.requestContext.getMessage(e,true);
customValidation.append(s);
如果(!s.endsWith(“.”)
customValidation.append(“.”);
}
String onInvalid=String.format(“this.setCustomValidity(“%s”)”,
customValidation.toString());
setAttribute(ONINVALID_ATTR,ONINVALID);
fieldElement.setAttribute(ONCHANGE_ATTR,“this.setCustomValidity(“”)”);
}
线索位于SpringValidatorAdapter中。getArgumentsForConstraints()
具有有效参数,可以为消息解析提供参数。 内部休眠消息可由
MessageInterpolator.interpolate()提供
最后的解决方案由
RequestContext提供
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('')");
}