SpringDataJPA的Specifications动态查询

今天药忘吃喽~ 2023-07-01 04:29 190阅读 0赞

有时我们在查询某个实体的时候,给定的条件是不固定的,这时就需要动态构建相应的查询语句,在SpringData JPA中可以通过JpaSpecificationExecutor接口查询。相比JPQL,其优势是类型安全,更加的面向对象

  1. import java.util.List;
  2. import org.springframework.data.domain.Page;
  3. import org.springframework.data.domain.Pageable;
  4. import org.springframework.data.domain.Sort;
  5. import org.springframework.data.jpa.domain.Specification;
  6. /**
  7. * JpaSpecificationExecutor中定义的方法
  8. **/
  9. public interface JpaSpecificationExecutor<T> {
  10. //根据条件查询一个对象
  11. T findOne(Specification<T> spec);
  12. //根据条件查询集合
  13. List<T> findAll(Specification<T> spec);
  14. //根据条件分页查询
  15. Page<T> findAll(Specification<T> spec, Pageable pageable);
  16. //排序查询查询
  17. List<T> findAll(Specification<T> spec, Sort sort);
  18. //统计查询
  19. long count(Specification<T> spec);
  20. }

对于JpaSpecificationExecutor,这个接口基本是围绕着Specification接口来定义的。我们可以简单的理解为,Specification构造的就是查询条件。

Specification接口中只定义了如下一个方法:

  1. //构造查询条件
  2. /**
  3. * root :Root接口,代表查询的根对象,可以通过root获取实体中的属性
  4. * query :代表一个顶层查询对象,用来自定义查询
  5. * cb :用来构建查询,此对象里有很多条件方法
  6. **/
  7. public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);

单条件查询

  1. package com.oceanstar.test;
  2. import com.oceanstar.dao.CustomerDao;
  3. import com.oceanstar.entity.Customer;
  4. import org.junit.Test;
  5. import org.junit.runner.RunWith;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.data.jpa.domain.Specification;
  8. import org.springframework.test.context.ContextConfiguration;
  9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  10. import javax.persistence.criteria.*;
  11. @RunWith(SpringJUnit4ClassRunner.class)
  12. @ContextConfiguration(locations = "classpath:applicationContext.xml")
  13. public class SpecTest {
  14. @Autowired
  15. private CustomerDao customerDao;
  16. //匿名内部类
  17. /**
  18. * 自定义查询条件
  19. * 1.实现Specification接口(提供泛型:查询的对象类型)
  20. * 2.实现toPredicate方法(构造查询条件)
  21. * 3.需要借助方法参数中的两个参数(
  22. * root:获取需要查询的对象属性
  23. * CriteriaBuilder:构造查询条件的,内部封装了很多的查询条件(模糊匹配,精准匹配)
  24. * )
  25. * 案例:根据客户名称查询,查询客户名为传智播客的客户
  26. * 查询条件
  27. * 1.查询方式
  28. * cb对象
  29. * 2.比较的属性名称
  30. * root对象
  31. *
  32. */
  33. /**
  34. * 根据条件,查询单个对象
  35. *
  36. */
  37. @Test
  38. public void testSpec() {
  39. //匿名内部类
  40. /**
  41. * 自定义查询条件
  42. * 1.实现Specification接口(提供泛型:查询的对象类型)
  43. * 2.实现toPredicate方法(构造查询条件)
  44. * 3.需要借助方法参数中的两个参数(
  45. * root:获取需要查询的对象属性
  46. * CriteriaBuilder:构造查询条件的,内部封装了很多的查询条件(模糊匹配,精准匹配)
  47. * )
  48. * 案例:根据客户名称查询,查询客户名为传智播客的客户
  49. * 查询条件
  50. * 1.查询方式
  51. * cb对象
  52. * 2.比较的属性名称
  53. * root对象
  54. *
  55. */
  56. Specification<Customer> spec = new Specification<Customer>() {
  57. @Override
  58. public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
  59. //1.获取比较的属性
  60. Path<Object> custName = root.get("custName");
  61. //2.构造查询条件 : select * from cst_customer where cust_name = '传智播客'
  62. /**
  63. * 第一个参数:需要比较的属性(path对象)
  64. * 第二个参数:当前需要比较的取值
  65. */
  66. Predicate predicate = cb.equal(custName, "aaaa");//进行精准的匹配 (比较的属性,比较的属性的取值)
  67. return predicate;
  68. }
  69. };
  70. Customer customer = customerDao.findOne(spec);
  71. System.out.println(customer);
  72. }
  73. }

