Spring Boot自制教程

Spring Boot

author:QYX

前言:因为原本是md文件代码就不转了,嫌麻烦,很早的时候写的,版本可能有点老了,更新了2.0的一些特性

一、hello world实现与底层解析

@SpringBootApplication: spring Boot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就用这个类的main方法来启动Springboot应用

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

@SpringBootConfiguration:SpringBoot的配置类

标注在某个类上,表示这是一个springboot的配置类

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

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

@EnableAutoConfiguration:开启自动配置功能

以前我们需要配置的东西,SpringBoot帮我们配置,该注解告诉spring boot开启配置功能,这样自动配置才能生效

 @AutoConfigurationPackage
 @Import({AutoConfigurationImportSelector.class})
 public @interface EnableAutoConfiguration {

@AutoConfigurationPackage:自动配置包

 @Import({Registrar.class})

Spring 的底层注解,给容器中导入一个组件,导入的组件由Registrar.class规定

将主配置类的(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器

@Import({AutoConfigurationImportSelector.class}):导入哪些组件的选择器

AutoConfigurationImportSelector:将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中,会给容器中导入非常多的自动配置类,

(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件,

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

 SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration,classloader)

从类路径下的META-INF/spring-factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入容器中,自动配置类就会生效,帮我进行自动配置工作。

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

今天使用Spring boot 的Test方法遇到了以下错误

二、yml与properties语法及使用

一、yml语言实战

代码模块

bean类

 package com.example.demo.bean;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.DoubleAccumulator;
 /**
  * 将配置文件中的配置每一个属性的值,映射到这个组件中
  * @ConfigurationProperties,告诉spring boot将本类中的所有属性与配置文件中的相关配置进行绑定
  * prefix = "person"配置文件中哪个下面的所有属性进行一一映射
  * 只有这个组件是容器中的组件,才能使用容器提供的功能
  */
 @Component
 @ConfigurationProperties(prefix = "person")
 public class Person
 {
     @Override
     public String toString() {
         return "Person{" +
                 "lastName='" + lastName + '\'' +
                 ", age=" + age +
                 ", boss=" + boss +
                 ", birth=" + birth +
                 ", maps=" + maps +
                 ", lists=" + lists +
                 ", dog=" + dog +
                 '}';
    }
 
     private String lastName;
     private Integer age;
     private boolean boss;
     private Date birth;
     private Map<String,Object> maps;
     private List<Object> lists;
     private Dog dog;
 
     public String getLastName() {
         return lastName;
    }
 
     public void setLastName(String lastName) {
         this.lastName = lastName;
    }
 
     public Integer getAge() {
         return age;
    }
 
     public void setAge(Integer age) {
         this.age = age;
    }
 
     public boolean isBoss() {
         return boss;
    }
 
     public void setBoss(boolean boss) {
         this.boss = boss;
    }
 
     public Date getBirth() {
         return birth;
    }
 
     public void setBirth(Date birth) {
         this.birth = birth;
    }
 
     public Map<String, Object> getMaps() {
         return maps;
    }
 
     public void setMaps(Map<String, Object> maps) {
         this.maps = maps;
    }
 
     public List<Object> getLists() {
         return lists;
    }
 
     public void setLists(List<Object> lists) {
         this.lists = lists;
    }
 
     public Dog getDog() {
         return dog;
    }
 
     public void setDog(Dog dog) {
         this.dog = dog;
    }
 }
 
 package com.example.demo.bean;
 
 public class Dog {
     private String name;
     private Integer age;
 
     public String getName() {
         return name;
    }
 
     @Override
     public String toString() {
         return "Dog{" +
                 "name='" + name + '\'' +
                 ", age=" + age +
                 '}';
    }
 
     public void setName(String name) {
         this.name = name;
    }
 
     public Integer getAge() {
         return age;
    }
 
     public void setAge(Integer age) {
         this.age = age;
    }
 }

yml文件

 server:
  port: 8888
 
 person:
  lastName: zhansan
  age: 18
  boss: false
  birth: 2017/12/12
  maps: {k1: v1,k2: v1}
  lists:
    - lisi
    - zhaoliu
  dog:
    name: xiaogou
    age: 2

Spring boot 测试类

 package com.example.demo;
 
 import com.example.demo.bean.Person;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.SpringBootConfiguration;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit4.SpringRunner;
 
 /**
  * spring boot的单元测试
  *
  */
 @RunWith(SpringRunner.class)
 @SpringBootTest(classes = Demo04Application.class)
 public class Demo04ApplicationTests {
 
     @Autowired
     private Person person;
     @org.junit.Test
     public void contextLoads() {
         System.out.println(person);
    }
 }
 

错误纠正及反思

其中我在一开始使用spring boot的Test类的时候,出现以下异常

 java.lang.IllegalStateException: Found multiple @SpringBootConfiguration annotated classes [Generic bean: class [com.example.demo.Demo04Application]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\Users\13554\IdeaProjects\demo\target\classes\com\example\demo\Demo04Application.class], Generic bean: class [com.example.demo.Demo05Application]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\Users\13554\IdeaProjects\demo\target\classes\com\example\demo\Demo05Application.class], Generic bean: class [com.example.demo.Demo06Application]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\Users\13554\IdeaProjects\demo\target\classes\com\example\demo\Demo06Application.class], Generic bean: class [com.example.demo.Demo07Application]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file 

