Specifications动态查询

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

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

对于JpaSpecificationExecutor,这个接口基本是围绕着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. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
  6. xmlns:jpa="http://www.springframework.org/schema/data/jpa"
  7. xmlns:task="http://www.springframework.org/schema/task"
  8. xmlns:contxt="http://www.springframework.org/schema/context"
  9. xsi:schemaLocation="
  10. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  11. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
  12. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
  13. http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
  14. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
  15. http://www.springframework.org/schema/data/jpa
  16. http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
  17.  
  18. <!-- 配置实体类管理工厂 -->
  19. <bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  20. <property name="dataSource" ref="dataSource"/>
  21.  
  22. <property name="packagesToScan" value="com.ytfs.entity"/>
  23. <property name="persistenceProvider">
  24. <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
  25. </property>
  26.  
  27. <property name="jpaVendorAdapter">
  28. <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
  29. <property name="showSql" value="true"/>
  30. <property name="database" value="MYSQL"/>
  31. <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
  32. <property name="generateDdl" value="false"/>
  33. </bean>
  34. </property>
  35. </bean>
  36.  
  37. <!-- 配置事务管理器 -->
  38.  
  39. <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
  40. <property name="dataSource" ref="dataSource"/>
  41. </bean>
  42.  
  43. <!-- 整合jpa -->
  44. <jpa:repositories base-package="com.ytfs.dao" transaction-manager-ref="transactionManager"
  45. entity-manager-factory-ref="entityManagerFactoryBean"/>
  46.  
  47. <!-- spring的包扫描 -->
  48.  
  49. <context:component-scan base-package="com.ytfs"/>
  50. <!-- 整合数据源 -->
  51. <context:property-placeholder location="classpath:jdbcConfig.properties"/>
  52. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
  53. <property name="driverClassName" value="${jdbc.driver}"/>
  54. <property name="username" value="${jdbc.username}"/>
  55. <property name="password" value="${jdbc.password}"/>
  56. <property name="url" value="${jdbc.url}"/>
  57. </bean>
  58. </beans>
  1. jdbc.driver=com.mysql.jdbc.Driver
  2. jdbc.url=jdbc:mysql://localhost:3306/jpa
  3. jdbc.username=root
  4. jdbc.password=root

实体类

  

  1. package com.ytfs.entity;
  2.  
  3. import javax.persistence.*;
  4. import java.io.Serializable;
  5.  
  6. /**
  7. * @Classname Customer
  8. * @Description TODO(客户的实体类)
  9. * @Date 2020/5/6 16:15
  10. * @Created by ytfs
  11. */
  12.  
  13. @Entity
  14. @Table(name = "cst_customer")
  15. public class Customer implements Serializable {
  16. /**
  17. * cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
  18. * `cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
  19. * `cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
  20. * `cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
  21. * `cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
  22. * `cust_address` varchar(128) DEFAULT NULL COMMENT '客户联系地址',
  23. * `cust_phone` v
  24. */
  25. @Id
  26. @GeneratedValue(strategy = GenerationType.IDENTITY)
  27. @Column(name = "cust_id")
  28. private Long custId;
  29.  
  30. @Column(name = "cust_name")
  31. private String custName;
  32.  
  33. @Column(name = "cust_source")
  34. private String custSource;
  35.  
  36. @Column(name = "cust_industry")
  37. private String custIndustry;
  38.  
  39. @Column(name = "cust_level")
  40. private String custLevel;
  41.  
  42. @Column(name = "cust_address")
  43. private String custAddress;
  44.  
  45. @Column(name = "cust_phone")
  46. private String custPhone;
  47.  
  48. public Long getCustId() {
  49. return custId;
  50. }
  51.  
  52. public void setCustId(Long custId) {
  53. this.custId = custId;
  54. }
  55.  
  56. public String getCustName() {
  57. return custName;
  58. }
  59.  
  60. public void setCustName(String custName) {
  61. this.custName = custName;
  62. }
  63.  
  64. public String getCustSource() {
  65. return custSource;
  66. }
  67.  
  68. public void setCustSource(String custSource) {
  69. this.custSource = custSource;
  70. }
  71.  
  72. public String getCustIndustry() {
  73. return custIndustry;
  74. }
  75.  
  76. public void setCustIndustry(String custIndustry) {
  77. this.custIndustry = custIndustry;
  78. }
  79.  
  80. public String getCustLevel() {
  81. return custLevel;
  82. }
  83.  
  84. public void setCustLevel(String custLevel) {
  85. this.custLevel = custLevel;
  86. }
  87.  
  88. public String getCustAddress() {
  89. return custAddress;
  90. }
  91.  
  92. public void setCustAddress(String custAddress) {
  93. this.custAddress = custAddress;
  94. }
  95.  
  96. public String getCustPhone() {
  97. return custPhone;
  98. }
  99.  
  100. public void setCustPhone(String custPhone) {
  101. this.custPhone = custPhone;
  102. }
  103.  
  104. @Override
  105. public String toString() {
  106. return "Customer{" +
  107. "custId=" + custId +
  108. ", custName='" + custName + '\'' +
  109. ", custSource='" + custSource + '\'' +
  110. ", custIndustry='" + custIndustry + '\'' +
  111. ", custLevel='" + custLevel + '\'' +
  112. ", custAddress='" + custAddress + '\'' +
  113. ", custPhone='" + custPhone + '\'' +
  114. '}';
  115. }
  116. }

