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 相关文章推荐
解决tk mapper 通用mapper的bug问题
Jun 16 Java/Android
Java Dubbo框架知识点梳理
Jun 26 Java/Android
HashMap实现保存两个key相同的数据
Jun 30 Java/Android
新手初学Java网络编程
Jul 07 Java/Android
spring cloud gateway中如何读取请求参数
Jul 15 Java/Android
springboot中rabbitmq实现消息可靠性机制详解
Sep 25 Java/Android
关于@OnetoMany关系映射的排序问题,使用注解@OrderBy
Dec 06 Java/Android
SSM项目使用拦截器实现登录验证功能
Jan 22 Java/Android
alibaba seata服务端具体实现
Feb 24 Java/Android
Java 深入探究讲解简单工厂模式
Apr 07 Java/Android
Java死锁的排查
May 11 Java/Android
Java中的Kafka为什么性能这么快及4大核心详析
Sep 23 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
PHP中Session引起的脚本阻塞问题解决办法
2014/04/08 PHP
PHP安装threads多线程扩展基础教程
2015/11/17 PHP
PHP程序员学习使用Swoole的理由
2018/06/24 PHP
window.location和document.location的区别分析
2008/12/23 Javascript
动态创建的表格单元格中的事件实现代码
2008/12/30 Javascript
jQuery 表单验证插件formValidation实现个性化错误提示
2009/06/23 Javascript
不使用浏览器运行javascript代码的方法
2013/07/24 Javascript
捕获和分析JavaScript Error的方法
2014/03/25 Javascript
Nodejs全栈框架StrongLoop推荐
2014/11/09 NodeJs
jQuery选择器及jquery案例详解(必看)
2016/05/20 Javascript
详解js中call与apply关键字的作用
2016/11/21 Javascript
ZeroClipboard.js使用一个flash复制多个文本框
2017/06/19 Javascript
element 结合vue 在表单验证时有值却提示错误的解决办法
2018/01/22 Javascript
Vue自定义过滤器格式化数字三位加一逗号实现代码
2018/03/23 Javascript
详解小程序缓存插件(mrc)
2018/08/17 Javascript
nodejs aes 加解密实例
2018/10/10 NodeJs
video.js 一个页面同时播放多个视频的实例代码
2018/11/27 Javascript
基于Taro的微信小程序模板消息-获取formId功能模块封装实践
2019/07/15 Javascript
html+vue.js 实现漂亮分页功能可兼容IE
2020/11/07 Javascript
python list排序的两种方法及实例讲解
2017/03/20 Python
python3中str(字符串)的使用教程
2017/03/23 Python
TensorFlow实现AutoEncoder自编码器
2018/03/09 Python
python定时关机小脚本
2018/06/20 Python
Python内存管理实例分析
2019/07/10 Python
pyenv与virtualenv安装实现python多版本多项目管理
2019/08/17 Python
HTML5的文档结构和新增标签完全解析
2017/04/21 HTML / CSS
俄罗斯在线购买飞机票、火车票、巴士票网站:Tutu.ru
2020/03/16 全球购物
专业求职信撰写要诀
2014/02/18 职场文书
大一新生学期自我评价
2014/04/09 职场文书
一年级学生评语大全
2014/04/21 职场文书
大学生毕业求职信
2014/06/12 职场文书
群众路线自查报告及整改措施
2014/11/04 职场文书
正规欠条模板
2015/07/03 职场文书
科级干部培训心得体会
2016/01/06 职场文书
《走遍天下书为侣》教学反思
2016/02/22 职场文书
CSS3点击按钮圆形进度打钩效果的实现代码
2021/03/30 HTML / CSS