内容概要

  1. SpringBoot入门
  2. SpringBoot配置
  3. SpringBoot与日志
  4. SpringBoot与Web开发
  5. SpringBoot与Docker
  6. SpringBoot与数据访问
  7. SpringBoot启动配置原理
  8. SpringBoot自定义Starters
  9. SpringBoot与缓存
  10. SpringBoot与消息
  11. SpringBoot与检索
  12. SpringBoot与任务
  13. SpringBoot与安全
  14. SpringBoot与分布式
  15. SpringBoot与开发热部署
  16. SpringBoot与监控管理

第一章 SpringBoot入门

1.1 SpringBoot简介

特点:约定大于配置;去繁从简;

背景:

J2EE笨重的开发;

繁多的配置;

低下的效率;

复杂的部署;

第三方技术集成难度大;

解决方案:

SpringBoot:一站式J2EE的解决方案;

SpringCloud:分布式整体解决方案;

优点:

快速创建可独立运行的Spring项目并与主流框架集成;

starters自动依赖管理及版本控制;

使用嵌入的Servlet容器,应用无需打包;

大量的自动配置,简化开发,也可修改默认值;

无需配置XML,无代码生成,开箱即用;

准生产环境的运行时应用监控;

是对Spring技术栈的一个整合。


1.2 微服务

单体应用: 开发,测试,部署简单;

微服务:功能拆分,灵活配置,通信协作。

SpringBoot官网 > 微服务文档


1.3 开发环境配置

  1. JDK版本;
  2. maven版本;
  3. 开发工具选择;
  4. 框架版本选择;

1.4 第一个应用:HelloWorld

  1. 创建一个Maven项目;
  2. 导入SpringBoot相关依赖;
  3. 编写主程序,启动SpringBoot应用;
1
2
3
4
5
6
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
}
  1. 编写业务逻辑,服务;
  2. 运行主程序测试;
  3. 打包jar包:
1
2
3
4
5
6
7
8
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

运行jar包:

1
java -jar xxx.jar

1.5 HelloWorld原理探究

POM文件:

  1. 父项目:
1
2
3
4
5
6
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
父项目:

SpringBoot的版本仲裁中心,导入依赖不需要写版本号。

  1. 导入的依赖:
1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

spring-boot-starter-web:

场景启动器:帮我们导入web模块正常运行所需的依赖的组件;

将所有的功能场景抽取出来,做成启动器,只需要在项目中导入相关的starter,所有的依赖都会被导入,版本由spring-boot自动管理。


1.6 主程序类原理探究

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* @author [email protected]
* @since 18-9-9 下午2:28
*/
@SpringBootApplication
public class MainApp {
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
}

@SpringBootApplication标注在某个类上,指定SpringBoot的主配置类,由这个类来启动SpringBoot应用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}

@SpringBootConfiguration:标注在某个类上,表示该类是SpringBoot的配置类。

@Configuration:配置类上标注该类。配置类也是一个组件:@Component;

@EnableAutoConfiguration:开启自动配置,

1
需要配置的东西由SpringBoot自动配置。
1
2
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
1
2
3
@AutoConfigurationPackage:自动配置包,给容器导入一个组件,导入的组件由AutoConfigurationPackage.Registrar;

将主配置类所在的及以下所有的子包里的所有组件添加到Spring容器中。
1
2
3
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
1
2
3
@Import:给容器中导入一些组件:AutoConfigurationImportSelector:选择哪些组件导入。

给容器中导入自动配置类(xxxAutoConfiguration):给容器中导入场景需要的所有的组件并配置好这些组件。

配置类

1
2
3
4
5
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指定的值,将这些值导入到Spring容器中,自动配置类生效。

需要自己指定的配置,已经由配置类自动配置好。

org/springframework/boot/spring-boot-autoconfigure/2.0.4.RELEASE/spring-boot-autoconfigure-2.0.4.RELEASE.jar!/META-INF/spring.factories

自动配置类


1.7 SpringBoot项目初始化器

SpringBoot项目向导:

IDEA > New Project > Spring Initializer > 项目详情 > 导入相关场景依赖。

@RestController注解:

@ResponseBody和@RequestMapping注解组合。

  1. 自动生成主程序;
  2. /resources中目录结构:
    1. static:保存静态资源;
    2. templates:存所有的模板页面(使用嵌入的tomcat,不支持JSP页面,但是可以使用模板引擎);
    3. application.properties:SpringBoot的默认配置文件。

第二章 SpringBoot配置文件

2.1 SpringBoot配置文件

SpringBoot使用全局配置文件,配置文件名是固定的。

  • application.properties;
  • application.yml。

配置文件的作用:修改SpringBoot默认配置。

YAML:不仅仅是一个标记语言,以数据为中心,比json和xml更适合做配置文件。

YAML:

1
2
server:
port: 8081

2.2 YAML基本语法

key: value 表示键值对,冒号之后的空格必须有的,以空格来控制层级关系。

1
2
3
server: 
port: 8081
path: /hello

属性和值大小写敏感。

字面量:字符串默认不加单引号和双引号,双引号会转义特殊字符单引号会转义特殊字符

