SpringBoot 的基本使用


创建一个maven工程
  • 创建 maven 工程
  • 导入相关依赖jar包
    <!-- Inherit defaults from Spring Boot -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>

    <!-- Add typical dependencies for a web application -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
  • 编写一个主程序,启动Spring Boot应用
//该类必须与Controller包同层
@SpringBootApplication
public class HelloWordMainApplication {
    public static void main(String[] args) {
        //启动Spring
        SpringApplication.run(HelloWordMainApplication.class,args);
    }
}
  • 编写相关的 Controller 和 Service
@Controller
public class HelloController {
    @ResponseBody
    @RequestMapping("/hello")
    public String hello(){
        return "Hello World";
    }
}
  • 简化部署工作
<!-- 这个插件,可以把应用打包成一个可执行的jar包,放到 pom.xml 文件中 -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


    <!--可以在maven中的生命周期里打成jar包,然后在cmd命令行中启动该jar包-->
    cd Dessktop
    java -jar spring-boot-01-helloword-1.0-SNAPSHOT.jar
    <!--最终可以通过访问 http://localhost:8080/hello 直接访问后台,不需要项目名-->

探究Hello World

  • POM文件(都可以点进去看)
    <!--父项目-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/>
    </parent>
    
    <!--父项目还依赖另一个父项目,由该项目来中的 <properties> 属性来管理spring boot所有的依赖版本,也称为Spring Boot 的仲裁中心,因此以后导入依赖默认不需要写版本号(没有在里面管理就要写版本号) -->
    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
    </parent>
  • 依赖导入
    • spring-boot-starter:Spring Boot 场景启动器,帮我们导入了web模块正常启动所依赖的组件
    <!-- Spring Boot 将所有的功能场景都抽取出来,做成一个个的starters(启动器),只需要在项目里面引入这些starter相关场景的所有依赖都会导入进来。需要导入什么功能就导入什么场景启动器 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

主程序类、主入口类

  • @SpringBootApplication:Spring Boot 应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot 就应该运行这个类的main方法来启动 SpringBoot 应用
  • @SpringBootConfiguration:修饰@SpringBootApplication,是Spring Boot 的配置类,可以标记在某个类上,表示是一个 Spring Boot 配置类
    • @Configuration:修饰@SpringBootConfiguratio,是Spring 配置类注解,该注解也是用 @Component 修饰的,表明是一个组件
@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}
)}
)
  • @EnableAutoConfiguration:开启自动配置功能,以前需要配置的东西Spring已经帮我们自动配置
//EnableAutoConfiguration中的修饰两个注解
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
  • @AutoConfigurationPackage:自动配置包
    • @Import({Registrar.class}):spring的底层注解,给容器中导入组件
      • Registrar.class:将主配置类(@SpringBootApplication)所在包及所有子包所有组件扫描到Spring容器中,所以主配置类要放在与包同级
  • @Import({AutoConfigurationImportSelector.class})
    • AutoConfigurationImportSelector导入哪些组件的选择器,该类中会将需要导入的组件以全类名的方式封装在数组中返回,这些组件会被类加载器在spring.factories中将其添加到容器中,有了这些自动配置类,免去了手动编写注入功能组件等的工作。
    //选择器
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }
  • SpringBoot在启动时会从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效了,帮我们自动进行配置工作
  • C:\Users\DELL.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.2.1.RELEASE\spring-boot-autoconfigure-2.2.1.RELEASE.jar!\META-INF\spring.factories

使用Spring Initializer快速创建SpringBoot项目

IDEA支持Spring项目的创建向导快速创建一个SpringBoot项目,选择所需要的模块,向导会联网创建SpringBoot项目

默认生成的SpringBoot项目
  • 主程序已经写好了,我们只需要导入自己的逻辑
  • resources文件夹目录结构
    • static:保存所有的静态资源,像js、css、images
    • templates:保存所有的模块页面(SpringBoot默认jar包使用嵌入式Tomcat,默认不支持JSP页面),但是可以使用模板引擎(freemarke、thymeleaf)
    • application.properties:SpringBoot应用的配置文件,可以修改一些默认配置,像端口号
  • 配置文件
    • 配置文件名称是固定的(已是默认值,也可手动更改)
      • application.properties
      • application.yml
  • YAML:标记语言(A Markup Language)
    • 以数据为中心进行配置,比xml、json等更适合做配置文件
#application.properties文件配置端口号
server.port=8081

#application.yml文件配置端口号
server:
  port: 8081

配置文件的编写

YAML 语法
  • 基本语法
    • k:(空格)v :表示一对键值对(必须有空格)
    • 空格的缩进来控制层级关系,只要左对齐的一列数据,就都是同一层级的,同时属性和值也是大小写敏感的。
server:
  port: 8081
  path: /hello

值的写法:
  • 字面量:普通的值(数字,字符串,布尔)
    • k:v :字面量直接写入
    • “” : 双引号不会转义字符串里面的特殊字符,特殊字符会作为本身表示的意思
      • name: “zhangshan \n lisi”
      • 输出:zhangsan \n lisi
    • ‘’ : 单引号会转义特殊字符,特殊字符最终只是一个普通的字符串数据
      • name: “zhangshan \n lisi”
      • 输出:zhangsan 换行 lisi
  • 对象、Map(属性和值)(键值对):k: v : 在下一行来写对象的属性和值的关系,注意缩进
    • 分行写法:注意缩进
    • 行内写法:大括号,里面键值对间有空格
#分行写法
friends:
    lastName:zhangsan
    age:20
#行内写法
friends: {lastName: zhangsan,age: 20}
  • 数组:用 - 值表示数组中的元素
    • 分行写法:注意缩进
    • 行内写法:中括号,里面对象间有空格
#分行写法
pets:
 - cat
 - dog
 - pig
#行内写法
pets: [cat,dog,pig]

配置文件值注入

配置文件:全局变量

person:
  name: zhangsan
  age: 20

pom.xml

  • 导入配置文件处理器,以后编写配置文件就会有提示了
        <!--配置数据源的jar包(配置文件处理器),将配置文件值注入对象-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <version>2.1.7.RELEASE</version>
            <optional>true</optional>
        </dependency>

JavaBean

  • 将配置文件配置的每一个属性的值,映射到这个组件中
  • @ConfigurationProperties(prefix = “person”):告诉springboot将本类中的所有属性和配置文件中相关的配置进行绑定
  • prefix = “person”:这个是指配置文件中哪个下面的所有属性进行一一映射
  • 同时只有是容器中的组件才能使用 @ConfigurationProperties(prefix = “person”),所有要加入注释 @Component
  • @Value():标注一个属性,注入属性值
