mirror of
https://github.com/yin5980280/easy.git
synced 2026-09-03 07:26:58 +08:00
【A】初始化自定义逻辑删除spring data jpa factory等
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package cn.org.easysite.spring.boot.jpa.entiy;
|
||||
package cn.org.easysite.spring.boot.jpa.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@@ -7,6 +7,7 @@ import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.OrderBy;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
@@ -32,6 +33,7 @@ public class BaseEntity extends BaseObject {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id", columnDefinition = "bigint(20) COMMENT '主键ID,自动生成'")
|
||||
@OrderBy("DESC")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,66 @@
|
||||
package cn.org.easysite.spring.boot.jpa.factory.bean;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport;
|
||||
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
|
||||
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
|
||||
import org.springframework.data.jpa.repository.support.JpaRepositoryImplementation;
|
||||
import org.springframework.data.jpa.repository.support.LogicJpaRepositoryImpl;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import cn.org.easysite.spring.boot.jpa.entity.BaseEntity;
|
||||
|
||||
/**
|
||||
* @author : yinlin
|
||||
* @version : 1.0
|
||||
* @date : 2019-05-16 17:44
|
||||
* @Description :
|
||||
* @Copyright : Copyright (c) 2018
|
||||
* @Company : EasySite Technology Chengdu Co. Ltd.
|
||||
* @link : cn.org.easysite.spring.boot.jpa.factory.bean.LogicJpaRespositoryFactoryBean
|
||||
*/
|
||||
public class LogicJpaRepositoryFactoryBean<R extends JpaRepository<T, ID>, T extends BaseEntity, ID extends Serializable> extends JpaRepositoryFactoryBean<R, T, ID> {
|
||||
/**
|
||||
* Creates a new {@link JpaRepositoryFactoryBean} for the given repository interface.
|
||||
*
|
||||
* @param repositoryInterface must not be {@literal null}.
|
||||
*/
|
||||
public LogicJpaRepositoryFactoryBean(Class<? extends R> repositoryInterface) {
|
||||
super(repositoryInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
|
||||
return new LogicRepositoryFactory(entityManager);
|
||||
}
|
||||
|
||||
public static class LogicRepositoryFactory<T extends BaseEntity, ID extends Serializable> extends JpaRepositoryFactory {
|
||||
|
||||
private final EntityManager em;
|
||||
/**
|
||||
* Creates a new {@link JpaRepositoryFactory}.
|
||||
*
|
||||
* @param entityManager must not be {@literal null}
|
||||
*/
|
||||
public LogicRepositoryFactory(EntityManager entityManager) {
|
||||
super(entityManager);
|
||||
this.em = entityManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JpaRepositoryImplementation getTargetRepository(RepositoryInformation information, EntityManager entityManager) {
|
||||
return new LogicJpaRepositoryImpl<T, ID>(JpaEntityInformationSupport.getEntityInformation((Class<T>) information.getDomainType(), em), entityManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
|
||||
return LogicJpaRepositoryImpl.class;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* @author : yinlin
|
||||
* @date : 2019-05-16 17:44
|
||||
* @version : 1.0
|
||||
* @Description :
|
||||
* @Copyright : Copyright (c) 2018
|
||||
* @Company : EasySite Technology Chengdu Co. Ltd.
|
||||
* @link : cn.org.easysite.spring.boot.jpa.factory.package-info
|
||||
*/
|
||||
package cn.org.easysite.spring.boot.jpa.factory;
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.org.easysite.spring.boot.jpa.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.repository.NoRepositoryBean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import cn.org.easysite.spring.boot.jpa.entity.BaseEntity;
|
||||
|
||||
/**
|
||||
* @author : yinlin
|
||||
* @version : 1.0
|
||||
* @date : 2019-04-30 10:06
|
||||
* @Description :
|
||||
* @Copyright : Copyright (c) 2018
|
||||
* @Company : EasySite Technology Chengdu Co. Ltd.
|
||||
* @link : cn.org.easysite.spring.boot.jpa.repository.LogicJpaRepository
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
public interface LogicJpaRepository<T extends BaseEntity, ID extends Serializable> extends JpaRepository<T, ID> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.provider.PersistenceProvider;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.LockModeType;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Order;
|
||||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import cn.org.easysite.spring.boot.jpa.entity.BaseEntity;
|
||||
import cn.org.easysite.spring.boot.jpa.repository.LogicJpaRepository;
|
||||
|
||||
import static org.springframework.data.jpa.repository.query.QueryUtils.applyAndBind;
|
||||
import static org.springframework.data.jpa.repository.query.QueryUtils.getQueryString;
|
||||
import static org.springframework.data.jpa.repository.query.QueryUtils.toOrders;
|
||||
|
||||
/**
|
||||
* @author : yinlin
|
||||
* @version : 1.0
|
||||
* @date : 2019-04-30 10:10
|
||||
* @Description :
|
||||
* @Copyright : Copyright (c) 2018
|
||||
* @Company : EasySite Technology Chengdu Co. Ltd.
|
||||
* @link : cn.org.easysite.spring.boot.jpa.repository.LogicJpaRepositoryImpl
|
||||
*/
|
||||
public class LogicJpaRepositoryImpl<T extends BaseEntity, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements LogicJpaRepository<T, ID> {
|
||||
|
||||
/**
|
||||
* 逻辑删除字段名.
|
||||
*/
|
||||
public final static String USABLE_FIELD = "usable";
|
||||
|
||||
|
||||
public static final String COUNT_QUERY_STRING = "select count(%s) from %s x where x.usable = true";
|
||||
|
||||
public static final String EXISTS_QUERY_STRING = "select count(%s) from %s x where x.%s = :id and x.usable = true";
|
||||
|
||||
public static final String DELETE_ALL_QUERY_STRING = "update %s x set s.usable = false";
|
||||
|
||||
private final JpaEntityInformation<T, ?> entityInformation;
|
||||
|
||||
private final EntityManager em;
|
||||
|
||||
private final PersistenceProvider provider;
|
||||
|
||||
private @Nullable CrudMethodMetadata metadata;
|
||||
|
||||
public LogicJpaRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
|
||||
super(entityInformation, entityManager);
|
||||
this.em = entityManager;
|
||||
this.entityInformation = entityInformation;
|
||||
this.provider = PersistenceProvider.fromEntityManager(entityManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link TypedQuery} for the given {@link Specification} and {@link Sort}.
|
||||
*
|
||||
* @param spec can be {@literal null}.
|
||||
* @param domainClass must not be {@literal null}.
|
||||
* @param sort must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass, Sort sort) {
|
||||
|
||||
CriteriaBuilder builder = em.getCriteriaBuilder();
|
||||
CriteriaQuery<S> query = builder.createQuery(domainClass);
|
||||
|
||||
Root<S> root = applySpecificationToCriteria(spec, domainClass, query);
|
||||
query.select(root);
|
||||
|
||||
if (sort.isSorted()) {
|
||||
query.orderBy(toOrders(sort, root, builder));
|
||||
}
|
||||
return applyRepositoryMethodMetadata(em.createQuery(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new count query for the given {@link Specification}.
|
||||
*
|
||||
* @param spec can be {@literal null}.
|
||||
* @param domainClass must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected <S extends T> TypedQuery<Long> getCountQuery(@Nullable Specification<S> spec, Class<S> domainClass) {
|
||||
|
||||
CriteriaBuilder builder = em.getCriteriaBuilder();
|
||||
CriteriaQuery<Long> query = builder.createQuery(Long.class);
|
||||
|
||||
Root<S> root = applySpecificationToCriteria(spec, domainClass, query);
|
||||
|
||||
if (query.isDistinct()) {
|
||||
query.select(builder.countDistinct(root));
|
||||
} else {
|
||||
query.select(builder.count(root));
|
||||
}
|
||||
|
||||
// Remove all Orders the Specifications might have applied
|
||||
query.orderBy(Collections.<Order> emptyList());
|
||||
|
||||
return em.createQuery(query);
|
||||
}
|
||||
|
||||
protected <S> TypedQuery<S> applyRepositoryMethodMetadata(TypedQuery<S> query) {
|
||||
|
||||
if (metadata == null) {
|
||||
return query;
|
||||
}
|
||||
|
||||
LockModeType type = metadata.getLockModeType();
|
||||
TypedQuery<S> toReturn = type == null ? query : query.setLockMode(type);
|
||||
|
||||
applyQueryHints(toReturn);
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
private void applyQueryHints(Query query) {
|
||||
|
||||
for (Map.Entry<String, Object> hint : getQueryHints().withFetchGraphs(em)) {
|
||||
query.setHint(hint.getKey(), hint.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given {@link Specification} to the given {@link CriteriaQuery}.
|
||||
*
|
||||
* @param spec can be {@literal null}.
|
||||
* @param domainClass must not be {@literal null}.
|
||||
* @param query must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected <S, U extends T> Root<U> applySpecificationToCriteria(@Nullable Specification<U> spec, Class<U> domainClass,
|
||||
CriteriaQuery<S> query) {
|
||||
|
||||
Assert.notNull(domainClass, "Domain class must not be null!");
|
||||
Assert.notNull(query, "CriteriaQuery must not be null!");
|
||||
|
||||
Root<U> root = query.from(domainClass);
|
||||
CriteriaBuilder builder = em.getCriteriaBuilder();
|
||||
Path<Boolean> deletedPath = root.get(USABLE_FIELD);
|
||||
Predicate deletedPredicate = builder.isTrue(deletedPath);
|
||||
if (spec == null) {
|
||||
query.where(deletedPath);
|
||||
return root;
|
||||
}
|
||||
|
||||
Predicate predicate = spec.toPredicate(root, query, builder);
|
||||
|
||||
if (predicate != null) {
|
||||
predicate = builder.and(deletedPredicate);
|
||||
query.where(predicate);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return em.createQuery(getCountQueryString(), Long.class).getSingleResult();
|
||||
}
|
||||
|
||||
private String getCountQueryString() {
|
||||
String countQuery = String.format(COUNT_QUERY_STRING, provider.getCountQueryPlaceholder(), "%s");
|
||||
return getQueryString(countQuery, entityInformation.getEntityName());
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void delete(T entity) {
|
||||
Assert.notNull(entity, "The entity must not be null!");
|
||||
entity.setUsable(false);
|
||||
em.persist(entity);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.JpaRepository#deleteInBatch(java.lang.Iterable)
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void deleteInBatch(Iterable<T> entities) {
|
||||
|
||||
Assert.notNull(entities, "The given Iterable of entities not be null!");
|
||||
|
||||
if (!entities.iterator().hasNext()) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyAndBind(getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName()), entities, em)
|
||||
.executeUpdate();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.JpaRepository#deleteAllInBatch()
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void deleteAllInBatch() {
|
||||
em.createQuery(getDeleteAllQueryString()).executeUpdate();
|
||||
}
|
||||
|
||||
protected String getDeleteAllQueryString() {
|
||||
return getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getOne(ID id) {
|
||||
T t = super.getOne(id);
|
||||
return t.getUsable() ? t : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.org.easysite.spring.boot.data.jpa.autoconfigure;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
|
||||
import cn.org.easysite.spring.boot.jpa.factory.bean.LogicJpaRepositoryFactoryBean;
|
||||
|
||||
/**
|
||||
* @author : yinlin
|
||||
* @version : 1.0
|
||||
* @date : 2019-05-16 18:14
|
||||
* @Description :
|
||||
* @Copyright : Copyright (c) 2018
|
||||
* @Company : EasySite Technology Chengdu Co. Ltd.
|
||||
* @link : cn.org.easysite.spring.boot.data.jpa.autoconfigure.LogicSpringDataJpaAutoConfiguration
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix = "spring.data.jpa.logic.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
|
||||
@EnableJpaRepositories(repositoryBaseClass = LogicJpaRepositoryFactoryBean.class)
|
||||
public class LogicSpringDataJpaAutoConfiguration {
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.org.easysite.spring.boot.data.jpa.autoconfigure.LogicSpringDataJpaAutoConfiguration
|
||||
@@ -0,0 +1 @@
|
||||
provides: easy-spring-boot-distributed-lock
|
||||
Reference in New Issue
Block a user