1、配置文件
SpringBoot使用一个全局的配置文件,配置文件名是固定的;
application.properties
application.yml
配置文件的作用:修改SpringBoot自动配置的默认值;SpringBoot在底层都给我们自动配置好;
YAML:以数据为中心,比json、xml等更适合做配置文件。
2、YMAL语法
key: value;kv之间有空格
大小写敏感
使用缩进表示层级关系
缩进不允许使用tab,只允许空格
缩进的空格数不重要,只要相同层级的元素左对齐即可
'#'表示注释
字符串无需加引号,如果要加,例如:单引号会将 \n 作为字符串输出,双引号会将 \n 作为换行输出
3、数据类型
字面量:单个的、不可再分的值。date、boolean、string、number、null
k: v
对象:键值对的集合。map、hash、set、object
#行内写法:
k: {k1:v1,k2:v2,k3:v3}
#或
k:
k1: v1
k2: v2
k3: v3
数组:一组按次序排列的值。array、list、queue
#行内写法:
k: [v1,v2,v3]
#或者
k:
- v1
- v2
- v3
4、配置文件值注入
/**
* 将配置文件中配置的每一个属性的值,映射到这个组件中
* @ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
* prefix = "person":配置文件中哪个下面的所有属性进行一一映射
*
* 只有这个组件是容器中的组件,才能容器提供的@ConfigurationProperties功能;
*
*/
@Component
@ConfigurationProperties(prefix = "person")
@Data
public class Person {
private String userName;
private Boolean boss;
private Date birth;
private Integer age;
private Pet pet;
private String[] interests;
private List<String> animal;
private Map<String, Object> score;
private Set<Double> salarys;
private Map<String, List<Pet>> allPets;
}
@Data
public class Pet {
private String name;
private Double weight;
}
person:
userName: zhangsan
boss: false
birth: 2019/12/12 20:12:33
age: 18
pet:
name: tomcat
weight: 23.4
interests: [篮球,游泳]
animal:
- jerry
- mario
score:
english:
first: 30
second: 40
third: 50
math: [131,140,148]
chinese: {first: 128,second: 136}
salarys: [3999,4999.98,5999.99]
allPets:
sick:
- {name: tom}
- {name: jerry,weight: 47}
health: [{name: mario,weight: 47}]
我们可以导入配置文件处理器,以后编写配置就有提示了
<!--导入配置文件处理器,配置文件进行绑定就会有提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
4.1、properties配置文件在idea中默认utf-8可能会乱码
在 idea 中的配置文件(application.properties) 中配置有中文,但是读取后中文乱码,先检查配置文件的字符编码是否为 UTF-8;
原因:Intellij idea 中默认的字符集是 UTF-8的,但是配置文件默认的字符集不是 UTF-8,而是ASCII码
File-->settings-->Editor-->File Encodings:查看 Project Encoding 和 Default encoding for properties files 的值是否为 UTF-8,如果不是则设置为 UTF-8
4.2、@Value获取值和@ConfigurationProperties获取值比较
@ConfigurationProperties | @Value | |
功能 | 批量注入配置文件中的属性 | 一个个指定 |
松散绑定(松散语法) | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
复杂类型封装 | 支持 | 不支持 |
配置文件yml 还是properties他们都能获取到值;
如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;
如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;
4.3、配置文件注入值数据校验
4.3.1 @Valid与@Validated作用
@Valid与@Validated都是用来校验接收参数的,如果不使用注解校验参数,那么就需要在业务代码中校验,这样会增加很多的工作量并且代码不优美。
@Validated与@Valid区别:
@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上,不支持嵌套检测
@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上,支持嵌套检测
SpringBoot使用@Valid注解需要引入如下POM
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
4.3.2 @Valid详解
如果@Valid|Validated校验不通过,那么错误信息就会封装到BindingResult对象了,可以通过BindingResult的相关方法获取详细的错误信息并返回给用户。 代码如下:
public class Employee {
@NotBlank(message = "手机号码不能为空")
@Length(message = "电话不能超过{max}个字符", max = 2)
private String phone;
@NotNull(message = "年龄不能为空")
@Range(message = "年龄范围在{min}到{max}之间", min = 1, max = 10)
private Integer age;
@NotEmpty(message = "兴趣爱好不能为空")
@Size(message = "兴趣爱好不能超过{max}个", max = 5)
private List<String> hobbylist;
// set,get省略
}
@RestController
@RequestMapping("/valid")
public class ValidControllerTest {
@GetMapping("/test1")
// 需要用 BindingResult 来做一个校验结果接收。
// 当校验不通过的时候,如果手动不 return ,则并不会阻止程序的执行;
public String test1(@Valid Employee employee, BindingResult bindingResult){
if(bindingResult.hasErrors()){
// 返回错误数据给浏览器
StringBuilder sb = new StringBuilder();
bindingResult.getAllErrors().forEach(v -> {
sb.append(v.getDefaultMessage());
sb.append('\n');
});
return sb.toString();
}
return "数据校验通过";
}
// http://localhost:8888/valid/test1?phone=&age=&hobbylist=
// 浏览器输出:年龄不能为空 手机号码不能为空 兴趣爱好不能为空
// http://localhost:8888/valid/test1?phone=123456&age=34&hobbylist=1,2,3,4,5,6,7
// 浏览器输出:电话不能超过2个字符 兴趣爱好不能超过5个 年龄范围在1到10之间
}
4.3.3 @Validated
SpringMVC注解,用于数据校验,当校验不通过的时候,程序会抛出400异常,阻止方法中的代码执行。
@RestController
@RequestMapping("/validated")
public class ValidatedControllerTest {
@GetMapping("/test1")
//@Validated 进行校验的时候,当校验不通过的时候,程序会抛出400异常,阻止方法中的代码执行,
// 这时需要再写一个全局校验异常捕获处理类,然后返回校验提示。
public String doLogin(@Validated Employee employee){
return "数据校验通过";
}
// http://localhost:8888/validated/test1?phone=&age=&hobbylist=
// There was an unexpected error (type=Bad Request, status=400).
// Validation failed for object='employee'. Error count: 3
}
@RestControllerAdvice //增强的 @RestController,可用于全局异常处理
public class ValidExceptionHandler {
@ExceptionHandler
public String validExceptionHandler(BindException exception) {
StringBuilder sb = new StringBuilder();
exception.getAllErrors().forEach(v -> {
sb.append(v.getDefaultMessage());
sb.append("\n");
});
return sb.toString();
}
}
4.3.4 嵌套检测
嵌套检测就是在一个beanA中,存在另外一个beanB属性。嵌套检测beanA同时也检测beanB。
public class BeanA {
@NotNull(message = "beanB不能为空")
//@Valid
private BeanB beanB;
// 省略 get,set
}
public class BeanB {
@NotNull(message = "数量不为空")
@Max(message = "数量最大为{value}", value = 10)
@Min(message = "数量最小为{value}", value = 0)
private int count;
// 省略 get,set
}
beanB 没有添加 @Valid 注解,所以只能检测 beanB 属性不为空,但是不能
检测 beanB 对象中 count 属性定义的最大值和最小值。
@RestController
@RequestMapping("/valid")
public class ValidControllerTest {
@PostMapping("/test2")
// 嵌套检测
public String test2(@Valid @RequestBody BeanA beanA, BindingResult bindingResult){
if(bindingResult.hasErrors()){
// 返回错误数据给浏览器
StringBuilder sb = new StringBuilder();
bindingResult.getAllErrors().forEach(v -> {
sb.append(v.getDefaultMessage());
sb.append('\n');
});
return sb.toString();
}
return "数据校验通过";
}
/**
测试数据:
{
"beanB":{
"password":12
}
}
不加 @Valid 注解:数据校验通过
加了 @Valid 注解:数量最大为10
*/
}
4.3.4 常用注解说明
@AssertFalse:
所注解的元素必须是Boolean类型,并且值为false
@AssertTrue:
所注解的元素必须是Boolean类型,并且值为true
@DecimalMax:
所注解的元素必须是数字,并且值要小于或等于给定的BigDecimalString值
@DecimalMin:
所注解的元素必须是数字,并且值要小于或等于给定的BigDecimalString值
@Digits:
所注解的元素必须是数字,并且它的值必须有指定的位数
@Email:
所注解的元素要匹配指定的正则表达式
@Max:
所注解的元素必须是数字,并且值要小于或等于给定的值。注意如果@Max所注解的元素是null,则@Max注解
会返回true,所以应该把@Max注解和@NotNull注解结合使用
@Min:
所注解的元素必须是数字,并且值要大于或等于给定的值。注意如果@Min所注解的元素是null,则@Min注解
会返回true,即也会通过校验,所以应该把@Min注解和@NotNull注解结合使用。
@NotBlank:
所注解的元素不能为null且不能为空白,用于校验CharSequence(含String、StringBuilder和StringBuffer)
@NotEmpty:
所注解的元素不能为null且长度大于0,可以是空白,用于校验CharSequence、数组、Collection和Map
@NotNull:
所注解的元素不能为null
@Null:
所注解的元素必须为null
@Pattern:
所注解的元素必须匹配指定的正则表达式。注意如果@Pattern所注解的元素是null,则@Pattern注解会返回
true,即也会通过校验,所以应该把@Pattern注解和@NotNull注解结合使用
@Size:
所注解的元素必须符合指定的大小,该注解可用于数组,CharSequence(含String、StringBuilder和
StringBuffer),Collection和Map。注意如果@Size所注解的元素是null,则@Size注解会返回true,即也
会通过校验,所以应该把@Size注解和@NotNull注解结合使用
4.4 @PropertySource&@ImportResource&@Bean
@PropertySource:加载指定的配置文件;
@PropertySource(value = {"classpath:person.properties"})
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String userName;
private Integer age;
private Boolean boss;
}
@ImportResource:导入Spring的配置文件,让配置文件里面的内容生效;
SpringBoot里面没有Spring的配置文件,我们自己编写的配置文件不能自动识别
想让Spring的配置文件生效,加载进来,@ImportResource标注在一个配置类上
======================beans.xml=========================
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="haha" class="com.atguigu.boot.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
<bean id="hehe" class="com.atguigu.boot.bean.Pet">
<property name="name" value="tomcat"></property>
</bean>
</beans>
@ImportResource("classpath:beans.xml")
@Configuration
public class MyConfig {}
======================测试=================
boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println("haha:"+haha);//true
System.out.println("hehe:"+hehe);//true
SpringBoot推荐给容器中添加组件的方式;推荐使用全注解的方式
配置类@Configuration------>Spring配置文件
使用@Bean给容器中添加组件
/**
* @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件
*
* 在配置文件中用<bean><bean/>标签添加组件
*
*/
@Configuration
public class MyAppConfig {
//将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名
@Bean
public HelloService helloService02(){
System.out.println("配置类@Bean给容器中添加组件了...");
return new HelloService();
}
}
4.5 随机数
blog:
# 随机字符串
value: ${random.value}
# 随机 int
number: ${random.int}
# 随机 long
bignumber: ${random.long}}
# 10 以内的随机数
test1: ${random.int(10)}
# 10-20的随机数
test2: ${random.int[10,20]}
4.6 占位符
方式一
在配置文件内可以直接使用占位符来进行配置的相互引用,如下所示:
#自定义的属性,引用了spring.application.name
guo:
name: ${spring.application.name}
spring:
application:
name: sc-gateway-application
在上面的配置中,name配置直接引用了spring.application.name的配置值,这样我们在系统中通过@Value("${guo.name}")或者通过@ConfigurationProperties方式使用时,得到的值都为sc-gateway-application。
方式二
占位符——形如:${guo.name} 是一种灵活的配置方式,可以让我们很灵活的使用配置参数,这种方式可以从Environment内获取对应的配置值。
在实际部署应用程序时,有很多通过命令行参数方式实现配置是动态,不过SpringBoot所提供的配置参数名称都比较长,对此我们完全可以利用占位符配置方式实现自定义参数名。
占位符是从Environment内读取对应的配置值,而命令行参数在应用程序启动时会被一并加入到Environment中,因此也就实现了占位符动态配置,其实这个“短”的含义,是你定义的新的配置名称比较短而已。
假设我们的guo.name值需要动态指定,我们自定义一个短变量名称my-name,配置文件改为:
guo
# 占位符获取配置的值,如果没有可以用:指定默认值
name: ${my-name:erbadagang}
在运行前,配置my-name的值为trek:
运行返回:configname = trek
实际运行中多数是使用jar命令启动,所以上图配置方法的等同: java -jar project-1.0.0.SNAPSHOT.jar --my-name=trek。
方式三
像上图红色标注的,都会被完整的替换为根目录,这样在安装项目时,只需修改一处就行了。
5、SpringBoot多环境配置
5.1、多Profile文件
在Spring Boot中多环境配置⽂件名需要满⾜ application-{profile}.properties/ymal 的格式,其
中 {profile} 对应你的环境标识,⽐如:
application-dev.properties :开发环境
application-test.properties :测试环境
application-prod.properties :⽣产环境
⾄于哪个具体的配置⽂件会被加载,需要在 application.properties/yml ⽂件中通过 spring.profiles.active 属性来设置,其值对应 {profile} 值。
如: spring.profiles.active=test 就会加载 application-test.properties 配置⽂件内容。
默认使用application.properties的配置;
使用方法:application.properties/yml中配置通⽤内容,并设置 spring.profiles.active=dev ,以开发环境为默认配置,application-{profile}.properties/yml 中配置各个环境不同的内容
激活指定profile
1、在配置文件中指定 spring.profiles.active=dev
2、命令行:
java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev;
多个参数时,用空格隔开,命令行参数优先级高于 jar 文件内部的配置文件参数。
3、虚拟机参数;
-Dspring.profiles.active=dev
5.2、yml文档块方式
1、yml 文件支持多文档块方式,同一个 yml 文件中,可以使用"---"来区分不同的文档,相当于不同的配置文件
2、这也是 Spring Boot 官方推荐的方式
spring:
profiles:
active: devel #指定激活哪个环境配置,激活后,第一个文档内容失效;不指定时,以第一个文档为准
server:
port: 8083
--- #"---"用于分隔不同的profiles()文档块
spring:
profiles: devel #指定环境标识为"devel",相当于"application-{profile}.properties/yml"中的profile
server:
port: 8081
---
spring:
profiles: deploy #指定环境标识为"deploy",相当于"application-{profile}.properties/yml"中的profile
server:
port: 8082
6、配置文件位置与加载顺序
1)Spring boot 启动时自动扫描以下位置的 application.properties 或者 application.yml 文件作为 Spring boot 的默认配置文件。
–file:./config/ -------------整个项目根目录下的config目录下
–file:./ ---------------------整个项目根目录下
–classpath:/config/---------类路径下的config目录下
–classpath:/-----------------类路径根目录下
2)优先级从上往下由高到底,高优先级的配置会覆盖低优先级的配置;Spring Boot 会从这四个位置加载所有的主配置文件,如果高优先级的内容与低优先级的内容相同,则覆盖;如果低优先级的内容在高优先级中没有,则形成互补。
3、应用启动后,1 位置的端口会生效,控制台会输出:Tomcat started on port(s): 8081 (http) with context path '/coco'
4、项目打包之后,与 jar 同目录下的位置相当于位置2,与 jar 同目录下的 config 子目录相当于位置 1.
7、外部配置加载位置与顺序
Spring Boot 支持多种外部配置方式,如下所示,从上往下加载优先级由高到低,内容相同时覆盖,不相同时累加。
1、命令行参数
2、来自 java:comp/env 的 JNDI 属性
3、使用“spring.config.location”改变默认的配置文件位置
4、Java 系统属性(System.getProperties())
5、操作系统环境变量
6、RandomValuePropertySource 配置的 random.* 属性值
由jar包外向jar包内进行寻找;
优先加载带profile
7、jar 包外部的 application-{profile}.properties 或 application.yml (带spring.profile) 配置文件
8、jar 包内部的 application-{profile}.properties 或 application.yml (带spring.profile) 配置文件
再来加载不带profile
9、jar 包外部的 application.properties 或 application.yml (不带spring.profile) 配置文件
10、jar 包内部的 application.properties 或 application.yml (不带spring.profile) 配置文件
11、@Configuration注解类上的@PropertySource
12、通过SpringApplication.setDefaultProperties指定的默认属性
官方文档:Externalized Configuration
命令行参数
1、命令行参数格式:java -jar xxxxx.jar --server.port=8082
2、多个参数时,用空格隔开,如: java -jar xxxxx.jar --server.port=8082 --server.servlet./context-path=/coco
3、修改端口同时指定上下文路径,命令行参数优先级高于 jar 文件内部的配置文件参数。
spring.config.location
1、通过 --spring.config.location 可以指定新的配置文件位置,自定义的外部配置文件优先级高于Jar文件内部的配置文件。
2、项目打包好以后,使用命令行参数的形式,启动项目的时候来指定配置文件的新位置:
新指定的配置文件和默认加载的这些配置文件共同起作用形成互补配置;
格式:java -jar spring-boot-xxx.jar --spring.config.location=G:/application.properties
spring-boot-xxx.jar 是打包好的应用文件、G:/application.properties是新的配置文件路径
3、当 application.properties 或 application.yml 文件在 xxx.jar 应用同目录下时,可以省略 --spring.config.location,直接双击运行,它会自动读取当前目录下的配置 application.properties 或 application.yml 文件。
8、Spring Boot 核心配置文件
1、SpringBoot 的核心配置文件有两个:bootstrap (.yml 或者 .properties),application (.yml 或者 .properties)。
2、Spring Boot 中有两种上下文,一种是 bootstrap, 另外一种是 application, bootstrap 是应用程序的父上下文。两个上下文共用一个环境,它是任何 Spring 应用程序的外部属性的来源。
3、boostrap 由父 ApplicationContext 加载,比 applicaton 优先加载,都可以用来配置参数。
4、bootstrap 优于 application 加载;bootstrap 偏向系统层级的参数配置,Bootstrap 属性有高优先级,默认情况下,它们不会被本地配置覆盖。application 偏向应用层级的参数配置。
4、使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;
a、一些固定的不能被覆盖的属性
b、一些加密/解密的场景;
参考文章:SpringBoot2.x配置文件使用占位符的几种方式_springboot 配置文件占位符
Spring Boot 核心配置文件,yml 语法规范、 多环境配置、配置文件加载顺序_springboot核心配置文件
@Valid与@Validated区别_valid和validated的区别