/**
 * @author Ming
 * @date 2019/11/14 - 22:48
 * 将配置文件配置的每一个属性的值,映射到这个组件中
 * @ConfigurationProperties(prefix = "person"):告诉springboot将本类中的所有属性和配置文件中相关的配置进行绑定
 * prefix = "person":这个是指配置文件中哪个下面的所有属性进行一一映射
 * 同时只有是容器中的组件才能使用 @ConfigurationProperties(prefix = "person"),所有要加入注释 @Component
 */
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    //...getter和setter方法...
    }


//也可以    
@Component
public class Person {
    @Email
    @Value("${person.name}")
    private String name;
    @Value("#{11*5}")
    private Integer age;
    private Map<String,Object> map;
    }
    
@Configurationproperties@Value
功能批量注入配置文件属性只能注入一个属性值
松散绑定(eg:last-name)支持不支持
SpEL不支持支持
JSR303数据校验支持不支持
复杂类型封装支持不支持

@PropertySource和@ImportResource

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

//person上的注解
@PropertySource(value = "classpath:person.properties")

//person.properties文件上的内容
person.name=李四person.properties
person.map.hhh='123'
person.map.k2=321

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

//标注在主配置类上,让配置文件生效
@ImportResource(location={"classpath:beans.xml"})

SpringBoot推荐给容器中添加组件的方式:不推荐使用xml文件,而使用配置类(注解方式)

  • 配置类==Spring配置文件
  • 使用@Bean向容器中添加组件,id就是标注注解的类名称,返回啥就向容器中添加啥
/**
 * @author Ming
 * @date 2019/11/24 - 23:18
 * @Configration:指明当前类是一个配置类,就是用来代替之前的Spring配置文件
 * 在配置类中的@Bean就相当于<bean></bean>,且 id 等于类的名称,返回啥就向容器添加啥
 */
@Configuration
public class MyApplicationConfig {

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

配置文件占位符

随机数:{random.int}、{random.uuid}、{random.int[1024,65536]}…
占位符获取之前配置的值,如果没有可以用冒号(:)指定默认值以防止报错

person.name=李四${random.uuid}
person.map.hhh='123'
person.map.k2=${person.name}

Profile

1、多Profile文件

  • 我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml,默认使用application.properties的配置
  • yml支持多文档块方式
    • 可以用—分开文档块,然后用active来激活
server:
    port: 8081
spring:
    profile:
        active:dev
---
server:
    port: 8081
spring:
    profiles:dev
---
server:
    port: 8084
spring:
    profiles: prod
  • 激活指定Pofile
    • 在配置文件的指定
    • 命令行激活:在配置里的Program arguments行中:–spring.profiles.active=dev
    • cmd命令行:java -jar jar包名称 --spring.profiles.active=dev
    • 虚拟机参数写法:在 VM options中配置:-Dspring.profiles.active=dev
<!-- 在application.properties中指定,dev也就是{profile}的值 -->
spring.profiles.active=dev
<!-- 在 VM options中指定,dev也就是{profile}的值 -->
-Dspring.profiles.active=dev

配置文件加载位置

可识别位置(有优先级):高优先级会覆盖低优先级

  • file:./config/
  • file:./
  • classpath:/config/
  • classpath:/

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


外部配置加载顺序
  • 命令行参数
java -jar spring-boot-01-helloword-1.0-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc
  • 1.来自java:comp/env的NDI属性
  • 2.java系统属性(System.getProperties())
  • 3.操作系统环境变量
  • RandomValuePropertySource配置的random.*属性值

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

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

再来加载不带profile

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

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

  • 8.@Configuration注解类上的@PropertySource

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


web开发

自动配置原理

SpringBoot提供配置文件的属性配置相关文档

自动配置原理

  • SpringBoot启动时加载自动配置类,开启了自动配置功能@EnableConfiguration
//扫描jar包类路径下META-INF/spring.factories,将扫描到的这些文件的内容整合成properties对象
//再从properties中获取到EnableConfiguration.class类(类名)对应的值
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }
    
//被调用的SpringFactoriesLoader加载器    
public final class SpringFactoriesLoader {
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
    private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap();

    private SpringFactoriesLoader() {
    }    
# 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.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveRestClientAutoConfiguration,\
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.rsocket.RSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\
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.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
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

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

@Configuration(
    proxyBeanMethods = false
)//表示是一个配置类,以前编写的文件一样,也可以给容器中添加组件
@EnableConfigurationProperties({HttpProperties.class})//启动指定类的ConfigurationProperties功能,将配置文件中对应的值和HttpEncodingProperties绑定起来,并且把它加入到IOC容器中
@ConditionalOnWebApplication(
    type = Type.SERVLET
)//Spring底层@Conditional注解,根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效
@ConditionalOnClass({CharacterEncodingFilter.class})//判断当前项目是否有这个配置类 CharacterEncodingFilter,SpringMVC中解决乱码问题的过滤器
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)//判断配置文件是否存在某个配置,如果不存在,判断也是成立的,即使不配置,也是默认生效的
public class HttpEncodingAutoConfiguration {
    //已经和SpringBoot配置文件映射了
    private final Encoding properties;

    //只有一个有参构造器的情况下,参数的值会从容器中拿
    public HttpEncodingAutoConfiguration(HttpProperties properties) {
        this.properties = properties.getEncoding();
    }

    @Bean//给容器中添加组件,组件的某些值需要从容器中拿
    @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;
    }

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

@ConfigurationProperties(
    prefix = "spring.http"
)//从配置文件中获取指定的值和bean属性进行绑定
public class HttpProperties {
使用精髓:
  • SpringBoot启动会自动加载大量的配置类

  • 首先看我们所需要的功能有没有SpringBoot默认写好的自动配置类

  • 有的话可以看这个自动配置类到底配置了哪些的组件(有的话就可以不用配了)

  • 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值
    自动配置类需要一定条件才能生效
    xxxxAutoConfiguration:自动配置类,给容器中添加组件
    xxxxProperties:封装配置文件中相关的属性值

  • 可以通过debug=true 属性来查看自动配置类是否生效


日志框架

市面上的框架:JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j

日志门面(日志抽象层)日志实现
JCL、SLF4j、jboss-loggingLog4j、JUL、Log4j2、Logback

SpringBoot底层是Spring框架,Spring框架使用的是JCL。然而SpringBoot使用的是SLF4J和logback


日志配置

