spring-boot基础学习

一、Spring Boot 入门

1、Spring Boot 简介

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

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

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

2、微服务

2014 , martin fowler

微服务:是一种架构风格

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

 

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

3、环境准备

1、Maven设置

在maven的setting.xml中添加

  
      
          1.8
          
              true
              1.8
          
          
              1.8
              1.8
              1.8
          
      
  

2、IDEA设置

设置maven环境

 

4、Spring Boot HelloWorld

实现一个功能:

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

 

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

2、导入依赖spring boot相关的依赖

  
      org.springframework.boot
      spring-boot-starter-parent
      1.5.9.RELEASE
  
      
          org.springframework.boot
          spring-boot-starter-web
      
  

3、编写一个主程序:启动spring-boot应用

  
  /**
   * @SpringBootApplication来标注一个主程序类
   */
  @SpringBootApplication
  public class HelloWorldMainApplication {
      public static void main(String[] args) {
  ​
          //Spring应用启动起来
          SpringApplication.run(HelloWorldMainApplication.class,args);
      }
  }

4、编写相关的Controller、Service

  
  @Controller
  public class HelloController {
      @ResponseBody
      @RequestMapping("/hello")
      public String hello(){
          return "Hello World!";
      }
  }

5、运行主程序测试

6、简化部署

  
  
  
      
          
              org.springframework.boot
              spring-boot-maven-plugin
          
      
  

将这个应用打成jar包,直接使用java -jar的命令进行执行。

5、Hello World探究

1、pom.xml文件

1、父项目

  
  
      org.springframework.boot
      spring-boot-starter-parent
      1.5.9.RELEASE
  
      
   他的父项目是:
   
       org.springframework.boot
       spring-boot-dependencies
       1.5.9.RELEASE
       ../../spring-boot-dependencies
  
  他来真正管理Spring Boot应用里面的所有依赖版本;

Spring Boot的版本仲裁中心;

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

2、导入的依赖

  
  
      org.springframework.boot
      spring-boot-starter-web
  

spring-boot-starter-web:

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

 

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

2.主程序类,主入口类

@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}
  )}
  )
  public @interface SpringBootApplication {

@SpringBootConfiguration:Spring Boot的配置类;

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

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

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

@EnableAutoConfiguration:开启自动配置功能;

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

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

​ @AutoConfigurationPackage:自动配置包

​ @Import(AutoConfigurationPackages.Registrar.class):

​ Spring的底层注解@Import,给容器中导入一个组件;导入的组件由AutoConfigurationPackages.Registrar.class

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

​ @Import(EnableAutoConfigurationImportSelector.class);

​ 给容器中导入组件?

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

​ 会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件;

 

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

​ SpringFactoricesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader);

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

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

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、配置文件

Spring Boot使用一个全局的配置文件,配置文件名是固定的;

  • application.properties

  • application.yml

 

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

 

