问题描述
我正在尝试通过Spring 3.0为Hibernate Validator 4.1设置自定义消息源.我已经设置了必要的配置:
I'm trying to set up a custom message source for Hibernate Validator 4.1 through Spring 3.0. I've set up the necessary configuration:
<!-- JSR-303 -->
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="validationMessageSource" ref="messageSource"/>
</bean>
翻译是从我的消息源提供的,但似乎在消息源中查找了消息本身中的替换令牌,即:a:
The translations are served from my message source, but it seems that the replacement tokens in the messages themselves are looked up in the message source, i.e. for a:
my.message=the property {prop} is invalid
在messageSource中有调用以查找"prop".进入我注意到Javadoc指出:
there are calls to look up 'prop' in the messageSource. Going into ResourceBundleMessageInterpolator.interpolateMessage
I note that the javadoc states:
注意: 用户包中的查询是递归的,而默认包中的查询不是递归的!
Note: Look-ups in user bundles is recursive whereas look-ups in default bundle are not!
在我看来,递归将始终针对用户指定的包进行,因此实际上我无法翻译像Size消息那样的标准消息.
This looks to me like the recursion will always take place for a user-specified bundle, so in effect I can not translate standard messages like the one for Size.
如何插入自己的消息源并能够在消息中替换参数?
How can I plug-in my own message source and be able to have parameters be replaced in the message?
推荐答案
Hibernate Validator的ResourceBundleMessageInterpolator创建两个ResourceBundleLocator实例(即PlatformResourceBundleLocator),一个实例用于UserDefined验证消息-userResourceBundleLocator,另一个用于JSR-303标准验证消息-defaultResourceBundleLocator.
Hibernate Validator's ResourceBundleMessageInterpolator create two instances of ResourceBundleLocator (i.e. PlatformResourceBundleLocator) one for UserDefined validation messages - userResourceBundleLocator and the other for JSR-303 Standard validation messages - defaultResourceBundleLocator.
出现在两个大括号内的任何文本,例如消息中的{someText}
被视为replaceToken. ResourceBundleMessageInterpolator尝试找到可以替换ResourceBundleLocators中的replacementToken的匹配值.
Any text that appears within two curly braces e.g. {someText}
in the message is treated as replacementToken. ResourceBundleMessageInterpolator tries to find the matching value which can replace the replacementToken in ResourceBundleLocators.
- 首先在UserDefinedValidationMessages中(递归),
- 然后在DefaultValidationMessages中(这不是递归的).
因此,如果将标准JSR-303消息放入自定义ResourceBundle中,例如validation_erros.properties
,它将被您的自定义消息替换.请参见示例标准NotNull验证消息可能不为空"替换为自定义"MyNotNullMessage"消息.
So, if you put a Standard JSR-303 message in custom ResourceBundle say, validation_erros.properties
, it will be replaced by your custom message. See in this EXAMPLE Standard NotNull validation message 'may not be null' has been replaced by custom 'MyNotNullMessage' message.
在经历了两个ResourceBundleLocator之后,ResourceBundleMessageInterpolator在resolveMessage(由两个包都解析)中查找更多replaceTokens.这些replaceToken只不过是 Annotation属性的名称,如果在resolveMessage中找到了此类replaceToken,它们就会由匹配的Annotation属性的值替换.
After going through both ResourceBundleLocators, ResourceBundleMessageInterpolator finds for more replaceTokens in the resolvedMessage (resolved by both bundles). These replacementToken are nothing but the names of Annotation's attributes, if such replaceTokens are found in the resolvedMessage, they are replaced by the values of matching Annotation attributes.
ResourceBundleMessageInterpolator.java [第168行,4.1.0.Final]
resolvedMessage = replaceAnnotationAttributes( resolvedMessage, annotationParameters );
提供了一个用自定义值替换{prop}的示例,希望对您有帮助....
Providing an example to replace {prop} with custom value, I hope it will help you....
MyNotNull.java
@Constraint(validatedBy = {MyNotNullValidator.class})
public @interface MyNotNull {
String propertyName(); //Annotation Attribute Name
String message() default "{myNotNull}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default {};
}
MyNotNullValidator.java
public class MyNotNullValidator implements ConstraintValidator<MyNotNull, Object> {
public void initialize(MyNotNull parameters) {
}
public boolean isValid(Object object, ConstraintValidatorContext constraintValidatorContext) {
return object != null;
}
}
User.java
class User {
private String userName;
/* whatever name you provide as propertyName will replace {propertyName} in resource bundle */
// Annotation Attribute Value
@MyNotNull(propertyName="userName")
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
validation_errors.properties
notNull={propertyName} cannot be null
测试
public void test() {
LocalValidatorFactoryBean factory = applicationContext.getBean("validator", LocalValidatorFactoryBean.class);
Validator validator = factory.getValidator();
User user = new User("James", "Bond");
user.setUserName(null);
Set<ConstraintViolation<User>> violations = validator.validate(user);
for(ConstraintViolation<User> violation : violations) {
System.out.println("Custom Message:- " + violation.getMessage());
}
}
输出
Custom Message:- userName cannot be null
这篇关于将自定义ResourceBundle与Hibernate Validator结合使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!