Spring Boot

一 Spring Boot概述

1 Spring Boot简介

	随着互联网的兴起,Spring势如破竹,占据着Java领域轻量级开发的王者地位。
	随着Java语言的发展以及市场开发的需求,Spring推陈出新,推出了全新的Spring Boot框架。
	Spring Boot是Spring家族的一个子项目,其设计初衷是为了简化Spring配置,从而可以轻松构建独立运行的程序,并极大提高开发效率。
	Spring Boot是基于Spring框架开发的全新框架,其设计目的是简化新Spring应用的初始化搭建和开发过程
	Spring Boot整合了许多框架和第三方库配置,几乎可以达到“开箱即用”

2 Spring Boot优点

可快速构建独立的Spring应用
直接嵌入Tomcat、Jetty和Undertow服务器(无需部署WAR文件
•提供依赖启动器简化构建配置
•极大程度的自动化配置Spring和第三方库
•提供生产就绪功能
•极少的代码生成和XML配置

3Spring是如何简化Java开发的

为了降低Java开发的复杂性,Spring采用了以下4种关键策略:

1、基于POJO的轻量级和最小侵入性编程,所有东西都是bean;

2、通过IOC,依赖注入(DI)和面向接口实现松耦合;

3、基于切面(AOP)和惯例进行声明式编程;

4、通过切面和模版减少样式代码,RedisTemplate,xxxTemplate;

使用Spring Boot到底有多爽,真的很爽,用下面这幅图来表达,我们快速去体验开发个接口的感觉吧!

1642496470533

4Spring入门程序

(1)开发环境准备

​ •JDK 1.8.0_201(及以上版本)

​ •Apache Maven 3.6.0

​ •SpringBoot 2.x 最新版

​ •IntelliJ IDEA

注意:
	开发环境准备好后,可以使用Maven方式构建项目,也可以使用Spring Initializr快捷方式构建项目.
(2)使用Maven方式构建Spring Boot项目

Spring官方提供了非常方便的工具让我们快速构建应用

Spring Initializr:https://start.spring.io/

**项目创建方式一:**使用Spring Initializr 的 Web页面创建项目

1、打开 https://start.spring.io/

2、填写项目信息

3、点击”Generate Project“按钮生成项目;下载此项目

4、解压项目包,并用IDEA以Maven项目导入,一路下一步即可,直到项目导入完毕。

5、如果是第一次使用,可能速度会比较慢,包比较多、需要耐心等待一切就绪。

**项目创建方式二:**使用 IDEA 直接创建项目

1、创建一个新项目

2、选择spring initalizr , 可以看到默认就是去官网的快速构建工具那里实现

3、填写项目信息

4、选择初始化的组件(初学勾选 Web 即可)

5、填写项目路径

6、等待项目构建成功

步骤
	创建Maven项目
	在pom.xml中添加Spring Boot相关依赖
	编写主程序启动类
	创建一个用于Web访问的Controller
	运行项目

1)创建Maven项目

image-20211116141021871

image-20211116141355300

2)在pom.xml中添加Spring Boot相关依赖

    <!-- 引入Spring Boot父依赖 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.4</version>
    </parent>
    <dependencies>
        <!-- 引入Web场景依赖启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

3)编写主程序启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication//标记该类为主程序启动类
public class MySpringBoot {
    public static void main(String[] args) {
        //SpringApplication.run()方法启动主程序类
        SpringApplication.run(MySpringBoot.class);
    }
}

4)创建一个用于Web访问的Controller

@RestController   
public class HelloController {
   @GetMapping("/hello")
   public String hello(){
        return "hello Spring Boot";
    }
}

5)运行项目

启动项目,在浏览器上访问 http://localhost:8080/hello

image-20211116144206809

(3)使用Spring Initializr方式构建Spring Boot项目
步骤:	
	创建Spring Boot项目
	创建一个用于Web访问的Controller
	运行项目

1)创建Spring Boot项目

image-20211116143010382

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8PStiM7F-1649526406159)(https://gitee.com/shuaiqiguoguo/cloudimage/raw/master/img/202204100145663.png)]

image-20211116143617887

image-20211116143722531

pom.xml

<!-- 父依赖 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath/>
</parent>

<dependencies>
   <!--web依赖,tomcat,dispatcherServlet,xml......-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
   <!--spring-boot-starter所有的springboot依赖都是使用这个开头的-->
   <!--单元测试-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <!-- 剔除依赖 -->
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

<build>
    <plugins>
        <!-- 打包插件 -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

2)创建一个用于Web访问的Controller

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "hello Spring Boot";
    }
}

主启动类

默认的主启动类

//@SpringBootApplication 来标注一个主程序类
//说明这是一个Spring Boot应用
@SpringBootApplication
public class SpringbootApplication {
   public static void main(String[] args) {
     //以为是启动了一个方法,没想到启动了一个服务
     //将springboot应用启动
      SpringApplication.run(SpringbootApplication.class, args);
   }
}

