spring boot 入门

第一次发CSDN博客,这里是小白自己整理的尚硅谷的SpringBoot视频第一部分的笔记,视频里面使用的是1.5版本的SpringBoot,我是用的是2.0.5版本的,其中有许多不一样,可能会有许多错误,请大家指正。其中docker的使用,我使用的是windows版本的docker,linux版本的与视频一致。全文手打,勿喷哈哈。

文章目录

  • 一、spring boot 入门
    • 1、Spring boot 简介
    • 2、微服务
    • 3、环境准备
      • 1、maven设置
      • 2、IDEA设置
    • 4、Spring Boot HelloWorld
      • 1、创建一个maven工程;(jar)
      • 2、导入spring boot 相关的依赖
      • 3、编写一个主程序,启动Spring Boot 应用
      • 4、编写相关的Controller、Service
      • 5、运行主程序测试
      • 6、简化部署
    • 5、Hello World探究
      • 1、POM文件
        • 1、父项目
        • 2、启动器
      • 2、主程序类,主入口类
    • 6、使用 Spring Initializer快速创建Spring Boot 项目
  • 二、配置文件
    • 1、配置文件
    • 2、YAML语法:
      • 1、基本语法
      • 2、值的写法
        • 字面量:普通的值(数字、字符串、布尔):
        • 对象、Map(属性和值)(键值对):
        • 数组(List、Set):
    • 3、配置文件值注入
      • 1、properties配置文件在idea中默认utf-8可能会乱码
      • 2、@Value获取值和@ConfigurationProperties获取值的比较
      • 3、配置文件注入数据校验(JSR303)
      • 4、@PropertySource(加载配置文件properties且只能加载properties文件) & @ImportResource(加载spring的xml配置文件)
    • 4、配置文件占位符
      • 1、随机数
      • 2、占位符获取之前配置的值,如果没有则可以用 : 指定默认值
    • 5、Profile
      • 1、多Profile文件
      • 2、yml支持多文档块方式
      • 3、激活指定profile
    • 6、配置文件加载位置
    • 7、外部配置加载顺序
    • 8、自动配置原理
      • 1、自动配置原理
      • 2、细节
        • 1、@Conditional派生注解(Spring注解版原生的@Conditional作用)
  • 三、日志
    • 1、日志框架
    • 2、SLF4j的使用
      • 1、如何在系统中使用SLF4j https://www.slf4j.org
      • 2、遗留问题
    • 3、SpringBoot日志关系
    • 4、日志使用
        • 1、默认配置
        • 2、指定配置
    • 5、切换日志框架
  • 四、Web开发
    • 1、简介
    • 2、SpringBoot对静态资源的映射规则
    • 3、模板引擎
      • 1、引入thymeleaf
      • 2、Thymeleaf使用&语法
      • 3、语法规则
    • 4、SpringMVC自动配置
      • 1、 27.1.1 Spring MVC Auto-configuration
      • 2、扩展SpringMVC
      • 3、全面接管SpringMVC;
    • 5、如何修改SpringBoot的默认配置
    • 6、RestfulCRUE
      • 1)、默认访问首页
      • 2)、国际化
      • 3)、登录
      • 4)、拦截器进行登录检查
      • 5)、CRUD-员工列表
  • 五、SpringBoot与Docker
    • 1、简介
    • 2、核心概念
    • 3、安装Docker
      • 1)、安装linux虚拟机
      • 2)、在linux虚拟机上安装Docker
      • 3)、在windows上安装docker
    • 4、docker的常用操作
        • 1)、docker镜像操作
        • 2)、docker容器操作
        • 3)、安装mysql的实例
        • 4)、官方的镜像加速
  • 六、SpringBoot与数据访问
    • 1、JDBC
    • 2、整合Druid数据源
    • 3、整合Mybatis
    • 4、注解版
      • **小问题:**
        • 1、自增长ID,通过给方法上添加@Options(useGeneratedKeys = true, keyProperty = "id")实现,此方法不建议使用于配置版mybatis
        • 2、关于驼峰命名法
        • 3、关于配置类的@Mapper注解
    • 5、配置版mybatis
    • 6、整合JPA
      • 1、什么是JPA?
      • 2、整合SpringData JPA
  • 七、启动配置原理
    • 1、创建SpringApplication对象,new SpringApplication(primarySources)
    • 2、运行run方法
    • 3、事件监听机制
  • 八、SpringBoot自定义starters(场景启动器)

一、spring boot 入门

1、Spring boot 简介

简化spring应用开发的一个框架;

整个Spring技术栈的一个大整合;

J2EE开发的一站式解决方案;

2、微服务

2014,Martin Fowler

微服务:架构风格

一个应用应该是一组小型服务;可以通过HTTP的方式进行沟通;

每一个功能元素最终都是一个可独立替换和独立升级的软件单元;