解决方案,在Test方法中的@SpringBootTest将其改为@SpringBootTest(classes = Demo04Application.class),即添加对应的映射类,便可解决此异常

 @RunWith(SpringRunner.class)
 @SpringBootTest(classes = Demo04Application.class)
 public class Demo04ApplicationTests {
 
     @Autowired
     private Person person;
     @org.junit.Test
     public void contextLoads() {
         System.out.println(person);
    }
 }

二、porperties的使用

代码实现

 #idea默认使用的是utf-8进行编码
 person.last-name="张三"
 person.age=18
 person.boss=true
 person.maps.k1=v1
 person.maps.k2=v2
 person.lists=1,2,3
 person.birth=2019/10/14

错误纠正与反思

properties文件的优先级比yml文件的优先级要高。,在具体输出时,可能会遇到控制台乱码的情况,这是因为idea默认使用的是UTF-8,而properties文件使用的是ASCII码。

改正中文乱码方法:

选择idea左上角的file-settings,进入后搜索file encodingsw,修改default encoding for properties files选项为UTF-8,同时选中Transparent native-to-ascii conversion,允许其转为ASCII码,即可解决

@Value获取值和@ConfigurationProperties获取值比较

     
  @Configuration @Value
功能 批量注入配置文件中的属性 一个个指定
松散绑定(松散语法---比如驼峰命名) 支持 不支持
SqEL 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装(map等) 支持 不支持

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

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

如果说,我们专门编写了一个JavaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties

三,配置文件注入值数据校验

@ConfigurationProperties

与@Bean结合为属性赋值

与@PropertySource(只能用于properties文件)结合读取指定文件

@ConfigurationProperties Validation

支持JSR303进行配置文件值校验

 @ConfigurationProperties(prefix="connection")
 @Validated
 public class FooProperties{
     @NotNull
     private InetAddress remoteAddress;
     @Vaild
     private final Security security=new Security();
 }

@ImportResource读取外部配置文件

@PropertySource&@ImportResource

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

 package com.example.demo.bean;
 
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.context.annotation.PropertySource;
 import org.springframework.stereotype.Component;
 
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.DoubleAccumulator;
 
 /**
  * 将配置文件中的配置每一个属性的值,映射到这个组件中
  * @ConfigurationProperties,告诉spring boot将本类中的所有属性与配置文件中的相关配置进行绑定
  * prefix = "person"配置文件中哪个下面的所有属性进行一一映射
  * 只有这个组件是容器中的组件,才能使用容器提供的功能
  */
 @Component
 //@ConfigurationProperties默认是从全局配置文件中获取值
 //@ConfigurationProperties(prefix = "person")
 //@PropertySource,可以从多个指定配置文件中读取值
 @ConfigurationProperties(prefix = "person")
 @PropertySource(value = {"classpath:person.properties"})
 public class Person
 {
     @Override
     public String toString() {
         return "Person{" +
                 "lastName='" + lastName + '\'' +
                 ", age=" + age +
                 ", boss=" + boss +
                 ", birth=" + birth +
                 ", maps=" + maps +
                 ", lists=" + lists +
                 ", dog=" + dog +
                 '}';
    }
 
     private String lastName;
     private Integer age;
     private boolean boss;
     private Date birth;
     private Map<String,Object> maps;
     private List<Object> lists;
     private Dog dog;
 
     public String getLastName() {
         return lastName;
    }
 
     public void setLastName(String lastName) {
         this.lastName = lastName;
    }
 
     public Integer getAge() {
         return age;
    }
 
     public void setAge(Integer age) {
         this.age = age;
    }
 
     public boolean isBoss() {
         return boss;
    }
 
     public void setBoss(boolean boss) {
         this.boss = boss;
    }
 
     public Date getBirth() {
         return birth;
    }
 
     public void setBirth(Date birth) {
         this.birth = birth;
    }
 
     public Map<String, Object> getMaps() {
         return maps;
    }
 
     public void setMaps(Map<String, Object> maps) {
         this.maps = maps;
    }
 
     public List<Object> getLists() {
         return lists;
    }
 
     public void setLists(List<Object> lists) {
         this.lists = lists;
    }
 
     public Dog getDog() {
         return dog;
    }
 
     public void setDog(Dog dog) {
         this.dog = dog;
    }
 }

