JPA 通过Specification如何实现复杂查询


Posted in Java/Android onNovember 23, 2021

JPA 通过Specification实现复杂查询

JPA中继承BaseRepo之后,可以使用最基本的增删改查,如果想实现复杂查询,则需要借助Specification来完成这个功能:

下面就简单介绍一下Specification的使用

public void findAll(ConstructPlanPageReqEntity constructPlanPageReqEntity) {
	Integer pageNum = page.getPageNum();
        Integer pageSize = page.getPageSize();
        String costType = constructPlanPageReqEntity.getCostType();
        String name = constructPlanPageReqEntity.getName();
        String planMoneyStart = constructPlanPageReqEntity.getPlanMoneyStart();
        String planMoneyEnd = constructPlanPageReqEntity.getPlanMoneyEnd();
        String singMoneyEnd = constructPlanPageReqEntity.getSingMoneyEnd();
        String signMoneyStart = constructPlanPageReqEntity.getSignMoneyStart();
        long projectId = Long.parseLong(constructPlanPageReqEntity.getProjectId());
        String status = constructPlanPageReqEntity.getStatus();
        //分页
        pageNum=pageNum-1;
        Pageable pageable = PageRequest.of(pageNum, pageSize);
//多条件匹配查询
        Specification specification= new Specification<ContractPlanBean>() {
            @Override
            public Predicate toPredicate(Root<ContractPlanBean> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                ArrayList<Predicate> list = new ArrayList<>();
                Path<String> costType1 = root.get("costType");
                Path<String> name1 = root.get("name");
                Path<Long> projectId1 = root.get("projectId");
                Path<Object> status1 = root.get("status");
                if (projectId>0){
                    list.add(criteriaBuilder.equal(projectId1,projectId));
                }
                if (StringUtil.isNotEmpty(status)){
                    list.add(criteriaBuilder.equal(status1,status));
                }
                //条件查询
                if (StringUtil.isNotEmpty(costType)){
                    list.add(criteriaBuilder.equal(costType1,costType));
                }
                //模糊查询
                if (StringUtil.isNotEmpty(name)){
                    list.add(criteriaBuilder.like(name1,"%"+name+"%"));
                }
                //范围查询
                if (StringUtil.isNotEmpty(planMoneyStart)&&StringUtil.isNotEmpty(planMoneyEnd)){
                    try {
                        list.add(criteriaBuilder.between(root.get("planMoney"),NumberUtil.strToDouble(planMoneyStart),NumberUtil.strToDouble(planMoneyEnd)));
                    } catch (Exception e) {
                        throw new ApiException("规划金额查询失败");
                    }
                }
                 //排序
                criteriaQuery.orderBy(criteriaBuilder.asc(root.get("name")));
                Predicate[] array = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(array));
            }
        };
}

以上代码实现了多条件查询,其中需要重写toPredicate方法,具体参数:

  • 用root.get()获取bean中的数据库对应字段
  • 用criteriaBuilder来组建条件查询语句

JPA 通过Specification如何实现复杂查询

上图是criteriaBuilder各种sql符号的方法名,根据需求组建不同的sql语句

criteriaBuilder.and(list.toArray(array))这句是最后定义各个sql查询条件的关系,这里用的and

至此,复杂sql语句就拼接完成,本人对Specification的使用未进行深入研究,个人觉得相对filter Strem的复杂查询来说Specification更繁琐,因此更倾向于通过Strem的复杂查询,这回就不多说了,下次就介绍下如何使用Stream进行复杂查询

spring-data-jpa Specification拼接复杂查询