1
k: v

对象(属性和值):本质是键值对。

1
2
3
student:
name: 张三
age: 14

行内写法:

1
student: {name: 张三,age: 15}

数组(List, Set):

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

1
2
3
4
pets:
- cat
- dog
- pig

行内写法:

1
pets: [cat,dog,pig]

2.2.1配置文件注入:

application.yml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server:
port: 8081

person:
name: 张三
age: 18
alive: true
birth: 2018/09/11
classes:
- v1
- v2
map:
k1: v1
k2: v2
dog:
name: dog
age: 4

JavaBean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.demo.po;

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

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
* @author [email protected]
* @since 18-9-11 下午8:36
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Student {
private String name;
private Integer age;
private boolean alive;
private Date birth;
private List<String> classes;
private Map<String, Object> map;
private Dog dog;

@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", alive=" + alive +
", birth=" + birth +
", classes=" + classes +
", map=" + map +
", dog=" + dog +
'}';
}
}

可以导入配置文件处理器之后,编写配置文件有IDE智能提示。

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

@ConfigurationProperties(prefix = “person”)获取配置文件的值。

application.properties乱码问题:file encoding勾选将properties配置文件转换成ascii码。

配置文件的旧写法:

1
2
3
<bean class="person">
<property name="lastName" value="zhagsa"/>
</bean>

2.2.2 @Value注入值

1
2
3
4
5
6
7
8
9
10
11
12
public class Student {
@Value("${person.name}")
private String name;
@Value("#{11*2}")
private Integer age;
@Value("true")
private boolean alive;
private Date birth;
private List<String> classes;
private Map<String, Object> map;
private Dog dog;
}

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

@ConfigurationProperties @Value
功能 批量注入配置文件中的属性 单个指定变量的值
松散绑定 支持 不支持
SpEL 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持

2.2.4 @Value和@ConfigurationProperties的比较

如果只是在某个业务逻辑中需要获取一下配置文件中的值,那就用@Value;如果专门编写了Java bean和配置文件进行映射,就直接使用@ConfigurationProperties。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.demo.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* @author [email protected]
* @since 18-9-12 下午9:30
*/
@RestController
public class DemoController {
@Value("${person.name}")
private String name;

@RequestMapping("/demo.do")
public String sayHello() {
return "Hello, " + name;
}
}

2.3 @PropertySource和@ImportSource

@ConfigurationProperties默认从全局配置文件中获取值。

2.3.1 @PropertySource获取配置文件的值:

1
2
@ConfigurationProperties(prefix = "person")
@PropertySource(value = {"classpath:person.properties"})

2.3.2 @ImportSource:导入Spring配置文件,是配置文件中的配置生效。

SpringBoot默认没有加载Spring配置文件,手动编写的配置文件也无法识别,想让配置文件生效,将@ImportSource标注在主配置类上。

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="demoService" class="com.demo.service.DemoService"/>
</beans>
1
2
3
4
5
6
7
8
@Autowired
private ApplicationContext applicationContext;

@Test
public void demoServiceTest() {
boolean hasDemoService = applicationContext.containsBean("demoService");
System.out.println(hasDemoService);
}

2.3.3 SpringBoot推荐的添加组件方式

SpringBoot推荐给容器中添加组件的方式:使用全注解,@Configuration标注配置类。

@Bean:**将方法的返回值添加到容器中,组件的默认id就是方法名。**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.demo.config;

import com.demo.service.DemoService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* @author [email protected]
* @since 18-9-12 下午9:52
*/
@Configuration
public class AppConfig {
/**
* @return
* @desc 将方法的返回值添加到容器中,组件的默认id就是方法名
*/
@Bean
public DemoService demoService() {
System.out.println("给容器中添加组件");
return new DemoService();
}
}

2.4 配置文件占位符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server:
port: 8081

person:
name: 张三${random.value}
age: ${random.int}
birth: 2018/09/11
map:
k1: ${random.value}
k2: v2
dog:
name: ${person.hello:defau}
age: 4
alive: true
classes:
- v1
- v2
  1. 随机数:

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

  1. 占位符获取配置之前的值,${app.name:默认值}

2.5 Profile多环境支持

profile为不同环境提供不同配置的功能。

  1. 多profile文件的方式:

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

    SpringBoot默认使用全局环境配置

  2. 激活指定profile:

    1
    2
    3
    spring:
    profiles:
    active: dev

    命令行方式:

    –spring.profiles.active=dev/prod

    虚拟机参数:

    -Dspring.profiles.active=dev/prod

  3. yaml支持文档块的方式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    server:
    port: 8080
    spring:
    profiles:
    active: dev
    ---

    server:
    port: 8083
    spring:
    profiles: dev

    ---

    server:
    port: 8084
    spring:
    profiles: prod

见下图:厉害了


2.6 配置文件加载位置

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

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

以上位置优先级从高到低。所有位置的配置文件都会被加载,高优先级的配置会覆盖低优先级的配置,高优先级和低优先级配置文件形成互补配置。

server.context-path=/config02 -> http://localhost:8080/config02/hello.do

