🎨
application-framework
  • Introduction
  • 设计模式篇
    • 设计原则
      • 单一职责原则
      • 里氏替换原则
      • 依赖倒置原则
      • 接口隔离原则
      • 迪米特法则
      • 开闭原则
    • 代理模式
    • 工厂模式
    • 策略模式
    • 等等..设计模式
    • 常用设计模式在开源软件的应用
    • Template设计模式介绍
  • SpringBoot篇
    • SpringBoot官方教程结构图
    • SpringBoot启动过程源码分析
    • SpringBoot启动过程定制化
    • SpringBoot实现自动配置的基础
    • SpringBoot实现自动配置的原理
    • SpringBoot启动类源码分析以及@EnableAutoConfiguration和@SpringBootApplication讲解
    • EnableAutoConfigurationImportSelector 是如何工作的 ?
    • ConfigurationClassParser 是如何工作的 ?
    • SpringBoot源码分析之Spring上下文refresh(重点)
    • SpringBoot中的ApplicationContext - 执行ApplicationContextInitializer初始化器
    • SpringBoot常用配置-Profile
    • Spring Boot API 版本权限控制
  • Mybatis篇
    • Mybatis基础教程
    • Mybatis-Spring基础教程
    • Sqlsession原理
    • Mybatis代码架构分析
    • Mybatis事务
    • Mybatis与Spring集成事务相关问题
    • 结果/参数绑定
    • Mybatis插件拓展/插件原理
    • Mybatis 使用Ehcache缓存机制//自带缓存与Spring结合使用
    • 使用代码生成器快速开发
    • Mybatis使用时的一些注意事项
    • Mybatis配置打印SQL语句
    • 持久层框架mybatis如何防止sql注入
    • SqlSessionTemplate与SqlSessionDaoSupport讲解
    • MapperFactoryBean与MapperScannerConfigurer讲解
    • Spring+MyBatis多数据源配置实现
    • Mybatis与Spring集成事务相关问题
  • Spring源码解读篇
    • Spring 架构图
    • Spring核心结构及组件分析
    • Spring5 Framework体系结构
    • Spring源码剖析
      • BeanFactory
      • BeanPostProcessor源码讲解
      • BeanFactoryPostProcessor源码讲解
      • BeanDefinition源码解析
      • RootBeanDefinition源码解析
      • AnnotatedBeanDefinition源码解析
      • ApplicationContext源码讲解
      • IoC容器的初始化?
      • @Configuration源码讲解
      • Bean的注解(annotation)
      • @ImportSelector、@Import、ImportResource工作原理分析
      • Bean的生命周期
    • IOC机制从设计理念/实现原理到源码解读
    • AOP实现原理
      • aop编程思想
      • aop在Spring中的应用
      • cglib和jdk动态代理
        • java/jdk代理实现与原理详细分析
        • cglib实现动态代理
    • Transaction事务处理源码分析及高级特性
      • 事务概念
      • Spring事务传播
      • 事务隔离级别
      • 事务实现源码分析
      • Spring事物应用实战(一)
      • Spring事务应用实战(二)之spring+hibernate+JTA 分布式事务的例子
    • SpringMVC源码解读
      • DispatcherServlet说明
      • 核心流程剖析及原理分析
      • 请求映射机制
      • 参数绑定与转换机制
      • 页面渲染机制
      • ContextLoader加载过程
      • web.xml 中的listener、 filter、servlet 加载顺序及其详解
      • Spring中WebApplicationContext、DispatcherServlet与web容器的ServletContext关系梳理
    • Spring新版本特性解读
  • JPA篇
    • 简单叙述
    • 基础教程
    • SpringData Jpa、Hibernate、Jpa 三者之间的关系
    • Spring data jpa 全面解析
    • 数据库schema含义
    • 数据库schema与catalog简介
    • Jpa关联映射以及字段映射注解讲解
      • @Entity、@Table、@id
      • @GeneratedValue
      • @Basic、@Column、@Transient
      • @MappedSuperclass、@Embedded、@OrderBy、@Lob、@Data
      • @OneToOne级联配置
      • @OneToMany、@ManyToOne级联配置
      • 更新的同时删除多的一方的旧数据
      • cascade级联属性讲解
      • JpaSpecificationExecutor接口
      • @Query 创建查询
      • @NamedQueries创建查询
      • @CreateDate @LastModifiedDate @EntityListeners、@SQLDelete、@Where
      • 注解关联时报错总结
      • JPA 多对多关联 中间表带有属性 两个外键作为中间表的联合主键时 直接操作中间表查询修改的方法
    • Jpa 使用@Query查询时 (参数可能为空)语句
    • Jpa校验/验证注解
      • Jpa的list校验方式
      • Jpa的基础校验/验证注解
  • Hibernate篇
    • Hibernate基础教程
    • Hibernate主键生成策略
    • Hibernate的体系结构
    • Hibernate面试题
    • 自定义一个方言类——Hibernate Dialect
    • Hibernate 不同数据库的连接及SQL方言
    • Hibernate中一级缓存和二级缓存的具体区别是什么?
    • Hibernate中,对象有三种状态:
Powered by GitBook
On this page
  • 概述
  • 接口使用方式——Repository
  • 简单查询场景
  • 复杂查询场景

Was this helpful?

  1. JPA篇
  2. Jpa关联映射以及字段映射注解讲解

JpaSpecificationExecutor接口

Previouscascade级联属性讲解Next@Query 创建查询

Last updated 5 years ago

Was this helpful?

概述

封装 JPA Criteria 查询条件。通常使用匿名内部类的方式来创建该接口的对象

接口使用方式——Repository

public interface TaskPlanRepository extends JpaRepository<TaskPlan, String>, JpaSpecificationExecutor<TaskPlan> {

}

官方接口API:

简单查询场景

public interface SpecificationExecutorRepository extends CrudRepository<User, Integer>,
        JpaSpecificationExecutor<User> {

}
@Service
public class SpecificationExecutorRepositoryManager {
    @Autowired
    private SpecificationExecutorRepository dao;
    /**
     * 描述:根据name来查询用户
     */
    public User findUserByName(final String name){
        return dao.findOne(new Specification<User>() {

            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query,
                    CriteriaBuilder cb) {
                Predicate predicate = cb.equal(root.get("name"), name);
                return predicate;
            }
        });
    }

    /**
     * 描述:根据name和email来查询用户
     */
    public User findUserByNameAndEmail(final String name, final String email){
        return dao.findOne(new Specification<User>() {

            @Override
            public Predicate toPredicate(Root<User> root,
                    CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> list = new ArrayList<Predicate>();
                Predicate predicate1 = cb.equal(root.get("name"), name);
                Predicate predicate2 = cb.equal(root.get("email"), email);
                list.add(predicate1);
                list.add(predicate2);
                // 注意此处的处理
                Predicate[] p = new Predicate[list.size()];
                return cb.and(list.toArray(p));
            }
        });
    }

    /**
     * 描述:组合查询
     */
    public User findUserByUser(final User userVo){
        return dao.findOne(new Specification<User>() {

            @Override
            public Predicate toPredicate(Root<User> root,
                    CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate predicate = cb.equal(root.get("name"), userVo.getName());
                cb.and(predicate, cb.equal(root.get("email"), userVo.getEmail()));
                cb.and(predicate, cb.equal(root.get("password"), userVo.getPassword()));
                return predicate;
            }
        });
    }

    /**
     * 描述:范围查询in方法,例如查询用户id在[2,10]中的用户
     */
    public List<User> findUserByIds(final List<Integer> ids){
        return dao.findAll(new Specification<User>() {

            @Override
            public Predicate toPredicate(Root<User> root,
                    CriteriaQuery<?> query, CriteriaBuilder cb) {
                return root.in(ids);
            }
        });
    }

    /**
     * 描述:范围查询gt方法,例如查询用户id大于9的所有用户
     */
    public List<User> findUserByGtId(final int id){
        return dao.findAll(new Specification<User>() {

            @Override
            public Predicate toPredicate(Root<User> root,
                    CriteriaQuery<?> query, CriteriaBuilder cb) {
                return cb.gt(root.get("id").as(Integer.class), id);
            }
        });
    }

    /**
     * 描述:范围查询lt方法,例如查询用户id小于10的用户
     */
    public List<User> findUserByLtId(final int id){
        return dao.findAll(new Specification<User>() {

            @Override
            public Predicate toPredicate(Root<User> root,
                    CriteriaQuery<?> query, CriteriaBuilder cb) {
                return cb.lt(root.get("id").as(Integer.class), id);
            }
        });
    }

    /**
     * 描述:范围查询between方法,例如查询id在3和10之间的用户
     */
    public List<User> findUserBetweenId(final int start, final int end){
        return dao.findAll(new Specification<User>() {

            @Override
            public Predicate toPredicate(Root<User> root,
                    CriteriaQuery<?> query, CriteriaBuilder cb) {
                return cb.between(root.get("id").as(Integer.class), start, end);
            }
        });
    }

    /**
     * 描述:排序和分页操作
     */
    public Page<User> findUserAndOrder(final int id){
        Sort sort = new Sort(Direction.DESC, "id");
        return dao.findAll(new Specification<User>() {

            @Override
            public Predicate toPredicate(Root<User> root,
                    CriteriaQuery<?> query, CriteriaBuilder cb) {
                return cb.gt(root.get("id").as(Integer.class), id);
            }
        }, new PageRequest(0, 5, sort));
    }

    /**
     * 描述:只有排序操作
     */
    public List<User> findUserAndOrderSecondMethod(final int id){
        return dao.findAll(new Specification<User>() {

            @Override
            public Predicate toPredicate(Root<User> root,
                    CriteriaQuery<?> query, CriteriaBuilder cb) {
                cb.gt(root.get("id").as(Integer.class), id);
                query.orderBy(cb.desc(root.get("id").as(Integer.class)));
                return query.getRestriction();
            }
        });
    }
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:applicationContext-config.xml" })
@TransactionConfiguration(defaultRollback = false)
@Transactional
public class SpecificationExecutorRepositoryManagerTest {
    @Autowired
    private SpecificationExecutorRepositoryManager manager;
    @Test
    public void testFindUserByName(){
        User user = manager.findUserByName("chhliu");
        System.out.println(JSON.toJSONString(user));
    }

