我正在使用JSR-303进行验证和Spring MVC 3.验证是通过控制器中的validator.validate(bean, errors)
手动完成的。
我使用name
注释了Foo
类的@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 :(得分: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);
}
}
答案 1 :(得分: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);
}
}