3)运行项目

启动项目,在浏览器上访问 http://localhost:8080/hello

image-20211116144149302

4)创建成功后的目录结构:

image-20211116150943937

(4)在pom.xml中添加常用依赖

<dependencies>
        <!-- web依赖启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 热部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <!-- 配置处理器依赖(提示自定义对象属性)-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>
    </dependencies>
(4)将项目打成jar包

将项目打成jar包,点击 maven的 package

1643002742623

如果遇到错误,可以配置打包时 跳过项目运行测试用例

<!--
    在工作中,很多情况下我们打包是不想执行测试用例的
    可能是测试用例不完事,或是测试用例会影响数据库数据
    跳过测试用例执
    -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <!--跳过项目运行测试用例-->
        <skipTests>true</skipTests>
    </configuration>
</plugin>

打成了jar包后,就可以在任何地方运行了!OK

如何更改启动时显示的字符拼成的字母,SpringBoot呢?也就是 banner 图案;

只需一步:到项目下的 resources 目录下新建一个banner.txt 即可。

图案可以到:https://www.bootschool.net/ascii 这个网站生成,然后拷贝到文件中即可!

1643016138988

SpringBoot这么简单的东西背后一定有故事,我们之后去进行一波源码分析!

Spring Boot核心配置

springboot加载配置文件

1.SpringBoot提供了2种配置文件类型:properties和yml/yaml
2.默认配置文件名称:application
3.在同一级目录下优先级为:properties>yml>yaml

YAML的基本语法

1.大小写敏感
2.使用缩进表示层级关系
3.缩进不允许使用tab,只允许空格
4.缩进的空格数不重要,只要相同层级的元素左对齐即可
5.'#'表示注释

配置文件

SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的

  • application.properties

    • 语法结构 :key=value
  • application.yml

    • 语法结构 :key:空格 value

**配置文件的作用 :**修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了;

比如我们可以在配置文件中修改Tomcat 默认启动的端口号!测试一下!

server.port=8081

yaml概述

YAML是 “YAML Ain’t a Markup Language” (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)

这种语言以数据为中心,而不是以标记语言为重点!

以前的配置文件,大多数都是使用xml来配置;比如一个简单的端口配置,我们来对比下yaml和xml

传统xml配置:

<server>    
	<port>8081<port>
</server>

yaml配置:

server:  
	prot: 8080
yaml基础语法

说明:语法要求严格!

1、空格不能省略

2、以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。

3、属性和值的大小写都是十分敏感的。

字面量:普通的值 [ 数字,布尔值,字符串 ]

字面量直接写在后面就可以 , 字符串默认不用加上双引号或者单引号;

k: v

注意:

  • “ ” 双引号,不会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;

    比如 :name: “kuang \n shen” 输出 :kuang 换行 shen

  • ‘’ 单引号,会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出

    比如 :name: ‘kuang \n shen’ 输出 :kuang \n shen

对象、Map(键值对)

#对象、Map格式
k:     
	v1:   
	v2:

在下一行来写对象的属性和值得关系,注意缩进;比如:

student:    
	name: fbb    
	age: 3

行内写法

student: {name: fbb,age: 3}

数组( List、set )

用 - 值表示数组中的一个元素,比如:

#数组
pets:
  - cat
  - dog
  - pig- cat - dog - pig

行内写法

pets: [cat,dog,pig]

修改SpringBoot的默认端口号

配置文件中添加,端口号的参数,就可以切换端口;

server: 
	port: 8082

注入配置文件

yaml文件更强大的地方在于,他可以给我们的实体类直接注入匹配值!

yaml注入配置文件

1、在springboot项目中的resources目录下新建一个文件 application.yml

2、编写一个实体类 Dog;

@Component  //注册bean到容器中
public class Dog {
    private String name;
    private Integer age;
    
    //有参无参构造、get、set方法、toString()方法  
}

3、思考,我们原来是如何给bean注入属性值的!@Value,给狗狗类测试一下:

@Component //注册bean
public class Dog {
    @Value("阿黄")
    private String name;
    @Value("18")
    private Integer age;
}

4、在SpringBoot的测试类下注入狗狗输出一下;

@SpringBootTest
class DemoApplicationTests {

    @Autowired //将狗狗自动注入进来
     private Dog dog;

    @Test
    public void contextLoads() {
        System.out.println(dog); //打印看下狗狗对象
    }
}

结果成功输出,@Value注入成功,这是我们原来的办法对吧。

1644327282231

5、我们在编写一个复杂一点的实体类:Person 类

@Component //注册bean到容器中
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
    
    //有参无参构造、get、set方法、toString()方法  
}

6、我们来使用yaml配置的方式进行注入,大家写的时候注意区别和优势,我们编写一个yaml配置!