    @Test
    public void testFindUserByNameAndEmail(){
        User user = manager.findUserByNameAndEmail("chhliu", "chhliu@.com");
        System.out.println(JSON.toJSONString(user));
    }

    @Test
    public void testFindUserByUserVo(){
        User user = new User();
        user.setName("chhliu");
        user.setEmail("chhliu@.com");
        User u = manager.findUserByUser(user);
        System.out.println(JSON.toJSONString(u));
    }

    @Test
    public void testFindUserByIds(){
        List<User> users = manager.findUserByIds(new ArrayList<Integer>(Arrays.asList(1,3,5,6)));
        System.out.println(JSON.toJSONString(users));
    }

    @Test
    public void testFindUserByGtId(){
        List<User> users = manager.findUserByGtId(5);
        System.out.println(JSON.toJSONString(users));
    }

    @Test
    public void testFindUserByLtId(){
        List<User> users = manager.findUserByLtId(5);
        System.out.println(JSON.toJSONString(users));
    }

    @Test
    public void testFindUserBetweenId(){
        List<User> users = manager.findUserBetweenId(4, 9);
        System.out.println(JSON.toJSONString(users));
    }

    @Test
    public void testFindUserAndOrder(){
        Page<User> users = manager.findUserAndOrder(1);
        System.out.println(JSON.toJSONString(users));
    }

    @Test
    public void testFindUserAndOrderSecondMethod(){
        List<User> users = manager.findUserAndOrderSecondMethod(1);
        System.out.println(JSON.toJSONString(users));
    }
}

复杂查询场景

  • 分页查询

