Spring boot中结合Specification自定义Repository实现

Spring Data  JPA中封装了很多条件查询的方法,我们可以使用封装的方法和@Query注解进行条件查询。这些都是比较简单的,直接调用接口就行。但是要想实现动态查询,就比较复杂了。下面我将结合Specification和自定义Repository实现来定制一个动态条件查询,实现当对应的条件参数为空时,不加入查询的条件中。


1.定义Specification:

package edu.dgut.supervision.customRepository;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.data.jpa.domain.Specification;

//定义Specification(自定义Repository实现)
public class CustomerSpecs {
	//根据任务编号,督查项目,督查点动态查询
	public static <T> Specification<T> byAuto(String renwuNo,String projectName,String name){
		
		return new Specification<T>(){

			@Override
			public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
				List<Predicate> predicates = new ArrayList<>();
		        if(null != renwuNo && !"".equals(renwuNo)){
		            predicates.add(criteriaBuilder.equal(root.get("renwuNo"), renwuNo));
		        }
		        if(null != projectName && !"".equals(projectName)){
		            predicates.add(criteriaBuilder.equal(root.get("projectName"), projectName));
		        }
		        if(null != name && !"".equals(name)){
		            predicates.add(criteriaBuilder.equal(root.get("name"), name));
		        }
		        return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
			}
		};
	}
}

toPredicate方法中构造自定义的查询条件,and是且关系,or是或关系。


2.定义Repository接口

package edu.dgut.supervision.customRepository;

import java.io.Serializable;
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.query.Param;

import edu.dgut.supervision.domain.VDuchataizhang;

/**
 * 自定义接口:根据任务编号,督查项目,督查点查询督查任务
 * @author Mike
 *
 * @param <T>
 * @param <ID>
 */
@NoRepositoryBean
public interface CustomRepository<T,ID extends Serializable> extends JpaRepository<T,ID>,JpaSpecificationExecutor<T>{
	List<VDuchataizhang> findByCondition(@Param("renwuNo")String renwuNo,@Param("projectName")String projectName,@Param("name")String name);
}


@NoRepositoryBean指明当前这个接口不是我们领域类的接口,该接口继承了JpaRepository,让我们具备了JpaRepository所提供的方法;继承了JpaSpecificationExecutor,让我们具备使用Specification能力


3.自定义接口的实现

package edu.dgut.supervision.customRepository;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;

import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import edu.dgut.supervision.domain.VDuchataizhang;

import static edu.dgut.supervision.customRepository.CustomerSpecs.*;

//自定义数据库接口实现
public class CustomRepositoryImpl <T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements 
CustomRepository<T,ID>{
	public CustomRepositoryImpl(Class<T> domainClass,EntityManager entityManager){
		super(domainClass,entityManager);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<VDuchataizhang> findByCondition(String renwuNo,String projectName,String name) {
		return (List<VDuchataizhang>) findAll(byAuto(renwuNo,projectName,name));
	}
}


此类继承了JpaRepository的实现类SimpleJpaRepository,让我们可以使用SimpleJpaRepository的方法,此类当然还要实现我们自定义的接口CustomRepository,findByCondition方法使用byAuto Specification构造的条件查询,并提供分页功能。


4.定义repositoryFactoryBean:

package edu.dgut.supervision.customRepository;

import java.io.Serializable;

import javax.persistence.EntityManager;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;

public class CustomRepositoryFactoryBean<T extends JpaRepository<S,ID>,S,ID extends Serializable>
	extends JpaRepositoryFactoryBean<T,S,ID>{
	
	public CustomRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
		super(repositoryInterface);
	}

	@Override
	protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager){
		return new CustomRepositoryFactory(entityManager);
	}
	
	private static class CustomRepositoryFactory extends JpaRepositoryFactory{

		public CustomRepositoryFactory(EntityManager entityManager) {
			super(entityManager);
		}
		
		@Override
		@SuppressWarnings({"unchecked"})
		protected <T,ID extends Serializable> SimpleJpaRepository<?,?> getTargetRepository(
						RepositoryInformation information,EntityManager entityManager){
				return new CustomRepositoryImpl<T,ID>((Class<T>)information.getDomainType(),entityManager);
		}
		
		@Override
		protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata){
			return CustomRepositoryImpl.class;
		}
		
	}
}

自定义JpaRepositoryFactoryBean替代默认RepositoryFactoryBean,我们会获得一个RepositoryFactory,RepositoryFactory将会注册我们自定义的Repository的实现。


5.开启自定义支持

package edu.dgut.supervision;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

import edu.dgut.supervision.customRepository.CustomRepositoryFactoryBean;

@SpringBootApplication
//开启自定义Repository的配置
@EnableJpaRepositories(repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class)
public class SupervisionApplication{
	
	public static void main(String[] args) {
		SpringApplication.run(SupervisionApplication.class, args);
	}
}
这一步非常重要,我之前就是忘记开启,所以自定义的repository不起作用。

6.继承自定义接口

package edu.dgut.supervision.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.transaction.annotation.Transactional;

import edu.dgut.supervision.customRepository.CustomRepository;
import edu.dgut.supervision.domain.VDuchataizhang;

/**
 * @author Jackie
 *
 */
@RepositoryRestResource(collectionResourceRel = "VDuchataizhang", path = "duchataizhang")
public interface DuchataizhangRepository extends PagingAndSortingRepository<VDuchataizhang, String>,CustomRepository<VDuchataizhang,String>{
	
	@Transactional(readOnly=true)
	@Query("select u from VDuchataizhang u where u.renwuNo = ?1")
	Page<VDuchataizhang> findByRenwuNo(@Param("renwuNo")String renwuNo,Pageable pageable);
	
	@Query("select u from VDuchataizhang u")
	List<VDuchataizhang> findAll();
	
	//根据任务编号和督查点获取对应的督查台账记录
	@Query("select u from VDuchataizhang u where u.renwuNo = ?1 and u.name = ?2")
	VDuchataizhang getProject(@Param("renwuNo")String renwuNo,@Param("name")String name);
	
	//根据任务编号和项目编号获取对应的督查台账记录
	@Query("select u from VDuchataizhang u where u.renwuNo = ?1 and u.projectNo = ?2")
	Page<VDuchataizhang> getByTaskNoAndProjectNo(@Param("renwuNo")String renwuNo,@Param("projectNo")String projectNo,Pageable pageable);

//	//根据任务编号获取督查任务
	@Query("select u from VDuchataizhang u where u.renwuNo = ?1")
	List<VDuchataizhang> findListByRenwuNo(@Param("renwuNo")String renwuNo);
}

只需让实体类Repository继承我们自定义的Repository接口,即可使用我们在自定义Repository中实现的功能。


7.调用自定义的Repository接口

/**
	 * 根据任务编号,督查项目,督查点查询督查任务
	 * @param renwuNo
	 * @param projectName
	 * @param name
	 * @return
	 */
	@RequestMapping("/findDuchataizhang")
	@ResponseBody
	public Map<String,Object> findDuchataizhang(String renwuNo,String projectName,String name){
		Map<String,Object> resultMap = new HashMap<String,Object>();
		//获取返回的数据
		resultMap.put("data", duchataizhangRepository.findByCondition(renwuNo,projectName,name));
		return resultMap;
	}

这样就实现了动态条件查询


猜你喜欢

转载自blog.csdn.net/java_mike/article/details/76220673