    Logger logger = LoggerFactory.getLogger(getClass());
    @Test
    void contextLoads() {
        //日志级别 由低到高trace<debug<info<warm<error
        //可以调整输出级别就可以在这个级别和更高级别输出
        //Spring默认级别是info级别
        logger.trace("trace日志");
        logger.debug("debug日志");
        logger.info("info日志");
        logger.warn("warm日志");
        logger.error("error日志");
    }

可以调节日志级别

#logging.level.+包名=级别名称
logging.level.com.springboot=trace
#在当前项目下生成springboot.log日志,不指定路径默认在根目录下
logging.file.name=D:/SpringBoot.log
#在项目当前磁盘根目录下创建也就是D盘
logging.path=/spring/log
#在控制台输出的格式,默认为时间+日志级别+线程Id+类名+信息
#logging.pattern.console=
#指定文件中日志输出格式
#logging.pattern.file=

SpringBoot对前端的支持


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(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                }

            }
        }
        
        //配置欢迎页映射
        @Bean
        public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
            WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
            welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
            return welcomePageHandlerMapping;
        }
  • 所有的 /webjars/** 都去classpath:/META-INF/resource/webjars/找资源
    • webjars:以jar包的形式引入静态资源,引入需要在xml文件中引入
    • http://localhost:8080/webjars/jquery/3.4.1/jquery.js

https://www.webjars.org/

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.4.1</version>
        </dependency>
  • /**,访问当前项目的任何资源
"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"
  • 欢迎页:静态资源文件夹下的所有index.html。被“/**”映射
    local
    • 放在resources/public文件下
    • css等放在resources/static下
    • 图标放在resources/resources下
    • 也可在application.properties中配置spring.resources
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,classpath:/


SpringBoot模板引擎
  • SpringBoot推荐是使用Thymeleaf模板引擎:语法简单,功能强大
    <!-- 修改版本号,thymeleaf3.+,layout2.+ -->
    <properties>
        <java.version>1.8</java.version>
        <!--<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>-->
        <thymeleaf-layout-dialect.version>2.2.1</thymeleaf-layout-dialect.version>
    </properties>
    
    <!-- 映入版本starter,默认是2点多版本 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

  • 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";
    private Charset encoding;
    private boolean cache;
    private Integer templateResolverOrder;
    private String[] viewNames;
    private String[] excludedViewNames;
    private boolean enableSpringElCompiler;
    private boolean renderHiddenMarkersBeforeCheckboxes;
    private boolean enabled;
    private final ThymeleafProperties.Servlet servlet;
    private final ThymeleafProperties.Reactive reactive;
    
    
    @RequestMapping("/success")
    public String success(){
        //解析完访问classpath:/templates/success.html
        //不能加ResponseBody,否则封装为字符串了
        return "success";
    }
  • 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>-->
<div th:text="${hello}">如果没有后端,则显示这些内容</div>
</body>
</html>
  • 3、语法规则
    • th:text:改变元素里面的文本内容
    • th:可以用其替换掉容易元素原先的值
  • 4、表达式语法
Simple expressions: (表达式语法)
    Variable Expressions:${...} 获取变量值,OGNL表达式
        1.获取属性值、调用方法
        2.使用内置的基本对象
        3.内置的工具对象
    Selection Variable Expressions: *{...} :和 ${} 功能一样
        1、补充:配合 th:object 使用
        <div th:object="${session.user}"> 
            <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p> 
            <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p> 
            <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
        </div>
    Message Expressions: #{...} :获取国际化内容
    Link URL Expressions: @{...} :定义 url 链接
        <!-- Will produce 'http://localhost:8080/gtvg/order/details?orderId=3' (plus rewriting) -->
        <a href="details.html" th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a> 
        <!-- Will produce '/gtvg/order/details?orderId=3' (plus rewriting) --> 
        <a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>
        <!-- Will produce '/gtvg/order/3/details' (plus rewriting) -->
        <a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>
    Fragment Expressions: ~{...} :片段引用表达式
    
Literals (字面量)
    Text literals: 'one text' , 'Another one!' ,… 
    Number literals: 0 , 34 , 3.0 , 12.3 ,… 
    Boolean literals: true , false 
    Null literal: null 
    Literal tokens: one , sometext , main ,… 
    
Text operations:(文本操作)
    String concatenation: + 
    Literal substitutions: |The name is ${name}| 
    
Arithmetic operations: (数学运算)
    Binary operators: + , - , * , / , % 
    Minus sign (unary operator): - 
    
Boolean operations: (布尔运算)
    Binary operators: and , or 
    Boolean negation (unary operator): ! , not
    
Comparisons and equality: (比较运算)
    Comparators: > , < , >= , <= ( gt , lt , ge , le ) 
    Equality operators: == , != ( eq , ne )
    
Conditional operators: (条件运算:比如三元运算符)
    If-then: (if) ? (then) 
    If-then-else: (if) ? (then) : (else) 
    Default: (value) ?: (defaultvalue) 
    
Special tokens: (特殊运算符)
    No-Operation:_

SpringMVC自动配置

Spring Boot为Spring MVC提供了自动配置,可与大多数应用程序完美配合。

自动配置在Spring的默认值之上添加了以下功能:

  • 包含ContentNegotiatingViewResolver和BeanNameViewResolver。
    • 配置 ViewResolver(视图解析器,根据方法的返回值得到视图对象),视图对象决定如何渲染(转发?重定向?)
    • ContentNegotiatingViewResolver :组合所有的视图解析器
    • 如何定制和添加一个视图解析器,自动的将其组合进来
  • 支持提供静态资源,包括对WebJars的支持。
  • 自动注册了 Converter,GenericConverter,Formatter豆类
    • Converter:转换器,类型转换使用Converter
    • Formatter:格式化器,如日期的转换
  • 支持HttpMessageConverters
    • 支持HttpMessageConverters:消息转换器,用于转换Http请求和响应的,如User对象转换为Json
    • HttpMessageConverters 是从容器中确定的,从容器中获取所有的HTTP转换器,所以可以自己给容器添加,将自己的组件注册在容器中。
  • 自动注册MessageCodesResolver
    • MessageCodesResolver:定义错误代码生成规则
  • 静态index.html支持:静态首页的访问
  • 定制Favicon支持
  • 自动使用ConfigurableWebBindingInitializer
    • ConfigurableWebBindingInitializer:我们也可以配置一个来替换原有的

如果您想保留Spring Boot MVC功能,而只想添加其他MVC配置(拦截器,格式化程序,视图控制器等),则可以添加自己@Configuration的type类 WebMvcConfigurerAdapter,但不添加 @EnableWebMvc。如果您希望提供的自定义实例RequestMappingHandlerMapping,RequestMappingHandlerAdapter或者 ExceptionHandlerExceptionResolver可以声明一个WebMvcRegistrationsAdapter 提供此类组件的实例。

如果您想完全控制Spring MVC,可以使用添加自己的@Configuration 注释@EnableWebMvc。

如何修改SpringBoot的默认配置
  • SpringBoot 在自动配置很多组件的时候,先看用户是否有自己配置的组件(@Bean、@Component),如果有就用用户自己配置的,如果没有就自动配置。如果有些组件可以有多个(视图解析器)的时候,SpringBoot将用户自己配置的和自身的组合起来
    • 扩展SpringMVC(添加配置类方法)
      • 编写一个配置类,该配置类(@Configuration),是WebMvcConfigurerAdapter类型,不能用 @EnableWebMvc 标注,添加了会使其他的MVC配置类失效
      • 原理:
        • WebMvcAutoConfiguration 是 SpringMVC 的自动配置类
        • 在做其他配置时会导入@ImportWebMvcConfiguration.class
//即保留了原有的自动配置,也能用我们的扩展
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
    //即保留了原有的自动配置,也能用我们的扩展
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
//        super.addViewControllers(registry);
        //浏览器发送 /hello 请求时来到 success.html
        registry.addViewController("hello").setViewName("success");
    }

    @Bean
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
        WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter(){
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                //super.addViewControllers(registry);
                registry.addViewController("/").setViewName("index");
                registry.addViewController("/index.html").setViewName("index");
            }
        };
        return adapter;
    };

}

国际化开发编码
  • 可编写一个配置类来代替原有的国际解析器
    • 1、添加一个配置类来继承 LocaleResolver 接口
    • 2、将该类添加到 MVC 的配置类中
public class MyLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest httpServletRequest) {
        Locale locale = Locale.getDefault();
        String l = httpServletRequest.getParameter("l");
        if(StringUtils.isEmpty(l)){
            String[] spilt =  l.split("_");
            locale = new Locale(spilt[0],spilt[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

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


禁用thymeleaf缓存
  • 1、在配置文件中配置相关信息
  • 2、ctrl+F9
# 禁用模板引擎缓存
spring.thymeleaf.cache=false

拦截器进行登录检查
  • 1、编写一个拦截器
  • 2、将拦截器注册到MVC中
/**
 * @author Ming
 * @date 2020/1/12 - 15:52
 *
 * 登录的拦截检查,要实现HandlerInterceptor 接口
 */
