Java Mybatis-Plus QueryWrapper多层嵌套or和and查询实现复杂筛选功能

前言

用 MyBatis-Plus框架 的 QueryWrapper,可以更方便、清晰、安全、易维护地构建动态查询条件,避免了手动拼接 SQL 字符串的繁琐和潜在的安全问题。特别对于刚使用新手或者习惯了编写SQL语句的猿来说,在面对复杂的查询逻辑条件,可能会有点蒙圈。这里本人就于实践中整了一点案例进行分享。本文是基于一个医生预约筛选查询的功能,其界面大致如下:
在这里插入图片描述

其中大致的逻辑是,根据名称、类型、领域等字段进行常规的查询,其中复杂的点在预约的三种方式和价格区间的组合查询,任选一/多种预约类型,传入价格区间进行查询,这里选择的任一预约类型的价格在区间内,就返回该条记录。记录价格间是或(or)的关系。

实现

这里就是采用了 MyBatis-Plus框架 的 QueryWrapper来实现,首先要定义医生的实体类型:

@Data
@TableComment("医生")
@TableName(autoResultMap = true)
public class Doctor {
    @ApiModelProperty("ID,创建勿填")
    @TableId(value = "id",type = IdType.ASSIGN_ID)
    @Column(comment = "ID")
    private Long id;

    @ApiModelProperty("姓名")
    @Column(comment = "姓名")
    private String name;

    @ApiModelProperty("性别 0:女  1:男")
    @Column(type = MySqlTypeConstant.TINYINT,defaultValue = "0",comment = "性别  0:女  1:男")
    private Integer sex;

    @ApiModelProperty("医生类型")
    @Column(comment = "医生类型")
    private Long doctorType;

    @ApiModelProperty("擅长领域")
    @Column(comment = "擅长领域")
    private Long expertIn;

    @ApiModelProperty("开启图文会诊")
    @Column(comment = "开启图文会诊", defaultValue = "false")
    private Boolean isText;

    @ApiModelProperty("图文会诊价格")
    @Column(comment = "图文会诊价格")
    private Long textPrice;

    @ApiModelProperty("开启电话会诊")
    @Column(comment = "开启电话会诊", defaultValue = "false")
    private Boolean  isPhone;

    @ApiModelProperty("电话会诊价格")
    @Column(comment = "电话会诊价格")
    private Long  phonePrice;

    @ApiModelProperty("开启线下会诊")
    @Column(comment = "开启线下会诊", defaultValue = "false")
    private Boolean  isOffline;

    @ApiModelProperty("线下会诊价格")
    @Column(comment = "线下会诊价格")
    private Long  offlinePrice;
}

然后根据查询的参数来设计查询的参数类型:

@Data
public class DoctorFilterParam {

    @ApiModelProperty("姓名")
    private String name;

    @ApiModelProperty("医生类型")
    private Long doctorType;

    @ApiModelProperty("擅长领域")
    private Long expertIn;

    @ApiModelProperty("筛选图文会诊")
    private Boolean isText;

    @ApiModelProperty("筛选电话会诊")
    private Boolean  isPhone;

    @ApiModelProperty("筛选线下会诊")
    private Boolean  isOffline;

    @ApiModelProperty("价格区间--开始")
    private Float  startPrice;

    @ApiModelProperty("价格区间--结束")
    private Float  endPrice;
}

这样参数的文档说明如下:
在这里插入图片描述

最后就是用QueryWrapper的lambda来编写实现查询的代码:

public List<Doctor> getFilterList(DoctorFilterParam param)
{
    QueryWrapper<Doctor> objectQueryWrapper = new QueryWrapper<>(Doctor.class);
    objectQueryWrapper.lambda()
       .and(param.getDoctorType() != null,
          dt -> dt.eq(Doctor::getDoctorType, param.getDoctorType()))
       .and(param.getExpertIn() != null,
          dt -> dt.eq(Doctor::getExpertIn,   param.getExpertIn()))
       .and(param.getName() != null,
          dt -> dt.like(Doctor::getName, param.getName()))
       .and(param.getIsPhone()
                            || param.getIsOffline()
                            || param.getIsText(),
           lt -> lt.or(param.getIsPhone(),
                 pc -> pc.eq(Doctor::getIsPhone,1)
                         .between(Doctor::getPhonePrice,param.getStartPrice(),param.getEndPrice()))
                     .or(param.getIsOffline(),
                          ol -> ol.eq(Doctor::getIsOffline,1)
                                  .between(Doctor::getOfflinePrice,param.getStartPrice(),param.getEndPrice()))
                     .or(param.getIsText(),
                          tc -> tc.eq(Doctor::getIsText,1)
                                  .between(Doctor::getTextPrice,param.getStartPrice(),param.getEndPrice()))
            );
    return this.list(objectQueryWrapper);
}

如上的代码实现查询的条件嵌套,主要就是or和and的嵌套,包含部分的区间查询between,没做全部的容错处理,传参差异可能有异常,仅供参考
下面就可以通过构建查询的参数进行一次查询测试:

DoctorFilterParam param = new DoctorFilterParam();
param.setIsPhone(true);
param.setIsOffline(true);
param.setIsText(true);
param.setName("牛");
param.setStartPrice(20.0f);
param.setEndPrice(20000.0f);
System.out.println(doctorService.getFilterList(param));

这个参数的查询条件就是查询名称含牛的、开通了电话、线下、图文会诊而且任一一直方式的价格在20至20000区间的医生。
然后转换后的SQL语句以及参数如下:

Preparing: SELECT id,name,sex,doctor_type,expert_in,is_text,text_price,is_phone,phone_price,is_offline,offline_price FROM oas_doctor WHERE ((name LIKE ?) AND ((is_phone = ? AND phone_price BETWEEN ? AND ?) OR (is_offline = ? AND offline_price BETWEEN ? AND ?) OR (is_text = ? AND text_price BETWEEN ? AND ?)))
Parameters: %牛%(String), 1(Integer), 20.0(Float), 20000.0(Float), 1(Integer), 20.0(Float), 20000.0(Float), 1(Integer), 20.0(Float), 20000.0(Float)

查询的结果格式也是一个又医生数据组成的数组:

在这里插入图片描述

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十幺卜入

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值