/***
* 项目分页查询
*/
public Page<TaskPlan> getTPListPage(TpFormVO vo) {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime").and(new Sort(Sort.Direction.DESC, "code"));
        Pageable pageable = new PageRequest(vo.getCurrentPage(), vo.getSize(), sort);
        return taskPlanRepository.findAll(new Specification<TaskPlan>() {

            @Override
            public Predicate toPredicate(Root<TaskPlan> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<Predicate>();

                if (StringUtils.isNotBlank(vo.getCreateTimeStart())) {//创建开始时间
                    predicates.add(cb.greaterThanOrEqualTo(root.<Date> get("createTime"), DateUtils.parseDate(vo.getCreateTimeStart())));
                }
                if (StringUtils.isNotBlank(vo.getCreateTimeEnd())) {//创建结束时间
                    predicates.add(cb.lessThanOrEqualTo(root.<Date> get("createTime"), DateUtils.parseDate(vo.getCreateTimeEnd())));
                }

                if (StringUtils.isNotBlank(vo.getDeliveryTimeStart())) {//交付开始时间
                    predicates.add(cb.greaterThanOrEqualTo(root.<Date> get("jjqzDate"), DateUtils.parseDate(vo.getDeliveryTimeStart())));
                }
                if (StringUtils.isNotBlank(vo.getDeliveryTimeEnd())) {//交付结束时间
                    predicates.add(cb.lessThanOrEqualTo(root.<Date> get("jjqzDate"), DateUtils.parseDate(vo.getDeliveryTimeEnd())));
                }
                if (StringUtils.isNotBlank(vo.getStatus()) && !vo.isALLStatus()) {//状态
                    predicates.add(cb.equal(root.<String> get("status"), vo.getStatus()));
                }

                //默认数据状态为1
                predicates.add(cb.equal(root.<String> get("state"), TaskPlan.STATE_TP.state_s.key));

                if (!predicates.isEmpty()) {
                    return cb.and(predicates.toArray(new Predicate[predicates.size()]));
                } else {
                    return cb.conjunction();
                }
            }
        }, pageable);
    }
  • 实现sql条件">=" 和 "<="的用法

predicates.add(cb.greaterThanOrEqualTo(root.<Date> get("createTime"), DateUtils.parseDate(vo.getCreateTimeStart())));

predicates.add(cb.lessThanOrEqualTo(root.<Date> get("createTime"), DateUtils.parseDate(vo.getCreateTimeEnd())));

greaterThanOrEqualTo代表 >= 当前条件时间, lessThanOrEqualTo代表<=当前条件时间,具体代码实现,参考上面的项目分页代码

  • 实现sql条件“=”的用法

Predicate predicate = cb.equal(root.<String> get("state"), TaskPlan.STATE_TP.state_s.key)

equal的用法,详细参考上面的项目分页代码

同样的不要忘记notEqual方法

predicates.add(cb.notEqual(root.<String> get("status"), ProcurementInformationEnum.INIT.value));
  • 实现sql条件“in”的用法

/**
     * 作品分页查询
     * @param vo
     * @return
     */
    public Page<WorkManage> getWorkManageListPage(WorkFormVO vo) {

        try{
            TaskPlan taskPlan = taskPlanService.getTP(vo.getCode());
            Sort sort = new Sort(Sort.Direction.DESC, "taskPlanCascade");
            Pageable pageable = new PageRequest(vo.getCurrentPage(), vo.getSize(), sort);
            return workManageRepository.findAll(new Specification<WorkManage>() {
                @Override
                public Predicate toPredicate(Root<WorkManage> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    List<Predicate> predicates = new ArrayList<Predicate>();
                    if (StringUtils.isNotBlank(vo.getType())) {//类别
                        if(vo.getType().contains(",")){
                            CriteriaBuilder.In<Integer> in = cb.in(root.get("type"));
                            Arrays.stream(vo.getType().split(",")).forEach(type->{
                                in.value(Integer.parseInt(type));
                            });
                            predicates.add(in);
                        }else{
                            predicates.add(cb.equal(root.<Integer> get("type"), Integer.parseInt(vo.getType())));
                        }
                    }
                    if (StringUtils.isNotBlank(vo.getMaterial())) {//材质
                        if(vo.getMaterial().contains(",")){
                            CriteriaBuilder.In<Integer> in = cb.in(root.get("material"));
                            Arrays.stream(vo.getMaterial().split(",")).forEach(material->{
                                in.value(Integer.parseInt(material));
                            });
                            predicates.add(cb.or(in));
                        }else{
                            predicates.add(cb.equal(root.<Integer> get("material"), Integer.parseInt(vo.getMaterial())));
                        }
                    }
                    if (StringUtils.isNotBlank(vo.getStatus())) {//鉴定状态
                        Join<Object, Object> workManage2Join = root.join("workManage2");
                        predicates.add(cb.equal(workManage2Join.<Integer> get("status"), Integer.parseInt(vo.getStatus())));
                    }
                    predicates.add(cb.equal(root.<TaskPlan> get("taskPlanCascade"), taskPlan));//关联项目关联
                    if (!predicates.isEmpty()) {
                        return cb.and(predicates.toArray(new Predicate[predicates.size()]));
                    } else {
                        return cb.conjunction();
                    }
                }
            }, pageable);
        }catch (Exception e){
            logger.error(e.getMessage());
            throw_process_exception(RetCode.business_work_exception.code, "业务异常[WORK分页获取异常]", e);
            return null;
        }

    }