person:
  name: fbb
  age: 3
  happy: false
  birth: 2000/01/01
  maps: {k1: v1,k2: v2}
  lists:
   - code
   - girl
   - music
  dog:
    name: 旺财
    age: 1

7、我们刚才已经把person这个对象的所有值都写好了,我们现在来注入到我们的类中!

/*
@ConfigurationProperties作用:
将配置文件中配置的每一个属性的值,映射到这个组件中;
告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
*/
@Component //注册bean
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
}

8、IDEA 提示,springboot配置注解处理器没有找到,让我们看文档,我们可以查看文档,找到一个依赖!

1644327477454

<!-- 导入配置文件处理器,配置文件进行绑定就会有提示,需要重启 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>

9、确认以上配置都OK之后,我们去测试类中测试一下:

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    Person person; //将person自动注入进来

    @Test
    public void contextLoads() {
        System.out.println(person); //打印person信息
    }
}

结果:所有值全部注入成功!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M2JuqDsD-1649526406162)(C:/Users/EDZ/Desktop/SpringBoot/笔记/images/1644325059420.png)]

yaml配置注入到实体类完全OK!

课堂测试:

1、将配置文件的key 值 和 属性的值设置为不一样,则结果输出为null,注入失败

2、在配置一个person2,然后将 @ConfigurationProperties(prefix = “person2”) 指向我们的person2;

加载指定的配置文件

**@PropertySource :**加载指定的配置文件;

@configurationProperties:默认从全局配置文件中获取值;

1、我们去在resources目录下新建一个person.properties文件

name=kuangshen

2、然后在我们的代码中指定加载person.properties文件

@PropertySource(value = "classpath:person.properties")
@Component //注册bean
public class Person {

    @Value("${name}")
    private String name;
    ......  
}

3、再次输出测试一下:指定配置文件绑定成功!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-of1Kg1Qk-1649526406163)(C:/Users/EDZ/Desktop/SpringBoot/笔记/images/1644325878331.png)]

配置文件占位符

配置文件还可以编写占位符生成随机数

person:
    name: qinjiang${random.uuid} # 随机uuid
    age: ${random.int}  # 随机int
    happy: false
    birth: 2000/01/01
    maps: {k1: v1,k2: v2}
    lists:
      - code
      - girl
      - music
    dog:
      name: ${person.hello:other}_旺财
      age: 1

回顾properties配置

我们上面采用的yaml方法都是最简单的方式,开发中最常用的;也是springboot所推荐的!那我们来唠唠其他的实现方式,道理都是相同的;写还是那样写;配置文件除了yml还有我们之前常用的properties , 我们没有讲,我们来唠唠!

【注意】properties配置文件在写中文的时候,会有乱码 , 我们需要去IDEA中设置编码格式为UTF-8;

settings–>FileEncodings 中配置;

1644385358499

测试步骤:

1、新建一个实体类User

@Component //注册bean
public class User {
    private String name;
    private int age;
    private String sex;
}

2、编辑配置文件 user.properties

user1.name=kuangshen
user1.age=18
user1.sex=男

3、我们在User类上使用@Value来进行注入!

@Component //注册bean
@PropertySource(value = "classpath:user.properties")
public class User {
    //直接使用@value
    @Value("${user.name}") //从配置文件中取值
    private String name;
    @Value("#{9*2}")  // #{SPEL} Spring表达式
    private int age;
    @Value("男")  // 字面量
    private String sex;
}

4、 Springboot测试

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    User user;

    @Test
    public void contextLoads() {
        System.out.println(user);
    }
}

结果正常输出:

1644385512053

对比小结

@Value这个使用起来并不友好!我们需要为每个属性单独注解赋值,比较麻烦;我们来看个功能对比图

1644385564694

1、@ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加

2、松散绑定:这个什么意思呢? 比如我的yml中写的last-name,这个和lastName是一样的, - 后面跟着的字母默认是大写的。这就是松散绑定。可以测试一下

3、JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性

4、复杂类型封装,yml中可以封装对象 , 使用value就不支持

结论:

配置yml和配置properties都可以获取到值 , 强烈推荐 yml;

如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下 @value;

如果说,我们专门编写了一个JavaBean来和配置文件进行一一映射,就直接@configurationProperties,不要犹豫!


多环境切换

profile是Spring对不同环境提供不同配置功能的支持,可以通过激活不同的环境版本,实现快速切换环境;

多配置文件

我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版本;

例如:

application-test.properties 代表测试环境配置

application-dev.properties 代表开发环境配置

但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件

我们需要通过一个配置来选择需要激活的环境:

#比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;
#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;
spring.profiles.active=dev

yaml的多文档块

server:
  port: 8081
#选择要激活那个环境块
spring:
  profiles:
    active: prod

---
server:
  port: 8083
spring:
  profiles: dev #配置环境的名称