还可以通过spring.config.location来改变默认的配置文件位置(项目打包后可以使用命令行参数的形式启动项目时候来指定配置文件的位置,指定的配置文件和默认加载的配置文件会形成互补配置)。

见下图:

图片丢失


2.7 外部配置文件加载顺序

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

  1. Devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active).
  2. @TestPropertySource annotations on your tests.
  3. @SpringBootTest#properties annotation attribute on your tests.
  4. Command line arguments.
  5. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).
  6. ServletConfig init parameters.
  7. ServletContext init parameters.
  8. JNDI attributes from java:comp/env.
  9. Java System properties (System.getProperties()).
  10. OS environment variables.
  11. A RandomValuePropertySource that has properties only in random.*.
  12. Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants).
  13. Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).
  14. Application properties outside of your packaged jar (application.properties and YAML variants).
  15. Application properties packaged inside your jar (application.properties and YAML variants).
  16. @PropertySource annotations on your @Configuration classes.
  17. Default properties (specified by setting SpringApplication.setDefaultProperties).

由jar包外向jar包内进行查找。

命令行参数(多个参数用空格分开);

  • java -jar xxx.jar –server.port=8081 server.context.path=/ab

优先加载带profile的配置文件。

  • jar包外的application-{profile}或application-{yml}或不带spring.profile的配置文件;
  • jar包内的application-{profile}或application-{yml}或不带spring.profile的配置文件;

再加载带不profile的配置文件。

  • jar包外的application-{profile}或application-{yml}或不带spring.profile的配置文件;
  • jar包内的application-{profile}或application-{yml}或不带spring.profile的配置文件;
  • @Configuration注解类上的@PropertySource;
  • 通过SpringApplication.setDefaultProperties指定的默认属性。

详细参见SpringBoot官网:SpringBoot外部配置文件加载顺序


2.8 自动配置原理

配置文件能写什么,怎么写?

自动配置原理:

  1. SpringBoot在启动的时候加载主配置类,开启了自动配置功能:@EnableAutoConfiguration;
  2. @EnableAutoConfiguration的作用:
    1. 利用@EnableAutoConfigurationImportSelector给容器导入一些组件;
    2. 可以查看selectImports中的内容;
    3. List configurations = getCandidateConfigurations(annotationMetadata, attributes) 方法;
      • SpringFactoriesLoader.loadFactoryNames();
      • 扫描所有jar包类路径下:META-INF/spring.factories;
      • 将扫描到的文件内容加载包装成properties对象。
  3. 每一个自动配置类进行功能的自动配置;
  4. 所有在配置文件中能配置的属性都在xxxProperties类中配置着,配置文件能配置什么都参照配置文件中的值;

SpringBoot的特点:

  1. SpringBoot启动时会加载大量的自动配置类;
  2. 看SpringBoot有没有自动配置类;
  3. 如果有,不用自己再写自动配置类。
  4. 给容器中自动配置类添加组件的时候,会从properties类中读取某些属性,我们就可以在配置文件中指定这些属性的值。

2.9 @Conditional自动配置

自动配置类需要在一定条件下才能生效。

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

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

自动配置文件:org/springframework/boot/spring-boot-autoconfigure/2.0.5.RELEASE/spring-boot-autoconfigure-2.0.5.RELEASE.jar!/META-INF/spring.factories

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# 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.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.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.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.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\
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.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.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

开启SpringBoot的debug,可以通过debug=true让控制台打印自动配置报告,便可以方便的知道哪些自动配置类生效了。

1
2
3
4
5
6
7
8
9
10
11
12
13
============================
CONDITIONS EVALUATION REPORT
============================


Positive matches:
-----------------

CodecsAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.http.codec.CodecConfigurer'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)

CodecsAutoConfiguration.JacksonCodecConfiguration matched:
- @ConditionalOnClass found required class 'com.fasterxml.jackson.databind.ObjectMapper'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
1
2
3
4
5
6
7
8
9
10
11
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', 'org.aspectj.weaver.AnnotatedElement' (OnClassCondition)

第三章 SpringBoot与日志


3.1 日志框架

  • System.out.println(“welcome!”); 不利于代码维护;
  • 使用日志框架;
  • 加入异步,自动归档等功能;
  • 与程序耦合控制;
  • 统一的接口层:日志门面。

常见的日志框架:

  • JUL(java.util.logging);
  • JCL;
  • jboss-logging;
  • logback;
  • log4j;
  • log4j2;
  • slf4j;

日志门面:SLF4J;

日志实现:Logback。

SpringBoot:底层是Spring框架,SpringBoot框架默认是JCL

SpringBoot选用SLF4J,Logback。


3.2 SLF4J的使用


3.2.1 如何在系统中使用SLF4J

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

给系统导入slf4j的jar和logback的实现jar:

1
2
3
4
5
6
7
8
9
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以后,配置文件还是作为日志实现框架本身的配置文件。


3.2.2 遗留问题

a(slf4j + logback):Spring(commons-logging),Hibernate(jboss-logging)

统一日志记录,即便是别的框架也使用同一日志框架。

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

  1. 将系统中其他日志框架排除在外;
  2. 用中间适配层包替换原有日志框架;
  3. 导入slf4j其他的实现。