@ConfigurationProperties(prefix="person")

在上述代码中,@ConfigurationProperties(prefix="person")必不可少,否则测试时,person对象则为空。

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

SpringBoot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别

想让Spring的配置文件生效,加载进来,@ImportResource标注在一个配置类上

 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.annotation.ImportResource;
 
 /**
  * @Spr*ingBootApplication 标注一个主程序类, 说明这是一个spring boot应用
  * @ImportResource:**导入Spring的配置文件,让配置文件里面的内容生效
  */
 @ImportResource(locations = {"classpath:bean.xml"})
 @SpringBootApplication
 public class HelloWorldMainApplication {
 
     public static void main(String[] args)
    {
 
         SpringApplication.run(HelloWorldMainApplication.class,args);
 
    }
 }

@PropertySource():可以扫描不是全局配置文件的配置

 //ConfigurationProperties只能扫描application(即全局配置文件)文件
 @PropertySource("value={classpath:person.properties}"):

Spring及Spring Boot支持全注解开发模式

使用注解方式注册bean

 package com.example.demo;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
 /**
  * @Configuration:指明当前类是一个配置类,就是替代之前的spring配置文件
  */
 @Configuration
 public class MyAppConfig {
 
     //将方法的返回值添加到容器中:容器中这个组件默认的id就是方法名
     @Bean
     public HelloService helloService()
    {
         return new HelloService();
    }
 }

配置文件占位符

1、随机数

RandomValuePropertySource:配置文件中可以使用随机数

${random.value} ${random.int} ${random.long} ${random.int(10)} ${random.int[1024,65536]}

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

 person.last-name=张三${random.uuid}
 person.age=${random.int}
 person.boss=true
 person.maps.k1=v1
 person.maps.k2=v2
 person.lists=1,2,3  
 person.birth=2019/10/14
 person.dog.name=${person.hello:hello}_dag

Profile

1、多profile文件

我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml,默认使用application.properties的配置

2、yml支持多文档块方式

 server:
  port: 8081
 spring:
  profiles:
    active: dev
 ---
 server:
  port: 8082
 spring:
  profiles: dev
 ---
 server:
  port: 8083
 spring:
  profiles: prod

3、激活指定profile

1、在配置文件中指定

例: spring.profiles.active=dev

2、命令行激活模式

2.1 测试开发时使用命令行参数

例:-点击右上角xxxapplication,选择edit configurations,在environment里的Program arguments输入 spring.profiles.active=prod

2.2 打包时使用命令行参数

例:使用cmd

java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar -spring.profiles.active=dev

3 虚拟机参数

例:点击右上角xxxapplication,选择edit configurations,在environment里的VM options 输入 -Dspring.profiles.active=prod

配置文件加载的优先级

配置文件默认的加载顺序

-file:../config/

-file:./

-classpath:/config/

-classpath:/

以上是按照优先级从高到低的顺序,所有位置的文件都会被加载,高优先级配置内容会覆盖低优先级配置内容

我们可以通过配置spring.config.location来改变配置文件的默认加载顺序

利用配置文件的加载顺序,我们可以进行配置文件的互补

使用spring-config-location来改变配置文件的默认加载顺序

在项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来改变配置文件的默认加载顺序

例:使用cmd,进入项目jar包所在目录,使用java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar -spring,config.location=E:/application.properties

外部配置文件的加载顺序

Spring Boot支持多种外部配置方式,以下为外部配置文件排列方式,按照优先级由高到低:高优先级的配置会覆盖低优先级的配置

所有的配置会形成互补配置