---

server:
  port: 8084
spring:
  profiles: prod  #配置环境的名称

注意:如果yml和properties同时都配置了端口,并且没有激活其他环境 , 默认会使用properties配置文件的!

配置文件加载位置

外部加载配置文件的方式十分多,我们选择最常用的即可,在开发的资源文件中进行配置!

官方外部配置文件说明参考文档

1644391855836

springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:

优先级
1:项目路径下的config文件夹配置文件优先级
2:项目路径下配置文件优先级
3:资源路径下的config文件夹配置文件优先级
4:资源路径下配置文件

优先级由高到底,高优先级的配置会覆盖低优先级的配置;

SpringBoot会从这四个位置全部加载主配置文件;互补配置;

我们在最低级的配置文件中设置一个项目访问路径的配置来测试互补问题;

#配置项目的访问路径
server.servlet.context-path=/fbb

SpringBoot 热部署

在编写代码的时候,你会发现我们只是简单把打印信息改变了下,就需要重新部署,如果是这样的编码方式,那么我们估计一天下来之后就真的是打几个 Hello World 之后就下班了。那么如何解决热部署的问题呢?

1 在pom.xml中添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
    <scope>true</scope>
</dependency>
(1) devtools可以实现页面热部署(即页面修改后会立即生效,这个可以直接在application.properties文件中配置spring.thymeleaf.cache=false来实现),
实现类文件热部署(类文件修改后不会立即生效),实现对属性文件的热部署。
即devtools会监听classpath下的文件变动,并且会立即重启应用(发生在保存时机),注意:因为其采用的虚拟机机制,该项重启是很快的
(2)配置了true后在修改java文件后也就支持了热启动,不过这种方式是属于项目重启(速度比较快的项目重启),会清空session中的值,也就是如果有用户登陆的话,项目重启后需要重新登陆。

2 在application.yml中配置一下devtools

spring:
  devtools:
    restart:
      enabled: true  #设置开启热部署
      additional-paths: src/main/java #重启目录
      exclude: WEB-INF/**
  freemarker:
    cache: false    #页面不加载缓存,修改即时生效

3 IDEA中配置

当我们修改了类文件后,idea不会自动编译,得修改idea设置。
(1)File-Settings-Compiler-Build Project automatically
(2)ctrl + shift + alt + / ,选择Registry,勾上 Compiler autoMake allow when app running

1644494063908

1644494209632

4 测试

修改类–>保存:应用会重启
修改配置文件–>保存:应用会重启
修改页面–>保存:应用不会重启,但会重新加载,页面会刷新

Springboot集成JDBC

1644482503323

1644482517633

1644482553070

pom依赖

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

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

        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

application.yml

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver

测试

@SpringBootTest
class SpringbootJdbcApplicationTests {
    @Autowired
    DataSource dataSource;
    @Test
    void contextLoads() throws SQLException {
        //查看一下默认的数据源   class com.zaxxer.hikari.HikariDataSource
        System.out.println(dataSource.getClass());

        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        //关闭
        connection.close();
    }
}

操作数据库信息 CRUD

编写JDBCController

@RestController
public class JDBCController {
    @Autowired
    JdbcTemplate jdbcTemplate;

    //查询数据库的所有信息
    //没有实体类,数据库的数据   怎么获取? Map
    @GetMapping("/userList")
    public List<Map<String,Object>> mapList(){
        String sql = "select * from user";
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
        return maps;
    }
}

启动springboot项目

访问:http://localhost:8080/userList

1644484412091

新增

 //新增
    @GetMapping("/addUser")
    public String addUser(){
        String sql = "insert into user(id,name,pwd) values (5,'冯宝宝','888')";
        jdbcTemplate.update(sql);
        return "OK";
    }

修改

 @GetMapping("/updateUser/{id}")
    public String updateUser(@PathVariable("id") int id){
        String sql = "update user set name=?,pwd=? where id="+id;
        //封装
        Object[] objects = new Object[2];
        objects[0] = "冯宝宝一号";
        objects[1] = "zzz";
        jdbcTemplate.update(sql,objects);
        return "updateUser-OK";
    }

删除

@GetMapping("/deleteUser/{id}")
    public String deleteUser(@PathVariable("id") int id){
        String sql = "delete from user where id = ?";
        jdbcTemplate.update(sql,id);
        return "deleteUser-OK";
    }

SpringBoot集成JAP

  • JPA是The Java Persistence API标准,Java持久层API,是一种能让对象能够快速映射到关系型数据库的技术规范。
  • JPA只是一种规范,它需要第三方自行实现其功能,在众多框架中Hibernate是最为强大的一个。
  • ring Data JPA 是采用基于JPA规范的Hibernate框架基础下提供了Repository层的实现。**Spring Data Repository极大地简化了实现各种持久层的数据库访问而写的样板代码量,同时CrudRepository提供了丰富的CRUD功能去管理实体类。**SpringBoot框架为Spring Data JPA提供了整合,spring-boot-starter-data-jpa能够让你快速使用这门技术,它提供了以下依赖。
    • Hibernate:最流行的JPA实现之一。
    • Spring Data JPA:帮助你去实现JPA-based repositories。
    • Spring ORM:Spring Framework提供的核心ORM支持。

1644500173915

2、在yml文件中进行配置

spring:
  devtools:
    restart:
      enabled: false
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test
    hikari: # springboot 2.0 整合了hikari ,据说这是目前性能最好的java数据库连接池
      username: root
      password: root
  jpa:
    hibernate:
      ddl-auto: update  # 第一次建表create  后面用update,要不然每次重启都会新建表
    show-sql: true

3、创建一个entity

@Data
@Entity  // 该注解声明一个实体类,与数据库中的表对应
public class User {

    @Id   // 表明id
    @GeneratedValue   //  自动生成
    private Long id ;

    private String name;
}

4、创建DAO

@Component
public interface UserMapper extends JpaRepository<User,Long> {
    /*
     * 我们在这里直接继承 JpaRepository
     * 这里面已经有很多现场的方法了
     * 这也是JPA的一大优点
     *
     * */
}

