Java开发学习(四十二)

一、条件查询的类

  • MyBatisPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合。

这个我们在前面都有见过,比如查询所有和分页查询的时候,都有看到过一个Wrapper类,这个类就是用来构建查询条件的,如下图所示:

Java开发学习(四十二)

那么条件查询如何使用Wrapper来构建呢?

二、环境构建

在构建条件查询之前,我们先来准备下环境

  • 创建一个SpringBoot项目

    参考Java开发学习(三十五)—-SpringBoot快速入门及起步依赖解析

  • pom.xml中添加对应的依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.5.0</version>
     </parent>
     <groupId>com.itheima</groupId>
     <artifactId>mybatisplus_02_dql</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <properties>
       <java.version>1.8</java.version>
     </properties>
     <dependencies>
    ​
       <dependency>
         <groupId>com.baomidou</groupId>
         <artifactId>mybatis-plus-boot-starter</artifactId>
         <version>3.4.1</version>
       </dependency>
    ​
       <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter</artifactId>
       </dependency>
    ​
       <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>druid</artifactId>
         <version>1.1.16</version>
       </dependency>
    ​
       <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <scope>runtime</scope>
       </dependency>
    ​
       <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
       </dependency>
    ​
       <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
       </dependency>
    ​
     </dependencies>
    ​
     <build>
       <plugins>
         <plugin>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
       </plugins>
     </build>
    ​
    </project>
    ​
  • 编写UserDao接口

    @Mapper
    public interface UserDao extends BaseMapper<User> {
    }
  • 编写模型类

    @Data
    public class User {
     private Long id;
     private String name;
     private String password;
     private Integer age;
     private String tel;
    }
  • 编写引导类

    @SpringBootApplication
    public class Mybatisplus02DqlApplication {
    ​
     public static void main(String[] args) {
       SpringApplication.run(Mybatisplus02DqlApplication.class, args);
      }
    ​
    }
  • 编写配置文件

    # dataSource
    spring:
    datasource:
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
      username: root
      password: root
    # MybatisPlus日志
    mybatis-plus:
    configuration:
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  • 编写测试类

    @SpringBootTest
    class Mybatisplus02DqlApplicationTests {
    ​
     @Autowired
     private UserDao userDao;
     
     @Test
     void testGetAll(){
       List<User> userList = userDao.selectList(null);
       System.out.println(userList);
      }
    }

    最终创建的项目结构为:

    Java开发学习(四十二)

  • 测试的时候,控制台打印的日志比较多,速度有点慢而且不利于查看运行结果,所以接下来我们把这个日志处理下:

    • 取消初始化spring日志打印,resources目录下添加logback.xml,名称固定,内容如下:

      <?xml version="1.0" encoding="UTF-8"?>
      <configuration>
      </configuration>
    • 取消MybatisPlus启动banner图标

      Java开发学习(四十二)

      application.yml添加如下内容:

      # mybatis-plus日志控制台输出
      mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      global-config:
        banner: off # 关闭mybatisplus启动图标
    • 取消SpringBoot的log打印

      Java开发学习(四十二)

      application.yml添加如下内容:

      spring:
      main:
        banner-mode: off # 关闭SpringBoot启动图标(banner)

解决控制台打印日志过多的相关操作可以不用去做,一般会被用来方便我们查看程序运行的结果。

三、构建条件查询

在进行查询的时候,我们的入口是在Wrapper这个类上,因为它是一个接口,所以我们需要去找它对应的实现类,关于实现类也有很多,说明我们有多种构建查询条件对象的方式,

Java开发学习(四十二)

  1. 先来看第一种:QueryWrapper

@SpringBootTest
class Mybatisplus02DqlApplicationTests {
​
 @Autowired
 private UserDao userDao;
 
 @Test
 void testGetAll(){
   QueryWrapper qw = new QueryWrapper();
   qw.lt("age",18);
   List<User> userList = userDao.selectList(qw);
   System.out.println(userList);
  }
}
  • lt: 小于(<) ,最终的sql语句为

    SELECT id,name,password,age,tel FROM user WHERE (age < ?)

第一种方式介绍完后,有个小问题就是在写条件的时候,容易出错,比如age写错,就会导致查询不成功

  1. 接着来看第二种:QueryWrapper的基础上使用lambda

@SpringBootTest
class Mybatisplus02DqlApplicationTests {
​
 @Autowired
 private UserDao userDao;
 
 @Test
 void testGetAll(){
   QueryWrapper<User> qw = new QueryWrapper<User>();
   qw.lambda().lt(User::getAge, 10);//添加条件
   List<User> userList = userDao.selectList(qw);
   System.out.println(userList);
  }
}
  • User::getAge,为lambda表达式中的,类名::方法名,最终的sql语句为:

SELECT id,name,password,age,tel FROM user WHERE (age < ?)

注意:构建LambdaQueryWrapper的时候泛型不能省。

此时我们再次编写条件的时候,就不会存在写错名称的情况,但是qw后面多了一层lambda()调用

  1. 接着来看第三种:LambdaQueryWrapper

@SpringBootTest
class Mybatisplus02DqlApplicationTests {
​
 @Autowired
 private UserDao userDao;
 
 @Test
 void testGetAll(){
   LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
   lqw.lt(User::getAge, 10);
   List<User> userList = userDao.selectList(lqw);
   System.out.println(userList);
  }
}

这种方式就解决了上一种方式所存在的问题。

四、多条件构建

三种构建查询对象的方式,每一种都有自己的特点,所以用哪一种都行,刚才都是一个条件,那如果有多个条件该如何构建呢?

需求:查询数据库表中,年龄在10岁到30岁之间的用户信息