[详细参照微服务文档][https://martinfowler.com/articles/microservices.html]

http://www.gulixueyuan.com/谷粒学院

3、环境准备

环境约束

-jdk1.8:Spring Boot 1.7及以上;java version “1.8.0_112”

-maven3.x:maven 3.3以上版本:Apache Maven 3.3.9

-IntelliJIDEA2017:IntelliJ IDEA 2017.2.2x64、STS

-Spring Boot 1.5.9.RELEASE:1.5.9;(本文作者使用2.0.6版本SpringBoot)

统一环境;

1、maven设置

给maven 的settings.xml配置文件中的profiles标签添加

<profile>
		<id>jdk-1.8</id>
		<activation>
			<activeByDefault>true</activeByDefault>
			<jdk>1.8</jdk>
		</activation>
        <properties>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
            <maven.cpmplier.compilerVersion>1.8</maven.cpmplier.compilerVersion>
        </properties>
	</profile>

2、IDEA设置

4、Spring Boot HelloWorld

一个功能

浏览器发送hello请求,服务器接受请求并处理,响应hello world字符串;

1、创建一个maven工程;(jar)

2、导入spring boot 相关的依赖

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.2.RELEASE</version>
    </parent>

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

3、编写一个主程序,启动Spring Boot 应用

/**
 * @ClassName HelloWorldMainApplication
 * @Author Peach
 * @SpringBootApplication 来标注这是一个springboot应用
 * @Date 2018/09/27 14:52
 * @Version 1.0
 **/
@SpringBootApplication
public class HelloWorldMainApplication {
    public static void main(String[] args) {
        //spring应用启动
        SpringApplication.run(HelloWorldMainApplication.class,args);
    }
}

4、编写相关的Controller、Service

/**
 * @ClassName HelloController
 * @Author Peach
 * @Date 2018/09/27 14:55
 * @Version 1.0
 **/
@Controller
public class HelloController {

    @ResponseBody
    @RequestMapping("hello")
    public String hello(){
        return "Hello world";
    }
}

5、运行主程序测试

6、简化部署

    <!--这个插件可以将项目打包成一个jar包 通过java -jar xxxxx.jar的方式来运行-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

将这个应用打成jar包,直接使用java -jar的命令运行执行;且这个jar包自带tomcat环境,不需要服务器打在tomcat

打包的方法:点击右边maven projects —选择你的项目—Lifecycle—双击package,打包完成后目标文件在你的target目录下

spring boot 入门_第1张图片

spring boot 入门_第2张图片

5、Hello World探究

1、POM文件

1、父项目

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.2.RELEASE</version>
    </parent>
    
    他的父项目是
    
    <parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-dependencies</artifactId>
		<version>1.4.2.RELEASE</version>
		<relativePath>../../spring-boot-dependencies</relativePath>
	</parent>
	他来真正管理Spring boot应用里面所有的依赖版本;

Spring Boot 的版本仲裁中心;

以后我们导入依赖默认是不许需要写版本的;(没有在dependencies里面管理的依赖自然需要声明版本号)

2、启动器

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

spring-boot-starter - web

​ spring-boot-starter:spring-boot场景启动器;帮我们导入了web模块正常运行所以依赖的组件

Spring Boot将所有的功能场景都抽取出来,做成一个个的starters(启动器),我们需要的时候只需要在项目中引用这些starter相关场景中的所有以来都会导入进来。要用什么功能就倒入什么功能的场景启动器

2、主程序类,主入口类

/**
 * @ClassName HelloWorldMainApplication
 * @Author Peach
 * @SpringBootApplication 来标注这是一个springboot应用
 * @Date 2018/09/27 14:52
 * @Version 1.0
 **/
@SpringBootApplication
public class HelloWorldMainApplication {
    public static void main(String[] args) {
        //spring应用启动
        SpringApplication.run(HelloWorldMainApplication.class,args);
    }
}

@SpringBootApplication :Spring Boot应用在某个类上,说明这个类是Spring Boot的主配置类,Spring Boot就应该运行这个类的main方法来启动Spring Boot应用;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public @interface SpringBootApplication {

@SpringBootConfiguration:Spring boot的配置类;

​ 标注在某个类上,表示这是一个spring boot的配置类;

​ @Configuration:配置类上来标注这个注解;

​ 配置类—配置文件;配置类也是容器中的一个组件;@Component

@EnableAutoConfiguration :开启自动配置功能

​ 以前需要配置的东西,Spring Boot帮我们配置,@EnableAutoConfiguration :告诉spring boot开启自动配置功能;这样自动配置才能够生效;

@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

​ @AutoConfigurationPackage:自动配置包

​ @Import(AutoConfigurationPackages.Registrar.class);

​ 属于spring 的底层注解,@Import的作用是给spring容器中导入一个组件,导入的组件由AutoConfigurationPackages.Registrar.class决定,

他的作用是将主配置类(@SpringBootApplication标注的这个类)的所在包及下面所有的子包里面的所有组件扫描到spring容器;

​ @Import(EnableAutoConfigurationImportSelector.class)

​ 给容器中导入组件?

​ EnableAutoConfigurationImportSelector : 导入哪些组件的选择器;

​ 将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中;

​ 会给容器中倒入非常多的自动配置类(xxxAutoConfiguration);就是个容器中导入这个场景中需要的所有组件,并配置好这些组件;
spring boot 入门_第3张图片

有了自动配置类,免去了我们手动编写配置注入功能组件等的工作;

SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader)

==Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效了,帮我们进行自动配置工作;==以前的我们需要自己指定的东西,自动配置类都帮我们做了;这些文件都在autoconfigure包中的spring.factories文件中

spring boot 入门_第4张图片

J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-1.4.2.RELEASE.jar

想要了解这些注解的底层原理都可以去Spring注解版(谷粒学院)

6、使用 Spring Initializer快速创建Spring Boot 项目

IDE都支持使用Spring的项目创建想到快速创建一个Spring Boot项目

选择我们需要的模块;想到会联网创建Spring Boot项目;

默认生成的Spring Boot项目;

  • 主程序已经生成好了,我们只需要编写自己的业务逻辑
  • resources文佳家中的目录结构
    • static:保存所有的静态资源;JS CSS images;
    • templates :保存所有的模板页面;(Spring Boot默认jar包使用嵌入式的Tomcat,默认不支持JSP页面);可以使用模板引擎(freemarker、thymeleaf);
    • application.properties:spring boot应用的配置文件;可以修改一些默认设置

二、配置文件

1、配置文件

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

  • application.properties

  • application.yml

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

YAML(YAML Ain’t Markup Language)

​ YAML A Markup Language:是一个标记语言

​ YAML isn’t Markup Language :不是一个标记语言

标记语言:

​ 以前的配置文件:大多都是用的是 xxxx.xml文件;

​ YAML:以数据为中心,比json、xml更适合作为配置文件;

​ YAML:配置实例

server:
  port: 8081

​ XML:

<server>
    <port>8081port>
server>

2、YAML语法:

1、基本语法

k:(空格)v:表示一对键值对(空格必须有);

空格的缩进来控制层级关系;主要是左对齐的一列数据,都是同一层级的

server:
	port: 8081
	path: /hello

属性和值也是大小写敏感的

2、值的写法

字面量:普通的值(数字、字符串、布尔):

​ k: v:字面直接写

​ 字符串默认不用加上单引号或者双引号

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

​ name:“zhangsan \n lisi” 输出:zhangsan 换行 lisi

​ ‘ ’:单引号 会转义特殊字符,特殊字符最终只是一个普通的字符串数据

​ name:‘zhangsan \n lisi’ 输出:zhangsan \n lisi

对象、Map(属性和值)(键值对):

​ k: v : 在下一行来写对象和属性的值得关系;注意缩进

​ 对象还是k: v的方式

friends:
	lastName: zhangsan
	age: 20

行内写法:

friends:{lastName: zhangsan,age: 18}

数组(List、Set):

用- 值表示数组中的一个元素

pets: 
 - cat
 - dog 
 - pig

行内写法

pets: [cat,dog,pig]

3、配置文件值注入

1、properties配置文件在idea中默认utf-8可能会乱码

打开file—settings—File Encodings配置如下

spring boot 入门_第5张图片
配置文件

person:
    lastName: zhangsan
    age: 18
    isBoss: true
    birth: 2017/12/12
    maps: {k1: v1,k2: 12}
    lists:
      - lisi
      - zhaoliu
    dog:
      name:  wangwang
      age: 2

对应的javaBean

/*
* @ConfigurationProperties 告诉Spring boot这个文件的所用属性和配置文件中的相关的配置进行绑定
* 将配置文件中的每一个属性的值映射到我们的组件当中
* (prefix = "person") 配置文件中的哪个属性进行一一映射
*
* 只有这个组件是容器中的组件才能使用容器提供的@ConfigurationProperties功能,所以需要加上@Component注解
* */

@Component
@ConfigurationProperties(prefix = "person")
public class Person {
    private String lastName;
    private Integer age;
    private String isBoss;
    private Date birth;

    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;

我们可以在Maven中导入配置文件处理器,以后编写配置文件就有==提示==了

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-configuration-processorartifactId>
            <optional>trueoptional>
        dependency>

2、@Value获取值和@ConfigurationProperties获取值的比较

@Component
@ConfigurationProperties(prefix = “person”)

导入配置文件使用这个@ConfigurationProperties(prefix = “person”)就行了,但是一定要将这个bean注入到容器中使用@Component

@ConfigurationProperties @Value
功能 批量注意配置文件中的属性 一个个指定
松散绑定(松散语法) 支持(lastName可以写成last-name) 不支持
SpEL 不支持 支持(#{12*2})
JSR303数据校验 支持 不支持
复杂类型封装(Map、List) 支持 不支持

@Value格式 : @Value("${属性全名}")

JSR303数据校验:(在bean上绑定@Validated表示这个bean需要校验,在属性上加上类似@Email的注解就可以将其校验,不符合email格式则会抛出异常)

SpringBoot主配置文件yml还是properties他们都能获取到值;

如果说我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,我们就适用@Value

如果说,我们专门编写了一个javaBean来和配置文件进行映射,

​ 我们就直接使用 @ConfigurationProperties,注意:@ConfigurationProperties注解是从全局配置文件(application.yml 或者 application.properties)中获取数据

3、配置文件注入数据校验(JSR303)

@Validated   #此处添加注解告诉SpringBoot这是一个需要数据校验的类
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
    @Email  #标注下方第一个属性是不是以一个Email的格式传入参数,如果不是则报错
    private String lastName;
    private Integer age;
    private Boolean isBoss;
    private Date birth;

    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;

4、@PropertySource(加载配置文件properties且只能加载properties文件) & @ImportResource(加载spring的xml配置文件)

@PropertySource :加载制定的配置文件(除了主配置文件之外的配置文件)

/*
 * @ConfigurationProperties 告诉Spring boot这个文件的所用属性和配置文件中的相关的配置进行绑定
 * 将配置文件中的每一个属性的值映射到我们的组件当中
 * (prefix = "person") 配置文件中的哪一个属性进行一一映射 是person开头的配置
 * @ConfigurationProperties(prefix = "person") 只能加载全局配置文件中的配置application.yml 或者 application.properties
 * 只有这个组件是容器中的组件才能使用容器提供的@ConfigurationProperties功能,所以需要加上注解
 @component
 * */
@Component
@PropertySource(value = {"classpath:person.properties"})
@ConfigurationProperties(prefix = "person")
public class Person {

    private String lastName;
    private Integer age;
    private Boolean isBoss;
    private Date birth;

    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;

注意:@PropertySource(value = {“classpath:person.properties”}) 注解需要和 @ConfigurationProperties(prefix = “person”) 注解一起使用,才能够取到参数,并且@PropertySource不支持加载yml文件,[详情见官方文档][https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-yaml-shortcomings]
在这里插入图片描述

@ImportResource:**导入Spring的 配置文件,让配置文件里面的内容生效;

Spring Boot 没有Spring 的配置文件(beans.xml),我们自己编写的配置文件也不能自动识别;

想让Spring的配置文件生效,加载进来;@ImportResource标在一个配置类(@Configuration配置的类 但是一般是主配置类)上。

@ImportResource(value = {"classpath:beans.xml"})
导入Spring的配置文件(标注bean的配置文件)让其生效  而不是SpringBoot的配置文件

@ImportResource语法格式为:

  • @ImportResource({“classpath:beans.xml”})
  • @ImportResource(value = {“classpath:beans.xml”})
  • @ImportResource(locations = {“classpath:beans.xml”})

不推荐编写Spring配置文件


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="helloService" class="com.example.springboot.service.HelloService">bean>
beans>

SpringBoot推荐的给容器中的添加组件的方式

1、配置类也就等于Spring的xml配置文件

2、使用@Bean给容器中添加组件

@Configuration
public class MyAppConfig {

    @Bean
    public HelloService helloService02(){
        System.out.println("配置类添加组件了");
        return new HelloService();
    }
}

@Bean 是将注解的该方法的返回值作为配置文件中的class,该方法的方法名作为id注入到ioc容器中,我们可以通过在测试类中自动注入ApplicationContext 用其中的containsBean(“bean的id”) 方法来判断一个一个bean是否被注入了。

4、配置文件占位符

1、随机数

random.value  {random.int}  ${random.long}

random.int(10) {random.int[1024,65536]} {random.uuid}

2、占位符获取之前配置的值,如果没有则可以用 : 指定默认值

${person.last-name:hello} :语法表示获取该文件中person.last-name的值,如果没有这个值,就用 : 后面的hello对其赋值

5、Profile

1、多Profile文件

我们在主配置文件编写的时候;文件名可以使applocation-{profile}.properties/yml

默认使用application.properties的配置

2、yml支持多文档块方式


server:
  port: 8081
spring:
  profiles:
    active: xxxx
#--- 表示文档块的分隔
---
server:
  port: 8082
spring:
  profiles: test
---
server:
  port: 8083
spring:
  profiles: hhh
---
server:
  port: 8084
spring:
  profiles: xxxx #表示属于哪个环境

3、激活指定profile

​ 1、在application.properties配置文件中指定激活某个环境 spring.profiles.active=test

​ 2、命令行方式:

​ --spring.profiles.active=dev

​ 操作步骤如下:

spring boot 入门_第6张图片

spring boot 入门_第7张图片

3、cmd运行时切换,可以在项目打包成jar包之后使用java -jar 的方式运行时写入 --spring.profiles.active=dev

spring boot 入门_第8张图片

4、虚拟机参数 -Dspring.profiles.active=test

spring boot 入门_第9张图片

6、配置文件加载位置

SpringBoot启动会扫描以下未知的application.properties或者application.yml文件作为SpringBoot默认配置文件

-file:./config/ 表示当前项目的根目录下面的config文件夹中的文件

-file:./ 表示当前文件的根目录

-classpath:/config/ 表示当前类路径(WEB-INF文件夹下的classes目录 )的config文件夹

-classpath:/ 表示当前类路径的根目录

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

SpringBoot会从这四个位置全部加载配置文件,形成==互补配置==

我们也可以通过spring.config.location来改变默认的配置

在我们通过java -jar 方式运行一个项目的时候在其后方加入–spring.config.location=配置文件路径的方式改变默认配置,当然这个方式配置的优先级是最高的

java -jar spring-boot-helloworld-quick-0.0.1-SNAPSHOT.jar --spring.config.location=C:\Users\Administrator\Desktop\application.properties

7、外部配置加载顺序

SpringBoot也可以从以下位置加载配置;优先级从高到低;高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置

1.命令行参数,通过java -jar 方式执行的时候在后端加上 --server.port=xxxx

​ java -jar spring-boot-helloworld-quick-0.0.1-SNAPSHOT.jar --server.port=8088 --server.context-path=/abc

多个配置用空格分开;--配置项=值

2.来自java:comp/env的JNDI属性

3.Java系统属性系统属性(属性(System.getPropertiesties())

4.操作系统环境变量

5.RandomValuePropertySource配置的random.*属性值

由jar包外向jar包内进行寻找

优先加载带profile的

6.jar包外部的application-{profile}.properties或application.yml带(spring.profile)配置文件

包外部,和打成的jar包放在同一目录下

7.Jar包内部的application-{profile}.properties或application.yml带(spring.profile)配置文件

再来加载不带profile的

8.jar包外部的application.properties或application.yml(不带spring.profile)配置文件

包外部,和打成的jar包放在同一目录下

9.jar包内部的application.properties或application.yml(不带spring.profile)配置文件

10.@Configuration注解类上的@PropertySource

11.通过SpringApplication.setDefaultProperties指定的默认属性

所有支持的配置来源;

[参考官方文档][https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#boot-features-external-config]

8、自动配置原理

配置文件到底能写什么?怎么写?自动配置的原理?

[配置文件能配置的属性参照][https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#common-application-properties]

1、自动配置原理

1)、SpringBoot启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration

2)、@EnableAutoConfiguration的作用:

  • 利用EnableAutoConfigurationImportSelector(自动装配选择器)给容器中导入一些组件

  • 可以查看选择器的selectImports()方法里的内容;

  • List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);获取候选的配置

    • SpringFactoriesLoader.loadFactoryNames()
      扫描得到资源 扫描所有jar包路径下  META-INF/spring.factories 文件
      将所有扫描到的文件的内容包装成一个properties对象
      从properties中获取到EnableAutoConfiguration.calss类(类名)对应的值,然后把他们添加在容器中
      

将类路径下 META-INF/spring.factories 里面配置的所有的EnableAutoConfiguration的值加入到容器中;

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

每一个xxxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们来做自动配置

3)、每一个自动配置类开始自动配置工作

4)、以**HttpEncodingAutoConfiguration(HTTP编码的自动配置)**为例解释自动配置原理;

@Configuration  //表示这是一个配置类,像以前写的配置文件一样,也可以给容器中添加组件
@EnableConfigurationProperties({HttpEncodingProperties.class}) //启动指定类的ConfigurationProperties功能;将配置文件中对应的值和参数中的HttpEncodingProperties绑定起来了,并把HttpEncodingProperties加入到ioc容器中

@ConditionalOnWebApplication //Spring底层@Conditional注解(Spring注解版有详细原理),根据不同的条件,如果满足指定的条件(及此表达式的返回结果为true),整个配置类里面的配置才会生效;   判断当前应用是不是web应用,如果是,当前配置类生效,如果不是则不生效

@ConditionalOnClass({CharacterEncodingFilter.class}) //判断当前项目有没有整个CharacterEncodingFilter类,也就是SprinMVC中进行乱码解决的过滤器;
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
) //判断配置文件中是否存在某个配置spring.http.encoding.enabled;如果不存在,判断也是成立的,如果存在则使用这个配置中的值
//即使我们配置文件中不配置spring.http.encoding.enabled=true,也是默认生效的;
public class HttpEncodingAutoConfiguration {
    
    	//他已经和SpringBoot的配置文件映射了
	  private final HttpEncodingProperties properties;

    //并且他只有一个有参构造器,在这样的情况下他就会从ioc容器中拿HttpEncodingProperties,这个值从上方的@EnableConfigurationProperties({HttpEncodingProperties.class})注解中来
     public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
        this.properties = properties;
    }
    
      @Bean //给容器中添加一个组件,这个组件的某些值,需要从properties中获取
    @ConditionalOnMissingBean({CharacterEncodingFilter.class}) //检查容器中是否存在CharacterEncodingFilter这个类穿件的bean,如果已经存在,那么就不加载这个bean
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
        return filter;
    }

