5. SpringBoot

  • 学习目标:

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

5.1 入门案例

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> <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version> 2.7.3</version>
      <relativePath/> <!-- lookup parent from repository -->
      </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>
    • Application类

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

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

5.2 SpringBoot工程官网创建方式

5.3 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>

5.4 SpringBoot概述

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方法就可以启动

5.5 Spring辅助功能:切换web服务器

使用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

5.6 配置文件格式

  • 修改服务器端口

    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

5.7 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>

5.8 多环境开发配置

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

  • 参数加载优先级:

    • 参考https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config
  • 多环境开发兼容问题(Maven与Boot)

    • Maven中设置生产环境

      <profiles>
      <profile>
      <id>dev</id>
      <properties>
      <profile.active>dev</profile.active>
      </properties>
      </profile> <profile>
      <id>pro</id>
      <properties>
      <profile.active>pro</profile.active>
      </properties>
      <activation>
      <activeByDefault>true</activeByDefault>
      </activation>
      </profile> <profile>
      <id>test</id>
      <properties>
      <profile.active>test</profile.active>
      </properties>
      </profile>
      </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>

5.9 配置文件分类

  • 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包下创建)

5.10 SpringBoot整合junit

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();
}
}

5.11 SpringBoot整合SSM

  • 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

5.12 基于SpringBoot的整合SSM案例

  • 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

6.1 入门案例

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<User> list = userDao.selectList(null);
      System.out.println(list);
      }
      }

6.2 MyBatisPlus简介

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

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

  • MyBatisPlus特性

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

6.3 标准数据层CRUD功能

@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);
} }

6.4 标准分页功能制作

@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

6.5 条件查询

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);

6.6 条件查询—null值处理

//模拟页面传递过来的查询数据
UserQuery userQuery = new UserQuery();
//userQuery.setAge(10);
userQuery.setAge2(30); LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>();
//先判定第一个参数是否为true,如果为true,如果为true连接当前条件
lambdaQueryWrapper.lt(null != userQuery.getAge2(),User::getAge,userQuery.getAge2());
lambdaQueryWrapper.gt(null != userQuery.getAge(),User::getAge,userQuery.getAge());
List<User> userList = userDao.selectList(lambdaQueryWrapper);
System.out.println(userList);

6.7 查询投影(查询的字段控制)

LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<User>();
//该格式只适用于lambda表达式
lambdaQueryWrapper.select(User::getId, User::getName,User::getAge);
List<User> 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);

6.8 查询条件

  • 范围匹配(>、=、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

6.9 映射匹配兼容性

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

    @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;
    }

6.10 id生成策略

  • 不同的表应用不同的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生成策略

6.11 多数据操作(删除与查询)

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

6.12 逻辑删除

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

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

    在数据库表中新增字段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

6.13 乐观锁

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

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

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

  • 添加拦截器

    @Configuration
    public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mPlusInterceptor(){
    //添加乐观锁
    mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor;
    }
    }

6.14 代码生成器

  • 模板: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();
      }
      }
  • 代码生成器模板

    • 添加坐标
    <dependencies>
    <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    </dependency>
    <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    </dependency>
    <dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    </dependency>
    <dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <optional>false</optional>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    </dependency>
    </dependencies>
    • 添加数据库配置和生成代码的位置
    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<FileOutConfig> 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;
    }
    }

