JPA--SpringDataJpa之Specifications动态查询
Specifications动态查询
JpaSpecificationExecutor 方法列表
- T findOne(Specification spec):查询单个对象
- List findAll(Specification spec):查询列表
Page findAll(Specification spec, Pageable pageable):分页查询
- pageable:分页参数
- 返回值:分页pageBean(page:是springdatajpa提供的)
List findAll(Specification spec, Sort sort):查询列表
- Sort:排序参数
- long count(Specification spec):统计查询
Specification :
Specification是查询条件,由我们自己实现。
需要实现Predicate toPredicate(Root root, CriteriaQuery<?> query, CriteriaBuilder cb)方法
- root:查询的根对象(查询的任何属性都可以从根对象中获取)
- CriteriaQuery:顶层查询对象,自定义查询方式(了解:一般不用)
- CriteriaBuilder:查询的构造器,封装了很多的查询条件
示例
实体类
package pers.zhang.entity;
/** * @author zhang * @date 2019/12/15 - 22:10 */
import javax.persistence.*;
/** * 1.实体类和表的映射关系 * @Entity * @Table * 2.类中属性和表中字段的映射关系 * @Id * @GeneratedValue * @Colum */
@Entity //声明实体类
@Table(name="cst_customer") //建立实体类和表的映射关系
public class Customer {
@Id//声明当前私有属性为主键
@GeneratedValue(strategy= GenerationType.IDENTITY) //配置主键的生成策略
@Column(name="cust_id") //指定和表中cust_id字段的映射关系
private Long custId;
@Column(name="cust_name") //指定和表中cust_name字段的映射关系
private String custName;
@Column(name="cust_source")//指定和表中cust_source字段的映射关系
private String custSource;
@Column(name="cust_industry")//指定和表中cust_industry字段的映射关系
private String custIndustry;
@Column(name="cust_level")//指定和表中cust_level字段的映射关系
private String custLevel;
@Column(name="cust_address")//指定和表中cust_address字段的映射关系
private String custAddress;
@Column(name="cust_phone")//指定和表中cust_phone字段的映射关系
private String custPhone;
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
@Override
public String toString() {
return "Customer{" +
"custId=" + custId +
", custName='" + custName + '\'' +
", custSource='" + custSource + '\'' +
", custIndustry='" + custIndustry + '\'' +
", custLevel='" + custLevel + '\'' +
", custAddress='" + custAddress + '\'' +
", custPhone='" + custPhone + '\'' +
'}';
}
}
Dao接口
public interface MyCustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
}
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class SpecTest {
@Autowired
private MyCustomerDao customerDao;
}
根据条件查询单个对象
方法名称 | sql对应关系 |
---|---|
equle | filed = value |
gt(greaterThan ) | filed > value |
lt(lessThan ) | filed < value |
ge(greaterThanOrEqualTo ) | filed >= value |
le( lessThanOrEqualTo) | filed <= value |
notEqule | filed != value |
like | filed like value |
notLike | filed not like value |
@Test
public void testSpec(){
/* 自定义查询条件: 1.实现Specification接口(提供泛型:查询对象类型) 2.实现toPredicate方法(构造查询条件) 3.需要借助方法参数中的两个参数(root:获取需要查询的对象属性 CriteriaBuilder:构造查询条件的,内部封装了很多的查询条件(模糊匹配,精确匹配)) 示例:根据客户名称查询,查询客户名为网易的客户 查询条件: 1.查询方式 criteriaBuilder对象 2.比较的属性名称 root对象 */
Specification<Customer> spec = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//获取比较的属性
Path<Object> custName = root.get("custName");
//构造查询条件 select * from cst_customer where cust_name = '网易'
//第一个参数:需要比较的属性
//第二个参数:当前需要比较的取值
Predicate predicate = criteriaBuilder.equal(custName, "网易");//精准匹配
return predicate;
}
};
Customer customer = customerDao.findOne(spec);
System.out.println(customer);
}
多条件查询单个值
/* 多条件查询 示例:根据客户名(网页)和客户行业(游戏)查询客户 */
@Test
public void testSpec1(){
/* root:获取属性(客户名,所属行业) criteriaBuilder: 1.构造客户名的精准匹配查询 2.构造所属行业的精准匹配查询 3.将以上两个查询联系起来 */
Specification<Customer> spec = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> custName = root.get("custName");
Path<Object> custIndustry = root.get("custIndustry");
//构造查询参数
//1.构造客户名的精准匹配
Predicate p1 = criteriaBuilder.equal(custName, "网易");
//2.构造所属行业的精准匹配
Predicate p2 = criteriaBuilder.equal(custIndustry, "游戏");
//3.将多个条件组合到一起,组合(满足条件一并且满足条件二:与关系 满足条件一或满足条件二即可:或关系)
Predicate and = criteriaBuilder.and(p1, p2);//以与的形式拼接多个查询条件
//criteriaBuilder.or() 以或的方式拼接条件
return and;
}
};
Customer customer = customerDao.findOne(spec);
System.out.println(customer);
}
查询列表
/* 查询列表: 示例:根据客户名称模糊匹配,返回客户列表 criteriaBuilder的方法: equal:直接得到path对象(属性),然后进行比较 gt,lt,ge,le,like:得到path对象,根据句path指定比较的参数类型,再去进行比较 指定参数的类型:path.as(类型的字节码对象) */
@Test
public void testSpec3(){
Specification<Customer> spec = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> custName = root.get("custName");
Predicate predicate = criteriaBuilder.like(custName.as(String.class), "%腾%");
return predicate;
}
};
List<Customer> all = customerDao.findAll(spec);
for(Customer c : all)
System.out.println(c);
}
排序查询
/* 排序查询 示例:根据客户名称模糊匹配,逆序,返回客户列表 */
@Test
public void testSpec4(){
Specification<Customer> spec = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> custName = root.get("custName");
Predicate predicate = criteriaBuilder.like(custName.as(String.class), "%腾%");
return predicate;
}
};
/* 创建排序对象Sort 需要调用构造方法传递参数 1. 排序的顺序(asc | desc) 2. 排序的属性名 */
Sort sort = new Sort(Sort.Direction.ASC, "custName");
List<Customer> all = customerDao.findAll(spec);
for(Customer c : all)
System.out.println(c);
}
分页查询
Page接口
public interface Page<T> extends Iterable<T> {
int getNumber(); //当前第几页 返回当前页的数目。总是非负的
int getSize(); //返回当前页面的大小。
int getTotalPages(); //返回分页总数。
int getNumberOfElements(); //返回当前页上的元素数。
long getTotalElements(); //返回元素总数。
boolean hasPreviousPage(); //返回如果有上一页。
boolean isFirstPage(); //返回当前页是否为第一页。
boolean hasNextPage(); //返回如果有下一页。
boolean isLastPage(); //返回当前页是否为最后一页。
Iterator<T> iterator();
List<T> getContent(); //将所有数据返回为List
boolean hasContent(); //返回数据是否有内容。
Sort getSort(); //返回页的排序参数。
}
Pageable 接口:
/** * 分页信息抽象接口 * * @author Oliver Gierke */
public interface Pageable {
/** * 返回要返回的页面. * * @return the page to be returned. */
int getPageNumber();
/** * 返回要返回的项目的数量。 * * @return the number of items of that page */
int getPageSize();
/** * 根据底层页面和页面大小返回偏移量。 * * @return the offset to be taken */
int getOffset();
/** * 返回排序参数。 * * @return */
Sort getSort();
}
/* 分页查询: 1.findAll(Specification, Pageable):有条件的分页 2.findALL(Pageable):没有条件的分页 Specification:查询条件 Pageable:分页参数 返回:Page(springdataJpa为我们封装好的pageBean对象) */
@Test
public void testSpec5(){
Specification spec = null;
/* PageRequest是Pageable的实现类,在创建pageable的过程中,需要调用它的构造方法传入两个参数 1.当前查询的页数(从0开始) 2.每页查询的数量 */
Pageable pageable = new PageRequest(0, 2);
Page page = customerDao.findAll(spec, pageable);
/* Page方法: getContent():获取查询的结果,返回List<?> getTotalElements():获取查询到的总条数,返回Long getTotalPages():获取查询到的总页数,返回int */
System.out.println("数据:" + page.getContent());
System.out.println("总条数:" + page.getTotalElements());
System.out.println("总页数" + page.getTotalPages());
}
还没有评论,来说两句吧...