public class MyHandlerInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object obj = request.getSession().getAttribute("loginUser");
        if(obj==null){
            //未登录,拦截,返回登录页面
            request.setAttribute("msg","没有权限,请先登录!");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }else{

            return true;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

=======================

    //MyMvcConfig类,重写方法
    @Bean
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
        WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter(){
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                //super.addViewControllers(registry);
                registry.addViewController("/").setViewName("login");
                registry.addViewController("/index.html").setViewName("login");
                registry.addViewController("/main.html").setViewName("main");
            }

            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                //注册拦截器,拦截所有请求,排除登录页面的请求,静态资源不需要排除
                registry.addInterceptor(new MyHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html","/","/user/login");
            }
        };

        return adapter;
    };

RestfulCRUD操作
  • 1、RestfulCRUD和普通的CRUD区别
普通CRUDRestfulCRUD
查询getEmpemp—GET
添加addEmp?xxxemp—POST
修改updateEmp?id=xxx&xxx=xxemp/{id}—PUT
删除deleteEmp?id=xxemp/{ID}—DELETE
  • 2、SpringBoot 错误处理机制
    • 默认是一个页面,如果不是则返回 JSON 数据
    • 默认给容器中添加了以下组件
      • 1、DefaultErrorAttributes
      • 2、BasicErrorAttributes:处理默认 /error 请求
      • 3、ErrorPageCustomizer:定制错误的响应规则
      • 4、DefaultErrorViewResolver:去哪个页面
    @RequestMapping(
        produces = {"text/html"}
    )//产生 Html 数据,浏览器来到这个处理
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = this.getStatus(request);
        Map<String, Object> 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);
    }

    @RequestMapping//产生 Json 数据,其他客户端用这个处理
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        HttpStatus status = this.getStatus(request);
        if (status == HttpStatus.NO_CONTENT) {
            return new ResponseEntity(status);
        } else {
            Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
            return new ResponseEntity(body, status);
        }
    }
    //DefaultErrorViewResolver:去哪个页面
    public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
        ModelAndView modelAndView = this.resolve(String.valueOf(status.value()), 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<String, Object> model) {
        //默认SpringBoot可以去到哪一个页面?error/404
        String errorViewName = "error/" + viewName;
        
        //模板引擎可以解析这个页面地址就用模板引擎解析
        TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);
        
        //模板引擎可用和不可用调用不同的方法
        return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);
    }
  • 一旦出现 4xx 或者 5xx 之类的错误,ErrorPageCustomizer会生效(定制错误的响应规则),就会来到 error 请求,就会被 BasicErrorAttributes 处理
//响应页面
protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
        Iterator var5 = this.errorViewResolvers.iterator();

        ModelAndView modelAndView;
        do {
            if (!var5.hasNext()) {
                return null;
            }

            ErrorViewResolver resolver = (ErrorViewResolver)var5.next();
            modelAndView = resolver.resolveErrorView(request, status, model);
        } while(modelAndView == null);

        return modelAndView;
    } 
  • 2、如何定制错误的页面
    • 1、有模板引擎的情况下,在 templates 下建立一个子文件夹 error,在里面放置一个名字为 404.html(相应的状态码400、500…) 的页面即可。
    • 2、如果没有匹配到可以在error文件夹下,可以放置一个4xx.html 和 5xx.html 去到没有被匹配到的(优先精确寻找状态码页面)
    • 3、能取出的错误共享信息:时间戳(timestamp)、状态码(status)、错误提示(error)、异常对象(exception)、异常消息(message)、JSR303数据校验(errors)
  • 3、如何定制错误的 Json 数据
  • 需要将我们定制的数据携带出去
    • 出现错误以后,会来到 /error 请求,会被BasicErrorController处理,相应出去可以获取的数据是由getErrorAttributes得到的(是AbstractError(ErrorController)规定的方法)
      • 1、完全来编写一个ErrorController的实现类(或者编写AbstractErrorController的子类),放在容器中
      • 2、页面上能用的数据,或者是json返回能用的数据都是通过errorAttributes.getAttributes()方法得到的
