在我的自定义注释中,我正在使用我要允许发送邮件的域
@Documented
@Constraint(validatedBy = ValidEmail.CheckIfValidMail.class)
//@Constraint(validatedBy = {})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
//@Repeatable(List.class)
@Retention(RUNTIME)
@Component
public @interface ValidEmail {
String message() default "Invalid String !!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@interface List {
ValidEmail[] value();
}
@Component
public class CheckIfValidMail implements ConstraintValidator<ValidEmail, String> {
@Autowired
UserServiceImplOld userServiceImpl;
// @Value("${app.mail.allowedDomains:gmail}")
private String[] allowedDomainsForMail;
@Value("${app.mail.allowedDomains:gmail}")
public void setAllowedDomainsForMail(String[] allowedDomainsForMail) {
this.allowedDomainsForMail = allowedDomainsForMail;
}
// private String[] allowedDomainsForMail = new String[] { "gmail", "rediffmail", "yahoo" };
protected String message;
@Override
public void initialize(ValidEmail validEmail) {
this.message = validEmail.message() + " Allowed Domain(s): " + Arrays.toString(allowedDomainsForMail);
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null)
return true;
String allowedDomainRegEx = String.join("|", allowedDomainsForMail);
String mailRegex = "^(?i)[A-Za-z0-9+_.-]+@(?:" + allowedDomainRegEx + ")\\.(?:.*)$";
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
return value.matches(emailRegex);
}
}
}
如果我从rest API调用此值,则每次存在该值时,但是如果我从代码中显式调用验证,则可以在调试中看到allowedMailDomains值为null
但是,如果我不使用属性文件和硬编码,则这两个时间都可以正常工作
Dto对象
@Data //lombok
public class UserDto{
@ValidEmail(message = "Wrong emailId format !!")
private String emailId;
@NotNull
private Boolean isLoginAllowed;
}
正在实施
UserDto addUserDto = new UserDto();
addUserDto.setEmailId("satish");
addUserDto.setisLoginAllowed(false);
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
System.out.println("Validating :-\n" + validator.validate(addUserDto));
因此,在验证时,它进入ValidMail接口,并且allowedMailDomains值为null
所以这里是问题:
在REST
API中运行代码时,您正在Spring容器中运行,该容器将CheckIfValidMail
初始化为Component
,然后从Spring
容器中获取所有值和所有内容需要。
以编程方式初始化它时,它没有初始化为Component
,也没有Container
来获取@Value
,我什至会怀疑Properties
是否已完全加载在第二种情况下(我看不到完整的代码,所以我不确定)。
没有完整的上下文,这是我头上的解决方案:
在验证器中执行此操作:
private String[] allowedMailDomains;
@Value("${poss.mail.allowedDomains:gmail}")
public void setAllowedMailDomains(String[] allowedMailDomains) {
this.allowedMailDomains = allowedMailDomains;
}
然后在程序验证中设置该值,然后该值将起作用。
否则,只需将其初始化在容器中,然后应将其修复。
尝试注册LocalValidatorFactoryBean
并使用它代替Validation.buildDefaultValidatorFactory()
。 LocalValidatorFactoryBean
应该允许您在验证程序中获得依赖项注入的好处。
默认情况下,LocalValidatorFactoryBean配置一个SpringConstraintValidatorFactory,该工厂使用Spring创建ConstraintValidator实例。这使您的自定义ConstraintValidators可以像其他任何Spring bean一样受益于依赖项注入。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@Configuration
public class ValidatorConfiguration {
@Bean
public ValidatorFactory localValidatorFactoryBean() {
return new LocalValidatorFactoryBean();
}
}
然后在您的实现类中自动装配该bean:
@Autowired
private ValidatorFactory validatorFactory;
并使用它代替DefaultValidatorFactory
:
Validator validator = validatorFactory.getValidator();
validator.validate(addUserDto);
要注入属性allowedMailDomains,您的类CheckIfValidMail必须是bean。因此,如果在类中添加@ Component批注(例如),该问题将得到解决。