也是一整块分页代码,其中,in的使用方式,是我们关注的要点如下:

CriteriaBuilder.In<Integer> in = cb.in(root.get("material"));
Arrays.stream(vo.getMaterial().split(",")).forEach(material->{
in.value(Integer.parseInt(material));
});
predicates.add(cb.or(in));

通过循环获取值,放到in的属性值里,在最后通过cb.or(in) 连接使用,打印的部分SQL如下:

where (
            workmanage0_.TYPE in (
                1 , 2
            )
        )
  • 关联查询的用法

Join<Object, Object> workManage2Join = root.join("workManage2");
predicates.add(cb.equal(workManage2Join.<Integer> get("status"), Integer.parseInt(vo.getStatus())));

root.join("workManage2") 连接的是当前对象的关联属性对象,创建一个Join对象,就可以通过该join对象,通过查询条件,关联查询数据,具体使用,参考上面的作品分页查询代码

  • 关联实体类查询,就是关联Id查询

predicates.add(cb.equal(root.<WorkManage2> get("workManage2"), workManage2));//这种是关联属性Id查询
  • 实现sql条件“or”的用法、"like"的用法

/**
     * 分页查询招标管理信息(用于后台)
     * @param pageable
     * @return
     */
    public Page<InviteBidManage> listForPage(final InviteBidManage inviteBidManage, Pageable pageable) {
        return inviteBidManageDao.findAll(new Specification<InviteBidManage>() {

            @Override
            public Predicate toPredicate(Root<InviteBidManage> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if (inviteBidManage == null) {
                    return cb.conjunction();
                }
                if (StringUtils.isNotBlank(inviteBidManage.getCondition())) {
                    Predicate projectNamePredicate = cb.like(root.<String> get("projectName"), "%" + inviteBidManage.getCondition() + "%");
                    Predicate projectCodePredicate = cb.like(root.<String> get("projectCode"), "%" + inviteBidManage.getCondition() + "%");
                    predicates.add(cb.or(projectNamePredicate, projectCodePredicate));
                }
                if (StringUtils.isNotBlank(inviteBidManage.getProperty())) {
                    predicates.add(cb.equal(root.<String> get("property"), inviteBidManage.getProperty()));
                }
                if (StringUtils.isNotBlank(inviteBidManage.getSource())) {
                    predicates.add(cb.equal(root.<String> get("source"), inviteBidManage.getSource()));
                }
                if (inviteBidManage.getState() != null && inviteBidManage.getState() != -1) {
                    predicates.add(cb.equal(root.<Integer> get("state"), inviteBidManage.getState()));
                }

                query.orderBy(cb.desc(root.<String> get("createdAt")));

                if (!predicates.isEmpty()) {
                    return cb.and(predicates.toArray(new Predicate[predicates.size()]));
                } else {
                    return cb.conjunction();
                }
            }
        }, pageable);
    }

根据上面的招标分页查询,or、like的用法如下:

if (StringUtils.isNotBlank(inviteBidManage.getCondition())) {
       Predicate projectNamePredicate = cb.like(root.<String> get("projectName"), "%" + inviteBidManage.getCondition() + "%");
       Predicate projectCodePredicate = cb.like(root.<String> get("projectCode"), "%" + inviteBidManage.getCondition() + "%");
       predicates.add(cb.or(projectNamePredicate, projectCodePredicate));
}

具体实现参考招标分页查询实现

  • 排序用法

query.orderBy(cb.desc(root.<String> get("createdAt")));

上面的是通过CriteriaBuilder实现排序,也可以通过Pageable的方式实现

Sort sort = new Sort(Sort.Direction.DESC, "createTime").and(new Sort(Sort.Direction.DESC, "code"));
Pageable pageable = new PageRequest(vo.getCurrentPage(), vo.getSize(), sort);

具体实现参考招标分页查询实现、项目分页查询实现

https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaSpecificationExecutor.html