YAML( YAML Ain't Markup Language)

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

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

标记语言:

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

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

​ YAML:配置实例

  
  server:
      port:8081

​ XML:配置实例

  
  
      8081
  

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、配置文件值注入

配置文件:

  
  person:
    lastName: zhangsan
    age: 21
    boss: false
    birth: 2017/12/12
    maps:
      k1: v1
      k2: v2
    lists:
      - lisi
      - zhaoliu
      - wangwu
    dog:
      name: xiaogou
      age: 2

javabean:

  
  /**
   * 将配置文件中配置的每一个属性的值,映射到这个组件中
   * @ConfigurationProperties  : 告诉SpringBoot 将本类中的所有属性和配置文件中相关的配置进行绑定;
   *      prefix = "person" : 配置文件中哪个下面的所有属性进行一一映射
   *
   * 只有这个组件是容器中的组件,才能使用容器提供的@ConfigurationProperties功能;
   */
  @Component
  @ConfigurationProperties(prefix = "person")
  public class Person {
  ​
     
      private String lastName;
      private Integer age;
      private Boolean boss;
      private Date birth;
      private Map maps;
      private List lists;
      private Dog dog; 
  

我们可以导入配置文件处理器,以后编写配置文件就会有提示了:

  
  
  
      org.springframework.boot
      spring-boot-configuration-processor
      true
  

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

 

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

  @ConfigurationProperties @Value
功能 批量注入配置文件中的属性 一个个的指定
松散绑定(松散语法) 支持 不支持
SqEL 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持

配置文件不管是yml还是properties都能获取到值;

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

  
  @RestController
  public class HelloController {
      @Value("#{11 * 2}")
      private String name;
      
      @RequestMapping("sayHello")
      public String sayHello(){
          return "hello" + name;
      }

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

3、配置文件注入之数据校验

  
  @Component
  @ConfigurationProperties(prefix = "person")
  @Validated
  public class Person {
  ​
      /**
       * 
       *      
       * 
       */
  ​
      //lastName必须是邮箱格式的。
      @Email
      private String lastName;
  ​
      @Value("#{11*2}")
      private Integer age;
  ​
      @Value("true")
      private Boolean boss;
      private Date birth;
      private Map maps;
      private List lists;
      private Dog dog; 
  

4、@PropertySource&@ImportResource

@PropertySource(value = {"classpath:xxx.properties"}):加载指定的配置文件

  
  /**
   * 将配置文件中配置的每一个属性的值,映射到这个组件中
   * @ConfigurationProperties  : 告诉SpringBoot 将本类中的所有属性和配置文件中相关的配置进行绑定;
   *      prefix = "person" : 配置文件中哪个下面的所有属性进行一一映射
   *
   * 只有这个组件是容器中的组件,才能使用容器提供的@ConfigurationProperties功能;
   * @ConfigurationProperties(prefix = "person")默认从全局配置文件中获取值
   */
  @PropertySource(value = {"classpath:person.properties"})
  @Component
  @ConfigurationProperties(prefix = "person")
  @Validated
  public class Person {
  ​
      /**
       * 
       *      
       * 
       */
      private String lastName;
  ​
      @Value("#{11*2}")
      private Integer age;
  ​
      @Value("true")
      private Boolean boss;
      private Date birth;
      private Map maps;
      private List lists;
      private Dog dog; 
  

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

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

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

  
  @ImportResource(locations = {"classpath:beans.xml"})
  导入Spring的配置文件让其生效

 

不来编写Spring的配置文件

  
  
  
  ​
      
  

 

SpringBoot推荐给容器中添加组件的方式;推荐使用全注解的方式;

1、配置类====Spring配置文件

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

  
  /**
   * @Configuration指明当前类是一个配置类;就是来代替之前的Spring配置文件
   */
  @Configuration
  public class MyAppConfig {
  ​
      /**
       * @Bean将方法的返回值添加到容器中;容器中这个组件默认的id就是方法的方法名
       *
       */
      @Bean
      public HelloService helloService(){
          return new HelloService();
      }
  }

4、配置文件占位符

1、随机数

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

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

  
  person.age=${random.int}
  person.birth=2017/12/12
  person.boss=false
  person.dog.name=dog_${person.hello:hello}
  person.dog.age=15
  person.last-name=张三${random.uuid}
  person.lists=a,b,c
  person.maps.k1=v1
  person.maps.k2=v2

5、Profile

1、多Profile文件

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

morning使用application.properties

2、yml支持多文档块方式

  
  server:
    port: 80
  ​
  person1:
    lastName: zhangsan
    age: 21
    boss: false
    birth: 2017/12/12
    maps:
      k1: v1
      k2: v2
    lists:
      - lisi
      - zhaoliu
      - wangwu
    dog:
      name: xiaogou
      age: 2
  ​
  #激活配置环境 dev
  spring:
    profiles:
      active: dev
  ​
  ​
  #下面的  ---  是文档块
  ---
  ​
  #文档块2
  server:
    port: 8081
  spring:
    profiles: dev
  ---
  ​
  #文档块3
  server:
    port: 8082
  spring:
    profiles: product   #指定这个文档块属于哪个环境

 

3、激活指定profile

​ 1、在配置文件中指定 spring.profiles.active=dev

​ 2、命令行:

​ --spring.profiles.active=dev

在启动jar包的时候使用命令来指定启动软件所使用的的配置环境。

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

6、配置文件加载位置

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

-file:./config/

-file:./

-classpath:/config/

-classpath:/

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

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

 

我们还可以通过spring.config.location来改变默认的配置文件位置

项目打包以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定配置文件和默认加载的这些配置文件共同起作用形成互补配置;

7、外部配置加载顺序

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

1、命令行参数

​ java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --server.port=8085 --server.context-path=/abc

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

 

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

3、Java系统属性( System.getProperties() )

4、操作系统环境变量

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

 

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

优先加载带profile

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

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

 

再来加载不带profile

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

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

 

10、@Configuration注解上的@PropertySource

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

所有支持的配置加载来源;参考官方文档

8、自动配置原理

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

配置文件能配置的属性;参照官方文档

 

1、自动配置原理:

 

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

2)、@EnableAutoConfiguration作用:

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

  •  

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

  • List configurations = this.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.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

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

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

4)、以HttpEncodingAutoConfiguration为例来解释自动配置原理;

  
  @Configuration  //表示这是一个配置类,和以前写的配置文件文件一样,也可以给容器中添加组件
  @EnableConfigurationProperties({HttpEncodingProperties.class})//启动指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把HttpEncodingProperties加入到ioc容器中
  ​
  @ConditionalOnWebApplication    //Spring底层@Conditional注解,根据不同的条件,如果满足指定的条件,整个配置类里面的配置才会生效。  判断当前应用是否是web应用,如果是,当前配置类生效
  ​
  @ConditionalOnClass({CharacterEncodingFilter.class})//判断当前项目有没有这个类CharacterEncodingFilter;SpringMvc中进行乱码解决的过滤器;
  ​
  @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;
      
      //只用一个有残构造器的情况下,HttpEncodingProperties参数的值就会从容器中拿
      public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
          this.properties = properties;
      }
      
      @Bean   //给容器中添加一个组件,这个组件的某些值需要从properties中获取
      @ConditionalOnMissingBean({CharacterEncodingFilter.class})//判断容器中没有这个组件
      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类中获取的,这些类里面的每一个属性又是和配置文件绑定的;

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

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

 

 

6)、SpringBoot的精髓:

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

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

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

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

​ xxxxAutoConfiguration:自动配置类;

​ 给容器中添加组件

​ xxxxProperties:封装配置文件中相关属性;

2、细节

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

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

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

怎么才能知道有哪些自动配置类生效了?

我们可以通过穷 debug=true属性;来让控制台答应自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;

  
  ​
  =========================
  AUTO-CONFIGURATION REPORT
  =========================
  ​
  ​
  Positive matches:  //匹配到生效的类
  -----------------
  ​
     DispatcherServletAutoConfiguration matched:
        - @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
        - @ConditionalOnWebApplication (required) found 'session' scope (OnWebApplicationCondition)
  ​
     DispatcherServletAutoConfiguration.DispatcherServletConfiguration matched:
        - @ConditionalOnClass found required class 'javax.servlet.ServletRegistration'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
        - Default DispatcherServlet did not find dispatcher servlet beans (DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition)
  ​
            
            
            Negative matches: //没有匹配生效的类
  -----------------
  ​
     ActiveMQAutoConfiguration:
        Did not match:
           - @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)
  ​
     AopAutoConfiguration:
        Did not match:
           - @ConditionalOnClass did not find required classes 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice' (OnClassCondition)
  ​

