SpringBoot&MyBatisPlus
阅读原文时间:2023年07月09日阅读:3

5. SpringBoot

  • 学习目标:

    • 掌握基于SpringBoot框架的程序开发步骤
    • 熟练使用SpringBoot配置信息修改服务器配置
    • 基于SpringBoot完成SSM整合项目开发

SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程

  • 原生开发SpringSSM程序过程

    • 创建工程,在pom中配对应的依赖
    • 添加Spring、MyBatis、SpringMVC的相关配置类
    • 添加Controller类、Service类、Dao
  • 实现步骤:

    • 创建工程

    • 编写controller

    • 运行Application

  • 最简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>
      &lt;parent&gt;
          &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
          &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
          &lt;version&gt; 2.7.3&lt;/version&gt;
          &lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
      &lt;/parent&gt;
      
      &lt;groupId&gt;com.mark&lt;/groupId&gt;
      &lt;artifactId&gt;SpringBoot_01_QuickStart&lt;/artifactId&gt;
      &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
      
      &lt;properties&gt;
          &lt;java.version&gt;11&lt;/java.version&gt;
      &lt;/properties&gt;
      
      &lt;dependencies&gt;
          &lt;dependency&gt;
              &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
              &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
          &lt;/dependency&gt;
      &lt;/dependencies&gt;
      </project>
    • Application类

      @SpringBootApplication
      public class Application {
          public static void main(String[] args) {
              SpringApplication.run(Application.class, args);
          }
      }
  • Spring程序与SpringBoot程序对比

  • 基于idea开发SpringBoot程序需要确保联网且能够加载到程序框架

  • 对SpringBoot项目打包(执行Maven构建指令package)

  • 执行启动指令

    java -jar springboot.jar

注意事项:

jar支持命令行启动需要依赖maven插件支持,需要确认在打包时是否具有SpringBoot对应的maven插件

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.7.3</version>
        </plugin>
    </plugins>
</build>

SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程

  • Spring程序缺点

    • 配置繁琐
    • 依赖设置繁琐
  • SpringBoot程序优点

    • 自动配置
    • 起步依赖(简化依赖配置)
    • 辅助功能(内置服务器,…)
  • 起步依赖帮助我们实现了快速配置

    <?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.7.3</version>
        </parent>
        <groupId>com.mark</groupId>
        <artifactId>SpringBoot_01_QuickStart</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <properties>
            <java.version>11</java.version>
        </properties>
        <dependencies>
              <!--起步依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        </dependencies>
    </project>
    • starter

      • SpringBoot中常见项目名称,定义了当前项目使用的所有项目坐标,以达到减少依赖配置的目的
    • partent

      • 所有SpringBoot项目要继承的项目,定义了若干个坐标版本号(依赖管理,而非依赖),以达到减少冲突的目的
      • spring-boot-starter-parent(2.5.0)与spring-boot-starter-parent(2.4.6)共计57处坐标版本不同
  • 实际开发

    • 使用任意坐标时,仅书写VGA中的G和A,V由SpringBoot提供
    • 如发生坐标错误,再指定version(要小心版本冲突)
  • SpringBoot启动

    • 启动方式

      @SpringBootApplication
      public class Application {
          public static void main(String[] args) {
              SpringApplication.run(Application.class, args);
          }
      }
    • Spring在创建项目时,采用jar的打包方式

    • SpringBoot的引导类是项目的入口,运行main方法就可以启动

使用jetty替换tomcat:使用maven依赖管理变更起步依赖项

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