根据当前不同的条件判断。决定这个配置类是否生效?

一旦这个配置类生效;这个配置类就会给容器中添加组件,这些组件的属性是从对应的properties类(也就是xxxxProperties)中获取的,而这些类里面的属性的每一个属性又是和配置文件绑定的

5)、所有在配置文件中能配置的属性都是在xxxxProperties类中封装着;配置文件能配置什么就可参照某个功能能对应的这个属性类,

@ConfigurationProperties(     //从配置文件中获取指定的值(这里是前缀为spring.http.encoding的文件)和bean进行绑定
    prefix = "spring.http.encoding"
)
public class HttpEncodingProperties {
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

精髓:

1)、SpringBoot启动名会加载大量的自动配置类

2)、我们看我们需要的功能有没有SpringBoot默认写好的自动配置类;

3)、我们再来看这个自动配置类中到底配置了哪些组件;(只要有我们需要的组件我们就不需要再来配置了)

4)、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值。

2、细节

1、@Conditional派生注解(Spring注解版原生的@Conditional作用)

作用:必须是@Conditional指定的**条件成立(即判断结果为true)**,才给容器中添加组件,配置类里面所有的内容才会生效;

@Conditional扩展注解 作用
@ConditionalOnJava 系统的java版本是否符合要求
@ConditionalOnBean 容器中存在指定Bean
@ConditionalOnMissingBean 容器中不存在指定Bean
@ConditionalOnExpression 满足SpEL表达式指定
@ConditionalOnClass 系统中有指定的类
@ConditionalOnMissingClass 系统中没有指定类
@ConditionalOnSingleCandidate 系统中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty 系统中指定的属性是否有指定的值
@ConditionalOnResource 类路径下是否存在资源文件
@ConditionalOnWebApplication 当前是不是web环境
@ConditionalOnNotWebApplication 当前不是web环境
@ConditionalOnJndi JNDI存在指定项

自动配置类必须在一定的条件下才会生效

我们怎么知道怎么知道哪些自动配置类生效了

我们可以在**全局配置文件中填写debug = true属性**来让控制台打印自动配置报告,这样我们可以很方便的知道哪些自动配置生效了

============================
CONDITIONS EVALUATION REPORT
============================


Positive matches:(自动配置类启用的)
-----------------

   CodecsAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.springframework.http.codec.CodecConfigurer'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
          
          
 Negative matches:(自动配置类没有启用的,没有匹配成功的自动配置类)
-----------------

   ActiveMQAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)


三、日志

1、日志框架

市面上的日志框架:

JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j。。。

日志门面(日志的抽象层) 日志的实现
JCL( Jakarta Commons Logging) SLF4j ( Simple Logging Facade for java) jboss-logging Log4j JUL( java.util.logging) Log4j2 Logback

左边选择一个门面(抽象层)、右边选择一个实现;

左边的门面:SLF4j;

右边的实现:Logback;

SpringBoot 底层使用的是Spring框架,Spring 框架默认使用的是JCL ;

SpringBoot选用SLF4j和Logback;

2、SLF4j的使用

1、如何在系统中使用SLF4j https://www.slf4j.org

以后开发的时候,日志记录的调用方法,不应该来直接调用日志的实现类。而是调用日志的抽象层里的方法;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloWorld {
  public static void main(String[] args) {
    Logger logger = LoggerFactory.getLogger(HelloWorld.class);
    logger.info("Hello World");
  }
}

图示:

spring boot 入门_第10张图片

每一个日志的实现框架都有自己的配置文件。使用slf4j之后,配置文件还是要写成日志实现框架自己本身的配置文件;

2、遗留问题

a(slf4j+logback):spring(commons-logging)、Hibernate(Jboss-logging)、Mybatis、xxx

统一日志记录,及时是别的框架和我一起统一使用slf4j进行输出?

spring boot 入门_第11张图片

如何让系统中的所有日志都统一到slf4j

1、移除系统中原有的日志实现类

2、导入中间包替换掉原来的包

3、调用其他的slf4j的实现框架

3、SpringBoot日志关系

    <dependency>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-jsonartifactId>
      <version>2.0.5.RELEASEversion>
      <scope>compilescope>
    dependency>

SpringBoot使用它来做日志功能

    <dependency>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-loggingartifactId>
      <version>2.0.5.RELEASEversion>
      <scope>compilescope>
    dependency>

SpringBoot底层依赖关系

spring boot 入门_第12张图片

总结:

​ 1)、SpringBoot底层也是使用sjf4j + logback的方式进行日志记录

​ 2)、SpringBoot也把其他的日志替换成了slf4j;

​ 3)、中间替换包?

public class SLF4JBridgeHandler extends Handler {
    private static final String FQCN = Logger.class.getName();
    private static final String UNKNOWN_LOGGER_NAME = "unknown.jul.logger";
    private static final int TRACE_LEVEL_THRESHOLD;
    private static final int DEBUG_LEVEL_THRESHOLD;
    private static final int INFO_LEVEL_THRESHOLD;
    private static final int WARN_LEVEL_THRESHOLD;

    public static void install() {
        LogManager.getLogManager().getLogger("").addHandler(new SLF4JBridgeHandler());
    }

spring boot 入门_第13张图片

4)、如果我们要引入其他框架,一定要把这个框架的默认日志配置的jar包移除掉

​ Spring框架使用的是jcl(commons logging),SpringBoot在集成的时候也将其移除了