Dao接口

  1. package com.ytfs.dao;
  2.  
  3. import com.ytfs.entity.Customer;
  4. import org.springframework.data.jpa.repository.JpaRepository;
  5. import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
  6.  
  7. /**
  8. * @Classname ICustomerDao
  9. * @Description TODO(客户的数据访问层)
  10. * @Date 2020/5/6 16:20
  11. * @Created by ytfs
  12. */
  13.  
  14. public interface ICustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> {
  15. }

查询测试

  1. package com.ytfs.test;
  2.  
  3. import com.ytfs.dao.ICustomerDao;
  4. import com.ytfs.entity.Customer;
  5. import org.junit.Test;
  6. import org.junit.runner.RunWith;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.data.domain.Page;
  9. import org.springframework.data.domain.PageRequest;
  10. import org.springframework.data.domain.Pageable;
  11. import org.springframework.data.domain.Sort;
  12. import org.springframework.data.jpa.domain.Specification;
  13. import org.springframework.test.context.ContextConfiguration;
  14. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  15.  
  16. import javax.persistence.criteria.*;
  17. import java.util.ArrayList;
  18. import java.util.List;
  19. import java.util.Optional;
  20.  
  21. /**
  22. * @Classname Test
  23. * @Description TODO(测试)
  24. * @Date 2020/5/6 16:21
  25. * @Created by ytfs
  26. */
  27.  
  28. @RunWith(SpringJUnit4ClassRunner.class)
  29. @ContextConfiguration(locations = "classpath:applicationContext.xml")
  30. public class TestSpringDataJPA {
  31.  
  32. @Autowired
  33. private ICustomerDao customerDao;
  34.  
  35. /**
  36. * 根据名称查询用户
  37. */
  38. @Test
  39. public void testFindAll() {
  40. //匿名内部类
  41. /**
  42. * 自定义查询条件
  43. * 1.实现Specification接口(提供泛型:查询的对象类型)
  44. * 2.实现toPredicate方法(构造查询条件)
  45. * 3.需要借助方法参数中的两个参数(
  46. * root:获取需要查询的对象属性
  47. * CriteriaBuilder:构造查询条件的,内部封装了很多的查询条件(模糊匹配,精准匹配)
  48. * )
  49. * 案例:根据客户名称查询,查询客户名为传智播客的客户
  50. * 查询条件
  51. * 1.查询方式
  52. * criteriaBuilder对象
  53. * 2.比较的属性名称
  54. * root对象
  55. *
  56. */
  57. Specification<Customer> spec = new Specification<Customer>() {
  58. @Override
  59. public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
  60. //1.获取比较的属性
  61. Path<Object> custName = root.get("custName");
  62. //2.构造查询条件 : select * from cst_customer where cust_name = '传智播客'
  63. /**
  64. * 第一个参数:需要比较的属性(path对象)
  65. * 第二个参数:当前需要比较的取值
  66. */
  67. Predicate predicate = criteriaBuilder.equal(custName, "雨听风说");//进行精准的匹配 (比较的属性,比较的属性的取值)
  68.  
  69. return predicate;
  70. }
  71. };
  72.  
  73. List<Customer> customers = this.customerDao.findAll(spec);
  74.  
  75. customers.forEach(System.out::println);
  76. }
  77.  
  78. /**
  79. * 多条件查询
  80. */
  81.  
  82. @Test
  83. public void testFindOne() {
  84. /**
  85. * root:获取属性
  86. * 客户名
  87. * id
  88. * criteriaBuilder:构造查询
  89. * 1.构造客户名的精准匹配查询
  90. * 2.构造所属行业的精准匹配查询
  91. * 3.将以上两个查询联系起来
  92. */
  93. Specification<Customer> spec = new Specification<Customer>() {
  94. @Override
  95. public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
  96.  
  97. Path<Object> path = root.get("custName");
  98.  
  99. Path<Object> path1 = root.get("custId");
  100. /*
  101. 构造查询
  102. */
  103. //1.构造客户名的精准匹配查询
  104. Predicate predicate = criteriaBuilder.equal(path, "雨听风说");//第一个参数,path(属性),第二个参数,属性的取值
  105. //2..构造id的精准匹配查询
  106. Predicate equal = criteriaBuilder.equal(path1, 1L);
  107.  
  108. //3.将多个查询条件组合到一起:组合(满足条件一并且满足条件二:与关系,满足条件一或满足条件二即可:或关系)
  109. // criteriaBuilder.or();//以或的形式拼接多个查询条件
  110. Predicate predicate1 = criteriaBuilder.and(predicate, equal);//以与的形式将条件拼接在一起
  111. return predicate1;
  112. }
  113. };
  114.  
  115. Optional<Customer> customers = this.customerDao.findOne(spec);
  116.  
  117. customers.stream().forEach(c -> {
  118. System.out.println("c = " + c);
  119. });
  120. }
  121.  
  122. /**
  123. * 案例:完成根据客户名称的模糊匹配,返回客户列表
  124. * 客户名称包含 ’听风‘
  125. *
  126. * equal :直接的到path对象(属性),然后进行比较即可
  127. * gt,lt,ge,le,like : 得到path对象,根据path指定比较的参数类型,再去进行比较
  128. * 指定参数类型:path.as(类型的字节码对象)
  129. */
  130. @Test
  131. public void testLike() {
  132.  
  133. Specification<Customer> spec = new Specification<Customer>() {
  134. @Override
  135. public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
  136.  
  137. Path<Object> custName = root.get("custName");
  138.  
  139. Predicate predicate = criteriaBuilder.like(custName.as(String.class), "%雨听%");
  140.  
  141. return predicate;
  142. }
  143. };
  144.  
  145. List<Customer> customers = this.customerDao.findAll(spec);
  146.  
  147. customers.forEach(System.out::println);
  148.  
  149. }
  150.  
  151. /**
  152. * 查询并排序
  153. */
  154.  
  155. @Test
  156. public void testLikeAndSort() {
  157.  
  158. Specification<Customer> spec = new Specification<Customer>() {
  159. @Override
  160. public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
  161.  
  162. Path<Object> custName = root.get("custName");
  163.  
  164. Predicate predicate = criteriaBuilder.like(custName.as(String.class), "%雨听%");
  165.  
  166. return predicate;
  167. }
  168. };
  169. //添加排序
  170. //创建排序对象,需要调用构造方法实例化sort对象
  171. //第一个参数:排序的顺序(倒序,正序)
  172. // Sort.by("custId").descending():倒序
  173. // Sort.by("custId").ascending(); : 升序
  174. //第二个参数:排序的属性名称
  175.  
  176. Sort sort = Sort.by("custId").descending();
  177. List<Customer> customers = this.customerDao.findAll(spec,sort);
  178.  
  179. customers.forEach(System.out::println);
  180. }
  181.  
  182. /**
  183. * 分页查询
  184. * Specification: 查询条件
  185. * Pageable:分页参数
  186. * 分页参数:查询的页码,每页查询的条数
  187. * findAll(Specification,Pageable):带有条件的分页
  188. * findAll(Pageable):没有条件的分页
  189. * 返回:Page(springDataJpa为我们封装好的pageBean对象,数据列表,共条数)
  190. */
  191. @Test
  192. public void testPage() {
  193.  
  194. //PageRequest对象是Pageable接口的实现类
  195. /**
  196. * 创建PageRequest的过程中,需要调用他的构造方法传入两个参数
  197. * 第一个参数:当前查询的页数(从0开始)
  198. * 第二个参数:每页查询的数量
  199. */
  200. Pageable pageable = PageRequest.of(0,2);
  201.  
  202. Page<Customer> page = this.customerDao.findAll(pageable);
  203.  
  204. System.out.println(page.getContent()); //得到数据集合列表
  205. System.out.println(page.getTotalElements());//得到总条数
  206. System.out.println(page.getTotalPages());//得到总页数
  207.  
  208. }
  209. }

