我有一个字段,例如 user_name
,它在表中应该是唯一的。
使用 Spring/Hibernate 验证对其进行验证的最佳方式是什么?
最佳答案
一种可能的解决方案是创建自定义 @UniqueKey
约束(和相应的 validator );并在数据库中查找现有记录,向 UniqueKeyValidator
提供 EntityManager
(或 Hibernate Session
)的实例。
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();
}
}
UniqueKeyValidator
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());
}
关于java - hibernate 唯一 key 验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4613055/
相关文章:
java - 如何使用 Spring 为 JUnit 测试注入(inject) ServletCon
java - Mybatis Spring多数据库Java配置
java - 如何将 Class 值设置为 spring bean 属性?
java - Spring Security 匿名 401 而不是 403
java - 在 Spring 5 Webflux 中启用 CORS?
java - 如何从spring security获取当前登录的用户对象?
java - Spring Servlet 项目的 web.xml 中加载 contextConfi