我想实现ConstraintsValidator
来验证电子邮件是否可用,然后再注册新用户,使用spring的机密性注入@Autowired
在验证器中注入JPA存储库以进行数据库搜索。
我如此更改了休眠的验证器工厂,以便spring实例化验证器,以便我可以使用@Autowired
一切正常,但是就像验证进入一个无限循环,这会导致stackoverflowexception
。
注意:当我使用REST JPA存储库时,验证是自动完成的(我没有呼叫validator.validate()
)
@Getter
@Setter
@Entity
@UniqueCompteEmail
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Compte implements Serializable, UserDetails {
private static final long serialVersionUID = -5230227676515387462L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer id;
@NotBlank
@NotNull
@Column(unique = true)
private String username;
@NotNull
@NotBlank
@Size(min = 6)
private String password;
@Email
@NotNull
@NotBlank
@Column(unique = true)
private String email;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return new HashSet<GrantedAuthority>();
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
public abstract CompteType getTypeCompte();
public abstract void setTypeCompte(CompteType typeCompte);
public static enum CompteType {
ETUDIANT, ADMINISTRATEUR
}
}
@Repository
public interface CompteRepository extends JpaRepository<Compte, Integer> {
public Optional<Compte> findByUsername(String username);
public Optional<Compte> findByEmail(String email);
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueCompteEmailValidator.class)
@Target({ ElementType.TYPE })
public @interface UniqueCompteEmail {
String message() default "{com.mssmfactory.bacsimulator.uniquecompteemail.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class UniqueCompteEmailValidator implements ConstraintValidator<UniqueCompteEmail, Compte> {
@Autowired
private CompteRepository compteRepository;
@Override
public void initialize(UniqueCompteEmail constraintAnnotation) {
}
@Override
public boolean isValid(Compte value, ConstraintValidatorContext context) {
if (value != null) {
Optional<Compte> compte = this.compteRepository.findByEmail(value.getEmail());
return !compte.isPresent();
} else
return false;
}
}
@Component
public class ValidatorAddingCustomizer implements HibernatePropertiesCustomizer {
@Autowired
private ValidatorFactory validatorFactory;
public void customize(Map<String, Object> hibernateProperties) {
if (validatorFactory != null) {
hibernateProperties.put("javax.persistence.validation.factory", validatorFactory);
}
}
}
答案 0 :(得分:0)
由于您未定义任何事件,因此将为所有事件调用验证器。
事件为(请参见here):
- BeforeCreateEvent
- AfterCreateEvent
- BeforeSaveEvent
- AfterSaveEvent
- BeforeLinkSaveEvent
- AfterLinkSaveEvent
- BeforeDeleteEvent
- AfterDeleteEvent
并且由于您将从db中获取验证方法,因此您陷入了无限循环。
您只需要使用对流名称为验证者添加注释。
@Component("beforeCreateCompteValidator")
public UniqueCompteEmailValidator implements Validator<Compte>{
}
并删除其他注释。
Spring可以识别此验证器,并附加到右钩子上。
有关更多信息,请参见Spring Validation