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 相关文章推荐
JVM入门之类加载与字节码技术(类加载与类的加载器)
Jun 15 Java/Android
spring项目中切面及AOP的使用方法
Jun 26 Java/Android
jackson json序列化实现首字母大写,第二个字母需小写
Jun 29 Java/Android
每日六道java新手入门面试题,通往自由的道路
Jun 30 Java/Android
JavaWeb 入门篇:创建Web项目,Idea配置tomcat
Jul 16 Java/Android
Java后台生成图片的完整步骤
Aug 04 Java/Android
Springboot如何同时装配两个相同类型数据库
Nov 17 Java/Android
Java使用JMeter进行高并发测试
Nov 23 Java/Android
Eclipse+Java+Swing+Mysql实现电影购票系统(详细代码)
Jan 18 Java/Android
SpringBoot整合Minio文件存储
Apr 03 Java/Android
解决springboot druid数据库连接失败后一直重连的方法
Apr 19 Java/Android
java版 简单三子棋游戏
May 04 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
ThinkPHP写第一个模块应用
2012/02/20 PHP
php调用dll的实例操作动画与代码分享
2012/08/14 PHP
基于Jquery的文字滚动跑马灯插件(一个页面多个滚动区)
2010/07/26 Javascript
原生js实现半透明遮罩层效果具体代码
2013/06/06 Javascript
javascript修改IMG标签的src问题
2014/03/28 Javascript
JavaScript变量声明详解
2014/11/27 Javascript
WEB前端设计师常用工具集锦
2014/12/09 Javascript
Angularjs制作简单的路由功能demo
2015/04/14 Javascript
JavaScript数据结构与算法之栈与队列
2016/01/29 Javascript
javascript函数自动执行常用方法汇总
2016/03/28 Javascript
【经典源码收藏】jQuery实用代码片段(筛选,搜索,样式,清除默认值,多选等)
2016/06/07 Javascript
javascript实现的左右无缝滚动效果
2016/09/19 Javascript
JavaScript数据结构之单链表和循环链表
2017/11/28 Javascript
(模仿京东用户注册)用JQuery实现简单表单验证,初学者必看
2018/01/08 jQuery
JavaScript作用域链实例详解
2019/01/21 Javascript
JavaScript刷新页面的几种方法总结
2019/03/28 Javascript
mongodb初始化并使用node.js实现mongodb操作封装方法
2019/04/02 Javascript
vue无限轮播插件代码实例
2019/05/10 Javascript
js实现随机8位验证码
2020/07/24 Javascript
layui实现给某一列加点击事件
2019/10/26 Javascript
vue如何使用async、await实现同步请求
2019/12/09 Javascript
Python三种遍历文件目录的方法实例代码
2018/01/19 Python
python和shell获取文本内容的方法
2018/06/05 Python
Python中Proxypool库的安装与配置
2018/10/19 Python
python2和python3应该学哪个(python3.6与python3.7的选择)
2019/10/01 Python
Python导入数值型Excel数据并生成矩阵操作
2020/06/09 Python
Python如何发送与接收大型数组
2020/08/07 Python
安装不同版本的tensorflow与models方法实现
2021/02/20 Python
高二美术教学反思
2014/01/14 职场文书
学生手册评语
2014/05/05 职场文书
自我推荐信范文
2014/05/09 职场文书
反腐倡廉演讲稿
2014/05/22 职场文书
人事主管岗位职责说明书
2014/07/30 职场文书
电力培训心得体会
2014/09/02 职场文书
农村婚礼司仪主持词
2015/06/29 职场文书
JavaScript前端面试扁平数据转tree与tree数据扁平化
2022/06/14 Javascript