3.3 SpringBoot日志关系

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

SpringBoot的日志功能:

1
2
3
4
5
6
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.0.5.RELEASE</version>
<scope>compile</scope>
</dependency>

SpringBoot底层依赖关系(pom.xml文件,show diagram查看maven项目依赖关系):

  1. SpringBoot底层也是用slf4j + logback的方式进行日志记录;
  2. SpringBoot也把其他的日志都替换成了slf4j;
  3. 中间替换包;
  4. 如果要引入其他框架,一定要把这个框架的默认日志依赖移除。

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


3.4 SpringBoot默认日志配置

日志的级别,由低到高,可以调整日志输出的级别:

1
2
3
4
5
6
7
Logger logger = LoggerFactory.getLogger(getClass());
//日志的级别,由低到高
logger.trace("这是日志...");
logger.debug("这是debug日志...");
logger.info("这是Info信息...");
logger.warn("这是警告...");
logger.error("这是错误信息...");

SpringBoot默认日志输出级别为info。

可以在application.yml中自定义日志输出级别: logging.level.com.hape.nmsl=trace

在当前项目下生成日志文件:logging.file=springboot.log

不指定路径在项目路径下生成日志文件。

logfile优先级高于logpath。

logpath:指定日志文件的路径,默认文件名spring.log。

logging.pattern.console:控制台输出日志的格式。

logging.pattern.file:日志文件输出格式。

日志输出格式:

1
2
3
4
5
6
7
8
9
10
11
%d:表示日期时间;

%thread:表示线程号;

%-5level:级别从左显示5个字符宽度;

%logger{50}:表示logger名字最长50个字符,否则按照句点分割;

%msg:日志信息;

%n:换行符。

日志格式配置实例:

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

3.5 指定日志文件和日志profile功能

给类路径下放上每个日志框架自己配置文件即可,

Because the standard logback.xml configuration file is loaded too early, you cannot use extensions in it. You need to either use logback-spring.xml or define a logging.config property.

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。

1
2
3
4
5
6
7
8
9
10
11
12
可以指定某一段配置只在某个环境下生效
<springProfile name="staging">
<!-- configuration to be enabled when the "staging" profile is active -->
</springProfile>

<springProfile name="dev, staging">
<!-- configuration to be enabled when the "dev" or "staging" profiles are active-->
</springProfile>

<springProfile name="!production">
<!-- configuration to be enabled when the "production" profile is not active -->
</springProfile>

3.6 切换日志框架

可以按照slf4j适配图进行相关的切换。

  1. 排除不使用的包;
  2. 导入相关的适配包;

不推荐更换SpringBoot默认使用的日志记录框架。


第四章 SpringBoot与Web开发

使用SpringBoot:

  • 创建SpringBoot应用,选中需要的模块;
  • SpringBoot自动配置好场景,需要在配置文件中指定少量配置,即可运行程序;
  • 编写相关的业务逻辑。

依赖于SpringBoot的自动配置。


4.1 webjar与静态资源映射规则