在这里我直接截图,我们可以看看JpaRepository中的一些方法

1644500319352

我们可以直接使用这些方法,包括其父类的好多方法。是不是很方便啊

5、Service

public interface UserService {
    List<User> findAll();
}

Impl

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        // 这里我们就可以直接使用 findAll 方法
        return userMapper.findAll();
    }
}

6、Controller

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/list")
    public List<User> findAll(){
        return userService.findAll();
    }
}

7、进行测试

我们启动项目,可以看到日志打印

1644500458035

数据表会自动创建,此时我们查看数据库

1644500480335

确实已经自动创建了数据表。

我们给表里添加两条数据,然后通过浏览器访问findAll接口:

1644500511890

得到结果如下:

1644500541936

这样,我们就整合完成了。是不是 So Easy!!!


SpringBoot集成Mybatis

MyBatis是一款优秀的持久层框架,Spring Boot官方并没有提供MyBatis依赖,但是MyBatis团队自行适配Spring Boot,提供了mybatis-spring-boot-starter依赖启动器实现数据访问操作.

1 基础环境搭建

步骤:
	数据准备:创建数据库、数据表并插入一定的数据
	创建项目,引入相应的启动器:使用Spring Initializr的方式构建项目,选择MySQL和MyBatis依赖,编写实体类。
	编写配置文件:在配置文件中进行数据库连接配置以及进行第三方数据源的默认参数覆盖。

(1)创建数据库

CREATE DATABASE springbootdata;

(2) 创建数据表t_article