@ControllerAdvice
public class MyExceptionHandler {

    /**
     * 可达到自适应效果的错误请求处理
     * @param e 错误
     * @param request 原生的request
     * @return 返回页面,模板引擎解析
     */
    @ExceptionHandler(UserException.class)
    public String handleException(Exception e, HttpServletRequest request){
        Map<String ,Object> map = new HashMap<>(8);
        map.put("data","放置的错误消息数据");
        map.put("message",e.getMessage());
        //设置状态码,然后转发
        map.put("javax.servlet.error.status_code",500);
        request.setAttribute("ext",map);
        //转发到 /error
        return "forward:/error";
    }
}

============================================================

@ControllerAdvice
public class MyExceptionHandler {

    /**
     * 可达到自适应效果的错误请求处理
     * @param e 错误
     * @param request 原生的request
     * @return 返回页面,模板引擎解析
     */
    @ExceptionHandler(UserException.class)
    public String handleException(Exception e, HttpServletRequest request){
        Map<String ,Object> map = new HashMap<>(8);
        map.put("data","放置的错误消息数据");
        map.put("message",e.getMessage());
        //设置状态码,然后转发
        map.put("javax.servlet.error.status_code",500);
        request.setAttribute("ext",map);
        //转发到 /error
        return "forward:/error";
    }
}

嵌入式 Servlet 容器

注册三大组件
  • 1、修改和定制一个Servlet容器的相关配置
    • (1)、修改和server有关的配置(ServerProperties)
    • (2)、编写一个EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定制器
    @Bean
    public WebServerFactoryCustomizer webServerFactoryCustomizer(){
        return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
            @Override
            public void customize(ConfigurableWebServerFactory factory) {
                factory.setPort(8082);
            }
        };
    }

  • 2、由于SpringBoot默认是以jar包方式启动嵌入式 Servlet 容器来启动SpringBoot的web应用,没有web.xml文件
    • 注册三大组件用以下方式(Servlet、Filter、Listener)
      • 1、ServletRegistrationBean
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("Hello MyServlet");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("Hello MyServlet");
    }
}

    /**
     * 注册Servlet组件
     * @return ServletRegistrationBean
     */
    @Bean
    public ServletRegistrationBean myServlet(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
        return registrationBean;
    }
///    
   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("MyFilter process...");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

    /**
     * 注册拦截器
     * @return FilterRegistrationBean
     */
    @Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new MyFilter());
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/myServlet","/myFilter"));
        return filterRegistrationBean;
    }
///    
public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized...web应用启动");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyed...web应用销毁");
    }
}    

    /**
     * 注册监听器
     * @return ServletListenerRegistrationBean
     */
    @Bean
    public ServletListenerRegistrationBean myListener(){
        ServletListenerRegistrationBean<MyListener> listenerRegistrationBean = new ServletListenerRegistrationBean<>(new MyListener());
        return listenerRegistrationBean;
    }
使用其他Servlet容器
  • SpringBoot支持的Servlet容器
    • Jetty(长链接应用)
    • Undertow(不支持jsp):高性能,非阻塞
  • 切换其他服务器
    • 1、在生成树(或者pom.xml文件)中去除服务器的相关依赖
    • 2、导入相关依赖
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        
        <!--引入其他的Servlet容器-->
		<dependency>
			<artifactId>spring-boot-starter-undertow</artifactId>
			<groupId>org.springframework.boot</groupId>
		</dependency>

嵌入式Servlet容器自动配置原理
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
//导入BeanPostProcessorsRegistrar:Spring注解版;给容器中导入一些组件
//导入了EmbeddedServletContainerCustomizerBeanPostProcessor:
//后置处理器:bean初始化前后(创建完对象,还没赋值赋值)执行初始化工作
public class EmbeddedServletContainerAutoConfiguration {
    
    @Configuration
	@ConditionalOnClass({ Servlet.class, Tomcat.class })//判断当前是否引入了Tomcat依赖;
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)//判断当前容器没有用户自己定义EmbeddedServletContainerFactory:嵌入式的Servlet容器工厂;作用:创建嵌入式的Servlet容器
	public static class EmbeddedTomcat {

		@Bean
		public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
			return new TomcatEmbeddedServletContainerFactory();
		}

	}
/SpringBoot 2.0后
@Configuration(
    proxyBeanMethods = false
)
@AutoConfigureOrder(-2147483648)
@ConditionalOnClass({ServletRequest.class})
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@EnableConfigurationProperties({ServerProperties.class})
@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, EmbeddedTomcat.class, EmbeddedJetty.class, EmbeddedUndertow.class})
public class ServletWebServerFactoryAutoConfiguration {
    public ServletWebServerFactoryAutoConfiguration() {
    }
	
  • 步骤:

    • 1)、SpringBoot根据导入的依赖情况,给容器中添加相应的EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】

    • 2)、容器中某个组件要创建对象就会惊动后置处理器;EmbeddedServletContainerCustomizerBeanPostProcessor;只要是嵌入式的Servlet容器工厂,后置处理器就工作;

    • 3)、后置处理器,从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法


自动配置原理(细)

EmbeddedServletContainerAutoConfiguration:嵌入式的Servlet容器自动配置?

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
//导入BeanPostProcessorsRegistrar:Spring注解版;给容器中导入一些组件
//导入了EmbeddedServletContainerCustomizerBeanPostProcessor:
//后置处理器:bean初始化前后(创建完对象,还没赋值赋值)执行初始化工作
public class EmbeddedServletContainerAutoConfiguration {
    
    @Configuration
	@ConditionalOnClass({ Servlet.class, Tomcat.class })//判断当前是否引入了Tomcat依赖;
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)//判断当前容器没有用户自己定义EmbeddedServletContainerFactory:嵌入式的Servlet容器工厂;作用:创建嵌入式的Servlet容器
	public static class EmbeddedTomcat {

		@Bean
		public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
			return new TomcatEmbeddedServletContainerFactory();
		}

	}
    
    /**
	 * Nested configuration if Jetty is being used.
	 */
	@Configuration
	@ConditionalOnClass({ Servlet.class, Server.class, Loader.class,
			WebAppContext.class })
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedJetty {

		@Bean
		public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
			return new JettyEmbeddedServletContainerFactory();
		}

	}

	/**
	 * Nested configuration if Undertow is being used.
	 */
	@Configuration
	@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedUndertow {

		@Bean
		public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() {
			return new UndertowEmbeddedServletContainerFactory();
		}

	}