SpringBoot对静态资源的映射规则:(WebMvcAutoConfiguration.java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache()
.getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry
.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod))
.setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(
this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod))
.setCacheControl(cacheControl));
}
}
  • 所有的/webjars/**,都到classpath:/META-INF/resources/webjars找资源;

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

在访问的时候只需要写webjars下的资源名称即可。(http://localhost:8080/webjars/jquery/3.3.1-1/jquery.js)

1
2
3
4
5
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1-1</version>
</dependency>
  • 访问当前项目下的任何资源(静态资源的文件夹)

    1
    2
    3
    4
    "classpath:/META-INF/resources/", 
    "classpath:/resources/",
    "classpath:/static/",
    "classpath:/public/"
  • 配置欢迎页

    1
    2
    3
    4
    5
    6
    7
    8
    @Bean
    public WelcomePageHandlerMapping welcomePageHandlerMapping(
    ApplicationContext applicationContext) {
    return new WelcomePageHandlerMapping(
    new TemplateAvailabilityProviders(applicationContext),
    applicationContext, getWelcomePage(),
    this.mvcProperties.getStaticPathPattern());
    }

    静态文件夹下的所有index.html页面;

    映射到 private String staticPathPattern = “/**”;

  • 配置喜欢的图标

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Configuration
    @ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true)
    public static class FaviconConfiguration implements ResourceLoaderAware {

    private final ResourceProperties resourceProperties;

    private ResourceLoader resourceLoader;

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

    映射到**favicon.ico静态资源文件夹。


4.2 引入Thymeleaf模板引擎

thymeleaf, jsp, freemaker, velocity

SpringBoot推荐的thymeleaf:

  1. 引入thymeleaf;
  2. 自定义thymeleaf版本。
1
2
3
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<!--布局功能支持程序 thymeleaf3 layout2以上版本适配-->
<thymeleaf.layout.dialect.version>2.1.1</thymeleaf.layout.dialect.version>

4.3 Thymeleaf语法

默认请求路径:classpath:templates/xxx.html

文档地址:Thymeleaf参考文档

使用方法:

  • 导入Thymeleaf名称空间;

    1
    <html lang="en" xmlns:th="http:y//www.thymeleaf.org">
  • 使用Thymeleaf语法;

    1
    <div th:text="${hello}">显示欢迎信息</div>
  • thymeleaf语法规则:

    • th:text:改变text文本值;

    • th:任意属性都可以替换;

    • 文档第十章/Attributes/优先级;

  • thymeleaf表达式;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    Simple expressions:
    Variable Expressions: ${...}
    Selection Variable Expressions: *{...}
    Message Expressions: #{...}
    Link URL Expressions: @{...}
    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:
    Page 17 of 106No-Operation: _

    内置对象:

    1
    2
    3
    4
    5
    6
    7
    #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.

4.4 SpringMVC自动配置功能

SpringBoot文档地址:官方文档地址

4.4.1 SpringMVC自动配置项

SpringMVC自动配置:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
  • Support for serving static resources, including support for WebJars (covered later in this document)).
  • Automatic registration of Converter, GenericConverter, and Formatter beans.
  • Support for HttpMessageConverters (covered later in this document).
  • Automatic registration of MessageCodesResolver (covered later in this document).
  • Static index.html support.
  • Custom Favicon support (covered later in this document).
  • Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).
1
2
3
4
5
6
7
8
9
10
11
12
@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(
beanFactory.getBean(ContentNegotiationManager.class));
// ContentNegotiatingViewResolver uses all the other view resolvers to locate
// a view so it should have a high precedence
resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
return resolver;
}
1
2
3
4
5
6
7
8
9
10
11
12
@Override
public void addFormatters(FormatterRegistry registry) {
for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
registry.addConverter(converter);
}
for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
registry.addConverter(converter);
}
for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
registry.addFormatter(formatter);
}
}
1
2
3
4
5
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
this.messageConvertersProvider.ifAvailable((customConverters) -> converters
.addAll(customConverters.getConverters()));
}
  • 如果用户有配置(@Bean,@Component),则使用组合配置;

4.4.2 扩展SpringMVC配置

添加一个配置类并且继承自WebMvcConfigurerAdapter。

将hello.do请求映射到hello.html视图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.web.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
* @author [email protected]
* @since 18-10-1 下午1:51
*/
@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
registry.addViewController("/hello.do").setViewName("/hello.html");
}
}
  • WebMvcAutoConfiguration是SpringMVC的自动配置类;
  • 在做其他自动配置时会导入:@Import(EnableWebMvcConfiguration.class)。
1
2
3
4
5
6
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
  • 容器中所有的WebMvcConfiguration都会被调用。

    所有的配置都会共同起作用。

4.4.3 全面接管SpringMVC

在配置类中添加@EnableWebMvc:丢弃所有的自动配置,手动配置所有的配置。

原理:

WebMvc:

1
2
3
4
5
6
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}

DelegatingWebMvcConfiguration:

1
2
3
4
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
}

WebMvcAutoConfiguration:

1
2
3
4
5
6
7
8
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
//容器中缺少此组件,该自动配置生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })

4.5 引入资源

SpringBoot中使用webjars引入jquery和bootstrap之类的资源:

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>index</title>
<link rel="stylesheet" th:href="@{webjars/bootstrap/4.1.3/css/bootstrap.css}" th:type="text/css"/>
</head>
<body>

</body>
</html>

即使更换项目访问名也可以正常加载静态资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.web.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
* @author [email protected]
* @since 18-10-1 下午1:51
*/
//@EnableWebMvc
@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
registry.addViewController("/hello.do").setViewName("/hello.html");
registry.addViewController("/").setViewName("/hello.html");
}

public WebMvcConfigurerAdapter webMvcConfigurerAdapter() {
return new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("/hello.html");
}
};
}
}

4.6 国际化

  1. 编写国际化配置文件;
  2. 使用ResourceBundleMessageSource管理国际化资源文件;
  3. 在页面使用fmt:message取出国际化内容。

配置如下图:

SpringBoot自动配置(MessageSourceAutoConfiguration.java):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Bean
//类路径下配置文件spring.messages
@ConfigurationProperties(prefix = "spring.messages")
public MessageSourceProperties messageSourceProperties() {
return new MessageSourceProperties();
}

@Bean
public MessageSource messageSource() {
MessageSourceProperties properties = messageSourceProperties();
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(properties.getBasename())) {
//设置国际化资源文件的基础名(去除国际语言代码)
messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(properties.getBasename())));
}
if (properties.getEncoding() != null) {
messageSource.setDefaultEncoding(properties.getEncoding().name());
}
messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
Duration cacheDuration = properties.getCacheDuration();
if (cacheDuration != null) {
messageSource.setCacheMillis(cacheDuration.toMillis());
}
messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
return messageSource;
}

设置配置文件地址:

1
spring.message=login

页面中获取国际化资源:

1
2
3
4
<lable class="sr-only" th:message="#{login.tip}">Tips</lable>
<lable class="sr-only" th:message="#{login.username}">Username</lable>
<lable class="sr-only" th:message="#{login.password}">Password</lable>
<lable class="sr-only" th:message="#{login.remember}">remember</lable>

