복붙노트

[SPRING] Spring Boot - Hibernate 커스텀 제약이 서비스를 삽입하지 않는다.

SPRING

Spring Boot - Hibernate 커스텀 제약이 서비스를 삽입하지 않는다.

나는 다른 세부 사항을 무시하고 그것을 짧게하려고 노력할 것이다 :

@Entity
public class User
    @UniqueEmail
    @Column(unique = true)
    private String email;
}

@Component
public class UniqueEmailValidatior implements ConstraintValidator<UniqueEmail,String>, InitializingBean {

    @Autowired private UserService userService;

    @Override
    public void initialize(UniqueEmail constraintAnnotation) {

    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if(userService == null) throw new IllegalStateException();
        if(value == null) return false;
        return !userService.isEmailExisted(value);
    }

}

이 작업은 Spring에서 유효성 검사 (Spring MVC @Valid 또는 @Autowire를 사용하여 유효성 검사기를 삽입 할 때)가 작동 할 때 모든 것이 정상적으로 작동합니다. 그러나 Spring Data JPA를 사용하여 엔티티를 저장하자마자 :

User save = userRepository.save(newUser);

Hibernate는 UserService 빈을 삽입하지 않고 새로운 UniqueEmailValidatior를 인스턴스화하려고 시도 할 것이다. 그렇다면 어떻게하면 Hibernate가 새로운 UniqueEmailValidatior 컴포넌트를 사용하도록 만들 수 있습니까? spring.jpa.properties.javax.persistence.validation.mode = none을 사용하여 최대 절전 모드 유효성 검사를 비활성화 할 수 있지만 다른 방법이 있기를 바랍니다.

업데이트 : 내 UserService는 다음과 같습니다.

   @Autowired private Validator validator;
   @Transactional
    public SimpleUserDTO newUser(UserRegisterDTO user) {
        validator.validate(user);
        System.out.println("This passes");
        User newUser = new User(user.getUsername(),
                passwordEncoder.encode(user.getPassword()),user.getEmail(),
                "USER",
                user.getAvatar());
        User save = userRepository.save(newUser);
        System.out.println("This won't pass");
        return ....
    }

해결법

  1. ==============================

    1.스프링 부트가 기존의 유효성 검사기를 EntityManager에 연결하는 것으로 예상 할 수 있습니다.

    스프링 부트가 기존의 유효성 검사기를 EntityManager에 연결하는 것으로 예상 할 수 있습니다.

    HibernatePropertiesCustomizer를 사용하고 기존 EntityManagerFactoryBuilder에 속성을 추가하고 유효성 검사기를 등록 할 수 있습니다.

    참고 : 여기서는 스프링 부트 2.0을 사용하고 있다고 가정합니다.

    @Component
    public class ValidatorAddingCustomizer implements HibernatePropertiesCustomizer {
    
        private final ObjectProvider<javax.validation.Validator> provider;
    
        public ValidatorAddingCustomizer(ObjectProvider<javax.validation.Validator> provider) {
            this.provider=provider;
        }
    
        public void customize(Map<String, Object> hibernateProperties) {
            Validator validator = provider.getIfUnique();
            if (validator != null) {
                hibernateProperties.put("javax.persistence.validation.factory", validator);
            }
        }
    }
    

    이런 식으로 기존 유효성 검사기를 최대 절전 모드로 연결하고 자동 배선을 사용합니다.

    참고 : 유효성 검사기에서 @Component를 사용할 필요가 없습니다. 자동 배선은 유효성 검사기 인스턴스를 반환하기 전에 유효성 검사기 팩토리에 빌드됩니다.

  2. ==============================

    2.Spring Bean을 ConstraintValidator에 삽입하려면 ValidatorFactory 초기화시 전달되어야하는 특정 ConstraintValidatorFactory가 필요하다.

    Spring Bean을 ConstraintValidator에 삽입하려면 ValidatorFactory 초기화시 전달되어야하는 특정 ConstraintValidatorFactory가 필요하다.

    의 라인을 따라 뭔가 :

    ValidatorFactory validatorFactory = Validation.byDefaultProvider()
        .configure()
        .constraintValidatorFactory( new MySpringAwareConstraintValidatorFactory( mySpringContext ) )
        .build();
    

    MySpringAwareConstraintValidatorFactory는 ConstraintValidator 내에 빈을 삽입하는 ConstraintValidatorFactory입니다.

    나는 스프링 데이터에 의해 사용되는 ValidatorFactory가 그들을 생성 할 때 밸리데이터를 삽입하지 않는다고 생각하는데, 이는 불행한 일이다.

    나는 당신이 그것을 무시할 수 있어야한다고 생각합니다. 또는, Spring Boot / Spring Data에 대한 이슈를 열어 두 번째로 ConstraintValidators를 제대로 주입 할 수있게해야합니다.

  3. ==============================

    3.대답은 여기에 게시하는 데 아주 큽니다. S.O에서이 기사를 확인하십시오. 이것은 당신이 시작하는 데 도움이됩니다.

    대답은 여기에 게시하는 데 아주 큽니다. S.O에서이 기사를 확인하십시오. 이것은 당신이 시작하는 데 도움이됩니다.

    Autowired spring 서비스로 맞춤형 검사기 테스트

    문제는 최대 절전 모드로 스프링 정의를 알 수 없습니다. 그러나 엔티티가 모든 유형의 javax.validation 유형을 인식하도록 만들 수 있습니다. 희망이 도움이됩니다.

  4. from https://stackoverflow.com/questions/50212117/spring-boot-hibernate-custom-constraint-doesnt-inject-service by cc-by-sa and MIT license