2010-11-18 76 views
3

我正在使用JSR-303进行验证和Spring MVC 3.验证是通过控制器中的validator.validate(bean, errors)手动完成的。Spring验证错误生成

我注释了Foo类的name属性@NotNull。当验证失败时,我注意到Spring MVC在Errors对象中生成了以下错误代码。

NotNull.form.foo.name 
NotNull.name 
NotNull.java.lang.String 
NotNull 

<form:errors>标签的工作方式是,它会经过所有的错误代码和查找默认的资源包,直到它返回一个非空的消息。有什么方法可以自定义这些错误代码或至少它们列出的顺序?

原因是我有一个自定义ResourceBundle对象,如果在资源包文本文件中找不到任何内容,该对象将返回从给定消息代码派生的默认消息。由于该标签在错误代码列表上向下,因此在本例中它将首先查找NotNull.form.foo.name。该文本文件当然没有这个条目,所以自定义ResourceBundle对象将返回一个默认消息。问题是,我已经在文本文件中为NotNull定义了一条消息,但是标签会看到它。

如果我可以以某种方式生成只有一个错误代码,或颠倒错误代码的顺序,它会工作。

有什么想法?谢谢。

+0

我不相信任何以下工作解决方案,而这一点:在你的春天建立... – markthegrea 2011-01-24 19:49:26

回答

2

找不到比这更简单的解决方案...

我-servlet.xml中

<bean id="handlerAdapter" class="org.opensource.web.StandardAnnotationMethodHandlerAdapter"> 
</bean> 

StandardAnnotationMethodHandlerAdapter.java

public class StandardAnnotationMethodHandlerAdapter extends AnnotationMethodHandlerAdapter { 
    @Override 
    protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object target, String objectName) throws Exception { 
    MyServletRequestDataBinder dataBinder = new MyServletRequestDataBinder(target, objectName); 
    return dataBinder; 
    } 
} 

MyServletRequestDataBinder。java的

public class MyServletRequestDataBinder extends ServletRequestDataBinder { 

private MessageCodesResolver messageCodesResolver = new MyMessageCodesResolver(); 

@Override 
public void initBeanPropertyAccess() { 
    super.initBeanPropertyAccess(); 
    BindingResult bindingResult = super.getBindingResult(); 
    if(bindingResult instanceof AbstractBindingResult) { 
     ((AbstractBindingResult)bindingResult).setMessageCodesResolver(messageCodesResolver); 
    } 
} 

@Override 
public void initDirectFieldAccess() { 
    super.initDirectFieldAccess(); 
    BindingResult bindingResult = super.getBindingResult(); 
    if(bindingResult instanceof AbstractBindingResult) { 
    ((AbstractBindingResult)bindingResult).setMessageCodesResolver(messageCodesResolver); 
    } 
} 
} 

MyMessageCodesResolver的.java

public class MyMessageCodesResolver extends DefaultMessageCodesResolver { 

public static final String NOT_NULL_ERROR_CODE = "NotNull"; 

@Override 
public String[] resolveMessageCodes(String errorCode, String objectName, String field, Class fieldType) { 
    if(NOT_NULL_ERROR_CODE.equalsIgnoreCase(errorCode)) { 
     String notNullErrorCode = errorCode + CODE_SEPARATOR + objectName + CODE_SEPARATOR + field; 
     //notNullErrorCode = postProcessMessageCode(notNullErrorCode); 
     return new String[] {notNullErrorCode}; 
    } 
     return super.resolveMessageCodes(errorCode, objectName, field, fieldType); 
} 
} 
2

我使用下面的类来使用Spring验证器手动执行JSR-303和HibernateValidator bean验证。也许它可能有用。

BeanValidator.java

import java.util.Locale; 
import java.util.Set; 
import javax.validation.ConstraintViolation; 
import javax.validation.Validation; 
import javax.validation.Validator; 
import javax.validation.ValidatorFactory; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.beans.factory.InitializingBean; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.context.MessageSource; 
import org.springframework.context.NoSuchMessageException; 
import org.springframework.stereotype.Component; 
import org.springframework.validation.Errors; 

public class BeanValidator implements org.springframework.validation.Validator, InitializingBean { 

private static final Logger log = LoggerFactory.getLogger(BeanValidator.class.getName()); 

private Validator validator; 

@Autowired 
MessageSource messageSource; 

@Override 
public void afterPropertiesSet() throws Exception { 
    ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); 
    validator = validatorFactory.usingContext().getValidator(); 
} 

@Override 
public boolean supports(Class clazz) { 
    return true; 
} 

@Override 
public void validate(Object target, Errors errors) { 
    Set<ConstraintViolation<Object>> constraintViolations = validator.validate(target); 
    for (ConstraintViolation<Object> constraintViolation : constraintViolations) { 
     String propertyPath = constraintViolation.getPropertyPath().toString(); 
     String message; 
     try { 
      message = messageSource.getMessage(constraintViolation.getMessage(), new Object[]{}, Locale.getDefault()); 
     } catch (NoSuchMessageException e) { 
      log.error(String.format("Could not interpolate message \"%s\" for validator. " 
        + e.getMessage(), constraintViolation.getMessage()), e); 
      message = constraintViolation.getMessage(); 
     } 
     errors.rejectValue(propertyPath, "", message); 
    } 
} 
} 

SpringMessageSourceMessageInterpolator.java

import javax.validation.MessageInterpolator; 
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; 
import org.springframework.beans.factory.InitializingBean; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.context.MessageSource; 
import org.springframework.context.MessageSourceAware; 
import org.springframework.context.NoSuchMessageException; 

public class SpringMessageSourceMessageInterpolator extends ResourceBundleMessageInterpolator implements MessageInterpolator, MessageSourceAware, InitializingBean { 

@Autowired 
private MessageSource messageSource; 

@Override 
public String interpolate(String messageTemplate, Context context) { 
    try { 
     return messageSource.getMessage(messageTemplate, new Object[]{}, Locale.getDefault()); 
    } catch (NoSuchMessageException e) { 
     return super.interpolate(messageTemplate, context); 
    } 
} 

@Override 
public String interpolate(String messageTemplate, Context context, Locale locale) { 
    try { 
     return messageSource.getMessage(messageTemplate, new Object[]{}, locale); 
    } catch (NoSuchMessageException e) { 
     return super.interpolate(messageTemplate, context, locale); 
    } 
} 

@Override 
public void setMessageSource(MessageSource messageSource) { 
    this.messageSource = messageSource; 
} 

@Override 
public void afterPropertiesSet() throws Exception { 
    if (messageSource == null) { 
     throw new IllegalStateException("MessageSource was not injected, could not initialize " 
       + this.getClass().getSimpleName()); 
    } 
} 
} 

的applicationContext.xml

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource" p:basename="messages"/> 

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> 
    <property name="messageInterpolator"> 
     <bean class="com.company.utils.spring.SpringMessageSourceMessageInterpolator" /> 
    </property> 
</bean> 

例bean属性

@NotNull(message = "validation.mandatoryField") 
private ClientGroup clientGroup; 

实例验证

@Controller 
public class MyController { 

    @Autowired 
    private BeanValidator validator; 

    @RequestMapping("/foo", method=RequestMethod.POST) 
    public void processFoo(ModelAttribute("foo") Foo foo, BindingResult result, Model model) { 
     //... 
     validator.validate(foo, result); 
    } 
}