浏览器根据浏览器语言设置的信息自动切换国际化。

SpringMVC区域信息组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties
.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
//默认根据请求头获取的区域信息展示国际化信息。

可以在请求参数上携带区域信息实现国际化:

1
2
https://localhost:8080/hello.do?language=zh_CN
https://localhost:8080/hello.do?language=en_US

手动配置区域信息解析器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.web.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;

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

/**
* @author [email protected]
* @since 18-10-3 下午4:43
*/
@Configuration
public class MyLocaleResolver implements LocaleResolver {

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

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

}
}

4.7 拦截器

  • PostMapping():RestfulAPI注解;
  • 开发期间禁用Thymeleaf的缓存:spring.thymeleaf.cache=false;
  • 错误消息的显示;
  • 防止表单重复提交,添加视图视图映射后,使用重定向。
  • 使用拦截器进行身份校验;
  • 编写拦截器,在配置类中注册拦截器。
  • 页面中使用Thymeleaf获取值。

4.8 CRUD实验

4.8.1 实验要求

实验要求:

  1. RestfulAPI风格:

    1. URI:/资源名称/资源标识;
    2. HTTP请求方式区分对资源的CRUD操作;
    操作 普通CRUD RestfulCRUD
    查询 getEmp emp—GET
    添加 addEmp?xxx emp—POST
    修改 updateEmp?id=xxx&xxx=xxx emp/{id}—PUT
    删除 deleteEmp?id=1 emp/{id}—DELETE
  1. 实验的请求架构:

    请求URI 请求方式
    查询所有的员工 emps GET
    查询某个员工 emp/{id} GET
    来到添加界面 emp GET
    添加员工 emp POST
    来到修改界面 emp/{id} PUT
    修改员工 emp PUT
    删除员工 emp/{id} DELETE

4.8.2 公共页面抽取—列表页

  1. 利用Thymeleaf抽取公共页面;

    1
    2
    3
    4
    5
    6
    7
    8
    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <body>
    <div th:fragment="copy">
    &copy; 2011 The Good Thymes Virtual Grocery
    </div>
    </body>
    </html>
  2. “~{templatename::selector}”:模板名选择器;

    ~{templatename::fragmentname}:模板名:片断名。

  3. 默认效果:

    insert片段都在div标签中

    1
    2
    3
    4
    <body>
    ...
    <div th:insert="footer :: copy"></div>
    </body>
  4. 三种引入功能片段的th属性:

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

4.8.3 链接高亮&列表完成

实现方法:引入公共片段时传入相关参数,公共片段根据参数高亮相关部分。

Thymeleaf日期工具对象(文档附录 > dates):

