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); }
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)); } }
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; }
这样就实现了动态条件查询