SpringBoot能自动适配所有的日志,而且底层选择使用slf4j+logback的方式记录日志,我们需要做的是在引入其他框架的时候,把这个框架依赖的日志框架排除掉;

4、日志使用

1、默认配置

SpringBoot默认帮我们配置好了日志;

//实例化记录器
    Logger logger = LoggerFactory.getLogger(getClass());
    
    @Test
    public void contextLoads() {
        //日志级别
        //由低到高 trace
        //可以调整需要输出的日志级别:日志只会在这个级别及以上的高级别生效.如果没有设置则使用默认级别的日志(也叫root级别)
        logger.trace("this is trace");
        logger.debug("this is debug");
        //SpringBoot默认调整的是info级别的日志
        logger.info("this is info");
        logger.warn("this is warn");
        logger.error("this is error");

日志输出格式


		%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n

SpringBoot修改日志的默认配置

logging.level.com.example=trace
#不指定路径则在当前项目下生成SpringBoot.log日志
#我们可以指定完整的路径,则会在我们指定的路径下生成日志文件
#logging.file=SpringBoot.log

#在当前磁盘(也就是当前项目所在的磁盘)的根目录下创建spring文件夹和log文件夹,使用spring.log作为默认的配置文件
logging.path=/spring/log

#在控制台输出的日志的格式
logging.pattern.console=%d{yyyy-MM-dd}===[%thread]===%-5level===%logger{50}===%m%n

#指定文件中日志输出的格式
#logging.pattern.file=%d{yyyy-MM-dd}===[%thread]===%-5level===%logger{50}===%m%n
logging.file logging.path Example Description
(none) (none) 只在控制台输出
指定文件名 (none) my.log 输出到日志文件my.log
(none) 指定目录 /var/log 输出到指定目录的spring.log文件中

2、指定配置

给类路径下放上每个日志框架的配置文件即可;SpringBoot就不使用他的默认配置文件

根据不同的日志系统,你可以按如下规则组织配置文件名,就能被正确加载:

  • Logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy

  • Log4j:log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml

  • Log4j2:log4j2-spring.xml, log4j2.xml

  • JDK (Java Util Logging):logging.properties

    --------------------- 本文来自 Inke 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/inke88/article/details/75007649?utm_source=copy

logback.xml:直接就被日志框架识别到了文件,无法由SpringBoot放入更好的功能‘表示日志框架是在SpringBoot日志加载之前被加载的

logback-spring.xml:日志框架无法识别,不加载配置项,由SpringBoot加载,可以使用SpringBoot的springProfile进行环境配置

<springProfile name="staging">
	
    可以指定在某个环境下生效
springProfile>

如果使用logback.xml作为日志配置文件,然后还要使用profile功能,就会有以下报错

no application action for[springProfile]

5、切换日志框架

可以按照slf4j的日志适配图,进行相关的切换;

slf4j + log4j的方式;

spring boot 入门_第14张图片

切换为log4j2

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

四、Web开发

1、简介

使用SpringBoot;**

1)、创建一个SpringBoot应用,选中我们需要的模块;

2)、SpringBoot已经帮我们将这些场景自动配置好了,只需要在配置文件中指定少量配置即可运行起来

3)、编写业务代码

自动配置原理?

这个场景SpringBoot帮我们配置了什么?能不能修改?能修改哪些配置?能不能扩展?xxx

xxxAutoConfiguration;帮我们自动配置组件
xxxProperties配置类来封装配置文件的内容;

2、SpringBoot对静态资源的映射规则

@ConfigurationProperties(
    prefix = "spring.resources",
    ignoreUnknownFields = false
)
public class ResourceProperties {
    //可以设置和静态资源有关的参数 比如缓存时间等
 public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
            } else {
                Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
                CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
                if (!registry.hasMappingForPattern("/webjars/**")) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                }

                String staticPathPattern = this.mvcProperties.getStaticPathPattern();
                if (!registry.hasMappingForPattern(staticPathPattern)) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                }

            }
        }

//配置首页(欢迎页)的映射
   @Bean
        public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext) {
            return new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
        }



		//配置喜欢的图标
        @Configuration
        @ConditionalOnProperty(
            value = {"spring.mvc.favicon.enabled"},
            matchIfMissing = true
        )
        public static class FaviconConfiguration implements ResourceLoaderAware {
            private final ResourceProperties resourceProperties;
            private ResourceLoader resourceLoader;

            public FaviconConfiguration(ResourceProperties resourceProperties) {
                this.resourceProperties = resourceProperties;
            }

            public void setResourceLoader(ResourceLoader resourceLoader) {
                this.resourceLoader = resourceLoader;
            }

            @Bean
            public SimpleUrlHandlerMapping faviconHandlerMapping() {
                SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
                mapping.setOrder(-2147483647);
                mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", this.faviconRequestHandler()));
                return mapping;
            }

            @Bean
            public ResourceHttpRequestHandler faviconRequestHandler() {
                ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
                requestHandler.setLocations(this.resolveFaviconLocations());
                return requestHandler;
            }

            private List<Resource> resolveFaviconLocations() {
                String[] staticLocations = WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter.getResourceLocations(this.resourceProperties.getStaticLocations());
                List<Resource> locations = new ArrayList(staticLocations.length + 1);
                Stream var10000 = Arrays.stream(staticLocations);
                ResourceLoader var10001 = this.resourceLoader;
                this.resourceLoader.getClass();
                var10000.map(var10001::getResource).forEach(locations::add);
                locations.add(new ClassPathResource("/"));
                return Collections.unmodifiableList(locations);
            }
        }












1)、所有/webjars/**,都去classpath:/META-INF/resources/webjars/找资源

​ webjars:以jar包的方式引入静态资源 [WebJars][https://www.webjars.org/]

spring boot 入门_第15张图片

我们发送到静态请求 localhost:8080/webjars/jquery/3.3.1-1/jquery.js

        <!--引入jquery-webjars-->在静态访问的时候只需要写下webjars下面的资源名称即可
		<dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.3.1-1</version>
        </dependency>

2)、"/**"访问当前项目的任意资源 ,(静态资源文件夹)

"classpath:/META-INF/resources/",
"classpath:/resources/", 
"classpath:/static/", 
"classpath:/public/" 
"/"  :当前项目的根路径

localhost:8080/abc === 去静态资源文件夹里面找abc

3)、欢迎页;静态资源文件夹下面所有的“index.html”页面;被"/**"映射

​ localhost:8080/ 找静态资源文件夹下面的index.html

4)、所有的**/favicon.ico都是放在静态文件夹中的

5)、如果想改变静态文件夹的路径需要在application.properties中配置前缀是spring.resources

@ConfigurationProperties(
    prefix = "spring.resources",
    ignoreUnknownFields = false
)
public class ResourceProperties {

配置文件中格式

spring.resources.static-locations=classpath:/hello/,classpath:/test/  #多个文件夹使用逗号分隔

3、模板引擎

JSP、Velocity、Freemarker、Thymeleaf;

spring boot 入门_第16张图片

SpringBoot推荐的Thymeleaf

语法更简单,功能更强大;

1、引入thymeleaf


    org.springframework.boot
    spring-boot-starter-thymeleaf


通过以下方式切换thymeleaf版本
3.0.2.RELEASE
2.1.1

                                         
                                       

2、Thymeleaf使用&语法

@ConfigurationProperties(
    prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    public static final String DEFAULT_SUFFIX = ".html";
    //

    private boolean checkTemplate = true;
    private boolean checkTemplateLocation = true;
    private String prefix = "classpath:/templates/";
    private String suffix = ".html";
    private String mode = "HTML";

只要我们把html页面放在"classpath:/templates/"里面,我们的thymeleaf就能帮我们自动渲染

使用:

​ 1、导入 thymeleaf 的名称空间,这个名称空间只是作为语法提示功能如果不导入依然可以进行程序编写

<html lang="en" xmlns:th="http://www.thymeleaf.org">

​ 2、使用thymeleaf的语法

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <hr>
    <h1>成功</h1>
    <div th:text="${message}+${test}"></div>
    <div th:text="${test}"></div>
</body>
</html>

3、语法规则

1)、th:text 改变元素里面的文本内容;

th:任意html属性;任意属性可以替换原来的属性值 例如:th:id 可以覆盖原先div的id属性

spring boot 入门_第17张图片

2)、表达式:

Simple expressions:(表达式语法)
    Variable Expressions: ${...}
    		1)、获取对象的属性、调用方法
    		2)、使用内置基本对象 写法:"${#locale.country}"
    		#ctx : the context object.
			#vars: the context variables.
            #locale : the context locale.
            #request : (only in Web Contexts) the HttpServletRequest object.
            #response : (only in Web Contexts) the HttpServletResponse object.
            #session : (only in Web Contexts) the HttpSession object.
            #servletContext : (only in Web Contexts) the ServletContext object.
            	${param.foo} // 从请求参数中中获取foo属性的值
            	能够获取的内置基本对象
            3)、内置工具对象
            #execInfo : information about the template being processed.
            #messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using
            #{…} syntax.
            #uris : methods for escaping parts of URLs/URIs Page 20 of 106
            #conversions : methods for executing the configured conversion service (if any).
            #dates : methods for java.util.Date objects: formatting, component extraction, etc.
            #calendars : analogous to #dates , but for java.util.Calendar objects.
            #numbers : methods for formatting numeric objects.
            #strings : methods for String objects: contains, startsWith, prepending/appending, etc.
            #objects : methods for objects in general.
            #bools : methods for boolean evaluation.
            #arrays : methods for arrays.
            #lists : methods for lists.
            #sets : methods for sets.
            #maps : methods for maps.
            #aggregates : methods for creating aggregates on arrays or collections.
            #ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).
            
            
            
    Selection Variable Expressions: *{...}获取变量值;
    	补充功能:配合 th:object="${session.user}" 使用,则可以在下方通过    		
    	

Name: Sebastian.

Surname: Pepper.

Nationality: Saturn.