1
#dates : methods for java.util.Date objects: formatting, component extraction, etc.
1
2
3
4
${#dates.format(date, 'dd/MMM/yyyy HH:mm')}
${#dates.arrayFormat(datesArray, 'dd/MMM/yyyy HH:mm')}
${#dates.listFormat(datesList, 'dd/MMM/yyyy HH:mm')}
${#dates.setFormat(datesSet, 'dd/MMM/yyyy HH:mm')}

4.8.4 添加员工 > 来到添加页面

  1. 添加表单:Bootstrap官网模板直接复制;
  2. 通过 **添加 **按钮跳转到添加页面;
  3. 使用th:each完成部门的遍历;

4.8.5 添加员工 > 完成添加

  1. 完成添加后 重定向 至列表页面(forward或者redirect);
  2. 提交的数据格式问题:日期格式:
    1. 日期格式化:SpringMVC将页面提交的值需要转换成指定的类型;
    2. 在配置文件中自定义表单提交的日期格式。

4.8.6 修改员工信息

  1. 配置HiddenHttpMethodFilter;

4.8.7 删除员工


4.9 定制错误页面

  1. 默认出错处理:返回一个默认的错误处理页面:在页面共享信息;

  2. 如果是其他客户端,默认响应一个json数据;

  3. 可以参照ErrorAutoConfiguration,错误处理的自动配置,在容器中添加如下组件:

    1. DefaultErrorAttributes;

    2. BasicErrorController:处理默认的error错误请求;

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      @RequestMapping(produces = "text/html")
      public ModelAndView errorHtml(HttpServletRequest request,
      HttpServletResponse response) {
      HttpStatus status = getStatus(request);
      Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
      request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
      response.setStatus(status.value());
      ModelAndView modelAndView = resolveErrorView(request, response, status, model);
      return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
      }
    3. ErrorPageCustomizer:系统出现错误,来到/error请求进行处理:web.xml;

    4. DefaultErrorViewResolver;

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      static {
      Map<Series, String> views = new EnumMap<>(Series.class);
      views.put(Series.CLIENT_ERROR, "4xx");
      views.put(Series.SERVER_ERROR, "5xx");
      SERIES_VIEWS = Collections.unmodifiableMap(views);
      }

      @Override
      public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
      Map<String, Object> model) {
      ModelAndView modelAndView = resolve(String.valueOf(status), model);
      if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
      modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
      }
      return modelAndView;
      }

      private ModelAndView resolve(String viewName, Map<String, Object> model) {
      String errorViewName = "error/" + viewName;
      TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
      .getProvider(errorViewName, this.applicationContext);
      if (provider != null) {
      return new ModelAndView(errorViewName, model);
      }
      return resolveResource(errorViewName, model);
      }

定制自定义错误页面:

  1. 有模板引擎的情况下:error/状态码,将错误命名为status_code.html放在classpath:error/下,发生此错误会来到该页面;

    可以使用4xx和5xx作为错误页面的文件名来匹配该类型的所有错误,精确匹配优先;

    页面能获取的信息:

    1. timestamp;
    2. message;
    3. status code;
    4. exception;
    5. errors。
  2. 没有模板引擎:静态资源文件夹下寻找。

定制自定义json数据:

  1. 没有自适应效果,浏览器和客户端返回的都是json数据:

    1
    2
    3
    @ControllerAdvice
    @ExceptionHandler
    @Response
  2. 自适应效果:转发给/error进行自适应效果处理,给request中传入自己的参数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @RequestMapping(produces = "text/html")
    public ModelAndView errorHtml(HttpServletRequest request,
    HttpServletResponse response) {
    HttpStatus status = getStatus(request);
    Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
    request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
    response.setStatus(status.value());
    ModelAndView modelAndView = resolveErrorView(request, response, status, model);
    return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
    }

    @RequestMapping
    @ResponseBody
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
    Map<String, Object> body = getErrorAttributes(request,
    isIncludeStackTrace(request, MediaType.ALL));
    HttpStatus status = getStatus(request);
    return new ResponseEntity<>(body, status);
    }
  3. 将自定义错误信息携带:

    响应数据由getErrorAttributes()获取:

    1. 编写一个ErrorController的实现类或者AbstractErrorController的子类,放在容器中;

    2. 页面上能用的数据或者json返回的数据都是errorAttributes.getErrorAttributes得到;DefaultErrorAttributes.getErrorAttributes()进行错误处理。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      package com.web.config;


      import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
      import org.springframework.stereotype.Component;

      import java.util.Map;

      /**
      * @author [email protected]
      * @since 18-10-7 下午4:25
      */
      @Component
      public class MyErrorHandler extends DefaultErrorAttributes {
      @Override
      public Map<String, Object> getErrorAttributes(
      org.springframework.web.reactive.function.server.ServerRequest request,
      boolean includeStackTrace) {
      return super.getErrorAttributes(request, includeStackTrace);
      }
      }

第五章 配置嵌入式Servlet容器


5.1 定制嵌入式Servlet容器

默认使用嵌入式tomcat8.5.4作为嵌入式的Servlet容器;

  1. 如何定制嵌入式的Servlet容器?
  2. SpringBoot能否支持其他的Servlet容器?
  1. 修改和Server有关的配置(server.properties):
1
2
server.port=8080
servet.context-path=/path
  1. 编写一个EmbeddedServletContainerCustomizer来修改嵌入式Servlet容器:

    1
    2
    3
    4
    5
    6
    @Bean
    public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer() {
    public void customize(ConfigurableEmbeddedServletContainer container) {
    container.setPort(8083);
    }
    }

与容器相关的类:ServerProperties.class

SpringBoot2.0:

1
2
3
4
5
6
7
8
@Component
public class EmbeddedTomcatConfig implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

@Override
public void customize(ConfigurableServletWebServerFactory factory) {
factory.setContextPath("/test");
}
}

5.2 注册Servlet容器三大组件

Servlet:ServletRegistrationBean

1
2
3
4
@Bean
public ServletRegistrationBean<MyServlet> myServlet() {
return new ServletRegistrationBean<>(new MyServlet(), "/servlet.do");
}

Filter:FilterRegistrationBean

1
2
3
4
5
6
7
@Bean
public FilterRegistrationBean<MyFilter> myFilter() {
FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new MyFilter());
registrationBean.setUrlPatterns(Arrays.asList("/hello.do", "/nihao.do"));
return registrationBean;
}

Listener:ServletListenerRegistrationBean

1
2
3
4
5
6
@Bean
public ServletListenerRegistrationBean<MyListener> myListener() {
ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<MyListener>();
registrationBean.setListener(new MyListener());
return registrationBean;
}

5.3 嵌入式Servlet容器自动配置原理

EmbeddedWebServerFactoryCustomizerAutoConfiguration.class

Tomcat:

1
2
3
4
5
6
7
8
9
10
@Configuration
@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
public static class TomcatWebServerFactoryCustomizerConfiguration {

@Bean
public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(
Environment environment, ServerProperties serverProperties) {
return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
}
}

Jetty:

1
2
3
4
5
6
7
8
9
10
11
@Configuration
@ConditionalOnClass({ Server.class, Loader.class, WebAppContext.class })
public static class JettyWebServerFactoryCustomizerConfiguration {

@Bean
public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(
Environment environment, ServerProperties serverProperties) {
return new JettyWebServerFactoryCustomizer(environment, serverProperties);
}

}

Undertow:

1
2
3
4
5
6
7
8
9
10
11
@Configuration
@ConditionalOnClass({ Undertow.class, SslClientAuthMode.class })
public static class UndertowWebServerFactoryCustomizerConfiguration {

@Bean
public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(
Environment environment, ServerProperties serverProperties) {
return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
}

}

