package com.devin.repository.base;import org.springframework.data.domain.Sort;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.data.jpa.repository.JpaSpecificationExecutor;import org.springframework.data.repository.NoRepositoryBean;import org.springframework.lang.NonNull;import java.util.List;/**
* Base repository interface contains some common methods.
*
* @param <DOMAIN> doamin type
* @param <ID> id type
* @author johnniang
*/@NoRepositoryBeanpublicinterfaceBaseRepository<DOMAIN, ID>extendsJpaRepository<DOMAIN, ID>{/**
* Finds all domain by id list and the specified sort.
*
* @param ids id list of domain must not be null
* @param sort the specified sort must not be null
* @return a list of domains
*/@NonNull
List<DOMAIN>findAllByIdIn(@NonNull Iterable<ID> ids,@NonNull Sort sort);/**
* Deletes by id list.
*
* @param ids id list of domain must not be null
* @return number of rows affected
*/longdeleteByIdIn(@NonNull Iterable<ID> ids);}
package com.devin.repository.base;import lombok.extern.slf4j.Slf4j;import org.springframework.data.domain.Sort;import org.springframework.data.jpa.domain.Specification;import org.springframework.data.jpa.repository.support.JpaEntityInformation;import org.springframework.data.jpa.repository.support.SimpleJpaRepository;import org.springframework.lang.Nullable;import org.springframework.util.Assert;import javax.persistence.EntityManager;import javax.persistence.TypedQuery;import javax.persistence.criteria.*;import java.util.ArrayList;import java.util.Collections;import java.util.List;/**
* Implementation of base repository.
*
* @param <DOMAIN> domain type
* @param <ID> id type
* @author johnniang
*/@Slf4jpublicclassBaseRepositoryImpl<DOMAIN, ID>extendsSimpleJpaRepository<DOMAIN, ID>implementsBaseRepository<DOMAIN, ID>{// private final Logger log = Logger.getLogger(getClass());privatefinal JpaEntityInformation<DOMAIN, ID> entityInformation;privatefinal EntityManager entityManager;publicBaseRepositoryImpl(JpaEntityInformation<DOMAIN, ID> entityInformation, EntityManager entityManager){super(entityInformation, entityManager);this.entityInformation = entityInformation;this.entityManager = entityManager;}/**
* Finds all domain by id list and the specified sort.
*
* @param ids id list of domain must not be null
* @param sort the specified sort must not be null
* @return a list of domains
*/@Overridepublic List<DOMAIN>findAllByIdIn(Iterable<ID> ids, Sort sort){
Assert.notNull(ids,"The given Iterable of Id's must not be null!");
log.debug("Customized findAllById method was invoked");if(!ids.iterator().hasNext()){return Collections.emptyList();}if(!this.entityInformation.hasCompositeId()){
ByIdsSpecification<DOMAIN> specification =newByIdsSpecification<>(this.entityInformation);
TypedQuery<DOMAIN> query =super.getQuery(specification, sort);return query.setParameter(specification.parameter, ids).getResultList();}else{
List<DOMAIN> results =newArrayList<>();
ids.forEach(id ->super.findById(id).ifPresent(results::add));return results;}}/**
* Deletes by id list.
*
* @param ids id list of domain must not be null
* @return number of rows affected
*/@OverridepubliclongdeleteByIdIn(Iterable<ID> ids){
log.debug("Customized deleteByIdIn method was invoked");// Find all domains
List<DOMAIN> domains =findAllById(ids);// Delete in batchdeleteInBatch(domains);// Return the size of domain deletedreturn domains.size();}privatestaticfinalclassByIdsSpecification<T>implementsSpecification<T>{privatestaticfinallong serialVersionUID =1L;privatefinal JpaEntityInformation<T,?> entityInformation;@Nullable
ParameterExpression<Iterable> parameter;ByIdsSpecification(JpaEntityInformation<T,?> entityInformation){this.entityInformation = entityInformation;}@Overridepublic Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb){
Path<?> path = root.get(this.entityInformation.getIdAttribute());this.parameter = cb.parameter(Iterable.class);return path.in(this.parameter);}}}
package cc.ryanc.halo.service.base;import cc.ryanc.halo.exception.NotFoundException;import org.springframework.data.domain.Page;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.lang.NonNull;import org.springframework.lang.Nullable;import java.util.Collection;import java.util.List;import java.util.Optional;/**
* CrudService interface contains some common methods.
*
* @param <DOMAIN> domain type
* @param <ID> id type
* @author johnniang
*/publicinterfaceCrudService<DOMAIN, ID>{/**
* List All
*
* @return List
*/@NonNull
List<DOMAIN>listAll();/**
* List all by sort
*
* @param sort sort
* @return List
*/@NonNull
List<DOMAIN>listAll(@NonNull Sort sort);/**
* List all by pageable
*
* @param pageable pageable
* @return Page
*/@NonNull
Page<DOMAIN>listAll(@NonNull Pageable pageable);/**
* List all by ids
*
* @param ids ids
* @return List
*/@NonNull
List<DOMAIN>listAllByIds(@NonNull Collection<ID> ids);/**
* List all by ids and sort
*
* @param ids ids
* @param sort sort
* @return List
*/@NonNull
List<DOMAIN>listAllByIds(@NonNull Collection<ID> ids,@NonNull Sort sort);/**
* Fetch by id
*
* @param id id
* @return Optional
*/@NonNull
Optional<DOMAIN>fetchById(@NonNull ID id);/**
* Get by id
*
* @param id id
* @return DOMAIN
* @throws NotFoundException If the specified id does not exist
*/@NonNull
DOMAIN getById(@NonNull ID id);/**
* Gets domain of nullable by id.
*
* @param id id
* @return DOMAIN
*/@Nullable
DOMAIN getByIdOfNullable(@NonNull ID id);/**
* Exists by id.
*
* @param id id
* @return boolean
*/booleanexistsById(@NonNull ID id);/**
* Must exist by id, or throw NotFoundException.
*
* @param id id
* @throws NotFoundException If the specified id does not exist
*/voidmustExistById(@NonNull ID id);/**
* count all
*
* @return long
*/longcount();/**
* save by domain
*
* @param domain domain
* @return DOMAIN
*/@NonNull
DOMAIN create(@NonNull DOMAIN domain);/**
* save by domains
*
* @param domains domains
* @return List
*/@NonNull
List<DOMAIN>createInBatch(@NonNull Collection<DOMAIN> domains);/**
* Updates by domain
*
* @param domain domain
* @return DOMAIN
*/@NonNull
DOMAIN update(@NonNull DOMAIN domain);/**
* Updates by domains
*
* @param domains domains
* @return List
*/@NonNull
List<DOMAIN>updateInBatch(@NonNull Collection<DOMAIN> domains);/**
* Removes by id
*
* @param id id
* @return DOMAIN
* @throws NotFoundException If the specified id does not exist
*/@NonNull
DOMAIN removeById(@NonNull ID id);/**
* Removes by id if present.
*
* @param id id
* @return DOMAIN
*/@Nullable
DOMAIN removeByIdOfNullable(@NonNull ID id);/**
* Remove by domain
*
* @param domain domain
*/voidremove(@NonNull DOMAIN domain);/**
* Remove by ids
*
* @param ids ids
*/voidremoveInBatch(@NonNull Collection<ID> ids);/**
* Remove all by domains
*
* @param domains domains
*/voidremoveAll(@NonNull Collection<DOMAIN> domains);/**
* Remove all
*/voidremoveAll();}
AbstractCrudService
package cc.ryanc.halo.service.base;import cc.ryanc.halo.exception.NotFoundException;import cc.ryanc.halo.logging.Logger;import cc.ryanc.halo.repository.base.BaseRepository;import org.springframework.data.domain.Page;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.util.Assert;import org.springframework.util.CollectionUtils;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.Collection;import java.util.Collections;import java.util.List;import java.util.Optional;/**
* Abstract service implementation.
*
* @param <DOMAIN> domain type
* @param <ID> id type
* @author johnniang
*/publicabstractclassAbstractCrudService<DOMAIN, ID>implementsCrudService<DOMAIN, ID>{privatefinal Logger log = Logger.getLogger(getClass());privatefinal String domainName;privatefinal BaseRepository<DOMAIN, ID> repository;protectedAbstractCrudService(BaseRepository<DOMAIN, ID> repository){this.repository = repository;// Get domain name
Class<DOMAIN> domainClass =(Class<DOMAIN>)fetchType(0);
domainName = domainClass.getSimpleName();}/**
* Gets actual generic type.
*
* @param index generic type index
* @return real generic type will be returned
*/private Type fetchType(int index){
Assert.isTrue(index >=0&& index <=1,"type index must be between 0 to 1");return((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[index];}/**
* List All
*
* @return List
*/@Overridepublic List<DOMAIN>listAll(){return repository.findAll();}/**
* List all by sort
*
* @param sort sort
* @return List
*/@Overridepublic List<DOMAIN>listAll(Sort sort){
Assert.notNull(sort,"Sort info must not be null");return repository.findAll(sort);}/**
* List all by pageable
*
* @param pageable pageable
* @return Page
*/@Overridepublic Page<DOMAIN>listAll(Pageable pageable){
Assert.notNull(pageable,"Pageable info must not be null");return repository.findAll(pageable);}/**
* List all by ids
*
* @param ids ids
* @return List
*/@Overridepublic List<DOMAIN>listAllByIds(Collection<ID> ids){return CollectionUtils.isEmpty(ids)? Collections.emptyList(): repository.findAllById(ids);}/**
* List all by ids and sort
*
* @param ids ids
* @param sort sort
* @return List
*/@Overridepublic List<DOMAIN>listAllByIds(Collection<ID> ids, Sort sort){
Assert.notNull(sort,"Sort info must not be null");return CollectionUtils.isEmpty(ids)? Collections.emptyList(): repository.findAllByIdIn(ids, sort);}/**
* Fetch by id
*
* @param id id
* @return Optional
*/@Overridepublic Optional<DOMAIN>fetchById(ID id){
Assert.notNull(id, domainName +" id must not be null");return repository.findById(id);}/**
* Get by id
*
* @param id id
* @return DOMAIN
* @throws NotFoundException If the specified id does not exist
*/@Overridepublic DOMAIN getById(ID id){returnfetchById(id).orElseThrow(()->newNotFoundException(domainName +" was not found"));}/**
* Gets domain of nullable by id.
*
* @param id id
* @return DOMAIN
*/@Overridepublic DOMAIN getByIdOfNullable(ID id){returnfetchById(id).orElse(null);}/**
* Exists by id.
*
* @param id id
* @return boolean
*/@OverridepublicbooleanexistsById(ID id){
Assert.notNull(id, domainName +" id must not be null");return repository.existsById(id);}/**
* Must exist by id, or throw NotFoundException.
*
* @param id id
* @throws NotFoundException If the specified id does not exist
*/@OverridepublicvoidmustExistById(ID id){if(!existsById(id)){thrownewNotFoundException(domainName +" was not exist");}}/**
* count all
*
* @return long
*/@Overridepubliclongcount(){return repository.count();}/**
* save by domain
*
* @param domain domain
* @return DOMAIN
*/@Overridepublic DOMAIN create(DOMAIN domain){
Assert.notNull(domain, domainName +" data must not be null");return repository.save(domain);}/**
* save by domains
*
* @param domains domains
* @return List
*/@Overridepublic List<DOMAIN>createInBatch(Collection<DOMAIN> domains){return CollectionUtils.isEmpty(domains)? Collections.emptyList(): repository.saveAll(domains);}/**
* Updates by domain
*
* @param domain domain
* @return DOMAIN
*/@Overridepublic DOMAIN update(DOMAIN domain){
Assert.notNull(domain, domainName +" data must not be null");return repository.saveAndFlush(domain);}/**
* Updates by domains
*
* @param domains domains
* @return List
*/@Overridepublic List<DOMAIN>updateInBatch(Collection<DOMAIN> domains){return CollectionUtils.isEmpty(domains)? Collections.emptyList(): repository.saveAll(domains);}/**
* Removes by id
*
* @param id id
* @return DOMAIN
* @throws NotFoundException If the specified id does not exist
*/@Overridepublic DOMAIN removeById(ID id){// Get non null domain by id
DOMAIN domain =getById(id);// Remove itremove(domain);// return the deleted domainreturn domain;}/**
* Removes by id if present.
*
* @param id id
* @return DOMAIN
*/@Overridepublic DOMAIN removeByIdOfNullable(ID id){returnfetchById(id).map(domain ->{remove(domain);return domain;}).orElse(null);}/**
* Remove by domain
*
* @param domain domain
*/@Overridepublicvoidremove(DOMAIN domain){
Assert.notNull(domain, domainName +" data must not be null");
repository.delete(domain);}/**
* Remove by ids
*
* @param ids ids
*/@OverridepublicvoidremoveInBatch(Collection<ID> ids){if(CollectionUtils.isEmpty(ids)){
log.warn(domainName +" id collection is empty");return;}
repository.deleteByIdIn(ids);}/**
* Remove all by domains
*
* @param domains domains
*/@OverridepublicvoidremoveAll(Collection<DOMAIN> domains){if(CollectionUtils.isEmpty(domains)){
log.warn(domainName +" collection is empty");return;}
repository.deleteInBatch(domains);}/**
* Remove all
*/@OverridepublicvoidremoveAll(){
repository.deleteAll();}}