簡體   English   中英

當第二次調用 class 方法時,@Value 字段顯示 null

[英]@Value field is showing null when second time the class method is called

在我的自定義注釋中,我正在使用我將允許郵件的域

@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 值是 Z37A6259CC0C1DAE299A7866489DFFBD0

但是,如果我沒有從屬性文件和硬編碼中獲取,那么它就像這樣同時工作

Dto object

@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

嘗試注冊LocalValidatorFactoryBean並使用它而不是Validation.buildDefaultValidatorFactory() LocalValidatorFactoryBean應該允許您在驗證器中獲得依賴注入的好處。

UPD: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#validation-beanvalidation-spring-constraints

默認情況下,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();
    }
}

然后在您的實現 class 中自動裝配此 bean:

@Autowired
private ValidatorFactory validatorFactory;

並使用它代替DefaultValidatorFactory

Validator validator = validatorFactory.getValidator();
validator.validate(addUserDto);

要注入屬性allowedMailDomains ,您的 class CheckIfValidMail必須是一個 bean。 因此,如果您在 class 中添加@Component注釋(例如),問題將得到解決。

所以這里是問題:

  • When running the code in the REST API, you are running in a Spring container which initializes the CheckIfValidMail as a Component , which then get's all the values and everything from the Spring container that it needs.

  • 當您以編程方式對其進行初始化時,它沒有被初始化為Component ,並且也沒有Container可以從中獲取@Value ,我什至懷疑在第二種情況下完全加載了Properties (我看不到整個代碼所以我不確定)。

如果沒有完整的上下文,這是我頭頂的一個解決方案:

在驗證器中執行以下操作:

private String[] allowedMailDomains;

@Value("${poss.mail.allowedDomains:gmail}")
public void setAllowedMailDomains(String[] allowedMailDomains) {
    this.allowedMailDomains = allowedMailDomains;
}

然后在您的程序驗證中設置該值,這應該可以工作。

否則,只需在容器中初始化它就可以修復它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM