如何在Spring Data JPA中实现动态查询
Specifications动态查询方法
T findOne(Specification<T> spec); //查询单个 List<T> findAll(Specification<T> spec); //查询列表 List<T> findAll(Specification<T> spec, Sort sort); //排序查询 Page<T> findAll(Specification<T> spec, Pageable pageable); //分页查询 long count(Specification<T> spec); //统计查询
查询条件-Specification
自定义Specification实现类,实现
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
构造查询条件,参数如下
- Root:查询的对象,查询条件/属性都可以从root对象中获取
- CriteriaQuery:上层查询对象,定义查询方式,一般不用
- CriteriaQueryBuilder:查询对象的构造器,封装了较多的查询条件
动态查询实现
1.新建Maven项目,加入Maven依赖 2.新建entity包,增加实体类Customer 3.新建dao包,增加CustomerDao 4.在test包中新建dao包,增加CustomerDao
findOne(Specification spec)
直接在CustomerDaoTest中书写测试方法
@Test public void testFindOne(){ // 匿名内部类 Specification<Customer> specification = (Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> { // 构造查询条件,实现toPredicate方法 //1.获取比较的属性 Path<Object> custName = root.get("custName"); //2.构造查询条件,equal为精准匹配 Predicate thor_odin = cb.equal(custName, "Thor Odin"); return thor_odin; }; Customer one = customerDao.findOne(specification); System.out.println(one); }
使用了lambda表达式实现Specification匿名内部类,测试结果如下
多个条件查询,使用and或者or连接多个查询条件
@Test public void testFindOneByMultiCondition(){ Specification<Customer> specification = (Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> { // 构造查询条件,实现toPredicate方法 //1.获取比较的属性 Path<Object> custName = root.get("custName"); Path<Object> custIndustry = root.get("custIndustry"); //2.构造查询条件,equal为精准匹配 Predicate thor_odin = cb.equal(custName,"Thor Odin"); Predicate asgard = cb.equal(custIndustry, "God of Thunder"); // 组合查询条件,以与的形式组合查询条件,也可以使用or Predicate mutil = cb.and(thor_odin, asgard); return mutil; }; Customer one = customerDao.findOne(specification); System.out.println(one); }
findAll(Specification spec)实现模糊查询
/** * equal方法可以直接使用path属性及属性值的方式得到Predicate对象 * gt,lt,ge,le,like需要使用path属性.as(属性类型.class)及属性vlaue来得到Predicate对象 */ @Test public void testFindAllByLike(){ Specification<Customer> specification = (Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> { // 构造查询条件,实现toPredicate方法 //1.获取比较的属性 Path<Object> custSource = root.get("custSource"); Predicate like = cb.like(custSource.as(String.class), "FB%"); return like; }; List<Customer> all = customerDao.findAll(specification); for (Customer customer : all) { System.out.println(customer); } }
List findAll(Specification spec, Sort sort); 排序查询
@Test public void testFindAllByLikeAsc(){ Specification<Customer> specification = (Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> { // 构造查询条件,实现toPredicate方法 //1.获取比较的属性 Path<Object> custSource = root.get("custSource"); Predicate like = cb.like(custSource.as(String.class), "FB%"); return like; }; // 排序规则,倒叙排列 Sort sort = new Sort(Sort.Direction.DESC,"custId"); List<Customer> all = customerDao.findAll(specification,sort); for (Customer customer : all) { System.out.println(customer); } } }
使用Sort构造排序规则,需要两个参数,排序规则和排序字段,输出结果如下
Page findAll(Specification spec, Pageable pageable)分页查询
先通过save()方法往表中添加数据
@Test public void testInsert(){ for (int i = 1; i <= 30; i++) { Customer customer = new Customer(); customer.setCustName("Spider Army No " + i); customer.setCustIndustry("Queen"); customer.setCustLevel("LV 1"); customerDao.save(customer); } }
新增分页测试代码
@Test public void testPaging(){ Specification spec = null; // 当前查询页数和每页查询数量 Pageable pageable = new PageRequest(0,5); Page<Customer> all = customerDao.findAll(null,pageable); //获取总页数 System.out.println(all.getTotalPages()); // 获取数据总量 System.out.println(all.getTotalElements()); // 获取当前页数据集合 List<Customer> content = all.getContent(); // 遍历集合,得到当前页的所有Customer数据 for (Customer customer : content) { System.out.println(customer); } }
执行分页查询测试成功查出首页数据