CREATE TABLE `t_article` (
  `id` int(20) NOT NULL AUTO_INCREMENT COMMENT '文章id',
  `title` varchar(200) DEFAULT NULL COMMENT '文章标题',
  `content` longtext COMMENT '文章内容',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

(3) 向数据表t_article插入相关数据

INSERT INTO `t_article` VALUES ('1', 'Spring Boot基础入门', '从入门到精通讲解...');
INSERT INTO `t_article` VALUES ('2', 'Spring Cloud基础入门', '从入门到精通讲解...');

(4) 创建数据表t_comment

  CREATE TABLE `t_comment` (
  `id` int(20) NOT NULL AUTO_INCREMENT COMMENT '评论id',
  `content` longtext COMMENT '评论内容',
  `author` varchar(200) DEFAULT NULL COMMENT '评论作者',
  `a_id` int(20) DEFAULT NULL COMMENT '关联的文章id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

(5) 向数据表t_****comment插入相关数据

INSERT INTO `t_comment` VALUES ('1', '很全、很详细', '狂奔的蜗牛', '1');
INSERT INTO `t_comment` VALUES ('2', '赞一个', 'tom', '1');
INSERT INTO `t_comment` VALUES ('3', '很详细', 'kitty', '1');
INSERT INTO `t_comment` VALUES ('4', '很好,非常详细', '张三', '1');
INSERT INTO `t_comment` VALUES ('5', '很不错', '张杨', '2');

(6) 创建项目,引入MySQL和MyBatis的依赖启动器

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

(7) 编写实体类Comment和Article

package com.ycy.entity;

import java.util.List;
public class Article {
    private Integer id;
    private String title;
    private String content;
    private List<Comment> commentList;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public List<Comment> getCommentList() {
        return commentList;
    }

    public void setCommentList(List<Comment> commentList) {
        this.commentList = commentList;
    }

    @Override
    public String toString() {
        return "Article{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", commentList=" + commentList +
                '}';
    }
}
package com.ycy.entity;

public class Comment {
    private Integer id;
    private String content;
    private String author;
    private Integer aId;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public Integer getaId() {
        return aId;
    }

    public void setaId(Integer aId) {
        this.aId = aId;
    }

    @Override
    public String toString() {
        return "Comment{" +
                "id=" + id +
                ", content='" + content + '\'' +
                ", author='" + author + '\'' +
                ", aId=" + aId +
                '}';
    }
}

(8) 编写配置文件

# 应用名称
spring.application.name=springboot1
# 应用服务 WEB 访问端口
server.port=8080
#下面这些内容是为了配置MyBatis映射
#指定Mybatis的Mapper文件
mybatis.mapper-locations=classpath:mappers/*xml
#指定Mybatis的实体目录
mybatis.type-aliases-package=com.ycy.mybatis.entity
# 开启驼峰命名匹配
mybatis.configuration.map-underscore-to-camel-case=true
# 数据库驱动:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库连接地址
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?serverTimezone=UTC
# 数据库用户名&密码:
spring.datasource.username=root
spring.datasource.password=root123
#配置第三方数据源
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.initial-size=10
spring.datasource.druid.max-active=20
spring.datasource.druid.min-idle=3

(9)在pom.xml中添加druid依赖启动器:

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.8</version>
        </dependency>

2 使用注解方式整合mybatis

(1)创建Mapper接口

package com.ycy.mapper;

import com.ycy.entity.Comment;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface CommentMapper {
    @Select("select * from t_comment")
    List<Comment> findAll();
}

注意:

	每个Mapper接口文件上面都需要添加@Mapper注解
	如果Mapper接口文件太多,可以直接在Spring Boot项目启动类上添加@MapperScan("")注解,这样不需要在接口文件中添加@Mapper注解

1644489665689

(2)测试

@SpringBootTest
public class MyTest1 {
    @Autowired
    private CommentMapper commentMapper;
    @Test
    public void test1(){
        List<Comment> comments = commentMapper.findAll();
        for (Comment comment : comments) {
            System.out.println(comment);
        }
    }
}

结果:

1644489714422

3 使用xml方式整合mybatis

(1)创建Mapper接口

package com.ycy.mapper;

import com.ycy.entity.Comment;
import java.util.List;
public interface CommentMapper2 {
    List<Comment> findAll();
}

(2)创建Mapper接口对应的xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ycy.mapper.CommentMapper2">
    <select id="findAll" resultType="Comment">
        select * from t_comment
    </select>
</mapper>

注意:

	在resources目录下创mappers文件夹,并将xml文件保存在mappers文件夹

image-20211118173049504

	如果使用xml方式整合mybatis,需要在全局配置文件中指定xml文件位置

image-20211118171258558

(3)测试

    @Autowired
    private CommentMapper2 commentMapper2;
    @Test
    public void test2(){
        List<Comment> comments = commentMapper2.findAll();
        for (Comment comment : comments) {
            System.out.println(comment);
        }
    }

结果:image-20211118173342762


SpringBoot集成Redis

实现步骤

1.搭建SpringBoot工程

2.引入redis起步依赖

3.配置redis相关属性

4.注入RedisTemplate模板

5.编写测试方法,测试

1.搭建SpringBoot工程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MMbzsz5D-1649526406168)(https://gitee.com/shuaiqiguoguo/cloudimage/raw/master/img/202204100145694.png)]

1644495667944

1644495704407

2.导入redis依赖

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

3.配置application.yml文件

spring:
  redis:
    host: 127.0.0.1  #redis主机ip
    port: 6379       #端口号

4.测试

@SpringBootTest
class SpringbootRedisApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void testSet() {
        //存入数据
        redisTemplate.boundValueOps("name").set("fbb");
    }
    @Test
    void testGet() {
        //获取数据
        Object name = redisTemplate.boundValueOps("name").get();
        System.out.println(name);
    }
    
}

User对象

@Component
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
    private int id;
    private String name;
}

依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
 @Test
    public void test3() throws JsonProcessingException {
        // 真实开发都是使用 json 来传递对象
        User user = new User(123,"冯宝宝");
        //String jsonUser = new ObjectMapper().writeValueAsString(user);
        redisTemplate.opsForValue().set("user", user);
        System.out.println(redisTemplate.opsForValue().get("user"));
    }
这种写法会报 org.springframework.data.redis.serializer.SerializationException: Cannot serialize; 错误,所有对象都需要序列化.

使用json传递对象 set("user", user);
User 类实现 Serializable 接口

RedisTemplate的使用

// opsForValue() 操作字符串
// opsForList() 操作List数据类型 
// opsForSet() 操作Set数据类型
// opsForHash() 操作Hash数据类型
// opsForZSet() 操作ZSet数据类型
// opsForGeo()
// opsForHyperLogLog()  

redis配置类

@Configuration   //redis配置类
public class RedisConfig {

    //固定的模板   直接拿去用即可
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        //json序列化配置
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        //String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();

        return template;
    }
}

编写RedisUtils工具类

@Component
public class RedisUtil {
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据 key 获取过期时间
     *
     * @param key 键(不能为 Null)
     * @return 时间(秒) 返回0代表永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断 key 是否存在
     *
     * @param key 键(不能为 Null)
     * @return true 存在 false 不存在
     */
    public boolean hashKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    public void del(String... key) {
        if (key != null && key.length > 0) {
            redisTemplate.delete(key[0]);
        } else {
            redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
        }
    }

    //==================================String====================================

    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true 成功 false 失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time > 0 若 time <= 0 将设置无限期
     * @return true 成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 递增
     *
     * @param key   键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 递减
     *
     * @param key   键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().decrement(key, delta);
    }

    // ===============================list=================================

    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取list缓存的长度
     *
     * @param key 键
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */

    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除N个值为value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */

    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }

    }

    // ============================set=============================

    /**
     * 根据key获取Set中的所有值
     *
     * @param key 键
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 将set数据放入缓存
     *
     * @param key    键
     * @param time   时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 获取set缓存的长度
     *
     * @param key 键
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */

    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    // ================================Map=================================

    /**
     * HashGet
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 获取hashKey对应的所有键值
     *
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashSet
     *
     * @param key 键
     * @param map 对应多个键值
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * HashSet 并设置时间
     *
     * @param key  键
     * @param map  对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几(大于0)
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少记(小于0)
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    // ===============================HyperLogLog=================================

    public long pfadd(String key, String value) {
        return redisTemplate.opsForHyperLogLog().add(key, value);
    }

    public long pfcount(String key) {
        return redisTemplate.opsForHyperLogLog().size(key);
    }

    public void pfremove(String key) {
        redisTemplate.opsForHyperLogLog().delete(key);
    }

    public void pfmerge(String key1, String key2) {
        redisTemplate.opsForHyperLogLog().union(key1, key2);
    }
}

测试

 @Autowired
 private RedisUtil redisUtil;

 
 @Test
    public void test4(){
        redisUtil.set("name","fbb");
        System.out.println(redisUtil.get("name"));
    }

使用分页插件

SSM项目中使用PageHelper分页插件

(1)在pom.xml中添加依赖

    <!-- 添加pagehelper依赖-->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.2.0</version>
    </dependency>

(2)在SqlSessionFactory 工厂中传入 PageHelper 的的插件

	<!-- 配置MyBatis工厂 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:sqlMapConfig.xml"/>
        <!-- 传入pagehelper插件 -->
        <property name="plugins">
            <array>
                <!-- 传入插件对象 -->
                <bean class="com.github.pagehelper.PageInterceptor">
                    <property name="properties">
                        <props>
                            <prop key="helperDialect">mysql</prop>
                            <prop key="reasonable">true</prop>
                        </props>
                    </property>
                </bean>
            </array>
        </property>
    </bean>

或者在MyBatis配置文件中添加如下内容:

    <!-- 引入 pageHelper插件 -->
    <!--注意这里要写成PageInterceptor, 5.0之前的版本都是写PageHelper, 5.0之后要换成PageInterceptor -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!-- reasonable:分页合理化参数,默认值为false。 当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。
默认false 时,直接根据参数进行查询。 -->
            <property name="helperDialect" value="mysql"/>
            <property name="reasonable" value="true" />
        </plugin>
    </plugins>

注意:

	选在其中一种方式添加pagehelper插件即可

(3)Mapper接口提供查询所有数据方法

public interface FileMapper {
    //查询所有数据
    @Select("select * from tb_file")
    List<File> findAll();
}

(4)在Service层提供分页查询方法

 public interface FileService {   
	//分页查询
    PageInfo<File> findAll(int pageNum,int size);
 }
    @Override
    public PageInfo<File> findAll(int pageNum, int size) {
        PageHelper.startPage(pageNum,size);
        List<File> all = fileMapper.findAll();
        PageInfo<File> pageInfo = new PageInfo(all);
        return pageInfo;
    }

Spring Boot整合MyBatis使用分页插件

(1)添加依赖启动器

		<dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.0</version>
        </dependency>

(2)全局配置文件中设置分页插件信息

# 配置pageHelper插件(官方推荐配置)
#指定方言,使用mysql数据库
pagehelper.helper-dialect=mysql 
#参数合理化
pagehelper.reasonable=true 
#支持通过 Mapper 接口参数来传递分页参数
pagehelper.support-methods-arguments=true
#为了支持startPage(Object params)方法,增加了该参数来配置参数映射
pagehelper.params=countSql
参数说明:
1)helperDialect:
	分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:    
   oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby 
特别注意:
	使用 SqlServer2012 数据库时,需要手动指定为sqlserver2012,否则会使用 SqlServer2005 的方式进行分页。
    你也可以实现AbstractHelperDialect,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。
2)offsetAsPageNum:
	默认值为false,该参数对使用RowBounds作为分页参数时有效。 
	当该参数设置为true时,会将RowBounds中的offset参数当成pageNum使用,可以用页码和页面大小两个参数进行分页。
3)rowBoundsWithCount:
	默认值为false,该参数对使用RowBounds作为分页参数时有效。 
	当该参数设置为true时,使用RowBounds分页会进行 count 查询。
4)pageSizeZero:
	默认值为false,当该参数设置为true时,如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是Page类型)。
5)reasonable:
	分页合理化参数,默认值为false。
	当该参数设置为true时,pageNum<=0时会查询第一页,pageNum>pages(超过总数时),会查询最后一页。默认false时,直接根据参数进行查询。
6)params:
	为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值, 默认值为:pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero。
7)、supportMethodsArguments:
	支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面params配置的字段中取值,查找到合适的值时就会自动分页。
    使用方法可以参考测试代码中的com.github.pagehelper.test.basic包下的ArgumentsMapTest和ArgumentsObjTest。
8)autoRuntimeDialect:
	默认值为false。设置为true时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择sqlserver2012,只能使用sqlserver)。
9)、closeConn:
	默认值为true。当使用运行时动态数据源或没有设置helperDialect属性自动获取数据库类型时,会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认true关闭,设置为false后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定。

(3)在Mapper接口中添加查询方法

public interface CommentMapper {
    @Select("select * from t_comment")
    List<Comment> findAll();
}

(4)在Service中添加分页查询方法

public interface CommentService {
    // 分页查询方法
    PageInfo<Comment> findAll(int pageNum, int pageSize);
}
package com.ycy.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ycy.entity.Comment;
import com.ycy.mapper.CommentMapper;
import com.ycy.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class CommentServiceImpl implements CommentService {
    @Autowired
    private CommentMapper commentMapper;
    @Override
    public PageInfo<Comment> findAll(int pageNum, int pageSize) {
        //使用PageHelper指定当前页和每页条数
        PageHelper.startPage(pageNum,pageSize);
        //查询数据
        List<Comment> all = commentMapper.findAll();
        //把查询结果封装到PageInfo中
        PageInfo<Comment> pageInfo = new PageInfo(all);
        return pageInfo;
    }
}

(5)测试

   @Autowired
    private CommentService commentService;
    @Test
    public void test1(){
        PageInfo<Comment> all = commentService.findAll(2, 3);//第二页,每页3条数据
        List<Comment> comments = all.getList();
        for (Comment comment : comments) {
            System.out.println(comment);
        }
    }

结果:image-20211120151144583

lombok插件

1.安装lombok插件

首先在IDEA里面安装使用lombok编写简略风格代码的插件,打开IDEA的Settings面板,并选择Plugins选项,然后在输入框输入”lombok”,得到搜索结果,点击安装,然后安装提示重启IDEA,安装成功(已经安装过的提示Restart IDE)

20200908150228966

2.添加lombok的jar

​ 官网下载lombok的jar包引用到项目里,或在自己的项目里添加lombok的maven的pom.xml依赖:

	<dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.12</version>
      <scope>provided</scope>
    </dependency>

3 附常用的lombok注解:

@Data:注解在类上,将类提供的所有属性都添加get、set方法,并添加、equals、canEquals、hashCode、toString方法
@Setter:注解在类上,为所有属性添加set方法、注解在属性上为该属性提供set方法
@Getter:注解在类上,为所有的属性添加get方法、注解在属性上为该属性提供get方法
@NotNull:在参数中使用时,如果调用时传了null值,就会抛出空指针异常
@Synchronized 用于方法,可以锁定指定的对象,如果不指定,则默认创建一个对象锁定
@Log作用于类,创建一个log属性
@Builder:使用builder模式创建对象
@NoArgsConstructor:创建一个无参构造函数
@AllArgsConstructor:创建一个全参构造函数
@ToStirng:创建一个toString方法
@Accessors(chain = true)使用链式设置属性,set方法返回的是this对象。
@RequiredArgsConstructor:创建对象
@UtilityClass:工具类
@ExtensionMethod:设置父类
@FieldDefaults:设置属性的使用范围,如private、public等,也可以设置属性是否被final修饰。
@Cleanup: 关闭流、连接点。
@EqualsAndHashCode:重写equals和hashcode方法。
@toString:创建toString方法。

4 示例

@Entity(name="t_comment")
@Data
public class Comment2 {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "content")
    private String content;
    private String author;
}

测试:

 	@Autowired
    private CommentRepository commentRepository;
    @Test
    public void test2(){
        Optional<Comment2> optional = commentRepository.findById(1);
        Comment2 comment2 = optional.get();
        System.out.println(comment2);
    }

结果:image-20211119174952444

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值