SpringBoot&MyBatisPlus的更多相关文章

  1. spring-boot+mybatisPlus+shiro的集成demo 我用了5天

    spring-boot + mybatis-plus + shiro 的集成demo我用了五天 关于shiro框架,我还是从飞机哪里听来的,就连小贱都知道,可我母鸡啊.简单百度了下,结论很好上手,比s ...

  2. IDEA上创建 Maven SpringBoot+mybatisplus+thymeleaf 项目

    概述 在WEB领域,Java也是在不断的探索和改进,从开始的JSP--->Struts1--->Struts2+Spring--->Spring MVC--->SpringBo ...

  3. springboot+mybatisplus 测试代码生成

    测试springboot + mybatisplus 实现代码生成   使用默认的模板引擎 pom.xml文件 <?xml version="1.0" encoding=&q ...

  4. 2、SpringBoot+MybatisPlus整合-------BaseCRUD

    开发工具:STS 代码下载链接:GitHub管理代码 版本: Springboot:1.5.14.RELEASE 使用2.0以上的Springboot,会报出一些异常.欢迎知道异常原因的大牛解惑. M ...

  5. SpringBoot+MyBatisPlus整合时提示:Invalid bound statement(not found):**.dao.UserDao.queryById

    场景 在使用SpringBoot+MyBatisPlus搭建后台启动项目时,使用EasyCode自动生成代码. 在访问后台接口时提示: Invilid bound statement (not fou ...

  6. springboot+mybatisplus+sharding-jdbc分库分表实例

    项目实践 现在Java项目使用mybatis多一些,所以我也做了一个springboot+mybatisplus+sharding-jdbc分库分表项目例子分享给大家. 要是用的springboot+ ...

  7. springboot + mybatisPlus 入门实例 入门demo

    springboot + mybatisPlus 入门实例 入门demo 使用mybatisPlus的优势 集成mybatisplus后,简单的CRUD就不用写了,如果没有特别的sql,就可以不用ma ...

  8. 关于写SpringBoot+Mybatisplus+Shiro项目的经验分享四:部署到阿里云

    框架: SpringBoot+Mybatisplus+Shiro 简单介绍:关于写SpringBoot+Mybatisplus+Shiro项目的经验分享一:简单介绍 阿里云开放必要端口,mysql与t ...

  9. 关于写SpringBoot+Mybatisplus+Shiro项目的经验分享三:问题2

    框架: SpringBoot+Mybatisplus+Shiro 简单介绍:关于写SpringBoot+Mybatisplus+Shiro项目的经验分享一:简单介绍 搜索框是该项目重要的一环,由于涉及 ...

  10. 关于写SpringBoot+Mybatisplus+Shiro项目的经验分享二:问题1

    框架: SpringBoot+Mybatisplus+Shiro 简单介绍:关于写SpringBoot+Mybatisplus+Shiro项目的经验分享一:简单介绍 添加时,如果失败,不能正确跳转 c ...

随机推荐

  1. 【java】学习路径27-HashSet、TreeSet,HashMap

    学习路径20-27的所有源代码都可以在此下载 https://www.aliyundrive.com/s/cg8jTRbg6vy HashSet.TreeSet中,Set表示集合,特性在于:无序的.不 ...

  2. ABAQUS和UG许可证冲突问题的解决方案

    前段时间重新安装了ABAQUS,更新到了2020版本后,发现NX UG怎么突然打不开了,搜索一下,发现是两个许可证有冲突.找了很多解决方案,主要归纳为以下两种: 方法一:Lmtools修改法 先说结论 ...

  3. Html飞机大战(二):面向对象绘制背景

    好家伙, 我们为了后续工作的顺利进行,我试着把每一个模块封装为对象 但冻手之前还是要构思一下 我们把天空封装成一个类: 1.来搞一手简单的对象分析:  属性方面的都好理解 来说明一下方法: (1) p ...

  4. KingbaseES V8R6集群同步模式synchronous参数配置详解

    如下图所示: 集群数据同步原理说明: synchronous参数配置测试: 集群节点信息: ID | Name | Role | Status | Upstream | repmgrd | PID | ...

  5. 如何修改SAO用户密码

    KingbaseES SAO 用户是专门用于审计管理的用户,用户配置审计策略需要使用该用户.在initdb 完成后,SAO  用户的默认密码保存在参数 sysaudit.audit_table_pas ...

  6. 解决element-ui中组件【el-upload】一次性上传多张图片的问题

    element-ui 中的组件 el-upload默认的行为是一张图片请求一次,在项目需求中,通常是多张图片要求只向后台请求一次,下面的做法就是为了实现这样的需求 前端 <el-upload r ...

  7. 从代码到发包,一个程序全搞定!Gitea 推出软件包自托管功能 Package Registry

    2022 年 7 月的最后一天,随着 Gitea 1.17.0 版本的正式发布,Gitea 开源社区推出了一项名为 Package Registry 的包管理功能,与 Gitea 代码仓库无缝集成,类 ...

  8. 放弃 Electron,拥抱 WebView2!JavaScript 快速开发独立 EXE 程序

    Electron 不错,但也不是完美的. Electron 带来了很多优秀的桌面软件,但并不一定总是适合我们的需求. 多个选择总是好事! 我使用 Electron 遇到的一些麻烦 1.Electron ...

  9. 聊聊单点登录(SSO)中的CAS认证

    SSO介绍 背景 随着企业的发展,一个大型系统里可能包含 n 多子系统, 用户在操作不同的系统时,需要多次登录,很麻烦,我们需要一种全新的登录方式来实现多系统应用群的登录,这就是单点登录. web 系 ...

  10. HCNP Routing&Switching之ARP安全

    前文我们了解了IP安全相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16652367.html:今天我们来聊一聊ARP安全相关话题: 什么是ARP? ...