三、Spring Boot与日志

1、日志框架

日志的出现:

小张:开发了一个大型系统;

​ 1、System.out.println("");将关键数据打印在控制台;去掉?卸载一个文件?

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

​ 3、高大上的几个功能?异步模式?自动归档?xxxx?zhanglogging-good.jar?

​ 4、将以前框架卸下来?换上新的框架,重新修改之前相关的API;zhanglogging-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

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

日志门面:SLF4J;

日志实现:Logback

 

Spring Boot:底层是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、xxxx

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

 

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

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

2、用中间包来替换原有的日志框架;

3、我们导入slf4j其他的实现;

 

3、SpringBoot日志关系

  
  
      org.springframework.boot
      spring-boot-starter-web
  

SpringBoot使用它做日志功能;

  
  
      org.springframework.boot
      spring-boot-starter-logging
      2.1.4.RELEASE
      compile
  

底层依赖关系

 

总结:

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

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

​ 3)、中间替换包。

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

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

4、日志使用

1、默认配置

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

  
  //记录器
      final Logger logger = LoggerFactory.getLogger(getClass());
  ​
      @Test
      public void contextLoads() {
  //        System.out.println();
  ​
          //日志的级别
          //由低到高  trace

SpringBoot修改日志的默认配置,在application.properties中配置:

  
  #在控制台输出的日志的格式
  #日志输出格式:
  #    %d表示日期时间
  #    %thread表示线程名
  #    %-5level:级别从左显示5个字符宽度
  #    %logger[50] 表示logger名字最长50个字符,否则按照据点分割
  #    %msg:日志消息
  #    %n是换行符
  logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
  ​
  #指定文件中日志输出的格式
  logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
  ​

2、指定配置

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

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

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

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

  
  
      可以指定某段配置只在某个环境下生效
  

四、web开发

1、简介

使用SpringBoot;

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

2)、SpringBoot已经默认将这些场景配置好了;只需要在配置文件中指定少量配置就可以运行起来;

3)、自己编写业务代码;

 

自动配置原理?

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

  
  xxxxAutoConfiguration:帮我们给容器中自动配置组件;
  xxxxProperties:配置类来封装配置文件的内容;

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

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

 