多条件查询

  1. package com.oceanstar.test;
  2. import com.oceanstar.dao.CustomerDao;
  3. import com.oceanstar.entity.Customer;
  4. import org.junit.Test;
  5. import org.junit.runner.RunWith;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.data.jpa.domain.Specification;
  8. import org.springframework.test.context.ContextConfiguration;
  9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  10. import javax.persistence.criteria.*;
  11. @RunWith(SpringJUnit4ClassRunner.class)
  12. @ContextConfiguration(locations = "classpath:applicationContext.xml")
  13. public class SpecTest {
  14. @Autowired
  15. private CustomerDao customerDao;
  16. /**
  17. * 多条件查询
  18. * 案例:根据客户名(传智播客)和客户所属行业查询(it教育)
  19. *
  20. */
  21. @Test
  22. public void testSpec1() {
  23. /**
  24. * root:获取属性
  25. * 客户名
  26. * 所属行业
  27. * cb:构造查询
  28. * 1.构造客户名的精准匹配查询
  29. * 2.构造所属行业的精准匹配查询
  30. * 3.将以上两个查询联系起来
  31. */
  32. Specification<Customer> spec = new Specification<Customer>() {
  33. @Override
  34. public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
  35. Path<Object> custName = root.get("custName");//客户名
  36. Path<Object> custIndustry = root.get("custIndustry");//所属行业
  37. //构造查询
  38. //1.构造客户名的精准匹配查询
  39. Predicate p1 = cb.equal(custName, "aaaa");//第一个参数,path(属性),第二个参数,属性的取值
  40. //2..构造所属行业的精准匹配查询
  41. Predicate p2 = cb.equal(custIndustry, "It");
  42. //3.将多个查询条件组合到一起:组合(满足条件一并且满足条件二:与关系,满足条件一或满足条件二即可:或关系)
  43. Predicate and = cb.and(p1, p2);//以与的形式拼接多个查询条件
  44. // cb.or();//以或的形式拼接多个查询条件
  45. return and;
  46. }
  47. };
  48. Customer customer = customerDao.findOne(spec);
  49. System.out.println(customer);
  50. }
  51. }

模糊查询

  1. package com.oceanstar.test;
  2. import com.oceanstar.dao.CustomerDao;
  3. import com.oceanstar.entity.Customer;
  4. import org.junit.Test;
  5. import org.junit.runner.RunWith;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.data.jpa.domain.Specification;
  8. import org.springframework.test.context.ContextConfiguration;
  9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  10. import javax.persistence.criteria.*;
  11. import java.util.List;
  12. @RunWith(SpringJUnit4ClassRunner.class)
  13. @ContextConfiguration(locations = "classpath:applicationContext.xml")
  14. public class SpecTest {
  15. @Autowired
  16. private CustomerDao customerDao;
  17. /**
  18. * 案例:完成根据客户名称的模糊匹配,返回客户列表
  19. * 客户名称以 ’传智播客‘ 开头
  20. *
  21. * equal :直接的到path对象(属性),然后进行比较即可
  22. * gt,lt,ge,le,like : 得到path对象,根据path指定比较的参数类型,再去进行比较
  23. * 指定参数类型:path.as(类型的字节码对象)
  24. */
  25. @Test
  26. public void testSpec3() {
  27. //构造查询条件
  28. Specification<Customer> spec = new Specification<Customer>() {
  29. @Override
  30. public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
  31. //查询属性:客户名
  32. Path<Object> custName = root.get("custName");
  33. //查询方式:模糊匹配
  34. Predicate like = cb.like(custName.as(String.class), "传智播客%");
  35. return like;
  36. }
  37. };
  38. List<Customer> list = customerDao.findAll(spec);
  39. for (Customer customer : list) {
  40. System.out.println(customer);
  41. }
  42. }
  43. }