1 命令行参数

例:打包后,使用java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar -server.port=8087

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

3 java系统属性(System.getProperties())

4 操作系统环境变量

5 RandomValuePropertySource配置的random.*属性值

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

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

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

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

10 @Configuration注解类上的@PropertySource注解

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

自动配置原理

自动配置原理:

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

2)@EnableAutoConfiguration作用:

  • 利用EnableAutoConfigurationSelector给容器中导入一些组件

  • 可以查看selectImports()方法的内容

  • List<String>Configurations=getCandidateConfigurations(annotationMetadata,attributes);获取候选的配置

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

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

     # Auto Configure
     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.CloudServiceConnectorsAutoConfiguration,\
     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.CassandraReactiveDataAutoConfiguration,\
     org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
     org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
     org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
     org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
     org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
     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.jdbc.JdbcRepositoriesAutoConfiguration,\
     org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
     org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
     org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
     org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
     org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
     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.RedisReactiveAutoConfiguration,\
     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.elasticsearch.rest.RestClientAutoConfiguration,\
     org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
     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.http.HttpMessageConvertersAutoConfiguration,\
     org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
     org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
     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.groovy.template.GroovyTemplateAutoConfiguration,\
     org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
     org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
     org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
     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.mongo.embedded.EmbeddedMongoAutoConfiguration,\
     org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
     org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
     org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
     org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
     org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
     org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
     org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
     org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
     org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
     org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
     org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
     org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
     org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
     org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
     org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
     org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
     org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
     org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
     org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
     org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
     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.client.RestTemplateAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
     org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
     org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
     org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
     org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
     org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
     org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration
     

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

    3)每一个自动配置类进行自动配置功能;

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

    @Configuration //表示这是一个配置类,跟以前编写的配置文件一样,也可以给容器中添加组件
    @EnableConfigurationProperties({HttpProperties.class}) //启动指定类的ConfigurationProperties功能,将配置文件对应的XXXProperties类进行绑定
    														//并把@EnableConfigurationProperties加入到ioc容器中
    @ConditionalOnWebApplication( //原型使用了spring中的@Conditional注解,根据不同的条件,如果满足指定的条件,那么整个配置类的配置都会生效:
        //判断当前应用是否是web应用,如果是当前配置类生效。,如果不是,则当前配置类不生效
        type = Type.SERVLET
    )
    @ConditionalOnClass({CharacterEncodingFilter.class}) //判断当前项目有没有指定的类,CharacterEncodingFilter是SpringMVC中解决乱码的过滤器
    @ConditionalOnProperty(
        prefix = "spring.http.encoding",
        value = {"enabled"},                   //判断配置文件中是否存在某个配置,spring.http.encoding.enable,matchIfMissing 可以指明,如果不存在,也是成立的
        matchIfMissing = true					//即使我们配置文件中不配置spring.http.encoding.enable=true,也是默认生效的
    )
    public class HttpEncodingAutoConfiguration
        
        //它已经和springBoot的配置文件映射了	
       	private final HttpEncodingProperties properties;
    	
    	public HttpEncodingAutoConfiguration(HttpProperties properties) {
            this.properties = properties.getEncoding();						//在只有一个有参构造器的情况下,参数值就会从容器中获取
        }
        
        @Bean	//给容器中添加一个组件,这个组件的某些值需要从properties中获取
        @ConditionalOnMissingBean 	//判断容器中没有这个组件
        public CharacterEncodingFilter characterEncodingFilter() {
            CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
            filter.setEncoding(this.properties.getCharset().name());
            filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
            filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
            return filter;
        }
    
    @ConfigurationProperties(
        prefix = "spring.http" //从配置文件中获取指定的值和bean的属性进行绑定 
    )
    public class HttpProperties {	
    

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

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

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

    Spring Boot的精髓

    1 Spring Boot启动时会加载大量的自动配置类

    2 我们需要的功能有没有Spring Boot默认写好的自动配置类

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

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

    细节

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

    作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置类里面所有的内容才生效

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

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

    如何知道哪些自动配置类生效

    我们可以在.properties文件中通过启用 debug=true属性,来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置启动了

    运行后,我们可以看到,Positive matches(自动配置类启动的),Negative matchs(没有启动,没有匹配成功的自动配置类)

    三、日志

    1 日志框架

    故事:

    小秦,开发一个大型系统

    1 System.out.println("")将关键 数据打印在控制台,去掉?写在一个文件?

    2 框架来记录系统的一些运行时信息,日志框架;qinlogging.jar

    3 高大上的几个功能?异步模式?自动归档;qinlogging-good.jar?

    4 将以前的框架卸下,换上新的框架,重新修改之前相关的API;qinlogging-prefect.jar;

    5 JDBC---数据库驱动

    写了一个统一的接口层:日志门面(日志的一个抽象层);logging-abstract.jar;给项目中导入具体的日志实现就行了,我们之前的日志框架都是实现的抽象层

    市面上的日志框架

    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

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

    Spring 默认选择的日志框架是JCL

    Jboss-logging 是特定框架使用,使用较少 JCL廉颇老矣,尚能饭否(最新一次更新是在2014年) SLF4j(最实用)

    日志门面:SLF4j(与Log4j和Logback是出自同一 作者)

    日志实现:Log4j Logback(Log4j与Logback是出自同一人之手,适配性不错) log4j2(apache公司出的,跟前两者不是同一作者)

    、SpringBoot:底层是Spring框架,Spring框架默认使用JCL\

    SpringBoot:选用SLF4j和Logback

    2 SLF4j使用

    1 如何在系统中使用SLF4j

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

    应该给系统里面导入SLF4j的jar包和Logback的实现jar包

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

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

    2 遗留问题

    a:(slf4j+logback):Spring(commons-logging),hibernate(jboss-logging)、mybatis.......

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

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

    1 将系统中其他日志框架先排除出去

    2 用 中间包来替换原有的日志框架(偷天换日包 jcl.over.slf4j.jar)

    3 我们导入slf4j其他的实现

3 SpringBoot日志关系

<dependency>
	<groupId>org.springframework.boot</groupId>
    <actifactId>spring-boot-starter</actifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
    <actifactId>spring-boot-starter-logging</actifactId>
</dependency>

SpringBoot使用它来做日志功能

底层依赖关系:

logback-core使用logback记录日志,jul-to-slf4j,log4j-to-slf4j是中间包,将其他日志转为slf4j,同时导入了日志抽象层slf4j

总结:

1 SpringBoot底层也是使用slf4j+logback的方式进行日志记录

2 SpringBoot也把其他的日志都替换成了slf4j

3 中间替换包

@suppressWarnings("rawtypes")
public abstract class LogFactory{
    static String UNSUPPOPTED_OPERATION_IN_JCL_OVER_SLF4J="http://www.slf4j.org/codes.html#unsupported_operation_in_jcl_over_slf4j";
    static LogFactory logFactory=new SLF4JFactory();
}

4 如果我们要引入其他框架?一定要把这个框架的默认日志依赖移除掉

<dependency>
	<groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
	<exclusions>
    	<groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
    </exclusions>
</dependency>

SpringBoot能自动适配所有的日志,而且底层使用slf4j+logback的方式记录日志,引入其他框架的时候,只需要把这个框架的日志框架排除调用

//日志的级别:

//由低到高 trace<debug<info<warn<error

//可以调整输出的日志级别:日志就只会在这个级别以后的高级版生效

在application.properties中添加:

logging.level.com.atguigu=trace

//SpringBoot默认给我们使用的是info级别的,如果没有指定级别的就用SpringBoot默认规定的级别,root级别(info)

Logger logger=LoggerFactory.getLogger(getClass());
@Test
public void contextLoads()
{
    logger.trace("这是trace日志...");
    logger.debug("这是debug日志...");
    logger.info("这是info日志...");
    logger.warn("这是warn日志...");
    logger.error("这是error日志....");
}
		日志输出格式:
			%d表示日期时间
			%thread表示线程名
			%-5level:级别从左显示5个字符宽度
			%logger{50}:表示logger名字最长50个字符,否则按照句点分割
			%msg:日志消息
			%n:换行符
			%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -%msg%n

SpringBoot修改日志的默认设置

logging.level.com.qyx=trace
#不指定路径在当前项目下生成springboot.log日志
#可以指定完整的路径
logging.file=G:/spring.log
#在当前磁盘的根路径下创建spring文件夹和里面的log文件,使用Spring.log作为默认文件
logging.path=/spring/log
#当控制台输出的日志的格式
logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} -%msg%n
#指定文件中日志输出的格式
logging.pattern.file=%d{yyyy-MM-dd} === [%thread] === %-5level === %logger{50} === -%msg%n