1)、所有/webjars/** 的请求,都去 classpath:/META-INF/resources/webjars/下面找资源;

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

https://www.webjars.org/

以前的静态资源要自己下载好,然后放在项目中,现在可以通过maven引用的方式使用。

  
  在访问的时候只需要写webjars下面资源的名称即可
  
      org.webjars
      jquery
      3.3.1
  

 

 

 

 

localhost:8080/webjars/jquery/3.3.1/jquery.js

 

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

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

静态资源放在这些文件夹下,都能够被访问到。

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

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

​ localhost:8080/ ==== 找index页面

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

3、模版引擎

JSP、Velocity、Freemarker、Thymeleaf

 

SpringBoot推荐Thymeleaf;

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

 

1、引入thymeleaf

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

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的名称空间

  
  

2、使用thymeleaf语法

  
  
  
  
      
      Title
  
  
  ​
      

成功!

       

3、语法规则

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

th:任意html属性;来替换原生属性的值

 

2)、表达式

  
  Simple expressions:(表达式语法)
      Variable Expressions: ${...}    获取变量值;
          1)获取对象的属性、调用方法
          2)使用内置对象
              #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.
           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: *{...}  变量的选择表达式
      Message Expressions: #{...}  获取国际化内容
      Link URL Expressions: @{...}    定义URL
      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)

4、SpringBoot中扩展SpringMVC的功能

编写一个配置类(@Configuration),是WebMvcConfigurationSupport(旧版本是WebMvcConfigurerAdapter)类型;不能标注@EnableWebMvc;如果标注了@EnableWebMvc,SpringBoot对SpringMVC的自动配置会全部失效(所有配置需要自己手动来配)

  
  //使用WebMvcConfigurerAdapter可以来扩展SpringMvc的功能
  //@EnableWebMvc
  @Configuration
  public class MyMvcConfig extends WebMvcConfigurerAdapter {
      //方法一
      @Override
      public void addViewControllers(ViewControllerRegistry registry) {
          registry.addViewController("/").setViewName("login");
          registry.addViewController("/login.html").setViewName("login");
          registry.addViewController("/login").setViewName("login");
      }
      
      
      //方法二
      //所有的WebMvcConfigurerAdapter组件都会一起起作用
      @Bean
      public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
          WebMvcConfigurerAdapter webMvcConfigurerAdapter = new WebMvcConfigurerAdapter(){
              @Override
              public void addViewControllers(ViewControllerRegistry registry) {
                  registry.addViewController("/").setViewName("login");
                  registry.addViewController("/login.html").setViewName("login");
                  registry.addViewController("/login").setViewName("login");
              }
          };
          return webMvcConfigurerAdapter;
      }
      
  }

5、实例项目

1、静态资源处理

1、静态资源都放在resources/static/路径下 引用的时候模版引擎会自动去找

 

2、html页面中引入的方式(引入webjars)

 

3、html页面中引入自定义的静态文件

 

static下的静态资源由模版引擎去解析 所以这里的路径前面不用写static

2、国际化

以前的SpringMVC的做法:

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

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

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

 

现在的SpringBoot的做法:

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

 

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

  
  @ConfigurationProperties(
      prefix = "spring.messages"
  )
  public class MessageSourceAutoConfiguration {
      //我们的配置文件可以直接放在类路径下叫messages.properties;
      private String basename = "messages";  
      
      @Bean
      public MessageSource messageSource() {
          ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
          if (StringUtils.hasText(this.basename)) {
      //设置国际化资源文件的基础名(去掉语言国家代码)          
              messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(this.basename)));
          }
  ​
          if (this.encoding != null) {
              messageSource.setDefaultEncoding(this.encoding.name());
          }
  ​
          messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
          messageSource.setCacheSeconds(this.cacheSeconds);
          messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat);
          return messageSource;
      }

//我们的配置文件可以直接放在类路径下叫messages.properties;然后不需要再做任何配置;

如果不是上面的情况,就需要指定基础名:

在配置文件中添加:

 

 

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

 

访问页面 可能会出现乱码

乱码原因前面提到过,是因为properties中的内容最终都要转换成ASCII码,需要自己设置

File --> Settings --> 搜索 file encodings 改变设置(修改当前项目的)

 

如果想要修改全局的配置,应用到所有项目,File --> Other settings --> settings for new projects..

国际化原理:

​ 国际化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进行国际化

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

自己编写LocaleResolver

  
  /**
   * 可以在连接上携带区域信息
   */
  public class MyLocaleResolver implements LocaleResolver {
  ​
      @Override
      public Locale resolveLocale(HttpServletRequest httpServletRequest) {
          String lang = httpServletRequest.getParameter("lang");
          Locale locale = Locale.getDefault();
          if(!StringUtils.isEmpty(lang)){
              String[] split = lang.split("_");
              locale = new Locale(split[0],split[1]);
          }
          return locale;
      }
  ​
      @Override
      public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
  ​
      }
  }

在springMVC配置类中注入自己定义的LocaleResolver

  
  /**
   * 注入自定义的MyLocaleResolver
   * @return  MyLocaleResolver
   */
  @Bean
  public LocaleResolver localeResolver(){
      return new MyLocaleResolver();
  }

3、登录

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

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

  
  #禁用缓存
  spring:
    thymeleaf:
      cache: false

 

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

 

登录错误信息的显示

  
  

4、拦截器进行登录检查

1)、自定义一个拦截器

  
  public class LoginHandlerInterceptor implements HandlerInterceptor {
      @Override
      public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
          final Object loginedUser = httpServletRequest.getSession().getAttribute("loginedUser");
          if(loginedUser == null){
              //未登录,返回到登录页面
              httpServletRequest.setAttribute("msg","您还未登录,请先登录");
              httpServletRequest.getRequestDispatcher("/login.html").forward(httpServletRequest,httpServletResponse);
              return false;
          }else {
              //已登录,放行请求
              return true;
          }
  ​
      }
      @Override
      public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {}
      @Override
      public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {}
  }