排序

  1. package com.oceanstar.test;
  2. import com.oceanstar.dao.CustomerDao;
  3. import com.oceanstar.entity.Customer;
  4. import org.junit.Test;
  5. import org.junit.runner.RunWith;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.data.domain.Sort;
  8. import org.springframework.data.jpa.domain.Specification;
  9. import org.springframework.test.context.ContextConfiguration;
  10. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  11. import javax.persistence.criteria.*;
  12. import java.util.List;
  13. @RunWith(SpringJUnit4ClassRunner.class)
  14. @ContextConfiguration(locations = "classpath:applicationContext.xml")
  15. public class SpecTest {
  16. @Autowired
  17. private CustomerDao customerDao;
  18. /**
  19. * 案例:完成根据客户名称的模糊匹配,返回客户列表
  20. * 客户名称以 ’传智播客‘ 开头
  21. *
  22. * equal :直接的到path对象(属性),然后进行比较即可
  23. * gt,lt,ge,le,like : 得到path对象,根据path指定比较的参数类型,再去进行比较
  24. * 指定参数类型:path.as(类型的字节码对象)
  25. */
  26. @Test
  27. public void testSpec3() {
  28. //构造查询条件
  29. Specification<Customer> spec = new Specification<Customer>() {
  30. @Override
  31. public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
  32. Path<Object> custName = root.get("custName");
  33. Predicate like = cb.like(custName.as(String.class), "传智播客%");
  34. return like;
  35. }
  36. };
  37. //添加排序
  38. //创建排序对象,需要调用构造方法实例化sort对象
  39. //第一个参数:排序的顺序(倒序,正序)
  40. // Sort.Direction.DESC:倒序
  41. // Sort.Direction.ASC : 升序
  42. //第二个参数:排序的属性名称
  43. Sort sort = new Sort(Sort.Direction.DESC,"custId");
  44. List<Customer> list = customerDao.findAll(spec, sort);
  45. for (Customer customer : list) {
  46. System.out.println(customer);
  47. }
  48. }
  49. }

分页查询

  1. package com.oceanstar.test;
  2. import com.oceanstar.dao.CustomerDao;
  3. import com.oceanstar.entity.Customer;
  4. import org.junit.Test;
  5. import org.junit.runner.RunWith;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.data.domain.Page;
  8. import org.springframework.data.domain.PageRequest;
  9. import org.springframework.data.domain.Pageable;
  10. import org.springframework.data.domain.Sort;
  11. import org.springframework.data.jpa.domain.Specification;
  12. import org.springframework.test.context.ContextConfiguration;
  13. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  14. @RunWith(SpringJUnit4ClassRunner.class)
  15. @ContextConfiguration(locations = "classpath:applicationContext.xml")
  16. public class SpecTest {
  17. @Autowired
  18. private CustomerDao customerDao;
  19. /**
  20. * 分页查询
  21. * Specification: 查询条件
  22. * Pageable:分页参数
  23. * 分页参数:查询的页码,每页查询的条数
  24. * findAll(Specification,Pageable):带有条件的分页
  25. * findAll(Pageable):没有条件的分页
  26. * 返回:Page(springDataJpa为我们封装好的pageBean对象,数据列表,共条数)
  27. */
  28. @Test
  29. public void testSpec4() {
  30. Specification spec = null;
  31. //PageRequest对象是Pageable接口的实现类
  32. /**
  33. * 创建PageRequest的过程中,需要调用他的构造方法传入两个参数
  34. * 第一个参数:当前查询的页数(从0开始)
  35. * 第二个参数:每页查询的数量
  36. */
  37. Pageable pageable = new PageRequest(0,2);
  38. //分页查询
  39. Page<Customer> page = customerDao.findAll(null, pageable);
  40. System.out.println(page.getContent()); //得到数据集合列表
  41. System.out.println(page.getTotalElements());//得到总条数
  42. System.out.println(page.getTotalPages());//得到总页数
  43. }
  44. }

对于Spring Data JPA中的分页查询,是其内部自动实现的封装过程,返回的是一个Spring Data JPA提供的pageBean对象

发表评论

表情:
评论列表 (有 0 条评论,190人围观)

还没有评论,来说两句吧...

相关阅读