通过以上方式获取到这个对象里面的每一个属性的值 Message Expressions: #{...} //用于获取国际化内容的 Link URL Expressions: @{...} //用于定义url链接的 @{/order/process(execId=${execId},execType='FAST')} Fragment Expressions: ~{...} //片段引用
...
Literals (字面量) Text literals: 'one text' , 'Another one!' ,… Number literals: 0 , 34 , 3.0 , 12.3 ,… Boolean literals: true , false Null literal: null Literal tokens: one , sometext , main ,… Text operations: (文本操作) String concatenation: + Literal substitutions: |The name is ${name}| Arithmetic operations:(数学运算) Binary operators: + , - , * , / , % Minus sign (unary operator): - Boolean operations:(布尔运算) Binary operators: and , or Boolean negation (unary operator): ! , not Comparisons and equality:(比较运算) Comparators: > , < , >= , <= ( gt , lt , ge , le ) Equality operators: == , != ( eq , ne ) Conditional operators:(条件运算)(支持三目运算) If-then: (if) ? (then) If-then-else: (if) ? (then) : (else) Default: (value) ?: (defaultvalue) Special tokens: (特殊操作,不执行任何操作) No-Operation: _

当我们需要遍历的时候,可以通过th:each的方式进行遍历参考代码如下:

<tr th:each="prod : ${prods}">
    <td th:text="${prod.name}">Onionstd>
    <td th:text="${prod.price}">2.41td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yestd>
tr> 

==注意:==当我们把th:each写在一个标签上时,这个标签会在每次遍历的时候都生成一次,上面例子中的 标签会反复生成,每遍历一次则会生成一个

我们还可以使用行内写法,直接使用${ }的方式取出后台返回的值,但是需要按照一定的写法才能实现。

<p>The message is "[(${msg})]"p>
<p>The message is "[[${msg}]]"p>

这两种写法的区别在于,[ [ ] ] 等价于 th:text [ ( ) ]等价于th:utext 一种会转义

另一种不会

转义:将该字符以本身的字符形式显示,例如

就直接被显示成

不转义:将该字符所表达的格式显示出来,例如

就直接被显示成一级标题的样式。

4、SpringMVC自动配置

[官方文档SpringMVC自动配置][https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#boot-features-developing-web-applications]

1、 27.1.1 Spring MVC Auto-configuration

Spring Boot 自动配置好了springMVC

The auto-configuration adds the following features on top of Spring’s defaults:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

    • 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图决定如何渲染(转发或者是重定向还是如何))
    • ContentNegotiatingViewResolver:组合所有的视图解析器;
    • 需要定制,如何定制:自动将容器中的视图解析器组合进来,我们只需要将自己编写的视图解析器通过(@Bean或者@Component注解将他们自动装配到容器中)
  • Support for serving static resources, including support for WebJars (covered later in this document)).静态资源文件夹路径,webjars

  • 自动注册了 Converter, GenericConverter, and Formatter beans.

    • Converter:转换器; 类型转换,也就是说从页面传递到后台的值都是String类型的,需要将他们转换成相应的其他类型,如true和false转换成boolean类型,18 19数字转换成Integer类型
    • Formatter:格式化器:格式化页面数据,2017-12-17 === Date;
    • 自己添加的格式化器转换器,我们只需要放在容器中即可
  • Support for HttpMessageConverters (covered later in this document).

    • HttpMessageConverters:消息转换器SpringMVC用来转换http请求和响应的;User–Json
    • MessageConverters:是从容器中确定;获取所有的httpMessageConverter;
    • 自己给容器中添加httpMessageConverter,只需要将自己的组件注册在容器中(@Bean,@Component)
  • Automatic registration of MessageCodesResolver (covered later in this document).定义错误代码生成规则

  • Static index.html support.静态首页访问

  • Custom Favicon support (covered later in this document).

  • Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).

    • 我们可以配置一个ConfigurableWebBindingInitializer来替换默认的;(添加到容器中)

    • 初始化WebDataBinder;
      他的功能是 请求数据绑定到javabean;
      

    org.springframework.boot.autoconfigure.web:web的所有自动场景

2、扩展SpringMVC

If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

    <mvc:view-controller path="/hello" view-name="success"/>
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/hello"/>
            <bean>bean>
        mvc:interceptor>
    mvc:interceptors>

编写一个配置类,(@Configuration),是@WebMvcConfigurer类型的,还不能标注@EnableWebMvc这个注解

这个是对springMVC的扩展配置,既保留了所有的自动配置,也能用我们扩展的配置;

@Configuration
public class myconfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // addViewControllers
        //浏览器发送 /atguigu 请求,页面也跳转到success页面
        registry.addViewController("/").setViewName("/success");
    }
}

原理:

1)、WebMvcConfigurer是SpringMVC的自动配置类,SpringBoot2.0.5版本以上都是通过实现WebMvcConfigurer接口并重写方法来扩展配置的。

2)、在做其他配置的时候会导入@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})

	@Configuration
	public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
        
        
	private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
        
	@Autowired(required = false) //自动装配一旦放在方法上,那么这个方法的参数就会从容器中获取,下面例子中的configurers则会从容器中获取,然后将所有容器里面的configurers复制到这个类中的this.configurers里面去 
	public void setConfigurers(List<WebMvcConfigurer> configurers) {
		if (!CollectionUtils.isEmpty(configurers)) {
			this.configurers.addWebMvcConfigurers(configurers);
            
            //其中的一个参考实现,将所有的WebMvcConfigurer相关的配置都调用一遍,
            	//将所有的WebMvcConfigurer相关配置都来一起调用,包括我们自己的
            	//@Override
          		//public void addViewControllers(ViewControllerRegistry registry) {
                	//for (WebMvcConfigurer delegate : this.delegates) {
						//delegate.addViewControllers(registry);
		}
	}

		}
	}

3)、容器中所有的WebMvcConfigurer都会一起来起作用。

4)、我们的配置类也会被调用

效果:springMVC的自动配置和我们扩展配置都会起作用

3、全面接管SpringMVC;

SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己配置();只需要在配置类中添加@EnableWebMvc注解,相应的,所有的web场景的自动配置都失效了,不推荐大家使用全面接管。

@EnableWebMvc
@Configuration
public class myconfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // addViewControllers
        //浏览器发送 /atguigu 请求,页面也跳转到success页面
        registry.addViewController("/").setViewName("/success");
    }
}

原理:

为什么@EnableWebMvc自动配置就失效了;

1)、@EnableWebMvc的核心

@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

2)、

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

3)、

@Configuration
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
//判断容器中没有WebMvcConfigurationSupport这个组件的时候,下面的自动配置才生效
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {

4)、@EnableWebMvc帮我们导入了DelegatingWebMvcConfiguration类,这个类又是继承自WebMvcConfigurationSupport类,所以在自动配置类的判断中,判定为失效的

5)、导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;

5、如何修改SpringBoot的默认配置

模式

​ 1)、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的,(@Bean,@Component)如果有就用用户配置的,入股没有才自动配置,如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来;

​ 2)、在SpringBoot中,会有非常多的xxxconfigurer帮助我们进行扩展配置,

6、RestfulCRUE

1)、默认访问首页

​ 我们需要将localhost:8080/的默认页面设置成首页

  @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("/index");
        registry.addViewController("/index.html").setViewName("index");
    }
}

在2.0.5版本以上的SpringBoot中,我们通过自定义的配置类,实现WebMvcConfigurer接口并重写addViewControllers()方法来进行添加

2)、国际化

1)、编写国际化配置文件;

2)、使用ResourceBundleMessageSource管理国际化资源文件

3)、在页面使用fmt:message取出国际化内容

步骤:

1)、编写国际化配置文件,抽取页面需要显示的国际化消息

spring boot 入门_第18张图片

设置的时候一定要看清楚国家_语言的格式,可能一个语言会有多个国家使用,例如美国和英国都使用的英语,但是在国际化中这两个国家的语言不通

2)、SpringBoot自动配置好了管理国际化资源文件的组件;

@Configuration
@ConditionalOnMissingBean(
    value = {MessageSource.class},
    search = SearchStrategy.CURRENT
)
@AutoConfigureOrder(-2147483648)
@Conditional({MessageSourceAutoConfiguration.ResourceBundleCondition.class})
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
    
    
            public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
            String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages");//我们的配置文件可以直接放在类路径下叫message.properties
                
            ConditionOutcome outcome = (ConditionOutcome)cache.get(basename);
            if (outcome == null) {
                outcome = this.getMatchOutcomeForBasename(context, basename);
                cache.put(basename, outcome);
            }

            return outcome;
        }
    
       @Bean
    public MessageSource messageSource() {
        MessageSourceProperties properties = this.messageSourceProperties();
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        if (StringUtils.hasText(properties.getBasename())) {
           //设置国际化资源文件的基础名(去掉语言国家代码的名字) messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
        }

        if (properties.getEncoding() != null) {
            messageSource.setDefaultEncoding(properties.getEncoding().name());
        }

        messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
        Duration cacheDuration = properties.getCacheDuration();
        if (cacheDuration != null) {
            messageSource.setCacheMillis(cacheDuration.toMillis());
        }

        messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
        messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
        return messageSource;
    }

3)、去页面获取国际化的值


<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
<h1>This is index pageh1>
<h1 th:text="#{login.tip}">h1>
<h1 th:text="#{login.btn}">h1>
<h1 th:text="#{login.password}">h1>
<h1 th:text="#{login.rememberme}">h1>
<h1 th:text="#{login.username}">h1>

body>
html>

效果:页面已经根据浏览器设置的语言进行了国际化切换

原理

​ 国际化Local(区域信息对象);LocaleResolver(获取区域信息对象)

   @Bean
        @ConditionalOnMissingBean
        @ConditionalOnProperty(
            prefix = "spring.mvc",
            name = {"locale"}
        )
        public LocaleResolver localeResolver() {
            if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.LocaleResolver.FIXED) {
                return new FixedLocaleResolver(this.mvcProperties.getLocale());
            } else {
                AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
                localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
                return localeResolver;
            }
        }