spring-data-jpa -hibernate --specificationExecutor的更多相关文章

  1. spring data jpa hibernate jpa 三者之间的关系

    JPA规范与ORM框架之间的关系是怎样的呢? JPA规范本质上就是一种ORM规范,注意不是ORM框架——因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服 ...

  2. Spring Boot 2.x 之 Spring Data JPA, Hibernate 5

    1. Spring Boot常用配置项 基于Spring Boot 2.0.6.RELEASE 1.1 配置属性类 spring.jpa前缀的相关配置项定义在JpaProperties类中, 1.2 ...

  3. Spring data jpa hibernate:查询异常java.sql.SQLException: Column '列名' not found

    使用spring boot,jap,hibernate不小心的错误: java.sql.SQLException: Column '列名' not found: 这句话的意思是:找不到此列 为什么会出 ...

  4. Spring Data JPA Hibernate @QueryHints

    另一个实例: http://leobluewing.iteye.com/blog/2032396 : 本文内容来源:https://blog.csdn.net/gavinchen1985/articl ...

  5. Spring Data Jpa(Hibernate) OneToMany

    这个其实非常简单.假设有topic 和 subscriber两个实体类,不考虑关联关系,则连个类的代码如下: /** * Created by csonezp on 2017/8/31. */ @En ...

  6. maven springmvc spring data jpa hibernate sqlserver demo

    搭建费了半天费,各种报错,缺少各种jar包,不兼容等,给那些没弄过的一个参考. 点击我下载

  7. 转:spring data jpa、 hibernate、 jpa 三者之间的关系

    原文链接:spring data jpa. hibernate. jpa 三者之间的关系 spring data jpa hibernate jpa 三者之间的关系 JPA规范与ORM框架之间的关系是 ...

  8. Spring Data JPA Tutorial Part Nine: Conclusions(未翻译)

    This is the ninth and the last part of my Spring Data JPA tutorial. Now it is time to take a look of ...

  9. Spring Data JPA 和MyBatis比较

    现在Dao持久层的解决方案中,大部分是采用Spring Data JPA或MyBatis解决方案,并且传统企业多用前者,互联网企业多用后者. Spring Data JPA 是Spring Data ...

  10. java(样品集成框架spring、spring mvc、spring data jpa、hibernate)

    这是你自己的参考springside集成框架的开源项目.主要的整合spring.spring mvc.spring data jpa.hibernate几个框架,对于这些框架中仍然感觉更舒适sprin ...

