com.kasinf.framework.rest.repository.BaseRepositoryImpl Maven / Gradle / Ivy
The newest version!
package com.kasinf.framework.rest.repository;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.kasinf.framework.rest.annotation.EnableQueryCache;
import com.kasinf.framework.rest.annotation.LogicDelete;
import com.kasinf.framework.rest.eneity.AbstractEntity;
import com.kasinf.framework.rest.eneity.type.LogicDeletable;
import com.kasinf.framework.rest.repository.callback.SearchCallback;
import com.kasinf.framework.rest.support.Searchable;
import lombok.Setter;
import org.hibernate.jpa.QueryHints;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.util.Assert;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.transaction.Transactional;
import java.io.Serializable;
import java.util.*;
/**
* 基础存储库实现
*
* @author lkhsh
*/
@Setter
public class BaseRepositoryImpl extends SimpleJpaRepository implements BaseRepository {
private final String LOGIC_DELETE_ALL_QUERY_STRING;
private final String DELETE_ALL_QUERY_STRING;
/**
* 实体管理器
*/
protected final EntityManager em;
/**
* 当前实体类
*/
protected final Class entityClass;
protected final JpaEntityInformation entityInformation;
/**
* 实体类全限定名
*/
protected final String entityName;
/**
* 主键名
*/
protected final String idName;
/**
* 逻辑删除的字段
*/
protected final LogicDelete logicDelete;
/**
* 查询缓存设置
*/
protected final boolean enableQueryCache;
/**
* 缓存区域
*/
protected final String cacheRegion;
/**
* 逻辑删除的值,转换之后的
*/
protected final Object deleteValue;
/**
* 查询回调
*/
private SearchCallback searchCallback = SearchCallback.DEFAULT;
private String countAllQl;
private String findAllQl;
public BaseRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.em = entityManager;
this.entityInformation = entityInformation;
this.entityClass = entityInformation.getJavaType();
this.entityName = entityInformation.getEntityName();
this.idName = entityInformation.getIdAttributeNames().iterator().next();
logicDelete = getLogicDelete(entityClass);
DELETE_ALL_QUERY_STRING = String.format("delete from %s x where x in :ids", entityName);
countAllQl = String.format("select count(x) from %s x where 1=1 ", entityName);
findAllQl = String.format("select x from %s x where 1=1 ", entityName);
if (logicDelete != null) {
deleteValue = Convert.convert(logicDelete.type(), logicDelete.value());
LOGIC_DELETE_ALL_QUERY_STRING = String.format("update %s x set x.%s=:deleteValue where x in :ids", entityName, logicDelete.of());
} else {
deleteValue = null;
LOGIC_DELETE_ALL_QUERY_STRING = "";
}
EnableQueryCache queryCache = getEnableQueryCache(entityClass);
if (queryCache != null) {
enableQueryCache = queryCache.value();
cacheRegion = queryCache.region();
} else {
enableQueryCache = false;
cacheRegion = null;
}
}
/**
* 获取自身或者父类上的 @EnableQueryCache 注解。
*
* @param entityClass 目标类
* @return {@link EnableQueryCache}
*/
private EnableQueryCache getEnableQueryCache(Class> entityClass) {
EnableQueryCache enableQueryCacheAnnotation = AnnotationUtils.findAnnotation(entityClass, EnableQueryCache.class);
if (enableQueryCacheAnnotation == null && entityClass.getSuperclass() != null && !"java.lang.Object".equals(entityClass.getSuperclass().getName())) {
return getEnableQueryCache(entityClass.getSuperclass());
}
return enableQueryCacheAnnotation;
}
/**
* 获取自身或者其父类上的 @LogicDelete 注解。
*
* @param entityClass 目标类
* @return {@link LogicDelete}
*/
private LogicDelete getLogicDelete(Class> entityClass) {
LogicDelete logicDelete = AnnotationUtil.getAnnotation(entityClass, LogicDelete.class);
if (logicDelete == null && entityClass.getSuperclass() != null && !"java.lang.Object".equals(entityClass.getSuperclass().getName())) {
return getLogicDelete(entityClass.getSuperclass());
}
return logicDelete;
}
/////////////////////////////////////////////////
////////覆盖默认spring data jpa的实现////////////
/////////////////////////////////////////////////
/**
* 删除对应实体,需要考虑是否是逻辑删除
*
* @param t 要删除的实体
*/
@Override
@Transactional(rollbackOn = Exception.class)
public void delete(T t) {
Assert.notNull(t, "Entity must not be null!");
if (logicDelete != null) {
// 注入属性
ReflectUtil.invoke(t, StrUtil.upperFirstAndAddPre(logicDelete.of(), "set"), deleteValue);
save(t);
} else if (t instanceof LogicDeletable) {
((LogicDeletable) t).markDeleted();
save(t);
} else {
super.delete(t);
}
}
/**
* 通过ID删除对象,添加逻辑删除的考虑
*
* @param id 对象ID
*/
@Override
@Transactional(rollbackOn = Exception.class)
public void deleteById(ID id) {
T t = super.getOne(id);
delete(t);
}
/**
* 删除指定对象列表,考虑对逻辑删除实体的操作
*
* @param entities 对象列表
*/
@Override
@Transactional(rollbackOn = Exception.class)
public void deleteInBatch(Iterable entities) {
Iterator iter = entities.iterator();
if (iter.hasNext()) {
Set models = new HashSet<>();
iter.forEachRemaining(models::add);
Query query = em.createQuery(
logicDelete != null ?
LOGIC_DELETE_ALL_QUERY_STRING :
(LogicDeletable.class.isAssignableFrom(this.entityClass)) ?
String.format("update %s x set x.isDelete=true where x in :ids", entityName) :
DELETE_ALL_QUERY_STRING);
query.setParameter("ids", models);
if (logicDelete != null) {
query.setParameter("deleteValue", deleteValue);
}
query.executeUpdate();
}
}
/**
* 删除全部,考虑逻辑删除,若要清空逻辑对象表的数据,需要在接口覆盖此方法
*/
@Override
@Transactional(rollbackOn = Exception.class)
public void deleteAll() {
String ql = logicDelete != null ?
LOGIC_DELETE_ALL_QUERY_STRING.replace("where x in ?1", "") :
(LogicDeletable.class.isAssignableFrom(this.entityClass)) ?
String.format("update %s x set x.isDelete=true", entityName) :
DELETE_ALL_QUERY_STRING.replace("where x in ?1", "");
Query query = em.createQuery(ql);
query.executeUpdate();
}
@Override
public boolean existsById(ID id) {
return findById(id).isPresent();
}
/////////////////////////////////////////////////
///////////////////自定义实现////////////////////
/////////////////////////////////////////////////
@Override
public T findOne(ID id) {
Optional t = findById(id);
return t.orElse(null);
}
/**
* 通过指定的ID数组删除对象,考虑对逻辑删除的处理
*
* @param ids 要删除的id数组
*/
@Override
@Transactional(rollbackOn = Exception.class)
public void deleteInBatch(ID[] ids) {
if (ArrayUtil.isNotEmpty(ids)) {
Set models = new HashSet<>(ids.length);
for (ID id : ids) {
T model;
try {
model = entityClass.newInstance();
} catch (Exception e) {
throw new RuntimeException("batch delete " + entityClass + " exception", e);
}
try {
ReflectUtil.setFieldValue(model, idName, id);
} catch (Exception e) {
throw new RuntimeException("batch delete " + entityClass + " exception, can not set id", e);
}
models.add(model);
}
deleteInBatch(models);
}
}
@Override
public Page findAll(Searchable searchable) {
List list = this.findAll(findAllQl, searchable, searchCallback);
long total = searchable.hasPageable() ? count(searchable) : list.size();
return new PageImpl(list, searchable.getPage(), total);
}
@Override
public List findList(Searchable searchable) {
return this.findAll(findAllQl, searchable, searchCallback);
}
@Override
public long count(Searchable searchable) {
return this.count(countAllQl, searchable, searchCallback);
}
/**
* 按条件统计
*
* @param ql 基本查询语句
* @param searchable 查询条件、分页、排序
* @param searchCallback 查询回调,自定义设置查询条件和赋值
*/
private long count(final String ql, final Searchable searchable, final SearchCallback searchCallback) {
searchable.changeDataCondition();
assertConverted(searchable);
StringBuilder s = new StringBuilder(ql);
searchCallback.prepareQl(s, searchable);
Query query = em.createQuery(s.toString());
applyEnableQueryCache(query);
searchCallback.setValues(query, searchable);
return (Long) query.getSingleResult();
}
/**
* @param ql 基本查询语句
* @param searchable 查询条件、分页、排序
* @param searchCallback 查询回调,自定义设置查询条件和赋值
*/
private List findAll(final String ql, final Searchable searchable, final SearchCallback searchCallback) {
searchable.changeDataCondition();
assertConverted(searchable);
StringBuilder s = new StringBuilder(ql);
searchCallback.prepareQl(s, searchable);
searchCallback.prepareOrder(s, searchable);
Query query = em.createQuery(s.toString());
applyEnableQueryCache(query);
searchCallback.setValues(query, searchable);
searchCallback.setPageable(query, searchable);
return query.getResultList();
}
private void assertConverted(Searchable searchable) {
if (!searchable.isConverted()) {
searchable.convert(this.entityClass);
}
}
/**
* 按顺序设置Query参数
*
* @param query:查询
* @param params:参数
*/
private void setParameters(Query query, Object... params) {
if (params != null) {
for (int i = 0; i < params.length; i++) {
query.setParameter(i + 1, params[i]);
}
}
}
public void applyEnableQueryCache(Query query) {
if (enableQueryCache) {
//开启查询缓存
query.setHint(QueryHints.HINT_CACHEABLE, true);
}
if (cacheRegion != null) {
//设置缓存区域
query.setHint(QueryHints.HINT_CACHE_REGION, cacheRegion);
}
}
}