4)、点击链接切换国际化

/*
* 首先需要编写一个国际化配置类
* 这里的国际化信息的来源可以从链接上传参数来达到然后通过request.getParameter("l");来获取到链接上面的值
* */
public class myLocaleResolver implements LocaleResolver {

    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String l = request.getParameter("l");
        Locale locale = Locale.getDefault();
        if (!StringUtils.isEmpty(l)){
            String[] split = l.split("_");
            locale = new Locale(split[0], split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}


//编写好我们的国际化配置之后,需要在webmvc配置文件中添加这个配置
    @Bean
    public LocaleResolver localeResolver(){
        return new myLocaleResolver();
    }

//这样我们的国际化配置就能生效了。

3)、登录

在开发期间想要模板引擎页面修改以后要实时生效,

1)、禁用模板引擎的缓存

#禁用缓存,实现页面的热部署
spring.thymeleaf.cache=false

2)、页面修改完成以后按住ctrl+f9重新编译,最后刷新页面就可以了

登录错误的消息提示

<p style="color: red" th:text="${#messages}" th:if="${not #strings.isEmpty(msg)}"></p>

4)、拦截器进行登录检查

1)、编写一个拦截器,实现HandlerInterceptor接口,重写里面的preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)方法,

public class mylanjieqi implements HandlerInterceptor {
    //此方法的返回值,true代表不拦截,false代表拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
        HttpSession session = request.getSession();
        Object loginuser = session.getAttribute("loginuser");
        if (loginuser == null){
            //返回登录页面
            request.setAttribute("msg","你没有权限这样做,请先登录");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }else
        {
            //session有值,则不拦截
            return true;
        }
    }
}

2)、将拦截器配置到我们写的webmvc配置类中,进行注册

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new mylanjieqi()).addPathPatterns("/**").excludePathPatterns("/index.html","/user/login","/","login");
    //通过addPathPatterns()方法将需要拦截的功能添加进去,excludePathPatterns()方法将不拦截的功能排除掉,而静态资源自动不拦截,SpringBoot帮我们自动放行了对静态资源的拦截。
}

5)、CRUD-员工列表

实验要求:

1)、RestfulCRUD:CRUD满足Rest风格;

URI:/资源名称/资源表示 HTTP请求方式来区分对资源CRUD的操作

普通CRUD(uri来区分操作) RestfulCRUD
查询 getEmp emp–GET
添加 addEmp?xxxx emp–POST
修改 updataEmp?id=xxx&xxx emp/{id}–PUT
删除 deleteEmp?id=? emp/{id}-DELETE

2)、实验的请求架构

实验功能 请求URI 请求方式
查询所有员工 emps GET
查询某个员工 emp/{id} GET
来到添加页面 emp GET
添加员工 emp POST
来到修改页面(查询出员工信息进行回显) emp/{id} GET
修改员工 emp PUT
删除员工 emp/{id} DELETE

3)、员工列表

使用thymeleaf公共元素抽取

1、抽取公共片段
<div th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
div>

2、引入公共片段,再另外一个html页面中加入如下代码
<body>
<div th:insert="~{footer :: copy}">div>//代表在footer页面有一个copy片段,插入footer的copy片段
body>

~{templatename::selector} :模板名::选择器
 ~{templatename::fragmentname} :模板名::片段名

3、默认效果:
insert的功能片段在div标签中
如果使用th:insert等属性进行引入,可以不用写~{}:
[[]];[(~{})]在行内写法则必须加上~{}

注意:这里的模板名,也用到了thymeleaf的命名规则,所以也不需要添加路径和后缀,直接写名字。****

语法规则:

~{templatename::selector} :模板名::选择器 也就是css中的选择器 例如:~{templatename::#id}
~{templatename::fragmentname} :模板名::片段名

4)、三种th属性去引入模板片段

th:insert :将公共片段整个插入到指定元素中footer被div包含进去了

th:replace:将声明引入的元素替换成公共片段,下面例子中是整个div被footer替换了

th:include:将被引入的片段的内容包含进这个标签中也就是没有下面的 footer标签

<footer th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
footer>

引入方式
<body>
...
<div th:insert="footer :: copy">div>
<div th:replace="footer :: copy">div>
<div th:include="footer :: copy">div>
body>

效果
<body>
...
<div>
    <footer>
    © 2011 The Good Thymes Virtual Grocery
    footer>
div>
    
    <footer>
    © 2011 The Good Thymes Virtual Grocery
    footer>
    
<div>
	© 2011 The Good Thymes Virtual Grocery
div>
body>

5)、公共部分的导航栏如果需要动态切换active,那么在模板中的添加了active class的组件中添加判断,获取一个从引入模板传递的值,通过三元表达式的th:class="${ value1==‘设定的值’ ? ‘添加了active 的class’ :‘没有添加active的class’}"判断它的值,设置它的class,当然需要在引入模板的时候添加参数,参数的写法如下:

<div th:replace="::frag (${value1},${value2})">...</div>
<div th:replace="::frag (onevar=${value1},twovar=${value2})">...</div>

这样就可以动态设置active的值了

五、SpringBoot与Docker

1、简介

Docker是一个开源的应用容器引擎;

Docker支持将软件编译成一个镜像;然后再镜像中各种软件做好配置,将镜像发布出去,其他使用者可以直接使用这个镜像;

运行中的这个镜像称为容器,容器的启动时非常快的。

Docker的图示

spring boot 入门_第19张图片

2、核心概念

docker主机(Host):安装了Docker程序的机器(Docker直接安装在 操作系统之上);

docker客户端(Client):连接docker主机进行操作;

docker仓库(Registry):用来保存各种打包好的软件镜像;

docker镜像(Images):软件打包好,放在docker仓库中;

docker容器(Container):镜像启动之后的实例成为一个容器;容器是独立运行的一个或者一组docker应用

使用Docker的步骤:

​ 1)、安装Docker

​ 2)、去Docker仓库找到这个软件对应的镜像

​ 3)、使用Docker运行这个镜像,这个镜像就会生成一个容器

​ 4)、对容器的启动停止就是软件的启动停止

3、安装Docker

1)、安装linux虚拟机

​ 1)、VMware、VirtualBox(安装);

​ 2)、导入虚拟机文件

​ 3)、双击启动虚拟机,使用: root/123456 登录

​ 4)、使用客户端连接linux服务器进行操作

​ 5)、设置虚拟机网络;

桥接网路=选好网卡接入网线;

​ 6)、设置好的网络之后用命令重启虚拟机的网络

service network restart	

​ 7)、查看linux的ip地址

ip addr

​ 8)、使用客户端连接;

2)、在linux虚拟机上安装Docker

​ 1、查看centos版本;

​ docker要求CnetOS系统的内核版本高于3.10

uname -r  //查看自己的内核版本号

​ 2、升级软件包及内核;(选做)

yum update //升级版本号

​ 3、安装docker

yum install docker

​ 4、启动docker

systemctl start docker

​ 5、将docker设置为开机启动

systemctl enable docker

​ 6、停止docker

systemctl stop docker

3)、在windows上安装docker

​ 1、查看windows的系统信息,docker只能在windows10 教育版和企业版上运行

​ 2、下载docker

​ 地址:https://store.docker.com/editions/community/docker-ce-desktop-windows

​ 在注册账号之后,便可以下载docker

​ 注意:docker是外国网站,注册时需要验证你不是机器人,需要你连接一个继续注册,我是使用的启点加速器

​ 详细请看:https://blog.csdn.net/debugbugbg/article/details/81865553#commentBox

​ 3、现在完成后直接安装,过程中需要重启计算机,

​ 4、重启完成之后,打开docker,右击小图标选择sign in进行登录;

spring boot 入门_第20张图片

spring boot 入门_第21张图片

​ 5、至此,docker已经启动完毕了,可以直接去cmd窗口使用docker了;

​ 输入 docker -v 查看当前docker的版本,以后在cmd窗口才做和在linux操作一致

spring boot 入门_第22张图片

4、docker的常用操作

1)、docker镜像操作

操作 命令 说明
检索 docker search eg:docker search redis 我们经常去docker hub上检索镜像的详细信息,如镜像的TAG
拉取 docker pull 镜像名:tag :tag是可选的,tag表示标签,多为软件的版本,默认是latest
列表 docker images 查看本地所有镜像
删除 docker rmi image-id 删除指定的本地镜像

​ 查看镜像需要到docker-hub上查看:https://hub.docker.com/

2)、docker容器操作

使用docker的流程:得到软件镜像(QQ安装程序)—运行镜像----产生一个容器(也就是我们正在运行的软件,运行的QQ);

操作命令 命令 说明
运行 docker run -name 你的名字 -d image-name :tag eg:docker run -name mysql01 -d mysql:latest -name:自定义容器名字 -d:后台运行 image-name:指定镜像模板 :tag 指定镜像的版本,默认为latest
列表 docker ps(查看运行中的容器); 加上 -a 就可以查看所有的容器,无论运行与否
停止 docker stop container-name/container-id 通过容器名字或者容器的id停止这个容器
启动 docker start container-name/container-id 通过容器的名字或者容器的id启动这个容器
删除 docker rm container-name/container-id 通过容器的名字或者id删除某个容器
端口映射 -p 3308:3306 eg:docker run -d -p 6379:6379 -name myredis docker.io/redis 将主机(安装docker的这个机器)的3308端口和容器里面的3306端口相绑定,这样外部访问主机的3308端口即可访问到容器内部的内容
容器日志 docker logs container-name/container-id 通过容器的名字或者容器的id查看这个容器的日志

更多命令,请查看官方文档