1)、EmbeddedServletContainerFactory(嵌入式Servlet容器工厂)

public interface EmbeddedServletContainerFactory {

   //获取嵌入式的Servlet容器
   EmbeddedServletContainer getEmbeddedServletContainer(
         ServletContextInitializer... initializers);

}

2)、EmbeddedServletContainer:(嵌入式的Servlet容器)

3)、以TomcatEmbeddedServletContainerFactory为例

@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
      ServletContextInitializer... initializers) {
    //创建一个Tomcat
   Tomcat tomcat = new Tomcat();
    
    //配置Tomcat的基本环节
   File baseDir = (this.baseDirectory != null ? this.baseDirectory
         : createTempDir("tomcat"));
   tomcat.setBaseDir(baseDir.getAbsolutePath());
   Connector connector = new Connector(this.protocol);
   tomcat.getService().addConnector(connector);
   customizeConnector(connector);
   tomcat.setConnector(connector);
   tomcat.getHost().setAutoDeploy(false);
   configureEngine(tomcat.getEngine());
   for (Connector additionalConnector : this.additionalTomcatConnectors) {
      tomcat.getService().addConnector(additionalConnector);
   }
   prepareContext(tomcat.getHost(), initializers);
    
    //将配置好的Tomcat传入进去,返回一个EmbeddedServletContainer;并且启动Tomcat服务器
   return getTomcatEmbeddedServletContainer(tomcat);
}

4)、我们对嵌入式容器的配置修改是怎么生效?

ServerProperties、EmbeddedServletContainerCustomizer

EmbeddedServletContainerCustomizer:定制器帮我们修改了Servlet容器的配置?

怎么修改的原理?

5)、容器中导入了EmbeddedServletContainerCustomizerBeanPostProcessor

//初始化之前
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
      throws BeansException {
    //如果当前初始化的是一个ConfigurableEmbeddedServletContainer类型的组件
   if (bean instanceof ConfigurableEmbeddedServletContainer) {
       //
      postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
   }
   return bean;
}

private void postProcessBeforeInitialization(
			ConfigurableEmbeddedServletContainer bean) {
    //获取所有的定制器,调用每一个定制器的customize方法来给Servlet容器进行属性赋值;
    for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
        customizer.customize(bean);
    }
}

private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
    if (this.customizers == null) {
        // Look up does not include the parent context
        this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
            this.beanFactory
            //从容器中获取所有这葛类型的组件:EmbeddedServletContainerCustomizer
            //定制Servlet容器,给容器中可以添加一个EmbeddedServletContainerCustomizer类型的组件
            .getBeansOfType(EmbeddedServletContainerCustomizer.class,
                            false, false)
            .values());
        Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
        this.customizers = Collections.unmodifiableList(this.customizers);
    }
    return this.customizers;
}

ServerProperties也是定制器

步骤:

1)、SpringBoot根据导入的依赖情况,给容器中添加相应的EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】

2)、容器中某个组件要创建对象就会惊动后置处理器;EmbeddedServletContainerCustomizerBeanPostProcessor;

只要是嵌入式的Servlet容器工厂,后置处理器就工作;

3)、后置处理器,从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法

###5)、嵌入式Servlet容器启动原理;

什么时候创建嵌入式的Servlet容器工厂?什么时候获取嵌入式的Servlet容器并启动Tomcat;

获取嵌入式的Servlet容器工厂:

1)、SpringBoot应用启动运行run方法

2)、refreshContext(context);SpringBoot刷新IOC容器【创建IOC容器对象,并初始化容器,创建容器中的每一个组件】;如果是web应用创建AnnotationConfigEmbeddedWebApplicationContext,否则:AnnotationConfigApplicationContext

3)、refresh(context);刷新刚才创建好的ioc容器;

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         initMessageSource();

         // Initialize event multicaster for this context.
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         onRefresh();

         // Check for listener beans and register them.
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // Propagate exception to caller.
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}

4)、 onRefresh(); web的ioc容器重写了onRefresh方法

5)、webioc容器会创建嵌入式的Servlet容器;createEmbeddedServletContainer();

6)、获取嵌入式的Servlet容器工厂:

EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();

从ioc容器中获取EmbeddedServletContainerFactory 组件;**TomcatEmbeddedServletContainerFactory**创建对象,后置处理器一看是这个对象,就获取所有的定制器来先定制Servlet容器的相关配置;

7)、使用容器工厂获取嵌入式的Servlet容器:this.embeddedServletContainer = containerFactory .getEmbeddedServletContainer(getSelfInitializer());

8)、嵌入式的Servlet容器创建对象并启动Servlet容器;

先启动嵌入式的Servlet容器,再将ioc容器中剩下没有创建出的对象获取出来;

IOC容器启动创建嵌入式的Servlet容器


使用外置的Servlet容器

  • 嵌入式Servlet容器:应用打成可执行的jar

  • 优点:简单、便携;

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

外置的Servlet容器:外面安装Tomcat—应用war包的方式打包;

步骤

1)、必须创建一个war项目;(利用idea创建好目录结构)

2)、将嵌入式的Tomcat指定为provided;

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-tomcat</artifactId>
   <scope>provided</scope>
</dependency>

3)、必须编写一个SpringBootServletInitializer的子类,并调用configure方法

public class ServletInitializer extends SpringBootServletInitializer {

   @Override
   protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
       //传入SpringBoot应用的主程序
      return application.sources(SpringBoot04WebJspApplication.class);
   }

}

4)、启动服务器就可以使用


Docker

1、简介

Docker是一个开源的应用容器引擎;是一个轻量级容器技术;

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

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

2、核心概念

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

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

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

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

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


SpringBoot与数据访问


原生JDBC的使用
        <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://116.62.46.122:3306/test?serverTimezone=GMT%2B8&useSSL=false
    driver-class-name: com.mysql.jdbc.Driver

效果:

默认数据源;

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

自动配置原理:

org.springframework.boot.autoconfigure.jdbc:

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

2、SpringBoot默认可以支持;

org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource、

3、自定义数据源类型