2 指定配置

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

Logging System Customization  
Logback logback-spring.xml,logback-spring.groovy,logback.xml or logback.grovy  
Log4j2 log4j2.xml or log4j2.xml  
JDK(Java Util Logging) logging.properties  

logback.xml:直接就被日志框架识别了;

logback-spring.xml:日志框架就不直接加载日志的配置项,由SpringBoot解析日志配置,可以使用SpringBoot的高级Profile功能

<springProfile name="staging">
    <!--可以指定某段配置只在某个环境下生效-->
</springProfile>

如果不加-spring后缀名,则会报错

no application action for [springProfile]
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!--
日志输出格式:
%d表示日期时间
%thread表示线程名
%-5level:级别从左显示5个字符宽度
%logger{50}表示logger名字最长50个字符,否则按照句点分割
%msg:日志消息
%n:换行符
<layout class="ch.qos.logback.classsic.PatternLayout">
<springProfile name="dev">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern>
</springProfile>
<springProfile name="!dev">
	<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%n</pattern>
	</springProfile>
	</layout>
	</appender>

3 切换日志框架

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

业务代码的编写

自动配置原理

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

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

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

详见配置类WebMvcAutoConfiguration.java的addResourceHandlers

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

webjars:以jar包的方式 引入静态资源:

jquery-3.4.1.jar

META-INF>resources>webjars>jquery>3.4.1>jquery.js

访问命令:localhost:8888/webjars/jquery/3.4.1/jquery.js (注:我把这里的默认端口号8080改为了8888)

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

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

@Configuration(prefix="spring.resources",ignoreUnknownFields=false)//ignoreUnknownFields是用来告诉SpringBoot在有属性不能匹配到声明的域时抛出异常。 
public class ResourceProperties implements ResourceLoaderAware{
    //可以设置和静态资源有关的参数,缓存时间
}

“/**” 访问当前项目的任何资源

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

localhost:8888/asserts/js/Chart.min.js

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

localhost:8888/ 找index页面

4所有的**/favicon.ico都是在静态资源文件下找

三 模板引擎

使用模板引擎thymeleaf
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId|>spring-boot-starter-thymeleaf</artifactId|>
</dependency>

1 引入thymeleaf

	<properties>
	<!--切换thymeleaf版本-->
        <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
        <!--布局功能支持程序 thymeleaf3主程序 适配Layout2以上版本-->
        <!--thymeleaf2 Layout1适配-->
        <thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
    </properties>
	<dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    </dependencies>

2 Thymeleaf使用&语法

@ConfigurationProperties(prefix="spring.thymeleaf")
public class ThymeleafProperties{
    private static final Charset DEFAULT_ENCODING=Charset.forName("UTF-8");
    private static final MimeType DEFAULT_CONTENT_TYPE=MimeType.valueOf("text/html");
    private static final String DEFAULT_PREIX="classpath:/templates/";
    public static final String DEFAULT_SUFFIX=".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>
    <h1>成功!</h1>
    <!--th:text 将div里面的文本内容设置为-->
	<div th:text="${hello}">这里是显示欢迎信息</div>
</body>
</html>

错误记录:

今天在进行上述网页的跳转访问时,网页报错Circular view path [success]: would dispatch back to the current handler URL [/success] again. Check your ViewResolver s,经我思考,这是因为thymeleaf的版本与当前springBoot支持的版本不兼容,提高thymeleaf版本即可

3 、语法规则

1)th:text:改变当前元素里面的文本内容。 可以使用 th:任意html属性;来替换原生属性的值

语法介绍:

1 标签

Order Feature Attrbutes
1 片段包含:类似jsp:include th:insert th:replace
2 遍历:类似c:forEach th:each
3 条件判断:c:if th:if th:unless th:switch th:case
4 声明变量:类似c:set th:object th:with
5 任意属性修改支持prepend(在前面追加),append(在后面追加) th:attr th:attrprepend th:atrappend
6 修改指定属性默认值 th:value th:href th:src
7 修改标签体内容 th:text(转义特殊字符) th:utext(不转义特殊字符)
8 声明片段 thLfragment
9 Fragment removal 删除 th:remove

2 表达式