随机推荐

  1. JavaScript数组的push()等方法的使用

    数组是值得有序集合.每个值在数组中有一个位置,用数字表示,叫做索引.JavaScript数组是无类型的:数组元素可以是任何类型,而且同一个数组中可以存在不同类型元素,甚至可以是对象或是其他数组,这就可 ...

  2. java 编程基础:注解(Annotation Processing Tool)注解处理器 利用注解解读类属性生成XML文件

    APT的介绍: APT(Annotation Processing Tool)是一种注解处理工具,它对源代码文件进行检测,并找出源文件所包含的注解信息,然后针对注解信息进行额外的处理. 使用APT工具 ...

  3. HTTP状态码一览表

    常见Http状态码大全 2018年03月16日 11:36:31 阅读数:153 一些常见的状态码为: 200 - 服务器成功返回网页404 - 请求的网页不存在503 - 服务不可用详细分解: 1x ...

  4. C++ 11新特性:std::future & std::shared_future) (转载)

    上一讲<C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)>主要介绍了 <future> 头文件中的 std::pack ...

  5. react Input 表单

    ​ input react 表单 input 密码框在谷歌浏览器下 会有黄色填充 官网的不太用,这个比较好用 type="password" autoComplete=" ...

  6. 使用docker自定义oraclejdk启动jar包

    Dockerfile文件 FROM centos:7 #把java与tomcat添加到容器中 ADD jdk-8u161-linux-x64.tar.gz /usr/local/ #安装 vim编辑器 ...

  7. Visiual Studio之c++项目瘦身(删除中间项)

    欢迎指正 本文主要涉及 Visiual Studio(简称VS) 创建的c++项目 和 windows下批处理相关点. 1.中间项 A.VS创建的c++项目,生成后,会有许多中间项,包括项目生成的中间 ...

  8. 【LeetCode】70. Climbing Stairs 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目大意 题目大意 解题方法 递归 记忆化搜索 动态规划 空间压缩DP 日期 [L ...

  9. 【LeetCode】229. Majority Element II 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 hashmap统计次数 摩尔投票法 Moore Vo ...

  10. 【LeetCode】67. Add Binary 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 BigInteger类 模拟加法 日期 题目地址:h ...