Jetty比Tomcat更轻量级,可扩展性更强(相较于Tomcat),谷歌搜索引擎(GAE)已经全面切换为Jetty

  • 修改服务器端口

    http://localhost:8080/books/1

    修改为80端口号:http://localjost/books/1

  • SpringBoot提供了多种属性配置方式

    • application.properties中修改

      在resources下的application.properties添加server.port=80

    • application.yml中修改

      在resources下新建application.yml文件,添加server:port:80

    • application.ymal中修改

      在resources下新建application.yaml文件,添加server:port:80

  • 注意:

    • 在之后主要在application.yml中修改配置
    • 如果三个文件都存在,properties为第一配置文件,yml为第二配置文件,yaml为第三配置文件。即如果三个文件有相同的配置,优先级为properties->yml->yaml
  • YAML(YAML Ain't Markup Language):一种数据序列化格式

  • 优点:

    • 容易阅读
    • 容易与脚本语言交互
    • 以数据为核心,重数据轻格式
  • YAML文件扩展名

    • .yml(主流)
    • .yaml
  • yaml语法规则

    • 大小写敏感

    • 属性层级关系使用多行描述,每行结尾使用冒号结束

    • 使用缩进表示层级关系,同层级左侧对齐,只允许使用空格(不允许使用Tb键)

    • 属性值前面添加空格(属性名与属性值之间使用冒号+空格作为分隔)

    • #表示注释

    • 数组数据在书写位置的下方使用减号作为数据的开始,每行书写一个数据,减号与数据间空格分隔

  • yaml数据读取的方式

    数据如下:

    lesson: SpringBoot
    
    server:
      port: 80
    
    person:
      name: mark
      age: 21
      tel: 123456789
      likes:
        - Java
        - Game
        - Music
    
    logging:
      level:
        root: info
    • 方式一:使用@value注解读取单个数据。引用方式:${一级属性名.二级属性名}

      @RestController
      @RequestMapping("/books")
      public class BookController {
          @Value("${lesson}")
          private String lesson;
          @Value("${server.port}")
          private Integer port;
          @Value("${person.likes[0]}")
          private String likes_00;
      @GetMapping("/{id}")
      public String getById(@PathVariable Integer id) {
          System.out.println(lesson);
          System.out.println(port);
          System.out.println(likes_00);
          return "hello Spring Boot";
      }
      }
    • 方式二:使用Environment对象加载所有环境信息并封装(一般在框架内部使用)

      @RestController
      @RequestMapping("/books")
      public class BookController {
          //加载所有的环境信息
          @Autowired
          private Environment environment;
      @GetMapping("/{id}")
      public String getById(@PathVariable Integer id) {
          System.out.println(environment.getProperty("lesson"));
          System.out.println(environment.getProperty("server.port"));
          System.out.println(environment.getProperty("person.likes[0]"));
          return "hello Spring Boot";
      }
      }
    • 方式三:自定义对象封装指定数据(常用)

      • 定义实体类,添加注解@Component@ConfigurationProperties

        @Getter
        @Setter
        @ToString
        //1.将其定义成一个bean使之能受Spring控制
        @Component
        //2.读取配置中的属性person
        @ConfigurationProperties(prefix = "person")
        public class Person {
            private String name;
            private Integer age;
            private String tel;
            private String[] likes;
        }
      • 使用时自动装配即可

        @RestController
        @RequestMapping("/books")
        public class BookController {
            @Autowired
            private Person person;
        @GetMapping("/{id}")
        public String getById(@PathVariable Integer id) {
            System.out.println(person);
            return "hello Spring Boot";
        }
        }
      • 自定义对象封装数据警告解决方案:添加以下依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

yaml、yml配置方式:

#设置启用的环境
spring:
  profiles:
    active: dev

---
#开发
spring:
  profiles: dev
server:
  port: 80

---
#生产
spring:
  profiles: pro
server:
  port: 81

---
#测试
spring:
  profiles: test
server:
  port: 82

上述是过时写法,以下为不过时写法

#设置启用的环境
spring:
  profiles:
    active: dev

---
spring:
  config:
    activate:
      on-profile: dev
server:
  port: 82

properties配置方式:(了解即可)

在主启动配置文件application.properties中添加

#设置启用的环境
spring.profiles.active=dev

新建分类配置文件application-dev.properties添加环境配置

server.port=80

同理新建application-pro.properties、application-test.properties添加环境配置

server.port=81


server.port=82
  • 多环境启动命令格式

    • 因为有中文,所以先设置编码

    • 在打包前首先执行clean,然后package打包。避免影响结果

    • cmd执行:带参数启动SpringBoot

      java -jar SpringBoot_04_profile-0.0.1-SNAPSHOT.jar --spring.profiles.active=test

      即在测试环境下运行

    • 使用临时参数启动SpringBoot

      java -jar SpringBoot_04_profile-0.0.1-SNAPSHOT.jar --spring.profiles.active=test --server.port=88

  • 参数加载优先级:

  • 多环境开发兼容问题(Maven与Boot)

    • Maven中设置生产环境

      <profiles>
          <profile>
              <id>dev</id>
              <properties>
                  <profile.active>dev</profile.active>
              </properties>
          </profile>
      &lt;profile&gt;
          &lt;id&gt;pro&lt;/id&gt;
          &lt;properties&gt;
              &lt;profile.active&gt;pro&lt;/profile.active&gt;
          &lt;/properties&gt;
          &lt;activation&gt;
              &lt;activeByDefault&gt;true&lt;/activeByDefault&gt;
          &lt;/activation&gt;
      &lt;/profile&gt;
      
      &lt;profile&gt;
          &lt;id&gt;test&lt;/id&gt;
          &lt;properties&gt;
              &lt;profile.active&gt;test&lt;/profile.active&gt;
          &lt;/properties&gt;
      &lt;/profile&gt;
      </profiles>
    • Boot的yml中设置生产环境

      #设置启用的环境
      spring:
        profiles:
          active: ${profile.active}
      
      ---
      #开发
      spring:
        profiles: dev
      server:
        port: 80
      
      ---
      #生产
      spring:
        profiles: pro
      server:
        port: 81
      
      ---
      #测试
      spring:
        profiles: test
      server:
        port: 82
    • 打包运行发现端口号是8080

    • 解决:

      • 添加插件

        <!--对资源文件进行解析-->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <version>3.2.0</version>
            <configuration>
                <encoding>UTF-8</encoding>
                <useDefaultDelimiters>true</useDefaultDelimiters>
            </configuration>
        </plugin>
  • SpringBoot中4级配置文件

    • 1级:file: config/application.yml ----最高
    • 2级:file: application.yml
    • 3级:classpath: config./application.yml
    • 4级:classpath: application.yml ----最低
  • 作用:

    • 1级与2级留做系统打包后设置通用属性(在资源管理器target目录下创建yml)
    • 3级与4级用于系统开发阶段设置通用属性(在IDEA的resources包下创建)

Spring整合Junit

//设置运行器
@RunWith(SpringJUnit4ClassRunner.class)
//加载环境
@ContextConfiguration(classes = SpringConfig.class)
public class BookServiceTest {

    @Autowired
    private BookService bookService;

    @Test
    public void testGetById() {
        Book book = bookService.getById(2);
        System.out.println(book);
    }
}

书写一个Service接口和实现类,直接在TestApplication中测试即可

@SpringBootTest
class SpringBoot07TestApplicationTests {
    @Autowired
    private BookService bookService;

    @Test
    void contextLoads() {
        bookService.save();
    }
}
  • SpringBoot整合Spring(不存在)

  • SpringBoot整合SpringMVC(不存在)

  • SpringBoot整合MyBatis(主要、唯一)

    • 创建工程,在创建模块时添加MyBatis和MySQL

    • 书写实体类(pojo)和dao接口

    • 在dao接口上添加注解@Mapper

    • 修改配置文件,设置数据源参数

      spring:
        datasource:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql:///ssm_db
          username: root
          password: 123
      • 如果使用的SpringBoot版本低于2.4.3(不含),MySQL驱动版本大于8.0时,需要在url连接串中配置时区,或在MySQL数据库端配置时区解决此问题

        url: jdbc:mysql:///ssm_db?serverTimezone=UTC
    • 现在就可以运行啦

  • 如何使用Druid数据库连接池?

    • 添加druid依赖

      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>1.1.16</version>
      </dependency>
    • 修改配置文件

      spring:
        datasource:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql:///ssm_db
          username: root
          password: 123
          type: com.alibaba.druid.pool.DruidDataSource
  • pom.xml

    配置起步依赖,必要的资源坐标(druid)

  • application.yml

    设置数据源、端口等

    #TODO 配置数据源相关信息
    server:
      port: 80
    
    spring:
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/ssm_db
        username: root
        password: 123
  • 配置类

    全部删除

  • dao

    设置@Mapper

  • 测试类

  • 页面

    • 将静态页面放在resources下的static目录下

    • 可以在static下创建index.html主页,这样不用输入地址即可进入

      <script>
          document.location.href="pages/books.html"
      </script>

6. MyBatisPlus

MyBatisPlus(简称MP)是基于MyBatis框架基础上的增强型工具,旨在简化开发、提高效率

  • SpringBoot整合MyBatis开发过程

    • 创建SpringBoot工程
    • 勾选配置使用的技术
    • 设置dataSource相关属性(JDBC参数)
    • 定义数据层接口映射配置
  • 基于SpringBoot使用MyBatisPlus

    • 创建工程,勾选MySQL

    • 手动添加MyBatisPlus、Druid依赖

      <dependency>
          <groupId>com.baomidou</groupId>
          <artifactId>mybatis-plus-boot-starter</artifactId>
          <version>3.5.2</version>
      </dependency>
      
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>1.2.11</version>
      </dependency>
    • 配置数据源

      spring:
        datasource:
          type: com.alibaba.druid.pool.DruidDataSource
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/ssm_db
          username: root
          password: 123
    • 创建domain下的实体类User

      @Getter
      @Setter
      @ToString
      public class User {
          private Long id;
          private String name;
          private String password;
          private Integer age;
          private String tel;
      }
    • 创建dao下的接口UserDao继承BeanMapper,添加泛型为User

      @Mapper
      public interface UserDao extends BaseMapper<User> {
      }
    • 接下里就可以测试了

      @SpringBootTest
      class MyBatisPlus01QuickStartApplicationTests {
          @Autowired
          private UserDao userDao;
      @Test
      void testGetAll() {
          List&lt;User&gt; list = userDao.selectList(null);
          System.out.println(list);
      }
      }
  • MyBatisPlus(简称MP)是基于MyBatis框架基础上的增强型工具,旨在简化开发、提高效率

  • 官网:https://mybatis.plus/ https://mp.baomidou.com

  • MyBatisPlus特性

    • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
    • 强大的 CRUD 操作:内置通用 Mapper、少量配置即可实现单表大部分 CRUD 操作
    • 支持 Lambda 形式调用:编写各类查询条件,无需再担心字段写错
    • 支持主键自动生成
    • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询

@SpringBootTest
class MyBatisPlus01QuickStartApplicationTests {

    @Autowired
    private UserDao userDao;

    @Test
    void testSave(){
        User user = new User();
        user.setName("王昭君");
        user.setPassword("123");
        user.setAge(12);
        user.setTel("123456888");
        userDao.insert(user);
    }

    @Test
    void testDelete(){
        userDao.deleteById(1567537461138120705L);
    }

    @Test
    void testUpdate(){
        User user = new User();
        user.setId(1L);
        user.setName("Tom666");
        //提供哪些字段,修改哪些字段
        userDao.updateById(user);
    }

    @Test
    void testById(){
        User user = userDao.selectById(2L);
        System.out.println(user);
    }

    @Test
    void testGetAll() {
        List<User> list = userDao.selectList(null);
        System.out.println(list);
    }

}


@Test
void testGetByPage(){
    //1:查第一页    2:一页有多少条数据
    IPage page =new Page(1,2);
    userDao.selectPage(page,null);
    System.out.println("当前页码值:"+page.getCurrent());
    System.out.println("当前页有:"+page.getSize()+"条");
    System.out.println("一共有:"+page.getPages()+"页");
    System.out.println("一共有:"+page.getTotal()+"条数据");
    System.out.println("数据:"+page.getRecords());
    //此时查数据发现查不出有多少页多少数据且数据为全部数据
    //这就需要配置PM的分页拦截器
}

此时查数据发现查不出有多少页多少数据且数据为全部数据

这就需要配置PM的分页拦截器

@Configuration
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mPlusInterceptor(){
        //1.定义MP的拦截器
        MybatisPlusInterceptor mybatisPlusInterceptor =new MybatisPlusInterceptor();
        //2.在MP的拦截器添加具体的拦截器
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

结果如下:

当前页码值:1
当前页有:2条
一共有:3页
一共有:5条数据
数据:[User(id=1, name=Tom666, password=tom, age=13, tel=18888888888), User(id=2, name=Jerry, password=jerry, age=12, tel=13999999999)]

可以在yml配置中开启日志

# 开启MP的日志(输出到控制台)
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

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

由于输出日志太多,因此可以配置一个logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

</configuration>

还可以清除MP和Spring的LOGO:在yml中配置banner

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatisplus_db
    username: root
    password: 123
  main:
    banner-mode: off

mybatis-plus:
  global-config:
    banner: false
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

这样输出结果就会很清爽

  • 方式一:

    @Test
    void testGetAll() {
        //按条件查询方式一:
        QueryWrapper wrapper = new QueryWrapper();
        //&lt:小于  &gt:大于
        wrapper.lt("age",18);
        List<User> userList = userDao.selectList(wrapper);
        System.out.println(userList);
    }
  • 方式二:

    //按条件查询方式二:
    QueryWrapper<User> wrapper = new QueryWrapper<User>();
    wrapper.lambda().lt(User::getAge,18);
    List<User> userList = userDao.selectList(wrapper);
    System.out.println(userList);
  • 方式三(推荐):

    //按条件查询方式三:
    LambdaQueryWrapper<User> lambdaQueryWrapper =new LambdaQueryWrapper<User>();
    lambdaQueryWrapper.lt(User::getAge,10);
    List<User> userList = userDao.selectList(lambdaQueryWrapper);
    System.out.println(userList);
    
    
    //方式三添加多个条件
    LambdaQueryWrapper<User> lambdaQueryWrapper =new LambdaQueryWrapper<User>();
    //lambdaQueryWrapper.lt(User::getAge,18);
    //lambdaQueryWrapper.gt(User::getAge,12);
    //12到18之间
    //lambdaQueryWrapper.lt(User::getAge,18).gt(User::getAge,12);
    //小于12或大于18
    lambdaQueryWrapper.lt(User::getAge,12).or().gt(User::getAge,18);
    List<User> userList = userDao.selectList(lambdaQueryWrapper);
    System.out.println(userList);

    //模拟页面传递过来的查询数据
    UserQuery userQuery = new UserQuery();
    //userQuery.setAge(10);
    userQuery.setAge2(30);

    LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper();
    //先判定第一个参数是否为true,如果为true,如果为true连接当前条件
    lambdaQueryWrapper.lt(null != userQuery.getAge2(),User::getAge,userQuery.getAge2());
    lambdaQueryWrapper.gt(null != userQuery.getAge(),User::getAge,userQuery.getAge());
    List userList = userDao.selectList(lambdaQueryWrapper);
    System.out.println(userList);

    LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper();
    //该格式只适用于lambda表达式
    lambdaQueryWrapper.select(User::getId, User::getName,User::getAge);
    List userList = userDao.selectList(lambdaQueryWrapper);
    System.out.println(userList);

    /*结果:
    Preparing: SELECT id,name,age FROM user
    ==> Parameters:
    <== Columns: id, name, age
    <== Row: 1, Tom666, 13
    <== Row: 2, Jerry, 12
    <== Row: 3, Mark, 21
    <== Row: 4, 诸葛亮, 15
    <== Row: 1567537209630830593, 王昭君, 12
    <== Total: 5
    */

非lambda表达式写法:

QueryWrapper<User> lambdaQuery = new QueryWrapper<User>();
lambdaQuery.select("id","name","age");
List<User> userList = userDao.selectList(lambdaQuery);
System.out.println(userList);

查询总数

QueryWrapper<User> lambdaQuery = new QueryWrapper<User>();
lambdaQuery.select("count(*) as count");
List<Map<String, Object>> userMaps = userDao.selectMaps(lambdaQuery);
System.out.println(userMaps);

/*结果:
==>  Preparing: SELECT count(*) FROM user
==> Parameters:
<==    Columns: count(*)
<==        Row: 5
<==      Total: 1
*/

分组统计

QueryWrapper<User> lambdaQuery = new QueryWrapper<User>();
//根据电话分组,查询个数
lambdaQuery.select("count(*) as count,tel");
lambdaQuery.groupBy("tel");
List<Map<String, Object>> userMaps = userDao.selectMaps(lambdaQuery);
System.out.println(userMaps);
  • 范围匹配(>、=、between)

  • 模糊匹配(like)

  • 空判定(null)

  • 包含性匹配(in)

  • 分组(group)

  • 排序(order)

    用户登录

    LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
    //等同于"="(equal)
    lambdaQuery.eq(User::getName, "Jerry").eq(User::getPassword, "jerry");
    User user = userDao.selectOne(lambdaQuery);
    System.out.println(user);

    购物设定价格区间、户籍设定年龄区间

    LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
    //范围查询 lt le gt ge between
    //方式二
    //lambdaQuery.le(User::getAge,30).ge(User::getAge,10);
    //方式二
    lambdaQuery.between(User::getAge,10,30);
    List<User> list = userDao.selectList(lambdaQuery);
    System.out.println(list);

    查信息,搜索新闻(非全文检索版:like匹配)

    LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();
    //模糊匹配 Right和Left代表百分号的位置
    lambdaQuery.likeRight(User::getName,"M");
    List<User> list = userDao.selectList(lambdaQuery);
    System.out.println(list);

    统计报表(分组查询聚合函数)

    QueryWrapper<User> lambdaQuery = new QueryWrapper<User>();
    lambdaQuery.select("count(*) as count");
    List<Map<String, Object>> userMaps = userDao.selectMaps(lambdaQuery);
    System.out.println(userMaps);

    更多条件查询查看http://mybatis.plus/guide/wrapper.html#abstractwrapper

  • 问题一:表字段与编码属性设计不同步

    @Data
    public class User {
        @TableField(value = "pwd");
        private String password;
    }
  • 问题二:编码中添加了数据库中未定义的属性

    @Data
    public class User {
        private Long id;
        private String name;
        private String password;
        private Integer age;
        private String tel;
        @TableField(exist = false)
        private boolean online;
    }
  • 问题三:采用默认查询开放了更多字段的查看权限

    @Data
    public class User {
        @TableField(value = "pwd",select = false);
        private String password;
    }
  • 问题四:表名与编码开发设计不同步

    @TableName("tbl_user")
    @Data
    public class User {
        private Long id;
        private String name;
        private String password;
        private Integer age;
        private String tel;
    }
  • 不同的表应用不同的id生成策略

    • 日志:自增(1,2,3,4,…)
    • 购物订单:特殊规则(F023948AK3843)
    • 外卖单:关联地区日期等信息(1004202003143491)
    • 关系表:可省略id
  • 注解:@TableId

  • 范例:

    @TableName("tbl_user")
    @Data
    public class User {
        @TableId(type = IdType.AUTO)
        private Long id;
        private String name;
    }
    • 相关属性:

      • value:设置数据库主键名称
      • type:设置主键属性的生成策略,值参照IdType枚举值
        • AUT0(0):使用数据库id自增策略控制id生成
        • NONE(1):不设置id生成策略
        • INPUT(2):用户手工输入id
        • ASSIGN ID(3):雪花算法生成id(可兼容数值型与字符串型)
        • ASSIGN UUID(4):以UUID生成算法作为id生成策略

    @Test
    void testDelete(){
    List list = new ArrayList<>();
    list.add(1567537209630830593L);
    list.add(1568108502637993985L);
    userDao.deleteBatchIds(list);
    }

    @Test
    void testSelectPro(){
    List list = new ArrayList<>();
    list.add(1L);
    list.add(3L);
    list.add(4L);
    userDao.selectBatchIds(list);
    }

  • 删除操作业务问题:业务数据从数据库张丢弃

  • 逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中

    在数据库表中新增字段delete,类型为int,长度为1,默认值为0

    @TableLogic(value="0",deval = "1")

    在User类标注后,执行delete不会删除该条数据但是查询无法查到

    还可以在通用配置添加逻辑删除字段

    mybatis-plus:
      global-config:
        banner: false
        db-config:
          #逻辑删除字段
          logic-delete-field: deleted
          #删除
          logic-delete-value: 1
          #没有被删除
          logic-not-delete-value: 0

业务并发现象带来的问题:秒杀

  • 在数据库表中新增字段version,类型为int,长度为int最大长度11,默认值为1

  • 在User对象中添加属性version,添加注解@Version

  • 添加拦截器

    @Configuration
    public class MyBatisPlusConfig {
        @Bean
        public MybatisPlusInterceptor mPlusInterceptor(){
            //添加乐观锁
            mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
    }
  • 模板:MP提供

  • 数据库相关配置:读取数据库获取信息

  • 开发者自定义配置:手工配置

  • 使用步骤:

    • 添加坐标

      <!--代码生成器-->
      <dependency>
          <groupId>com.baomidou</groupId>
          <artifactId>mybatis-plus-generator</artifactId>
          <version>3.4.1</version>
      </dependency>
      
      <!--velocity模板引擎-->
      <dependency>
          <groupId>org.apache.velocity</groupId>
          <artifactId>velocity-engine-core</artifactId>
          <version>2.3</version>
      </dependency>
    • 代码生成器类Generator

      public class Generator {
          public static void main(String[] args) {
              AutoGenerator autoGenerator = new AutoGenerator();
              DataSourceConfig dataSource = new DataSourceConfig();
              dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
              dataSource.setUrl("jdbc:mysql:///mybatisplus_db?serverTimezone=UTC");
              dataSource.setUsername("root");
              dataSource.setPassword("123");
              autoGenerator.setDataSource(dataSource);
              autoGenerator.execute();
          //设置全局配置
          GlobalConfig globalConfig = new GlobalConfig();
          //设置代码生成位置
          globalConfig.setOutputDir(System.getProperty("user.dir") + "/MyBatisPlus_04_generator/src/main/java");
          //设置生成完毕后是否打开生成代码所在的目录
          globalConfig.setOpen(false);
          //设置作者
          globalConfig.setAuthor("Mark");
          //设置是否覆盖原始生成的文件
          globalConfig.setFileOverride(true);
          //设置数据层接口名,%s为占位符,指代模块名称
          globalConfig.setMapperName("%sDao");
          //设置Id生成策略
          globalConfig.setIdType(IdType.ASSIGN_ID);
          autoGenerator.setGlobalConfig(globalConfig);
      //设置包名相关配置
      PackageConfig packageInfo = new PackageConfig();
      //设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
      packageInfo.setParent("com.aaa");
      //设置实体类包名
      packageInfo.setEntity("domain");
      //设置数据层包名
      packageInfo.setMapper("dao");
      autoGenerator.setPackageInfo(packageInfo);
      
      //策略设置
      StrategyConfig strategyConfig = new StrategyConfig();
      //设置当前参与生成的表名,参数为可变参数
      strategyConfig.setInclude("tbl_user");
      //设置数据库表的前缀名称,模块名 = 数据库表名 - 前缀名  例如: User = tbl_user - tbl_
      strategyConfig.setTablePrefix("tbl_");
      //设置是否启用Rest风格
      strategyConfig.setRestControllerStyle(true);
      //设置乐观锁字段名
      strategyConfig.setVersionFieldName("version");
      //设置逻辑删除字段名
      strategyConfig.setLogicDeleteFieldName("deleted");
      //设置是否启用lombok
      strategyConfig.setEntityLombokModel(true);
      autoGenerator.setStrategy(strategyConfig);
      //2.执行生成操作
      autoGenerator.execute();
      }
      }
  • 代码生成器模板

    • 添加坐标

      com.baomidou mybatis-plus-boot-starter com.baomidou mybatis-plus-generator cn.hutool hutool-all org.apache.velocity velocity-engine-core false mysql mysql-connector-java

    • 添加数据库配置和生成代码的位置

      dataSource.url=jdbc:mysql://123.456.789.000/tableName?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false
      dataSource.driverName=com.mysql.cj.jdbc.Driver
      dataSource.username=root
      dataSource.password=9999
      package.base=com.mark.mall.modules

    • MyBatisPlusGenerator类

      public class MyBatisPlusGenerator {

      public static void main(String[] args) {
      String projectPath = System.getProperty("user.dir") + "/tuling-mpbg";
      String moduleName = scanner("模块名");
      String[] tableNames = scanner("表名,多个英文逗号分割").split(",");
      // 代码生成器
      AutoGenerator autoGenerator = new AutoGenerator();
      autoGenerator.setGlobalConfig(initGlobalConfig(projectPath));
      autoGenerator.setDataSource(initDataSourceConfig());
      autoGenerator.setPackageInfo(initPackageConfig(moduleName));
      autoGenerator.setCfg(initInjectionConfig(projectPath, moduleName));
      autoGenerator.setTemplate(initTemplateConfig()); //
      autoGenerator.setStrategy(initStrategyConfig(tableNames));
      autoGenerator.setTemplateEngine(new VelocityTemplateEngine());
      autoGenerator.execute();
      }

      /**

      • 读取控制台内容信息
        */
        private static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        System.out.println(("请输入" + tip + ":"));
        if (scanner.hasNext()) {
        String next = scanner.next();
        if (StrUtil.isNotEmpty(next)) {
        return next;
        }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
        }

      /**

      • 初始化全局配置
        */
        private static GlobalConfig initGlobalConfig(String projectPath) {
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(projectPath + "/src/main/java");
        globalConfig.setAuthor("XuShu");
        globalConfig.setOpen(false);
        globalConfig.setSwagger2(true);
        globalConfig.setBaseResultMap(true);
        globalConfig.setFileOverride(true);
        globalConfig.setDateType(DateType.ONLY_DATE);
        globalConfig.setEntityName("%s");
        globalConfig.setMapperName("%sMapper");
        globalConfig.setXmlName("%sMapper");
        globalConfig.setServiceName("%sService");
        globalConfig.setServiceImplName("%sServiceImpl");
        globalConfig.setControllerName("%sController");
        return globalConfig;
        }

      /**

      • 初始化数据源配置
        */
        private static DataSourceConfig initDataSourceConfig() {
        Props props = new Props("generator.properties");
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl(props.getStr("dataSource.url"));
        dataSourceConfig.setDriverName(props.getStr("dataSource.driverName"));
        dataSourceConfig.setUsername(props.getStr("dataSource.username"));
        dataSourceConfig.setPassword(props.getStr("dataSource.password"));
        return dataSourceConfig;
        }

      /**

      • 初始化包配置
        */
        private static PackageConfig initPackageConfig(String moduleName) {
        Props props = new Props("generator.properties");
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setModuleName(moduleName);
        packageConfig.setParent(props.getStr("package.base"));
        packageConfig.setEntity("model");
        return packageConfig;
        }

      /**

      • 初始化模板配置
        */
        private static TemplateConfig initTemplateConfig() {
        TemplateConfig templateConfig = new TemplateConfig();
        //可以对controller、service、entity模板进行配置
        //mapper.xml模板需单独配置
        templateConfig.setXml(null);
        return templateConfig;
        }

      /**

      • 初始化策略配置
        / private static StrategyConfig initStrategyConfig(String[] tableNames) { StrategyConfig strategyConfig = new StrategyConfig(); strategyConfig.setNaming(NamingStrategy.underline_to_camel); strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel); strategyConfig.setEntityLombokModel(true); strategyConfig.setRestControllerStyle(true); //当表名中带号时可以启用通配符模式
        if (tableNames.length == 1 && tableNames[0].contains("*")) {
        String[] likeStr = tableNames[0].split(""); String likePrefix = likeStr[0] + "";
        strategyConfig.setLikeTable(new LikeTable(likePrefix));
        } else {
        strategyConfig.setInclude(tableNames);
        }
        return strategyConfig;
        }

      /**

      • 初始化自定义配置
        */
        private static InjectionConfig initInjectionConfig(String projectPath, String moduleName) {
        // 自定义配置
        InjectionConfig injectionConfig = new InjectionConfig() {
        @Override
        public void initMap() {
        // 可用于自定义属性
        }
        };
        // 模板引擎是Velocity
        String templatePath = "/templates/mapper.xml.vm";
        // 自定义输出配置
        List focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
        @Override
        public String outputFile(TableInfo tableInfo) {
        // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
        return projectPath + "/src/main/resources/mapper/" + moduleName
        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
        }
        });
        injectionConfig.setFileOutConfigList(focList);
        return injectionConfig;
        }
        }