@SpringBootTest
class Mybatisplus02DqlApplicationTests {
​
 @Autowired
 private UserDao userDao;
 
 @Test
 void testGetAll(){
   LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
   lqw.lt(User::getAge, 30);
   lqw.gt(User::getAge, 10);
   List<User> userList = userDao.selectList(lqw);
   System.out.println(userList);
  }
}
  • gt:大于(>),最终的SQL语句为

    SELECT id,name,password,age,tel FROM user WHERE (age < ? AND age > ?)
  • 构建多条件的时候,可以支持链式编程

    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
    lqw.lt(User::getAge, 30).gt(User::getAge, 10);
    List<User> userList = userDao.selectList(lqw);
    System.out.println(userList);

需求:查询数据库表中,年龄小于10或年龄大于30的数据

@SpringBootTest
class Mybatisplus02DqlApplicationTests {
​
 @Autowired
 private UserDao userDao;
 
 @Test
 void testGetAll(){
   LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
   lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
   List<User> userList = userDao.selectList(lqw);
   System.out.println(userList);
  }
}
  • or()就相当于我们sql语句中的or关键字,不加默认是and,最终的sql语句为:

    SELECT id,name,password,age,tel FROM user WHERE (age < ? OR age > ?)

五、null判定

先来看一张图,

Java开发学习(四十二)

  • 我们在做条件查询的时候,一般会有很多条件可以供用户进行选择查询。

  • 这些条件用户可以选择使用也可以选择不使用,比如我要查询价格在8000以上的手机

  • 在输入条件的时候,价格有一个区间范围,按照需求只需要在第一个价格输入框中输入8000

  • 后台在做价格查询的时候,一般会让 price>值1 and price <值2

  • 因为前端没有输入值2,所以如果不处理的话,就会出现 price>8000 and price < null问题

  • 这个时候查询的结果就会出问题,具体该如何解决?

需求:查询数据库表中,根据输入年龄范围来查询符合条件的记录

用户在输入值的时候,

如果只输入第一个框,说明要查询大于该年龄的用户

如果只输入第二个框,说明要查询小于该年龄的用户

如果两个框都输入了,说明要查询年龄在两个范围之间的用户

思考第一个问题:后台如果想接收前端的两个数据,该如何接收?

我们可以使用两个简单数据类型,也可以使用一个模型类,但是User类中目前只有一个age属性,如:

@Data
public class User {
 private Long id;
 private String name;
 private String password;
 private Integer age;
 private String tel;
}

使用一个age属性,如何去接收页面上的两个值呢?这个时候我们有两个解决方案

方案一:添加属性age2,这种做法可以但是会影响到原模型类的属性内容

@Data
public class User {
 private Long id;
 private String name;
 private String password;
 private Integer age;
 private String tel;
 private Integer age2;
}

方案二:新建一个模型类,让其继承User类,并在其中添加age2属性,UserQuery在拥有User属性后同时添加了age2属性。

@Data
public class User {
 private Long id;
 private String name;
 private String password;
 private Integer age;
 private String tel;
}
​
@Data
public class UserQuery extends User {
 private Integer age2;
}

环境准备好后,我们来实现下刚才的需求:

@SpringBootTest
class Mybatisplus02DqlApplicationTests {
​
 @Autowired
 private UserDao userDao;
 
 @Test
 void testGetAll(){
   //模拟页面传递过来的查询数据
   UserQuery uq = new UserQuery();
   uq.setAge(10);
   uq.setAge2(30);
   LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
   if(null != uq.getAge2()){
     lqw.lt(User::getAge, uq.getAge2());
    }
   if( null != uq.getAge()) {
     lqw.gt(User::getAge, uq.getAge());
    }
   List<User> userList = userDao.selectList(lqw);
   System.out.println(userList);
  }
}

上面的写法可以完成条件为非空的判断,但是问题很明显,如果条件多的话,每个条件都需要判断,代码量就比较大,来看MybatisPlus给我们提供的简化方式:

@SpringBootTest
class Mybatisplus02DqlApplicationTests {
​
 @Autowired
 private UserDao userDao;
 
 @Test
 void testGetAll(){
   //模拟页面传递过来的查询数据
   UserQuery uq = new UserQuery();
   uq.setAge(10);
   uq.setAge2(30);
   LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
   lqw.lt(null!=uq.getAge2(),User::getAge, uq.getAge2());
   lqw.gt(null!=uq.getAge(),User::getAge, uq.getAge());
   List<User> userList = userDao.selectList(lqw);
   System.out.println(userList);
  }
}
  • lt()方法

    Java开发学习(四十二)

    condition为boolean类型,返回true,则添加条件,返回false则不添加条件

© 版权声明
好牛新坐标
版权声明:
1、IT大王遵守相关法律法规,由于本站资源全部来源于网络程序/投稿,故资源量太大无法一一准确核实资源侵权的真实性;
2、出于传递信息之目的,故IT大王可能会误刊发损害或影响您的合法权益,请您积极与我们联系处理(所有内容不代表本站观点与立场);
3、因时间、精力有限,我们无法一一核实每一条消息的真实性,但我们会在发布之前尽最大努力来核实这些信息;
4、无论出于何种目的要求本站删除内容,您均需要提供根据国家版权局发布的示范格式
《要求删除或断开链接侵权网络内容的通知》:https://itdw.cn/ziliao/sfgs.pdf,
国家知识产权局《要求删除或断开链接侵权网络内容的通知》填写说明: http://www.ncac.gov.cn/chinacopyright/contents/12227/342400.shtml
未按照国家知识产权局格式通知一律不予处理;请按照此通知格式填写发至本站的邮箱 wl6@163.com

相关文章