(表达式语法)
${...}:获取变量;OGNL
1)、获取对象的属性,调用方法
2)、使用内置的基础对象
#ctx
#vars
#locate
#request
#response
#session
#servletContext
${session.foo}
4)、使用内置的一些工具对象
*{...}选择表达式;和${}在功能上一样
补充:配合th:object=${session.user}
<div th:object="${session.user}">
<p>Name:<span th:text="*{firstName}">Sebastian</span></p>
<p>SurName:<span th:text="*{lasstName}">Pepper</span></p> 
<p>Nationality:<span th:text="*{nationality}">Saturn</span></p>    
</div>
#{...}:获取国际化内容
@{...}:定义URL
~{...}片段引用表达式
(字面量)
(文本操作)
(数学运算)
(布尔运算)
(比较运算)
(条件运算 三元运算符)
(特殊操作,没有操作_)

Spring MVC auto_configuration

Spring Boot自动配置好了SpringMVC

以下是SpringBoot对SpringMVC的默认

1 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(转发?重定向?))

2 ContentNegotiatingViewResolver:组合所有的视图解析器

如何定制:我们可以自己给容器中添加一个视图解析器;SpringBoot会自动的将其组合进来

3 静态首页访问,静态资源文件夹路径Webjars

4 自动注册了Converter,GenericConverter,Formater beans

Converter 转换器;类型转换使用Converter

Formatter 格式化器;2017-12-17==Date

@Bean
@ConditionalOnProperty(prefix="spring.mvc",name="data-format")//在文件中配置日志格式化的规则
public Formatter<Date>dataFormatter()
{
    return new DateFormatter(this.mvcProperties.getDateFormat());
}

自己添加的格式化器,我们只需要放在容器中即可

Support for HttpMessageConverters(see below)

HttpMessageConverter:SpringMVC用来转换Http请求和响应的;User--json

HttpMessageConverters是从容器中确定,获取所有的HttpMessageConverter

自己给容器中添加HttpMessageConverter,只需要将自己的组件放在容器中(@Bean,@Component)

Automatic registration of MessageCodeResolver

MessageCodeResolver:定义错误代码生成规则的

Automatic use of a ConfigurablewebBindingInitializer bean

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

初始化WebDataBinder; //web请求绑定器
请求数据=====javabean中;

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

5 如何修改SpringBoot的默认配置

模式:

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

2、扩展SpringMVC

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

编写一个配置类(@Configuration),是WebMvcConfigurer类型:不能标注@EnableWebMvc注解(2.0以上版本)

编写一个配置类(@Configuration),是WebMvcConfigurerAdapter类型,不能标注@EnableWebMvc注解(2.0以下版本)

package com.example.demo09;

import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //super.addViewControllers(registry);
        //浏览器发送 /test 请求来到success页面
        registry.addViewController("/test").setViewName("sucess");
    }
}

原理:

1)、WebMvcAutoConfiguration是SpringMVC的自动配置类

2)、在做其他自动配置时会导入;@Import(EnableWebMvcConfiguration.class)

@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguraion{
    private fianl WebMvcConfigurerComposite configurers=new WebMvcConfigurerComposite();
    //从容器中获取所有的WebMvcConfigurer,required=false表示如果该容器中没有该bean,则直接跳过不报错,如果为true则会报错,@Autowried注解默认使用的是true
    @AutoWried(required=false)
    public void setConfigurers(List<WebMvcConfigurer> configurers)
    {
        if(!CollectionUtils.isEmpty(configurers))
        {
            this.configurers.addWebMvcConfigurers(configurers);
        }
    }
    //一个参考实现:将所有的WebMvcConfigurer相关配置都来一起调用
    //@Override
  //  public void addViewControllers(ViewControllerRegistry registry)
   // {
    //    for(WebMvcConfigurer delegate:this.delegates)
   //     {
    //        delegate.addViewControllers(registry);
     //   }
//	}
}

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

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

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

3 全面接管SpringMVC

SpringBoot对SpringMVC的自动配置都不需要了,所有的配置都需要我们自己配,所有的SpringMVC的自动配置都失效,我们需要在配置类中添加@EnableWebMvc即可

@EnableWebMvc注解让自动配置失效的原理:

1)@EnableWebMvc的核心

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

2)

@Configuration
public class DelegatingWebMvcConfiguration implements WebMvcConfigurer{
    
    
}

3)

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({Servlet.class},DispatcherServlet.class,WebMvcConfigurerAdapter.class)
//容器中没有这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Orderd.HIGHEST_PRECEDENCE+10)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class,VaildationAutoConfiguration.class})
public class WebMvcAutoConfiguration{
    
}

