我有一个字段,例如,user_name在表中应该是唯一的。
user_name
使用Spring / Hibernate验证进行验证的最佳方法是什么?
一种可能的解决方案是创建自定义@UniqueKey约束(和相应的验证器)。并要查找数据库中的现有记录,请提供EntityManager(或HibernateSession)to 的实例UniqueKeyValidator。
@UniqueKey
EntityManager
Session
UniqueKeyValidator
EntityManagerAwareValidator
public interface EntityManagerAwareValidator { void setEntityManager(EntityManager entityManager); }
ConstraintValidatorFactoryImpl
public class ConstraintValidatorFactoryImpl implements ConstraintValidatorFactory { private EntityManagerFactory entityManagerFactory; public ConstraintValidatorFactoryImpl(EntityManagerFactory entityManagerFactory) { this.entityManagerFactory = entityManagerFactory; } @Override public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) { T instance = null; try { instance = key.newInstance(); } catch (Exception e) { // could not instantiate class e.printStackTrace(); } if(EntityManagerAwareValidator.class.isAssignableFrom(key)) { EntityManagerAwareValidator validator = (EntityManagerAwareValidator) instance; validator.setEntityManager(entityManagerFactory.createEntityManager()); } return instance; } }
唯一键
@Constraint(validatedBy={UniqueKeyValidator.class}) @Target({ElementType.TYPE}) @Retention(RUNTIME) public @interface UniqueKey { String[] columnNames(); String message() default "{UniqueKey.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; @Target({ ElementType.TYPE }) @Retention(RUNTIME) @Documented @interface List { UniqueKey[] value(); } }
public class UniqueKeyValidator implements ConstraintValidator<UniqueKey, Serializable>, EntityManagerAwareValidator { private EntityManager entityManager; @Override public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } private String[] columnNames; @Override public void initialize(UniqueKey constraintAnnotation) { this.columnNames = constraintAnnotation.columnNames(); } @Override public boolean isValid(Serializable target, ConstraintValidatorContext context) { Class<?> entityClass = target.getClass(); CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery(); Root<?> root = criteriaQuery.from(entityClass); List<Predicate> predicates = new ArrayList<Predicate> (columnNames.length); try { for(int i=0; i<columnNames.length; i++) { String propertyName = columnNames[i]; PropertyDescriptor desc = new PropertyDescriptor(propertyName, entityClass); Method readMethod = desc.getReadMethod(); Object propertyValue = readMethod.invoke(target); Predicate predicate = criteriaBuilder.equal(root.get(propertyName), propertyValue); predicates.add(predicate); } } catch (Exception e) { e.printStackTrace(); } criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()])); TypedQuery<Object> typedQuery = entityManager.createQuery(criteriaQuery); List<Object> resultSet = typedQuery.getResultList(); return resultSet.size() == 0; } }
用法
@UniqueKey(columnNames={"userName"}) // @UniqueKey(columnNames={"userName", "emailId"}) // composite unique key //@UniqueKey.List(value = {@UniqueKey(columnNames = { "userName" }), @UniqueKey(columnNames = { "emailId" })}) // more than one unique keys public class User implements Serializable { private String userName; private String password; private String emailId; protected User() { super(); } public User(String userName) { this.userName = userName; } .... }
测试
public void uniqueKey() { EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default"); ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); ValidatorContext validatorContext = validatorFactory.usingContext(); validatorContext.constraintValidatorFactory(new ConstraintValidatorFactoryImpl(entityManagerFactory)); Validator validator = validatorContext.getValidator(); EntityManager em = entityManagerFactory.createEntityManager(); User se = new User("abc", poizon); Set<ConstraintViolation<User>> violations = validator.validate(se); System.out.println("Size:- " + violations.size()); em.getTransaction().begin(); em.persist(se); em.getTransaction().commit(); User se1 = new User("abc"); violations = validator.validate(se1); System.out.println("Size:- " + violations.size()); }