步骤:

 1、搜索tomcat镜像
 	docker search tomcat 
 2、拉取tomcat镜像
 	docker pull tomcat
 3、根据镜像启动容器
 	docker run --name mytomcat -d tomcat:latest
 4、查看运行中的容器
 	docker ps
 5、停止运行中的容器
 	docker stop mytoncat/容器的id
 6、查看所有的容器
 	docker ps -a
 7、删除一个容器(这个容器一定是停止状态才行,区别于删除镜像)
 	docker rm 容器的id  // docker rmi 镜像的id 
 8、启动容器
 	docker start 容器id
 9、启动一个做了端口映射的tomcat
 	docker run --name mytomcat -d -p 8888:8080 tomcat:latest
 	-d:后台运行
 	-p:将主机的端口和容器的端口相互绑定  主机端口:容器内部的端口
 10、为了掩饰简单关闭了linux的防火墙
 	service firewalld status;查看防火墙状态
 	service firewalld stop;关闭防火墙
 11、查看容器日志
 	docker logs container-id/container-name
 
 更多命令参考官方文档

3)、安装mysql的实例

docker pull mysql

错误的启动

PS C:\Users\Administrator> docker run --name mysql01 -d mysql
cb38e2a596ebb8cccc3f0711a4a2d713e26e5179e68220f6658c821de6e7aa2e

PS C:\Users\Administrator> docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
cb38e2a596eb        mysql               "docker-entrypoint.s…"   17 seconds ago      Exited (1) 16 seconds ago                       mysql01

错误信息:
PS C:\Users\Administrator> docker logs mysql01
error: database is uninitialized and password option is not specified
  You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD
  //我们mysql的启动需要给root用户设置一个密码,可以是空密码或者一个随机密码但是必须指定一个

正确的启动

PS C:\Users\Administrator> docker run --name mysql02 -e MYSQL_ROOT_PASSWORD=sxt510922 -d mysql:latest
c6ea0af29c848ba917289d8be8ee05cfad9b58bd0f9b5e85c6ec9fe1d3c16805

但是这样配置我们依然无法连接这个mysql,因为没有端口映射,无法从外部连接

做了端口映射的启动

PS C:\Users\Administrator> docker run --name mysql02 -e MYSQL_ROOT_PASSWORD=sxt510922 -d -p 3307:3306 mysql:latest
633eb07209bed865db36ecc8a4953c9da934f443865631301dec0430aa6a3203

再使用ps -a 查看一下当前运行的docker
PS C:\Users\Administrator> docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
633eb07209be        mysql:latest        "docker-entrypoint.s…"   14 seconds ago      Up 12 seconds       33060/tcp, 0.0.0.0:3307->3306/tcp   mysql02

几个其他的高级操作

$ docker run --name some-mysql -v /my/custom:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
//把主机的/my/custom文件夹挂在到 mysql容器的/etc/mysql/conf.d文件
改mysql的配置文件就只需要把mysql的配置文件

//不使用配置文件的命令
$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
指定一些mysql的参数

4)、官方的镜像加速

docker默认使用的是美国的镜像仓库,但是在国内也有托管的,我们只需要在使用pull命令的时候添加用写代码就可以快速下载了

docker pull registry.docker-cn.com/library/镜像的名字:版本号

详情见官网:https://www.docker-cn.com/registry-mirror

六、SpringBoot与数据访问

1、JDBC

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

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

如果我们需要访问数据库,在添加了sql和jdbc模块之后,在yml或者properties配置文件中添加如下配置就可以了

spring:
  datasource:
    username: 你的名字
    password: 你的密码
    url: jdbc:mysql://localhost:3306/sms
    driver-class-name: com.mysql.jdbc.Driver

效果:

​ SpringBoot 2.0.5版本 默认使用的是org.apache.tomcat.jdbc.pool.Datasource数据源

​ 数据源的相关配置都在DataSourceProperties这个类里面,通过按住Ctrl点击配置文件中的属性即可进入此类。

自动配置原理:

org.springframework.boot.autoconfigure.jdbc

1、参考DataSourceConfiguration,根据配置创建数据源,,默认使用tomcat连接池;可以使用spring.datasource.type指定自定义的数据源类型例如c3p0

2、SpringBoot默认支持的是:

org.apache.tomcat.jdbc.pool.DataSource、
com.zaxxer.hikari.HikariDataSource、
org.apache.commons.dbcp2.BasicDataSource.class

3、自定义数据源

包括自定义数据源,如果我们指定的数据源不是以上几种,那么则使用我们自己指定的数据源
	@ConditionalOnMissingBean(DataSource.class)
	@ConditionalOnProperty(name = "spring.datasource.type")
	static class Generic {

		@Bean
		public DataSource dataSource(DataSourceProperties properties) {
			//是使用DataSourceBuilder来创建数据源,利用反射创建type的数据源,并且绑定相关属性
			return properties.initializeDataSourceBuilder().build();
		}

	}

4、1.5.9版本的DataSourceInitializer也就是2.0.5版本中的DataSourceInitializerInvoker,实现了ApplicationListener这个监听器

​ 作用:

​ 1)、this.dataSourceInitializer.initSchema(); 运行建表语句

​ 2)、initializer.initSchema(); 初始化schema

默认只需要将文件命名为:

schema-*.sql、data-*.sql
默认规则:schema.sql  schema-all.sql
也可以使用     schema: classpath:auditing_money.sql 来指定某一个sql文件的位置

注意

​ 在SpringBoot1.x中, 运行schema.sql不需要配置便可直接运行,但是在SpringBoot2.x中,我们需要在配置文件中配置一下:

spring.datasource.initialization-mode: always

配置好了之后,便可通过.

--------------------- 作者:老丑 来源:CSDN 原文:https://blog.csdn.net/qq_41473874/article/details/82184462?utm_source=copy 版权声明:本文为博主原创文章,转载请附上博文链接!

5、操作数据库:自动配置了JdbcTemplate操作数据库

可以使用jdbcTemplate.queryForList(“select * from smbms_address”);这样的方式来查询数据库中的内容

@Controller
public class Hellocontroller {
    @Autowired
    JdbcTemplate jdbcTemplate;

    @ResponseBody
    @GetMapping(value = "emp")
    public String getemp(){
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from smbms_address");
        return maps.toString();
    }

2、整合Druid数据源

步骤:

​ 1、在pom.xml文件中导入Druid的相关依赖

<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>druidartifactId>
    <version>1.1.11version>
dependency>

​ 也可以直接导入启动器


    com.alibaba
    druid-spring-boot-starter
    1.1.10

​ 2、在application.yml或者application.properties文件中配置使用DruidDataSource

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource

​ 3、在application.yml或者application.properties配置DataSource信息(这里是yml的格式)

​ **注意:**这里的配置一定要写,不然druid的监控是无法获取到值的。

initialSize: 6
minIdle: 5
maxActive: 20
timeBetweenEvictionRunsMillis: 600000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
filters: stat,wall
maxPoo1PreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqIMillis=500

​ 4、创建druidconfig类(类名自拟)应用上面的配置

@Configuration
public class druidconfig {

    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druid(){
        return new DruidDataSource();
    }
}

​ 5、在druidconfig中配置sql管理后台的filter和servlet

//配置servlet
//可以使用注解@WebServlet实现,具体实现慢慢研究
@Bean
public ServletRegistrationBean statViewServlet(){
    ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");//将servlet注入容器中并设置url为/druid/*
    Map<String,String> map = new HashMap<>();//通过map存放初始化配置文件
    map.put("loginUsername","admin");
    map.put("loginPassword","123456");
    map.put("allow","localhost");//默认就是允许所有访问
    map.put("deny","192.168.0.1");//拒绝下面的地址访问
    bean.setInitParameters(map);//应用配置文件
    return bean;
}

//配置拦截器filter
	@Bean
    public FilterRegistrationBean webStatFilter(){
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new WebStatFilter());
        Map<String,String> map = new HashMap<>();
        map.put("exclusions","*.js,*.css,/druid/*");
        bean.setInitParameters(map);
        bean.setUrlPatterns(Arrays.asList("/*"));//设置需要拦截的请求,为了监控sql所以拦截所有的请求
        return bean;
    }

3、整合Mybatis

导入相关的starters

<dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>1.3.2version>
        dependency>

他的依赖如图:

spring boot 入门_第23张图片

步骤:

​ 1)、配置数据源相关属性,见上一节的Druid

​ 2)、给数据库建表

​ 3)、创建javaBean

4、注解版

/**
 * @ClassName peachMapper
 * @Author Peach
 * @Date 2018/10/11 10:19
 * @Version 1.0
 **/
public interface peachMapper {

    @Select(value = "select * from auditing_leave where id = #{id}")
    public auditing_leave queryById(Integer id);

    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert(value = "insert into auditing_leave(name_test) values(#{nameTest})")
    public int insert(auditing_leave al);

}

注解版通过编写接口和@Select注解来实现

小问题:

1、自增长ID,通过给方法上添加@Options(useGeneratedKeys = true, keyProperty = “id”)实现,此方法不建议使用于配置版mybatis

//    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert(value = "insert into auditing_leave(name_test) values(#{nameTest})")
    public int insert(auditing_leave al);

注意:这里需要注意,Mapper和数据库配置的自增长是不同的,在数据库配置的自增长只适用于数据库

Mapper配置的自增长可以用于插入后的返回

例如:controller有如下代码,

    @GetMapping("/emp")
    @ResponseBody
    public String addsome(auditing_leave al){
        mapper.insert(al);
        return al.toString();
    }

使用数据库自增长,访问此方法返回结果如下

spring boot 入门_第24张图片

但是数据库中是有id的,

spring boot 入门_第25张图片

使用Mapper自增长注解返回结果如下

spring boot 入门_第26张图片

数据中依然有id

spring boot 入门_第27张图片

希望有习惯 插入之后直接调用插入返回的对象的同学注意一下

2、关于驼峰命名法

我的mybatis-spring-boot-starter版本是1.3.2,它默认是支持驼峰命名的。我的SpringBoot当前版本是2.0.5

如果是其他版本t的同学,可能需要编写配置类