2)、将自定义的拦截器添加到WebMvcConfigurerAdapter组件中

  
  /**
   * 添加过滤器
   * @param registry
   */
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
      //静态资源:*.css  *.js
      //SpringBoot已经做好了静态资源映射,不需要考虑静态资源
  ​
      registry.addInterceptor(new LoginHandlerInterceptor())
          .addPathPatterns("/**")
          .excludePathPatterns("/","/login","/login.html","/user/login");
  }

5、CRUD-员工操作(查看IDEA中的项目)

实验要求:

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

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

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

2)、试验的请求架构;

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

3)、员工列表:

Thymeleaf公共页面元素抽取

  
  1.抽取公共片段
  
  
      
          
      © 2011 The Good Thymes Virtual Grocery        
    ​ 2.引入公共片段   ...    
或   ...    
​ 3、默认效果: insert的功能片段在div标签中 如果使用th:insert等属性进行引入,可以不用写~{}; 如果是[[~{}]];[(~{})] 就必须写

 

三种引入功能片段的th属性:

th:insert:将公共片段整个插入到声明 引入的元素中th:replace:将声明引入的元素替换为公共片段th:include:将被引入的片段的内容包含进这个标签中

  
  
© 2011 The Good Thymes Virtual Grocery
​ 引入方式:
​ 引入效果
   
  © 2011 The Good Thymes Virtual Grocery    
© 2011 The Good Thymes Virtual Grocery
© 2011 The Good Thymes Virtual Grocery

成功实例:

 

  
  

 

