SpringDataJPA之JpaSpecificationExecutor接口的使用

SpringDataJPA之JpaSpecificationExecutor接口的使用

JpaSpecificationExecutor:该接口不能单独使用,如上图所示该接口并未直接或间接继承 Repository所以该接口不是 Repository的实现接口,没有对应的操作数据库的方法,必须和以上三个接口组合使用,主要用非主键查询,以及一些别的查询。
JpaSpecificationExecutor接口是独立于前面几个几口的一个工具接口,因此不能单独使用,下面结合JpaRepository接口进行方法的实现。
由于导包,创建POJO,applicationContext.xml,数据库文件和前面的Respositiry的相同就不再贴代码了,直接上它的接口和测试类。

  1. 创建接口实现继承
package com.OVA.dao;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

import com.OVA.pojo.Users;

/**
 * @author OVA_Wom 
 * JpaSpecificationExecutor
 * 该接口不能单独使用,需要配合JPA中的其他的接口使用,用于非主键条件的查询,主要处理多条件查询和排序分页处理
 * 原因:JpaSpecificationExecutor该接口没有继承Respository这个JPA标记接口,Spring无法生成对应的代理对象
 **/
public interface UserDao extends JpaRepository<Users, Integer>,JpaSpecificationExecutor<Users> {
	
}
  1. 测试类编写
package test;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.OVA.dao.UserDao;
import com.OVA.pojo.Users;

/**
 * @author OVA_Wom JpaSpecificationExecuto测试接口
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestJpaSpecificationExecutorTest {
	@Autowired
	private UserDao userdao;
	Users users = null;

	// 单条件查询,根据用户姓名查询数据
	@Test
	public void TestFindByName() {
		/*
		 * 泛型是查询的对象,Specification实际上是一个封装了查询规则的查询对象
		 * 注意:Specification其实就是对hibernatejpa QBC查询方式的封装,
		 * 其中包括,CriteriaBuilder,CriteriaQuery
		 * Root,Predicate对像;由于Specification是一个接口类型
		 * 所以使用匿名内部类的方式进行实现这个接口,让它回调toPredicate方法
		 */
		Specification<Users> specification = new Specification<Users>() {
			/*
			 * Predicate对象封装了要查询的条件 root是查询的根对象,对要查询的对象进行一个二次封装,方便去数据库中的各个字段
			 * CriteriaQuery<?>封装了一个基本的查询 select* from对象名;
			 * CriteriaBuilder创建查询,创建CriteriaQuery<?>对象
			 */
			@Override
			public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				// 进行姓名的比较
				Predicate pre = cb.equal(root.get("username"), "董小姐");
				return pre;
			}
		};
		List<Users> findAll = userdao.findAll(specification);
		for (Users users : findAll) {
			System.out.println(users);
		}
	}

	// 方式一 多条加查询
	// 用户姓名和年龄作为查询的条件
	@Test
	public void TestFindByNameAndAge1() {
		Specification<Users> specification = new Specification<Users>() {

			@Override
			public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				// 设置多个查询条件
				List<Predicate> list = new ArrayList<>();
				Predicate username = cb.equal(root.get("username"), "董小姐");
				// greaterThanOrEqualTo年龄大于等于40
				Predicate userage = cb.greaterThanOrEqualTo(root.get("userage"), 40);
				list.add(username);
				list.add(userage);
				/*
				 * 如果查询条件多与两个就要使用Predicate[]数组方式
				 * 创建Predicate[]数组,数组长度为list.size()
				 */
				Predicate[] predicates = new Predicate[list.size()];
				// list.toArray将集合里面数据转存到数组里面
				Predicate[] array = list.toArray(predicates);
				// 该方式需要传入一个数组
				Predicate and = cb.and(array);
				return and;
			}
		};
		List<Users> findAll = userdao.findAll(specification);
		for (Users users : findAll) {
			System.out.println(users);
		}
	}

	// 方式二 多条件查询
	// 用户姓名或者年龄作为查询的条件
	@Test
	public void TestFindByNameAndAge2() {

		Specification<Users> specification = new Specification<Users>() {

			@Override
			public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//查询年龄小于30或者姓名是董小姐的用户
				return cb.or(cb.equal(root.get("username"), "董小姐"), cb.lessThanOrEqualTo(root.get("userage"), 30));
			}
		};
		List<Users> findAll = userdao.findAll(specification);
		for (Users users : findAll) {
			System.out.println(users);
		}
	}
	@Test
	//JpaSpecificationExecutor实现排序
	//查询姓名以董开头的用户的姓名,并且按照ID降序排序
	public void TestFindByNameSort(){
		Specification<Users> specification=new Specification<Users>() {

			@Override
			public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				return cb.like(root.get("username").as(String.class), "董%");
			}
			
		};
		//排序
		Sort sort=new Sort(Direction.DESC,"userid");
		 List<Users> findAll = userdao.findAll(specification,sort);
		for (Users users : findAll) {
			System.out.println(users);
		}
	}
	@Test
	//JpaSpecificationExecutor实现分页
	//查询姓名以董开头的用户的姓名
	public void TestFindByNamePage(){
		Specification<Users> specification=new Specification<Users>() {

			@Override
			public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				return cb.like(root.get("username").as(String.class), "董%");
			}
			
		};
		//分页
		//一页显示的条数
		int size=2;
		//打印第几页下表从0开始
		int page=0;
		Pageable pageable=new PageRequest(page, size);
		 Page<Users> findAll = userdao.findAll(specification,pageable);
		 System.out.println("总页数"+findAll.getTotalPages());
		 System.out.println("分页总条数"+findAll.getTotalElements());
		for (Users users : findAll.getContent()) {
			System.out.println(users);
		}
	}
	@Test
	//JpaSpecificationExecutor实现查询分页并且排序
	//查询姓名以董开头的用户的姓名以ID降序并且分页显示
	//由于排序对象被整合到了Pagable对象中所以我们调用PageRequest(page, size, sort)
	public void TestFindByNamePageAndSort(){
		Sort sort = new Sort(Direction.DESC,"userid");
		int size=2;
		int page=0;
		PageRequest pageRequest = new PageRequest(page, size, sort);
		Specification<Users> specification=new Specification<Users>() {

			@Override
			public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				// TODO Auto-generated method stub
				return cb.like(root.get("username"), "董%");
			}
		};
		Page<Users> findAll = userdao.findAll(specification,pageRequest);
		System.out.println("总页数"+findAll.getTotalPages());
		System.out.println("总条数:"+findAll.getTotalElements());
		for (Users users : findAll.getContent()) {
		System.out.println(users);	
		}
	}
}


代码已经加详细的注释,以上就是JpaSpecificationExecuto接口的基本内容,不足之处还请大神指正。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值