配置文件:Server.properties:

1
2
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {

ConfigurableTomcatWebServerFactory.class:


5.4 使用外置的Servlet容器

内置的servlet容器不支持jsp;

  1. 向项目中导入tomcat服务器,创建web.xml文件,添加application.properties配置;打包方式为war包;

必须编写一个ServletInitializer文件;

1
2
3
4
5
6
public class ServletInitializer extends SpringBootServletInitializer {
@override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(${MainClass}.class);
}
}
  1. 将嵌入式spring-boot-start-web内嵌的tomcat的scope指定为provided;

第六章 Docker技术

6.1 docker简介

概念:Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、bare metal、OpenStack 集群和其他的基础应用平台。

Docker入门


6.2 Docker核心概念

  1. docker主机(Host):安装了Docker程序的机器(Docker直接安装在操作系统之上);
  2. docker客户端(Client):连接Docker主机进行操作;
  3. docker仓库(Registry):用来保存各种打包好的软件镜像;
  4. docker镜像(Images):软件打包好的镜像,放在docker仓库中;
  5. docker容器(Container):镜像启动后的实例称为一个容器,容器是独立运行的一个或一组应用;

使用docker容器的步骤:

  1. 安装docker;
  2. 去docker仓库找到这个软件对应的镜像;
  3. 使用docker运行这个镜像,就会生成一个Docker镜像容器;
  4. 对容器的启动和停止就是对软件的启动和停止。

6.3 Docker常用操作

镜像官方网站:Docker Hub

1
2
3
4
docker search mysql     //搜索镜像
docker pull mysql:5.5 //拉取镜像
docker images //查看本地所有镜像
docker rmi images-id //删除本地镜像

各个独立的容器互不干扰,独立运行。


6.4 环境搭建

6.4.1 安装MySQL:

启动一个MySQL实例(需要指定密码和端口映射):

1
$ docker run -p port --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

官方文档:MySQL文档

几个高级操作:

1
2
3
4
5
使用配置文件:
$ docker run --name some-mysql -v /my/custom:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

不适用配置文件:
$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

6.4.2 安装Redis

6.4.3 安装RabbitMQ

6.4.4 安装ElasticSearch


第七章 SpringBoot与数据库访问

SpringBoot与数据访问相关的场景启动器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
spring-boot-starter-data-cassandra

Starter for using Cassandra distributed database and Spring Data Cassandra

Pom

spring-boot-starter-data-cassandra-reactive

Starter for using Cassandra distributed database and Spring Data Cassandra Reactive

Pom

spring-boot-starter-data-couchbase

Starter for using Couchbase document-oriented database and Spring Data Couchbase

Pom

spring-boot-starter-data-couchbase-reactive

Starter for using Couchbase document-oriented database and Spring Data Couchbase Reactive

Pom

spring-boot-starter-data-elasticsearch

Starter for using Elasticsearch search and analytics engine and Spring Data Elasticsearch

Pom

spring-boot-starter-data-jpa

Starter for using Spring Data JPA with Hibernate

Pom

spring-boot-starter-data-ldap

Starter for using Spring Data LDAP

Pom

spring-boot-starter-data-mongodb

Starter for using MongoDB document-oriented database and Spring Data MongoDB

Pom

spring-boot-starter-data-mongodb-reactive

Starter for using MongoDB document-oriented database and Spring Data MongoDB Reactive

Pom

spring-boot-starter-data-neo4j

Starter for using Neo4j graph database and Spring Data Neo4j

Pom

spring-boot-starter-data-redis

Starter for using Redis key-value data store with Spring Data Redis and the Lettuce client

Pom

spring-boot-starter-data-redis-reactive

Starter for using Redis key-value data store with Spring Data Redis reactive and the Lettuce client

Pom

spring-boot-starter-data-rest

Starter for exposing Spring Data repositories over REST using Spring Data REST

Pom

spring-boot-starter-data-solr

Starter for using the Apache Solr search platform with Spring Data Solr

Pom

7.1 整合JDBC与数据源

建表语句执行:classpath:schema-*.sql

数据操作语句:classpath:data-*.sql

也可以使用schema在application.yml中自定义数据文件地址。


7.2 Druid数据源配置

  1. 引入依赖;
  2. 配置属性。
1
type指定数据源

添加一个配置类,将Druid配置映射到数据源。

结合过滤器和Servlet设置Druid监控。


7.3 整合MyBatis

启动器:

1
mybatis-spring-boot-starter

获取插入数据库的记录的ID:

@Options(userGeneratedKeys=, keyProperty=)

开启MyBatis驼峰命名:

写一个配置类,实现ConfigurationCustomizer接口中的customize()方法:

1
configuration.setMapUnderscopeToCamelCase(true);

批量扫描所有的@Mapper注解:

@MapperScan(value=””)

相关配置文件见官网文档。

全局配置文件配置:

1
2
mybatis-config-location:classpath:mybatis/config.xml
mybatis-config-mapper:class:mybatis/mapper.xml

7.4 SpringData数据访问JPA