Grails 3.3.10自定义约束注册后不生效问题求助
解决Grails 3.3.10自定义约束失效问题
我帮你梳理一下几个关键的问题点,这些应该就是导致自定义约束失效的核心原因:
1. 约束支持的类型不匹配
你的DateOfBirthConstraint类里的supports方法返回的是支持String类型,但你实际在IdentityCO里把约束用在了Date类型的dateOfBirth属性上——这就导致GORM在验证时直接跳过了这个约束,因为它认为这个约束不适用当前属性类型。
修复方法:修改supports方法,让它支持Date类型:
@Override public boolean supports(Class type) { return type != null && Date.class.isAssignableFrom(type); }
2. isValid方法的逻辑错误
你的isValid方法不仅返回类型错误(应该是boolean而不是void),而且判断逻辑完全写反了:
- 当前代码中,当日期有效时,
isValid会返回false,导致processValidate里的if (isValid(propertyValue))不会触发错误提示 - 同时方法的参数也没有声明类型
修复后的isValid方法:
protected boolean isValid(Object propertyValue) { if (!(propertyValue instanceof Date)) { return false; } Date dobDate = (Date) propertyValue; int dobYear = SimpleInteractDateUtils.getYear(dobDate); // 有效条件:年份在范围内,且日期早于今天零点 return YEAR_RANGE.contains(dobYear) && dobDate.before(new Date().clearTime()); }
3. 约束注册方式不正确
Grails 3.x的GORM验证系统改用了工厂模式来创建约束实例,直接调用addConstraint(DateOfBirthConstraint)是无法正确实例化约束的,必须通过对应的ConstraintFactory来注册。
步骤1:创建约束工厂类
package com.simpleinteract.constraints import org.grails.datastore.gorm.validation.constraints.ConstraintFactory import org.springframework.context.MessageSource class DateOfBirthConstraintFactory implements ConstraintFactory { private final MessageSource messageSource DateOfBirthConstraintFactory(MessageSource messageSource) { this.messageSource = messageSource } @Override DateOfBirthConstraint newInstance(Class<?> constraintOwningClass, String constraintPropertyName, Object constraintParameter) { return new DateOfBirthConstraint(constraintOwningClass, constraintPropertyName, constraintParameter, messageSource) } }
步骤2:修改Bootstrap中的注册逻辑
import com.simpleinteract.constraints.DateOfBirthConstraint import com.simpleinteract.constraints.DateOfBirthConstraintFactory import org.grails.datastore.gorm.validation.constraints.ConstraintRegistry class BootStrap { ConstraintRegistry gormValidatorRegistry MessageSource messageSource // 注入Spring的消息源 def init = { servletContext -> // 注册约束工厂,关联约束名称 gormValidatorRegistry.addConstraint(DateOfBirthConstraint.CONSTRAINT_NAME, new DateOfBirthConstraintFactory(messageSource)) } }
4. processValidate的判断逻辑修正
原来的代码中,当isValid返回true时才触发错误,这和预期完全相反——应该是当验证不通过(isValid返回false)时,才拒绝当前值:
@Override protected void processValidate(Object target, Object propertyValue, Errors errors) { if (!dob) { return; } // 验证不通过时才触发错误 if (!isValid(propertyValue)) { Object[] args = [constraintPropertyName, constraintOwningClass.simpleName, propertyValue] rejectValue(target, errors, DEFAULT_MESSAGE_CODE, CONSTRAINT_NAME + "." + DEFAULT_CODE, args); } }
最后验证
完成以上修改后,你可以重新启动应用,测试IdentityCO的验证逻辑:
def invalidIdentity = new IdentityCO(dateOfBirth: new Date()) // 今天的日期,应该触发约束错误 invalidIdentity.validate() assert invalidIdentity.hasErrors() assert invalidIdentity.errors.hasFieldError('dateOfBirth')
内容的提问来源于stack exchange,提问作者Kanika Sahu
相关产品推荐
相关产品推荐