/**
 * Generic DataSource configuration.
 */
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {

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

}

4、DataSourceInitializer:ApplicationListener

作用:

	1)、runSchemaScripts();运行建表语句;

	2)、runDataScripts();运行插入数据的sql语句;

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

schema-*.sql、data-*.sql
默认规则:schema.sql,schema-all.sql;
可以使用   
	schema:
      - classpath:department.sql
      指定位置

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


整合Druid数据源
  • 1、导入 Druid 依赖的jar包
        <!--  引入自定义数据源连接池  -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
  • 2、配置相关的yml文件内容
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://116.62.46.122:3306/test?serverTimezone=GMT%2B8&useSSL=false
    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,去掉后监控界面sql无法统计,'wall'用于防火墙
    filters: stat,wall,slf4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
  • 3、配置Druid的配置文件,即可访问 Druid 的监控后台

配合拦截器的链接地址:http://localhost:8080/druid/

//导入druid数据源
@Configuration
public class DruidConfig {

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

    //配置Druid的监控
    // 1、配置一个管理后台的Servlet
    @Bean
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
        Map<String,String> initParam = new HashMap<>(8);

        //配置监控的参数,登录后台的账号密码(eg:用户名,密码等)
        initParam.put("loginUsername","admin");
        initParam.put("loginPassword","123456");
        //默认是允许全部
//        initParam.put("allow","localhost");
        initParam.put("allow","");

        servletRegistrationBean.setInitParameters(initParam);
        return servletRegistrationBean;
    }

    //2、注册一个web监控的过滤器
    @Bean
    public FilterRegistrationBean webStatFilter(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        Map<String,String> initParam = new HashMap<>(8);

        //不拦截那些应用
        initParam.put("exclusions","*.js,*.css,/druid/*");

        filterRegistrationBean.setInitParameters(initParam);
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
        return filterRegistrationBean;
    }

整合 mybatis

基础章
  • 1、导入相关的场景启动器:改启动器为 mybatis 官方为配设 SpringBoot 做的
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>
  • 2、注入 Druid 数据源(参考上一部分):
  • 3、编写相关的接口,加上 @Component 和 @Mapper
    • 插入时,若想获得主键,可增加配置
//@Component 注解可加可不加
@Component
@Mapper //指定这是一个操作数据库的mapper
public interface UserMapper {

    /**
     * 根据 id 查询用户
     * @param id 用户 id
     * @return 返回用户
     */
    @Select("select * from user where id=#{id}")
    public User getUserById(Integer id);

    /**
     * 根据 id 删除用户
     * @param id 用户 id
     * @return 返回影响行数
     */
    @Delete("delete from user where id=#{id}")
    public int deleteUserById(Integer id);

    /**
     * 插入用户
     * @param user 用户消息
     * @return 返回影响行数
     */
    @Options(useGeneratedKeys = true,keyProperty = "id")
    @Insert("insert into user(name,age) values(#{name},#{age})")
    public int insertUser(User user);

    /**
     * 根据用户 id 更新用户信息
     * @param user 用户信息
     * @return 返回值
     */
    @Update("update user set name = #{name} , age=#{age} where id=#{id}")
    public int updateUser(User user);

}
配置章
以配置类方式配置
  • 若数据库采用蛇形命名法,而实体类用驼峰命名法,则需要更改映射规则,可以采用添加配置类形式
@Configuration
public class MyBatisConfig {

    @Bean
    public ConfigurationCustomizer configurationCustomizer(){
        return new ConfigurationCustomizer() {
            @Override
            public void customize(org.apache.ibatis.session.Configuration configuration) {
                configuration.setMapUnderscoreToCamelCase(true);
            }
        };
    }
}
  • 若一个一个类扫描太过麻烦,可在主配置类上添加配置注解 @MapperScan 来指定扫描哪个包下接口,然后改包下接口就可不加 @Mapper。( @MapperScan(“com.spring.mapper”))