//开启驼峰命名法
@Configuration
public class MybatisConfig {
    @Bean
    public ConfigurationCustomizer customizer (){
        return new ConfigurationCustomizer() {
            @Override
            public void customize(org.apache.ibatis.session.Configuration configuration) {
                configuration.setMapUnderscoreToCamelCase(true);
//                通过使用configuration.setxxxxx方法可以自定义mybatis的属性
            }
        };
    }
}

3、关于配置类的@Mapper注解

如果每一个配置类都写一个@Mapper注解是不是很麻烦,可以在我们自己编写mybatisconfig类或者SpringBoot的启动类上添加注解@MapperScan(value = “你的Mapper包的全类名”)

@MapperScan(value = "com.example.class06practice.mapper")

5、配置版mybatis

步骤:

​ 1、编写Mapper接口

@Mapper
public interface TestMapper {

    public auditing_money getone(Integer id);

    @Options(useGeneratedKeys = true, keyProperty = "id")//通过options设置id自增长
    @Insert(value = "insert into auditing_money(type) values(#{type})")
    public int insert(auditing_money am);
}

​ 2、在resources目录下创建mybatis主配置文件和mapper配置文件

​ 主配置文件mybatis-config.xml



<configuration>

configuration>

​ 对应Mapper的配置文件



<mapper namespace="com.example.class06practice.mapper.TestMapper">
    
    <select id="getone">
        select * from auditing_money where id = #{id}
    select>
    
    <insert id="insert"  parameterType="com.example.class06practice.vo.auditing_money" >
        insert into auditing_money(type) values (#{type})
    insert>

mapper>

​ 3、在application.yml配置文件中指定这两种配置文件的位置

mybatis:
  config-location: classpath:mybatis/mybatis-config.xml  主配置文件的位置
  mapper-locations: classpath:mybatis/Mapper/*.xml		 Mapper配置文件的位置
  
//将MAPPER的日志级别调整到debug级别就可以将sql语句打印出来
logging:
  level:
    com.example.class06practice.mapper: debug

6、整合JPA

1、什么是JPA?

​ JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。

图示:

spring boot 入门_第28张图片

2、整合SpringData JPA

JPA:ORM(对象关系映射 Object Relational Mapping)

​ 1)、导入Jpa相关的starter或者maven依赖

​ 2)、编写一个实体类(Bean)和数据表进行映射,并配置好映射关系;

@Entity
@Table(name = "user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
    private Integer id;

    @Column(name = "last_name",length = 50)
    private String name;

    @Column//默认类名就是属性名
    private String Email;

    private Data birthday;

    private String address;
    
    //以下省略getter和setter方法

}

​ *注意:此处需要注意的是 @Id的包不要导错了,应该是javax.persistence.的包,如果导错则会抛出No identifier specified for entity: com.example.springdemo.entity.AnyUser的异常。

必须注意:如果此处想要自己编写复杂的查询语句,不用内置的查询语句,则需要用到@Query注解,@Query注解需要设置其中的nativeQuery=true属性才能正常使用。代码如下

@Query(value = “select * from user”,nativeQuery = true)

//spring-data-jpa 版本2.0.5以上无法继承JpaRepository,改为继承Repository
//    @org.springframework.stereotype.Repository
//    @Component
public interface UserRepository extends Repository<User,Integer> {
    User save(User user);


    User findById(Integer id);

    @Query(value = "select * from user",nativeQuery = true)
    List getaa();
}

​ 3)、编写一个Dao来操作实体类所对应的数据表(Repository)

注意:spring-data-jpa 版本2.0.5以上无法继承JpaRepository,改为继承Repository

//spring-data-jpa 版本2.0.5以上无法继承JpaRepository,改为继承Repository
public interface UserRepository extends Repository<User,Integer> {

}

​ 4)、基本的配置,jpa基本配置都是以jpa开头的

jpa:
  hibernate:
    #设置数据表的生成方式为updata 如果有则更新,如果没有则创建一张
    ddl-auto: update
  #设置在控制台打印sql语句
  show-sql: true

​ 5)、jap的内置查询语法

关键词 示例 对应的sql片段
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection ages) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

七、启动配置原理

几个重要的时间回调机制

配置在META-INF/spring.factories

ApplicationContextInitializer ioc容器 上下文初始化器

SpringApplicationRunListener spring 应用启动监听器

只需要加在ioc容器中的

ApplicationRunner 应用启动器

CommandLineRunner 命令行启动器

启动流程:

1、创建SpringApplication对象,new SpringApplication(primarySources)

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        //保存赋值主配置类
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        //判断当前是否一个web应用
		this.webApplicationType = deduceWebApplicationType();
        //从类路径下找到META-INF/spring.factories下面所有的ApplicationContextInitializer;然后保存起来
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) 
        //从类路径下找到META-INF/spring.factories配置的所有ApplicationListener
        getSpringFactoriesInstances(ApplicationListener.class));
        //从多个配置类中找到有main方法的配置类作为程序的主配置类
		this.mainApplicationClass = deduceMainApplicationClass();
	}

spring boot 入门_第29张图片

spring boot 入门_第30张图片

2、运行run方法

	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
        //获取SpringApplicationRunListeners;从类路径下META-INF/spring.factories
		SpringApplicationRunListeners listeners = getRunListeners(args);
        //回调所有的获取SpringApplicationRunListener.starting()方法
		listeners.starting();
		try {
            //封装命令行参数
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
            //准备环境
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
            //完成后会回调SpringApplicationRunListener.environmentPrepared()方法表示环境准备完成
            
            //打印Banner也就是Spring的那个大的文字组成的图标
			Banner printedBanner = printBanner(environment);
            
            //创建ApplicationContext也就是ioc容器在此决定创建一个webioc还是一个普通的ioc
			context = createApplicationContext();
            
            //处理异常报告
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
            
            //准备上下文环境 将environment保存到ioc中;而且还要调用applyInitializers()方法
            //回调之前所有已经保存的ApplicationContextInitializer的initialize()方法 
            //回调所有的SpringApplicationRunListener的contextPrepared()方法
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
            //prepareContext运行完成之后回调所有的SpringApplicationRunListeners的contextLoaded()方法。
            
            //是刷新容器;ioc容器初始化(如果是web应用,还会创建嵌入式的tomcat );Spring注解版
            //扫描、加载、创建所有组件的地方(配置类、组件、自动配置)
			refreshContext(context);
            //从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
			//ApplicationRunner先回调再调CommandLineRunner
            afterRefresh(context, applicationArguments);
            
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
            //所有的springApplicationRunListener回调started()方法
			listeners.started(context);
			callRunners(context, applicationArguments);
            
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
        //整个SpringBoot应用启动完成之后,返回启动的ioc容器
		return context;
	}

3、事件监听机制

配置在META-INF/spring.factories

ApplicationContextInitializer ioc容器 上下文初始化器

SpringApplicationRunListener spring 应用启动监听器

只需要加在ioc容器中的

ApplicationRunner 应用启动器

CommandLineRunner 命令行启动器

需要使用这些监听器和获取启动器启动时的参数的话,只需要编写配置类,实现上面对应的接口及其方法,

ApplicationRunner 应用启动器和CommandLineRunner 命令行启动器需要将该类通过@Component注解到ioc容器中,而ApplicationContextInitializer ioc容器 上下文初始化器和SpringApplicationRunListener spring 应用启动监听器则需要在resource目录下创建一个META-INF文件夹,在META-INF文件夹中创建spring.factories配置文件进行配置如下:

 #Initializers
org.springframework.context.ApplicationContextInitializer=\
  com.example.practice1015.druid.listener.listener

org.springframework.boot.SpringApplicationRunListener=\
  com.example.practice1015.druid.listener.helloSpringApplicationRunListener

一个CommandLineRunner的例子,其他的监听器和启动器都是如此来编写,只是引入方式不同

@Component
public class helloCommandLineRunner implements CommandLineRunner{
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner 正在监听"+args.length + "=="+Arrays.asList(args));
    }
}

八、SpringBoot自定义starters(场景启动器)

starter:

​ 1、这个场景需要用到的依赖是什么

​ 2、如何编写自动配置

@Configuration //告诉SpringBoot这个是一个配置类
@ConditionalOnWebApplication //判断一些ConditionalOnXXXX,指定条件成立的情况下,自动配置生效这个是一个web应用
@AutoConfigureOrder //指定自动配置类的顺序
@AutoConfigureAfter //配置它在哪个自动配置类之后执行
@Bean //给容器中添加组件
@ConfigurationProperties //结合相关的xxxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效并加入到容器中

自动配置类要能加载,必须把需要自动夹杂IDE类配置在在classpath下META-INF下的spring.factories中
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

​ 3、模式

启动器只用来做依赖导入;

专门来写一个自动配置模块;

启动器依赖自动配置;别人只需要引入启动器(Starter)

-mybatis-spring-boot-starter;自定义启动器名-spring-boot-starter;

​ 4、实现大体步骤:

​ 1、创建空项目

​ 2、添加新的Modules的model

​ 3、填写好Modules的GroupId和Artifactid

​ 4、创建Spring Initializer的Modules(xxxx-spring-boot-starter-autoconfiger),不选择任何的模块然后finished

​ 5、在starter的项目中的pom文件中引入autoconfiger项目的依赖(位于pom文件)

​ 6、在autoconfiger项目中做出如下修改:

​ 删除原有的项目启动器和配置文件(不删文件夹)

​ 7、编写你的业务逻辑已经properties所对应的配置文件类

​ 8、编写一个xxxxxAutoConfiguration类,将你的所有业务逻辑类装配到容器中

​ 9、在classpath:META-INF/spring.factories类中中配置出你得自动配置类

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.atguigu.starter.service.HelloServiceAutoConfiguration

​ 10、将两个模块安装到maven仓库中便于引用,因为starter依赖于xxxxautoconfig所以优先安装xxxxautoconfig。

​ 11、接下来就可以去其他相信通过引入hello的starter来引用helloservice了

结束!

你可能感兴趣的:(spring boot 入门)