在引入模版的时候传入参数(菜单栏选中菜单的变化)

  
  
  • 菜单一
  •  

    引入模版的时候传参

      
      

    6、错误处理机制

    1、SpringBoot默认的错误处理机制

    默认效果:

    ​ 1)、浏览器,返回一个默认的错误页面

     

    浏览器发送请求的请求头:

     

     

    ​ 2)、如果是其他客户端(安卓手机...)访问、默认响应一个json数据

     

    其他客户端发送请求的请求头:

     

     

    原理:

    ​ 可以参照ErrorMvcAutoConfiguration;错误处理的自动配置;

    ​ 给容器中添加了以下组件

    ​ 1、DefaultErrorAttributes:

    ​ 2、BasicErrorController:处理默认/error请求

      
      @Controller
      @RequestMapping({"${server.error.path:${error.path:/error}}"})
      public class BasicErrorController extends AbstractErrorController {
          //产生html类型的数据   浏览器发送的请求来到这个方法处理
          @RequestMapping(
              produces = {"text/html"}
          )
          public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
              HttpStatus status = this.getStatus(request);
              Map model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
              response.setStatus(status.value());
              
              //去哪个页面作为错误页面;包含页面地址和页面内容
              ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
              return modelAndView != null ? modelAndView : new ModelAndView("error", model);
          }
      ​
          //生成json数据  其他客户端发送的请求来到这个方法处理
          @RequestMapping
          @ResponseBody
          public ResponseEntity> error(HttpServletRequest request) {
              Map body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
              HttpStatus status = this.getStatus(request);
              return new ResponseEntity(body, status);
          }

     

    ​ 3、ErrorPageCustomizer:

      
      @Value("${error.path:/error}")
      private String path = "/error";  //系统出现错误以后来到error请求进行处理;(类似于web.xml注册的错误页面规则)

    ​ 4、DefaultErrorViewResolver:

      
      public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map model) {
              ModelAndView modelAndView = this.resolve(String.valueOf(status), model);
              if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
                  modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);
              }
      ​
              return modelAndView;
          }
      ​
          private ModelAndView resolve(String viewName, Map model) {
              //默认SpringBoot可以去找到一个页面;  error/404
              String errorViewName = "error/" + viewName;
              
              //模版引擎可以解析这个页面地址 就用模版引擎
              TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);
              //模版引擎可用的情况下返回到errorViewName对应的页面
              //模版引擎不可用,就在静态资源文件夹下找errorViewName对应的页面  error/404
              return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);
          }

     

    步骤:

    ​ 一旦系统出现4xx或者5xx之类的错误;ErrorPageCustomizer就会生效(定制错误的响应规则);就会来到/error请求;就会被BasicErrorController处理;

    ​ 1)、响应页面;去哪个页面是由DefaultErrorViewResolver解析得到的;

    2、如何定制错误响应

    1)、如何定制错误的页面;

    有模版引擎的情况下:error/状态码【将错误页面命名为 错误状态码.html放在模版引擎error文件夹下】

    ​ 我们可以使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,精确优先(优先寻找精确的状态码.html)

    ​ 页面能获取到的信息:

    ​ timestamp:时间戳

    ​ status:状态码

    ​ error:错误提示

    ​ exception:异常对象

    ​ message:异常消息

    ​ errors:JSR303数据校验的错误都在这里

    如果没有模版引擎:(模版引擎找不到这个错误页面),静态资源文件下找

    以上都没有错误页面:就默认来到SpringBoot默认的错误提示页面

     

    2)、如何定制错误的json数据;

    ​ 1)、自定义异常处理&返回定制json数据;

      
      @ControllerAdvice
      public class MyExceptionHandler {
      ​
          @ResponseBody
          @ExceptionHandler(Exception.class)
          public Map handleException(Exception e){
              Map map = new HashMap();
              map.put("code","user.notexist");
              map.put("message",e.getMessage());
              return map;
          }
      }
      //没有自适应效果。。。
      ​

    ​ 2)、转发到/error进行自适应响应效果处理

      
      @ExceptionHandler(Exception.class)
      public String handleException(Exception e, HttpServletRequest request){
          Map map = new HashMap();
      ​
          //传入我们自己的错误状态码  4xx 5xx   否则就不会进入定制错误页面的解析流程
          request.setAttribute("javax.servlet.error.status_code",400);
      ​
      ​
          map.put("code","user.notexist");
          map.put("message",e.getMessage());
          //转发到/error
          return "forward:/error";
      }

    3)、将我们的定制数据携带出去;

    出现错误以后,回来到/error请求,会被BasicErrorController处理,响应出去可以获取的数据是由getErrorAttributes()得到的(是AbstractErrorController(ErrorController)规定的方法);

    ​ 1、完全编写一个ErrorController的实现类【或者是编写AbstractErrorController的子类】,放在容器中;

    ​ 2、页面上能用的数据,或者是json返回能用的数据,都是通过errorAttributes.getErrorAttributes得到的;

    ​ 容器中DefaultErrorAttributes默认进行数据处理的;

    ​ 自定义的ErrorAttributes

      
      //给容器中加入我们自己定义的ErrorAttributes
      @Component
      public class MyErrorAttributes extends DefaultErrorAttributes {
      ​
          //返回值的map就是页面和json能获取的所有字段
          @Override
          public Map getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
              Map errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
              errorAttributes.put("错误信息","错误信息的内容");
      ​
              //我们异常处理器携带的数据
              Map ext = (Map) requestAttributes.getAttribute("ext", 0);
              errorAttributes.put("ext",ext);
      ​
              return errorAttributes;
          }
      }
      ​

    最终的效果:响应是自适应的,可以通过定制ErrorAttributes改变需要返回的内容;

    7、配置嵌入式Servlet容器

    SpringBoot默认使用Tomcat作为嵌入式的Servlet容器;

     

    问题?

    1)、如何定制和修改Servlet容器的相关配置;

    1、修改和server有关的配置(ServerProperties【也是EmbeddedServletContainerCustomizer】)

      
      server:
        context-path: /crud
        port: 8080
        tomcat:
          uri-encoding: UTF-8
        
      #通用的Servlet容器的设置   server.xxx
      #Tomcat的设置    server.tomcat.xxx

    2、编写一个EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定制器;来修改Servlet其他的一些配置

      
      @Bean
      public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
          return new EmbeddedServletContainerCustomizer() {
              //定制嵌入式的Servlet容器相关的规则
              @Override
              public void customize(ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) {
                  configurableEmbeddedServletContainer.setPort(8080);
                  //...
              }
          };
      }

    2)、注册Servlet三大组件【Servlet、Filter、Listener】

    由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启东SpringBoot的web应用,没有web.xml文件。

    注册三大组件用以下方式:

    ServletRegistrationBean

    编写一个Servlet

      
      public class MyServlet extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doPost(req, resp);
          }
      ​
          @Override
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              response.getWriter().append("hello my servlet");
          }
      }
      
      //注册Servlet
      @Bean
      public ServletRegistrationBean servletRegistrationBean(){
          ServletRegistrationBean servletRegistrationBean =
              new ServletRegistrationBean(new MyServlet(),"/myServlet");
          return servletRegistrationBean;
      }

     

    FilterRegistrationBean

      
      public class MyFilter implements Filter {
          @Override
          public void init(FilterConfig filterConfig) throws ServletException { }
          @Override
          public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
              System.out.println("my filter process");
              filterChain.doFilter(servletRequest,servletResponse);
          }
          @Override
          public void destroy() { }
      }
      
      //注册filter
      @Bean
      public FilterRegistrationBean filterRegistrationBean(){
          FilterRegistrationBean filterRegistrationBean =
                  new FilterRegistrationBean();
          filterRegistrationBean.setFilter(new MyFilter());
          filterRegistrationBean.setUrlPatterns(Arrays.asList("/myServlet","/hello"));
          return filterRegistrationBean;
      }

    ServletListenerRegistrationBean

      
      public class MyListener implements ServletContextListener {
          @Override
          public void contextInitialized(ServletContextEvent servletContextEvent) {
              System.out.println("contextInitialized...web 应用启动了...");
          }
          @Override
          public void contextDestroyed(ServletContextEvent servletContextEvent) {
              System.out.println("contextDestroyed...web应用销毁了...");
          }
      }
      
      //注册listener
      @Bean
      public ServletListenerRegistrationBean servletListenerRegistrationBean(){
          ServletListenerRegistrationBean servletListenerRegistrationBean =
              new ServletListenerRegistrationBean(new MyListener());
          return servletListenerRegistrationBean;
      }

     

    2)、SpringBoot能不能支持其他的Servlet容器;

    3)、替换为其他嵌入式Servlet容器

     

    Tomcat(默认使用)

    Undertow(不支持JSP,并发性能好)

    Jetty(适合长连接,入聊天程序)

     

    切换至jetty

      
      
      
          org.springframework.boot
          spring-boot-starter-web
          
              
                  spring-boot-starter-tomcat
                  org.springframework.boot
              
          
      
      
          spring-boot-starter-jetty
          org.springframework.boot
      

    切换至Undertow

      
      
      
          org.springframework.boot
          spring-boot-starter-web
          
              
                  spring-boot-starter-tomcat
                  org.springframework.boot
              
          
      
      
          spring-boot-starter-undertow
          org.springframework.boot
      

    8、使用外置的Servlet容器

    嵌入式Servlet容器:

    ​ 优点:简单、便携;

    ​ 缺点:默认不支持JSP、优化定制比较复杂(使用定制器,自己编写嵌入式Servlet容器的创建工厂);

    【跳过】

    五、Docker

    1、简介

    Docker是一个开源的应用引擎;基于Go语言并遵从Apache2.0协议开源。

    Docker可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。

    容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低。

    Docker支持将软件编译成一个镜像;然后在镜像中各种软件做好配置,将镜像发布出去,其他使用者可以直接使用这个镜像。**运行中的这个镜像称为容器,容器启动时非常快速的。**类似windows里面的ghost操作系统,安装好后很么都有了

    2、核心概念

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

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

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

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

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

     

    使用Docker的步骤:

    1)、安装Docker;

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

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

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

    具体笔记博客Docker分类中;博客地址

     

    六、Spring Boot与数据访问

    1、配置

      
      spring:
        datasource:
          username: yxh_mysql
          password: a
          url: jdbc:mysql://47.110.156.54:3306/travelers
          driver-class-name: com.mysql.jdbc.Driver

    配置效果:

    ​ 默认使用的是org.apache.tomcat.jdbc.pool.DataSource数据源

    ​ 数据源的相关配置都在DataSourceProperties里面;

    2、配置Druid

    引入数据源:

      
      
      
          com.alibaba
          druid
          1.1.10
      

    application.yml:

      
      spring:
        datasource:
          username: yxh_mysql
          password: a
          url: jdbc:mysql://47.110.156.54:3306/travelers
          driver-class-name: com.mysql.jdbc.Driver
          type: com.alibaba.druid.pool.DruidDataSource
      ​
          initialSize: 5
          minIdle: 5
          maxActive: 20
          maxWait: 60000
          timeBetweenEvictionRunsMillis: 60000
          minEvictableIdleTimeMillis: 300000
          validationQuery: SELECT 1 FROM DUAL
          testWhileIdle: true
          testOnBorrow: false
          testOnReturn: false
          poolPreparedStatements: true
          filters: stat,wall,log4j
          maxPoolPreparedStatementPerConnectionSize: 20
          useGlobalDataSourceStat: true
          connectionProperties: druid.stat.mergeSql=true;druid.stat.showSqlMillis=500

    配置类:

      
      @Configuration
      public class DruidConfig {
      ​
          @ConfigurationProperties(prefix = "spring.datasource")
          @Bean
          public DataSource druid(){
              return new DruidDataSource();
          }
      ​
          //配置Druid的监控
          //1、配置一个管理后台的Servlet
          @Bean
          public ServletRegistrationBean statViewServlet(){
              ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
              Map map = new HashMap();
              map.put("loginUsername","admin");
              map.put("loginPassword","123456");
              map.put("allow","");  //默认就是允许所有访问
              map.put("deny","127.0.0.1");  //不让这个IP地址访问
              bean.setInitParameters(map);
              return bean;
          }
          //2、配置一个监控的filter
          @Bean
          public FilterRegistrationBean webStatFilter(){
              FilterRegistrationBean bean = new FilterRegistrationBean();
              bean.setFilter(new WebStatFilter());
      ​
              Map map = new HashMap();
              map.put("exclusions","*.js,*.css,/druid/*");  //不能拦截的请求
              bean.setInitParameters(map);
      ​
              bean.setUrlPatterns(Arrays.asList("/*"));
      ​
              return bean;
      ​
          }
      }

    访问http://localhost:8080/druid/login.html进入mysql监控网页

    3、整合mybatis

    引入数据源:

      
      
      
          com.alibaba
          druid
          1.1.10
      

    application.yml:

      
      spring:
        datasource:
          username: yxh_mysql
          password: a
          url: jdbc:mysql://47.110.156.54:3306/travelers
          driver-class-name: com.mysql.jdbc.Driver
          type: com.alibaba.druid.pool.DruidDataSource
      ​
          initialSize: 5
          minIdle: 5
          maxActive: 20
          maxWait: 60000
          timeBetweenEvictionRunsMillis: 60000
          minEvictableIdleTimeMillis: 300000
          validationQuery: SELECT 1 FROM DUAL
          testWhileIdle: true
          testOnBorrow: false
          testOnReturn: false
          poolPreparedStatements: true
          filters: stat,wall,log4j
          maxPoolPreparedStatementPerConnectionSize: 20
          useGlobalDataSourceStat: true
          connectionProperties: druid.stat.mergeSql=true;druid.stat.showSqlMillis=500

    配置类:

     

      
      @Configuration
      public class DruidConfig {
      ​
          @ConfigurationProperties(prefix = "spring.datasource")
          @Bean
          public DataSource druid(){
              return new DruidDataSource();
          }
      ​
          //配置Druid的监控
          //1、配置一个管理后台的Servlet
          @Bean
          public ServletRegistrationBean statViewServlet(){
              ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
              Map map = new HashMap();
              map.put("loginUsername","admin");
              map.put("loginPassword","123456");
              map.put("allow","");  //默认就是允许所有访问
              map.put("deny","127.0.0.1");  //不让这个IP地址访问
              bean.setInitParameters(map);
              return bean;
          }
          //2、配置一个监控的filter
          @Bean
          public FilterRegistrationBean webStatFilter(){
              FilterRegistrationBean bean = new FilterRegistrationBean();
              bean.setFilter(new WebStatFilter());
      ​
              Map map = new HashMap();
              map.put("exclusions","*.js,*.css,/druid/*");  //不能拦截的请求
              bean.setInitParameters(map);
      ​
              bean.setUrlPatterns(Arrays.asList("/*"));
      ​
              return bean;
      ​
          }
      }

    1、注解版:

      
      //指定这是一个操作数据库的mapper
      @Mapper
      public interface UserMapper{
          
          @Select("select * from user where id=#{id}")
          public User getUserById(Integer id);
          
          @Delete("delete from user where id=#{id}")
          public int deleteUserById(Integer id);
          
          //返回主键
          @Options(useGenerateKeys = true,keyProperty = "id")
          @Insert("insert into user(username) values(#{username})")
          public int insertUser(User user);
          
          @Update("update user set username=#{username} where id=#{id}")
          public int updateUser(User user);
      }

    问题:

    数据库中的下划线命名法和javabean中的驼峰命名法的适配:

    解决:

    编写配置类,自定义MyBatis的配置:

      
      //javabean与数据库字段对应
      ​
      @MapperScan("com.yc.springboot.mapper")  //扫描所有的mapper
      @Configuration
      public class MyBatisConfig {
          
          @Bean
          public ConfigurationCustomizer configurationCustomizer(){
              return new ConfigurationCustomizer() {
                  @Override
                  public void customize(org.apache.ibatis.session.Configuration configuration) {
                      configuration.setMapUnderscoreToCamelCase(true);
                  }
              };
          }
      }

    2、配置文件版

    MyBatis官方文档

    1)、mybatis的全局配置文件:文件名:

     

      
      
      
      
          
              
              
          
      

     

    2)、mapper.xml配置

     

      
      
      
      
          
      

    3)、全局配置文件application.yml文件中添加配置:

      
      mybatis:
        config-location: classpath:mybatis/mybatis-config.xml
        mapper-locations: classpath:mybatis/mapper/*.xml

    4、整合JPA

    JPA:ORM(Object Relational Mapping);

    1)、编写一个实体类(bean)和数据表进行映射,并且配置好映射;

      
      //使用JPA注解配置映射关系
      ​
      @Entity  //告诉JPA这是一个实体类
      @Table(name="users")  //@Table指定和那个数据表对应  如果省略默认表名就是users
      @Data
      public class Users {
      ​
          @Id  //标注这是主键
          @GeneratedValue(strategy = GenerationType.IDENTITY)  //自增主键
          private Integer userId;
      ​
          @Column(name="user_username",length = 50)  //这是和数据表对应的一个列
          private String userUsername;
      ​
          @Column(name="user_password")   //省略默认列名就是属性名
          private String userPassword;
      }

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

      
      //JpaRepository  JpaRepository<对象,主键类型>
      public interface UsersRepository extends JpaRepository {
      ​
      }

    3)、基本的配置application.yml

      
      spring:
        datasource:
          url: jdbc:mysql://47.110.156.54:3306/travelers
          username: yxh_mysql
          password: a
          driver-class-name: com.mysql.jdbc.Driver
        jpa:
          hibernate:
            #更新或者创建数据表结构
            ddl-auto: update
          #在控制台可以看到sql
          show-sql: true

    4)、测试

      
      @Autowired
      private UsersRepository usersRepository;
      ​
      @Test
      public void contextLoads() {
          List all = usersRepository.findAll();
          System.out.println(all);
      }

    七、Spring Boot启动配置原理

    八、Spring Boot自定义starter

     

    你可能感兴趣的:(Spring,springboot)