public Page<ServiceItem> findAll(Map<String, String[]> params, ServiceItemConsumeStatus serviceItemConsumeStatus,ServiceItemStatus serviceItemStatus, Pageable pageable) {
        return dao.findAll(spec(serviceItemConsumeStatus, serviceItemStatus, params), pageable);
    }
    private Specification<ServiceItem> spec(final ServiceItemConsumeStatus serviceItemConsumeStatus, 
    final ServiceItemStatus serviceItemStatus, Map<String, String[]> params) {
        Collection<SearchFilter> filters = SearchFilter.parse(params).values();
        final Specification<ServiceItem> fsp = SearchFilter.spec(filters, ServiceItem.class);
        Specification<ServiceItem> sp = new Specification<ServiceItem>() {
            public Predicate toPredicate(Root<ServiceItem> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate pred = fsp.toPredicate(root, query, cb);
                if (ServiceItemConsumeStatus.可消费.equals(serviceItemConsumeStatus)) {
                    pred = cb.and(pred, cb.gt(root.get("countLeft").as(int.class), 0));
                } else if (ServiceItemConsumeStatus.消费完毕.equals(serviceItemConsumeStatus)) {
                    pred = cb.and(pred, cb.le(root.get("countLeft").as(int.class), 0));
                }
                if (serviceItemStatus != null) {
                    pred = cb.and(pred, cb.equal(root.get("status"), serviceItemStatus));
                }
                return pred;
            }
        };
        return sp;
    }

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Java/Android 相关文章推荐
分享一些Java的常用工具
Jun 11 Java/Android
Java循环队列与非循环队列的区别总结
Jun 22 Java/Android
详细了解java监听器和过滤器
Jul 09 Java/Android
详解Java七大阻塞队列之SynchronousQueue
Sep 04 Java/Android
java executor包参数处理功能 
Feb 15 Java/Android
Java中Quartz高可用定时任务快速入门
Apr 03 Java/Android
Java Lambda表达式常用的函数式接口
Apr 07 Java/Android
Java 超详细讲解十大排序算法面试无忧
Apr 08 Java/Android
Spring Cloud Netflix 套件中的负载均衡组件 Ribbon
Apr 13 Java/Android
Java时间工具类Date的常用处理方法
May 25 Java/Android
Spring Boot项目如何优雅实现Excel导入与导出功能
Jun 10 Java/Android
spring 项目实现限流方法示例
Jul 15 Java/Android
Java使用JMeter进行高并发测试
Java 在线考试云平台的实现
OpenCV实现反阈值二值化
聊聊SpringBoot自动装配的魔力
Nov 17 #Java/Android
Springboot如何同时装配两个相同类型数据库
Nov 17 #Java/Android
OpenCV实现普通阈值
聊聊Lombok中的@Builder注解使用教程
Nov 17 #Java/Android
You might like
全国FM电台频率大全 - 13 福建省
2020/03/11 无线电
PHP编码规范-php coding standard
2007/03/16 PHP
php中json_decode()和json_encode()的使用方法
2012/06/04 PHP
PHP函数addslashes和mysql_real_escape_string的区别
2014/04/22 PHP
PHP读取大文件的多种方法介绍
2016/04/04 PHP
laravel手动创建数组分页的实现代码
2018/06/07 PHP
使用ucenter实现多站点同步登录的讲解
2019/03/21 PHP
JS条形码(一维码)插件JsBarcode用法详解【编码类型、参数、属性】
2017/04/19 Javascript
vue2 前后端分离项目ajax跨域session问题解决方法
2017/04/27 Javascript
用nodejs实现json和jsonp服务的方法
2017/08/25 NodeJs
babel的使用及安装配置教程
2018/02/22 Javascript
微信小程序开发之获取用户手机号码(php接口解密)
2020/05/17 Javascript
JS禁用右键、禁用Ctrl+u、禁用Ctrl+s、禁用F12的实现代码
2020/12/01 Javascript
[01:51]历届DOTA2国际邀请赛举办地回顾 TI9落地上海
2018/08/26 DOTA
Python同时向控制台和文件输出日志logging的方法
2015/05/26 Python
Python中的super()方法使用简介
2015/08/14 Python
Python实现的根据IP地址计算子网掩码位数功能示例
2018/05/23 Python
python+opencv+caffe+摄像头做目标检测的实例代码
2018/08/03 Python
Python3解释器知识点总结
2019/02/19 Python
Scrapy框架爬取西刺代理网免费高匿代理的实现代码
2019/02/22 Python
python适合人工智能的理由和优势
2019/06/28 Python
解决django中ModelForm多表单组合的问题
2019/07/18 Python
Windows系统下pycharm中的pip换源
2020/02/23 Python
Django获取model中的字段名和字段的verbose_name方式
2020/05/19 Python
Opencv求取连通区域重心实例
2020/06/04 Python
英国领先的NHS批准的在线药店:Pharmacy2U
2017/01/06 全球购物
DHC美国官网:日本通信销售第一的化妆品品牌
2017/11/12 全球购物
goodhealth官方海外旗舰店:新西兰国民营养师
2017/12/15 全球购物
澳大利亚网上买书:Angus & Robertson
2019/07/21 全球购物
Hello Molly美国:女性时尚在线
2019/08/26 全球购物
商务英语专业毕业生自荐信
2013/11/05 职场文书
前台文员的岗位职责
2013/11/14 职场文书
优秀的2014年两会精神解读
2014/03/17 职场文书
2015年学校安全工作总结
2015/04/22 职场文书
OpenCV-Python实现轮廓的特征值
2021/06/09 Python
Oracle 死锁的检测查询及处理
2021/09/25 Oracle