package cn.itcast.test;

import cn.itcast.dao.UserDao;
import cn.itcast.entity.User;
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.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.persistence.criteria.*;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class SpecTest {

    @Autowired
    private UserDao userDao;

    //匿名内部类
    /**
     * 根据条件，查询单个对象
     * 自定义查询条件
     *      1.实现Specification借口(提供反省，查询的对象类型)
     *      2.实现toPredicate方法(构造查询条件)
     *      3.需要借助方法参数中的两个参数(
     *          root:获取需要查询的对象属性
     *          CriteriaBuilder: 构造查询条件，内部封装了很多的查询条件(模糊匹配，精准匹配)
     *      )
     *  根据客户名称查询
     *          查询条件
     *              1.查询方式(精准，模糊)
     *                  criteriaBuilder对象
     *              2.比较的属性名称，根据哪个属性，以什么样的方式
     *                  root对象
     */
    @Test
    public void testSpec1(){
        Specification<User> specification = new Specification<User>() {
            public Predicate toPredicate(Root<User> root,
                                         CriteriaQuery<?> criteriaQuery,
                                         CriteriaBuilder criteriaBuilder) {
                //1.获取比较的属性 要属性名称
                Path<Object> name = root.get("name");
                //2.构造查询条件  select * from jpa where name = '张三'
                Predicate predicate = criteriaBuilder.equal(name, "张三");//进行精准匹配(比较的属性的取值)
                return predicate;
            }
        };
        User user = userDao.findOne(specification);
        System.out.println(user);
    }

    /**
     * 多条件查询
     *      案例： 根据客户名(张三)和客户年龄(20)查询
     * root: 获取属性
     *          客户名
     *          年龄
     * criteriaBuilder:
     *      1.构造客户名的精准匹配查询
     *      2.构造所属行业的精准匹配查询
     *      3.将以上两个查询联系起来
     */
    @Test
    public void testSpec2(){
        Specification<User> specification =
                new Specification<User>() {
            public Predicate toPredicate(Root<User> root,
                                         CriteriaQuery<?> criteriaQuery,
                                         CriteriaBuilder criteriaBuilder) {
                //1.构造查询
                Path<Object> name = root.get("name");
                Path<Object> age = root.get("age");
                //2.构造精准查询
                Predicate p1 = criteriaBuilder.equal(name, "张三");
                Predicate p2 = criteriaBuilder.equal(age, 20);
                //3.多个查询条件组合到一起(满足条件1并且满足条件2,满足条件1或条件2)
                //and方式拼接多个，or方式拼接多个
                Predicate predicate = criteriaBuilder.and(p1, p2);
                return predicate;
            }
        };
        User user = userDao.findOne(specification);
        System.out.println(user);
    }

    /**
     * 完成柑橘客户名称的模糊查询，返回客户列表
     *
     * equal: 直接得到path对象(属性)，然后进行比较
     * gt.lt.ge.le.like等 : 需要得到path对象，根据path
     * 指定比较的参数类型，再去进行比较
     * 指定参数类型: path.as(类型的字节码文件)
     */
    @Test
    public void testSpec3(){
        Specification<User> specification = new Specification<User>() {
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                //1.构造查询条件
                Path<Object> name = root.get("name");
                //2.查询方式，模糊查询
                Predicate like = criteriaBuilder.like(name.as(String.class), "张%");
                return like;
            }
        };
//        List<User> list = userDao.findAll(specification);
//        for (Object obj : list){
//            System.out.println(obj);
//        }
        //添加排序
        //创建排序对象,需要调用构造方法实例化对象
        //第一个参数是排序的顺序(倒叙，正序)
        //第二个参数排序的属性名
        Sort sort = new Sort(Sort.Direction.DESC,"id");
        List<User> list = userDao.findAll(specification, sort);
        for (User user : list){
            System.out.println(user);
        }
    }

    /**
     * 分页查询
     *  specification: 查询条件
     *  Pageable: 分页参数
     *      fenecanshu ： 查询的页码，每页多少条数据
     *  findAll(specification,Pageable)
     *      page封装好的pageable对象，数据列表，共条数
     */
    @Test
    public void testSpec4(){
        Specification specification = null;
        //PageRequest是Pageable的实现类
        /**
         * 调用的两个参数
         *      第一个参数:当前查询的页数
         *      第二个参数：每页查询的数量
         */
        Pageable pageable = new PageRequest(0,2);

        Page<User> page = userDao.findAll(null, pageable);
        System.out.println(page.getContent());//得到的数据集合列表
        System.out.println(page.getTotalElements());//得到的总条数
        System.out.println(page.getTotalPages());//得到的总页数
    }
}