4)、@EnableWebMvc将WebMvcConfigurationSupport组件导入进来

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

5 如何修改SpringBoot的默认配置

模式:

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

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

6、ResultCRUD

1)、默认访问首页

2)、国际化

传统的SpringMvc方式实现国际化

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

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

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

使用SpringBoot方式实现国际化

步骤:

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

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

@ConfiguationProperties(prefix="spring.message")
public class MessageSourceAutoConfiguration{
    private String basename="messages";
    //我们的配置文件可以直接放在类路径下叫messages.properties
}
@Bean
    public MessageSource messageSource(MessageSourceProperties properties) {
        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)、去页面获取国际化的值

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
		<meta name="description" content="">
		<meta name="author" content="">
		<title>Signin Template for Bootstrap</title>
		<!-- Bootstrap core CSS -->
		<link href="asserts/css/bootstrap.min.css" rel="stylesheet" th:href="@{/webjars/bootstrap/4.3.1/css/bootstrap.css}">
		<!-- Custom styles for this template -->
		<link href="asserts/css/signin.css" rel="stylesheet" th:href="@{/asserts/css/signin.css}">
	</head>

	<body class="text-center">
		<form class="form-signin" action="dashboard.html">
			<img class="mb-4" th:src="@{asserts/img/bootstrap-solid.svg}" src="asserts/img/bootstrap-solid.svg" alt="" width="72" height="72">
			<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
			<label class="sr-only" th:text="#{login.username}">Username</label>
			<input type="text" class="form-control" placeholder="Username" required="" autofocus="" th:placeholder="#{login.username}">
			<label class="sr-only" th:text="#{login.password}">Password</label>
			<input type="password" class="form-control" placeholder="Password" required="" th:placeholder="#{login.password}">
			<div class="checkbox mb-3">
				<label>
          <input type="checkbox" value="remember-me"> [[#{login.remember}]]
        </label>
			</div>
			<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
			<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
			<a class="btn btn-sm">中文</a>
			<a class="btn btn-sm">English</a>
		</form>

	</body>
</html>

原理:

国际化Locale(区域信息对象):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;
            }
        }
默认的就是根据请求头带来的区域信息获取Locale进行国际化
package com.example.demo09.component;

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

/**
 * 可以在连接上携带区域信息
 */
public class MyLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest httpServletRequest) {
        String l=httpServletRequest.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 httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

    }
}

   @Bean
   public LocaleResolver localeResolver()
   {
       return new MyLocaleResolver();
   }
}

3)、登录

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

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

#禁用缓存
spring.thymeleaf.cache=false

2)、页面修改完成以后ctrl+F9,重新编译

登录错误消息的显示

 

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

CRUD-员工列表

实验要求:

1)、RestfulCRUD:CRUD满足Rest风格

URI:/资源名称/资源标识 HTTP请求方式区分对资源的CRUD操作

  普通CRUD(Uri来区分操作) RestfulCRUD
查询 getEmp emp---GET
添加 addEmp?xxx emp---POST
修改 updateEmp?id=xxx&xxx=xx emp/{id}---put
删除 deleteEmp?id=1 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">
&copy;2011 The Good Thymes Virtual Grocery
</div>

2、引入公共片段
<div th:insert="~{footer::copy}"></div>
~{templatename:selector}:模板名::选择器
~{templatename:fragmentname}模板名::片段名

3、默认效果
insert的功能片段在div标签中
三种引入功能片段的th标签
th:insert	将公共片段整个插入到声明引入的元素中
th:replace	将声明引入的元素替换为公共片段	
th:include 	将被引入的片段的内容包含进这个标签体中

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

效果:
<div>
    <footer>
    	xxxxxx
    </footer>
</div>

<footer>
	xxxxxx
</footer>

<div>
    xxxxx
</div>

如果使用th:insert等属性进行插入,可以不用写~{};

行内写法可以加上:[[~{ }]];[(~{ })]s

引入片段的时候传入参数

SpringBoot2.0配置SQL文件并执行

在SpringBoot2.x中我们需要在properties或者yml文件中配置initialization-mode: ALWAYS即可

代码如下

``

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/choose?serverTimezone=UTC
    initialization-mode: ALWAYS
    schema:
      - classpath:sql/test.sql
    username: root
    password: 123456

配置完成后,点击run命令即可运行schema中指定的SQL文件

 

猜你喜欢

转载自www.cnblogs.com/qyx66/p/12180801.html