@MapperScan(value = "com.springboot.mapper")
@SpringBootApplication
public class SpringBootDataMybatisApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootDataMybatisApplication.class, args);
    }
}
以配置文件方式配置
  • 1、编写一个主配置文件,资料在GitHub 的 MyBatis页面查找
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
</configuration>

  • 2、编写每个接口的映射,资料在GitHub 的 MyBatis页面查找
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.springboot.mapper.RoleMapper">
    <select id="getRoleById" resultType="com.springboot.domain.Role">
        select * from role where id = #{id}
    </select>
    <insert id="insertRole" keyProperty="id" useGeneratedKeys="true">
        insert into role(role_name,role_introduction) values(#{roleName},#{roleIntroduction})
    </insert>

</mapper>
  • 3、在 application.yml 中添加 mybatis 配置文件的路径
mybatis:
  config-location: classpath:mybatis/mybatis-config.xml #指定主配置类
  mapper-locations: classpath:mybatis/mapper/*.xml #指定相关映射文件位置

整合 SpringBoot 的 JPA
  • JPA也是 ORM 思想(object、relational、mapping)
  • 1、导入场景启动器(创建项目时可添加),编写数据源
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
  • 2、编写一个实体类,添加注解表示这是一个与表格对应的实体类
//使用JPA注解配置映射关系
@Entity  //告诉JPA这是一个实体类
@Table(name = "user") //表示表名为user,没有标注默认是实体类名的小写
public class User {
    @Id //标志这是一个主键
    @GeneratedValue(strategy = GenerationType.IDENTITY) //表示这是一个自增主键
    private Integer id;
    @Column(name = "name",length = 50) // 和表的一列对应,长度为50
    private String name;
    @Column // 不加默认列名为属性名
    private Integer age;
    
}
  • 3、编写一个基本的操作接口(继承JpaRepository,不需要重写它的方法,泛型第一个表示对应的表格实体类,第二个表示主键类型)以及编写基本的配置(更新数据库和显示 sql 语句)
// 继承JpaRepository来实现对数据库的操作
public interface UserRepository extends JpaRepository<User,Integer> {
}

//

spring:
  jpa:
    hibernate:
      ddl-auto: update # 表示如果更新或者创建表格时更新结构
    show-sql: true #表示输出sql语句
  • 4、编写 Controller ,使用 UserRepository 来实现基本增删查改(类似Hibernate)
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    UserRepository userRepository;
    
    @GetMapping("/getUserById/{id}")
    public User getUserById(@PathVariable("id") Integer id){
        return userRepository.findById(id).get();
    }
    
    @GetMapping("/insertUser")
    public User insertUser(User user){
        return userRepository.save(user);
    }
}

SpringBoot启动原理以及监听


SpringBoot 的 Application启动原理

几个重要的事件回调机制

配置在META-INF/spring.factories

ApplicationContextInitializer

SpringApplicationRunListener

只需要放在ioc容器中

ApplicationRunner

CommandLineRunner

启动流程:

1、创建SpringApplication对象

initialize(sources);
private void initialize(Object[] sources) {
    //保存主配置类
    if (sources != null && sources.length > 0) {
        this.sources.addAll(Arrays.asList(sources));
    }
    //判断当前是否一个web应用
    this.webEnvironment = deduceWebEnvironment();
    //从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
    setInitializers((Collection) getSpringFactoriesInstances(
        ApplicationContextInitializer.class));
    //从类路径下找到ETA-INF/spring.factories配置的所有ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //从多个配置类中找到有main方法的主配置类
    this.mainApplicationClass = deduceMainApplicationClass();
}

2、运行run方法

public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   ConfigurableApplicationContext context = null;
   FailureAnalyzers analyzers = null;
   configureHeadlessProperty();
    
   //获取SpringApplicationRunListeners;从类路径下META-INF/spring.factories
   SpringApplicationRunListeners listeners = getRunListeners(args);
    //回调所有的获取SpringApplicationRunListener.starting()方法
   listeners.starting();
   try {
       //封装命令行参数
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
      //准备环境
      ConfigurableEnvironment environment = prepareEnvironment(listeners,
            applicationArguments);
       		//创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
       
      Banner printedBanner = printBanner(environment);
       
       //创建ApplicationContext;决定创建web的ioc还是普通的ioc
      context = createApplicationContext();
       
      analyzers = new FailureAnalyzers(context);
       //准备上下文环境;将environment保存到ioc中;而且applyInitializers();
       //applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
       //回调所有的SpringApplicationRunListener的contextPrepared();
       //
      prepareContext(context, environment, listeners, applicationArguments,
            printedBanner);
       //prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
       
       //s刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版
       //扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
      refreshContext(context);
       //从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
       //ApplicationRunner先回调,CommandLineRunner再回调
      afterRefresh(context, applicationArguments);
       //所有的SpringApplicationRunListener回调finished方法
      listeners.finished(context, null);
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass)
               .logStarted(getApplicationLog(), stopWatch);
      }
       //整个SpringBoot应用启动完成以后返回启动的ioc容器;
      return context;
   }
   catch (Throwable ex) {
      handleRunFailure(context, listeners, analyzers, ex);
      throw new IllegalStateException(ex);
   }
}

SpringBoot事件监听
  • 1、实现以下方法
    • ApplicationContextInitializer
    • SpringApplicationRunListener
    • ApplicationRunner
    • CommandLineRunner
public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("ApplicationContextInitializer...initialize..."+applicationContext);
    }
}
///
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {

    //必须有的构造器
    public HelloSpringApplicationRunListener(SpringApplication application, String[] args){

    }

    @Override
    public void starting() {
        System.out.println("SpringApplicationRunListener...starting...");
    }

    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        Object o = environment.getSystemProperties().get("os.name");
        System.out.println("SpringApplicationRunListener...environmentPrepared.."+o);
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("SpringApplicationRunListener...contextPrepared...");
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("SpringApplicationRunListener...contextLoaded...");
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("SpringApplicationRunListener...failed...");
    }

}
///
@Component
public class HelloApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner...run....");
    }
}
//
@Component
public class HelloCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));
    }
}
  • 2、在resource目录下创建META-INF然后创建spring.factories文件,在其中指定ApplicationContextInitializerSpringApplicationRunListener的全类名
org.springframework.context.ApplicationContextInitializer=\
com.springboot.listener.HelloApplicationContextInitializer

org.springframework.boot.SpringApplicationRunListener=\
com.springboot.listener.HelloSpringApplicationRunListener

自定义场景启动器
starter:
1、这个场景需要使用到的依赖是什么?

2、如何编写自动配置
@Configuration  //指定这个类是一个配置类
@ConditionalOnXXX  //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter  //指定自动配置类的顺序
@Bean  //给容器中添加组件
@ConfigurationPropertie//结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效加入到容器中

自动配置类要能加载
将需要启动就加载的自动配置类,配置在META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
3、模式:

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

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

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

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

步骤:

1)、启动器模块

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>test-spring-boot-autoconfigurer</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>test-spring-boot-autoconfigurer</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<!-- 引入 spring-boot-starter,所有 starter 所需要的基本配置  -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

	</dependencies>

</project>
package com.springboot.starter;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @author Ming
 * @date 2020/1/17 - 15:03
 */
@Component
@ConfigurationProperties(prefix = "springboot.hello")
public class HelloProperties {

    private String prefix;
    private String suffix;

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getSuffix() {
        return suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
}
package com.springboot.starter;

import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author Ming
 * @date 2020/1/17 - 15:02
 */
public class HelloService {

    HelloProperties helloProperties;

    public HelloProperties getHelloProperties() {
        return helloProperties;
    }

    public void setHelloProperties(HelloProperties helloProperties) {
        this.helloProperties = helloProperties;
    }

    public String sayHello(String name){
        return helloProperties.getPrefix() + "-" + name + ": 这个是测试的语句" + helloProperties.getSuffix();
    }

}
package com.springboot.starter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author Ming
 * @date 2020/1/17 - 15:08
 */
@Configuration
@ConditionalOnWebApplication  //web应用才生效
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {

    @Autowired
    HelloProperties helloProperties;

    @Bean
    public HelloService helloService(){
        HelloService helloService = new HelloService();
        helloService.setHelloProperties(helloProperties);
        return helloService;
    }

}

2)在将两个模块添加导 Maven 仓库中
3)在其他工程的使用

  • 在其他工程需要使用需要将场景启动器添加到依赖
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>test-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
  • 可在 application.properties 文件中配置相关的属性值
springboot.hello.prefix=HEAD HELLO
springboot.hello.suffix=HELLO WORLD

  • 然后在类里面即可直接注入
package com.springboot.controller;

import com.springboot.starter.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Ming
 * @date 2020/1/17 - 15:20
 */
@RestController
@RequestMapping("/hello")
public class HelloController {

    @Autowired
    HelloService helloService;

    @GetMapping("sayHello")
    public String sayHello(){
        return helloService.sayHello("haha");
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值