SpringBoot 的核心配置文件
配置文件名:application.properties | yml
不能改变
扩展名
k=vk: v
application.properties 或 application.ymlproperties 优先级最高定义 SpringBoot 的相关设置
properties 格式
# 设置端口号
server.port=80
# 设置访问应用的上下文路径;访问路径在 /root下
server.servlet.context-path=/root
yml 格式
# 下级换行空格,赋值冒号空格
server:
port: 80
servlet:
context-path: /root
# 行内写法
server: { port: 80, servlet: {context-path: /js} }
# 数组
array:
- cat
- dog
# 行内数组
array: [cat, dog]
配置文件中所有能配置的项都和配置类中属性相关
xxxxProperties 类中封装
xxxxAutoConfigurartion:自动配置类,给容器中添加组件
xxxxProperties:封装配置文件中相关属性
debug=true 可查看生效的配置语法
大小写敏感
使用缩进表示层级关系
缩进时不允许使用 Tab 键,只允许使用空格
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
# :注释,从这个字符一直到行尾,都会被解析器忽略
k: v:字面量直接写
字符串默认不用加上 '' 或 ""
"":双引号不会转义字符串里面的特殊字符
'':单引号会转义特殊字符
支持的数据结构有三种
对象:键值对的集合,又称为映射 / 哈希 / 字典
数组:一组按次序排列的值,又称为序列/ 清单 / 列表
纯量:单个的、不可再分的值
yml 支持不同开发环境写在同一个文件
---- 隔开等价于多个配置文件缩进/区块 以及内置(inline)两种格式,表示清单(数组)和散列表
--- # 缩进数组
- Casablanca
- North by Northwest
- Notorious
--- # 内置数组
[milk, pumpkin pie, eggs, juice]
--- # 散列表
person:
name: John Smith
age: 33
--- # 內置
person: {name: John Smith, age: 33}
配置和显示都按句子换行
直接使用 \n 换行
\n 在显示的时候换行,配置行末的 \ 让字符串换行继续写
必须使用双引号定义字符串,不能用单引号
\n 换行string: "I am a coder.\n\
My blog is didispace.com."
# 输出效果
# I am a coder.
# My blog is didispace.com
|
|:文中自动换行,文末新增一空行
|+:文中自动换行,文末新增两空行
|-:文中自动换行,文末不新增行
换行字符会被转换成空白字符,而引领空白字符则会被自动消去
---
string: |
I am a coder.
---
string: |+
I am a coder.
---
string: |-
I am a coder.
配置按段落,显示在一行
直接换行写
# 单双引号都可
string: 'I am a coder.
My blog is didispace.com.'
>
>:文中不自动换行,文末新增一空行
>+:文中不自动换行,文末新增两空行
>-:文中不自动换行,文末不新增行
---
string: >
I am a coder.
---
string: >+
I am a coder.
---
string: >-
I am a coder.
# 分为两种不同环境
server:
port: 8081
spring:
profiles:
active: prod # 激活对应的环境配置
---
server:
port: 8083
spring:
profiles: dev # 指定属于哪个环境
--- # 数据结构可以用类似大纲的缩进方式呈现
receipt: Oz-Ware Purchase Invoice
date: 2012-08-06
customer:
given: Dorothy
family: Gale
items:
- part_no: A4786
descrip: Water Bucket (Filled)
price: 1.47
quantity: 4
- part_no: E1628
descrip: High Heeled "Ruby" Slippers
size: 8
price: 133.7
quantity: 1
bill-to: &id001 # 锚点
street: |
123 Tornado Alley
Suite 16
city: East Centerville
state: KS
ship-to: *id001 # 引用
specialDelivery: >
Follow the Yellow Brick
Road to the Emerald City.
Pay no attention to the
man behind the curtain.
items 两个元素构成的数组(或称清单)
bill-to 散列表的内容复制到 ship-to 散列表--- 分隔... 可以用来表示文件结
高优先级的配置文件会覆盖低优先级的配置文件
SpringBoot 会从四个位置全部加载主配置文件
spring.config.location 改变默认的配置文件位置java -jar spring-boot-demo-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties
按优先级顺序排序:
file:./config:
config 目录中file:./
classpath:/config/
resource 目录下的 cofig 目录中classpath:/:默认生成配置文件位置
resource 目录下直接创建src/main/java 目录下目录结构
项目名
- src
- main
- java
- 第四位置
- resource
- static
- templates
- config
- 第三位置
- 第四位置
- test
- target
- pom.xml
- config
- application.properties:第一位置
- 第二位置
项目开发中经历多个阶段:开发、测试、上线 等
为了方便在不同环境间切换 SpringBoot 提供了多环境配置
application-环境标识.properties | yml
application-dev.properties 开发环境在主配置文件指定使用的配置文件
spring.profiles.active=dev
yml 格式配置支持多文档模块
--- 将同一个文档中分隔为多个文档
Profile 组spring.profiles 为 spring.config.activate.on-profile--- # 主配置文件
server:
port: 82
spring:
profiles:
active: dev # 指定使用开发环境配置文件
--- # 开发环境配置文件
server:
port: 83
spring:
config:
activate:
on-profile: dev # 开发环境,不同环境配置文件标识
--- # 生产环境配置文件
server:
port: 84
spring:
config:
activate:
on-profile: pro # 生产环境
配置文件中可以自定义 key
demo:
name: 张三${random.uuid}
age: 19
map:
demo1: 18
demo2: 20
hobby:
- 唱
- 跳
- rap
@Value(${key})
# 主配置文件
spring:
profiles:
active: dev # 指定使用开发环境配置文件,dev是自定义名
server:
servlet:
context-path: /demo
port: 8081
name: 张三 # 开发环境配置文件不存在这两个key,故使用这两个 key 赋值
age: 18
address: 北京
---
# 开发环境配置文件
server:
port: 8001 # 使用这个端口号赋值
servlet:
context-path: /test
address: 上海 # 使用这个地址赋值
---
# 以下属于Java类中注解引用配置文件赋值
@Value("${name}") # 张三
private String name;
@Value("${age}") # 18
private Integer age;
@Value("${address}") # 上海
private String address;
@Value("${server.port}") # 8001
private Integer port;
Spring Boot 配置文件支持占位符:${}
${random.value}
${random.int}
${random.long}
${random.int(10)}
${random.int[1024,65536]}
: 指定默认值person.last-name=张三${random.uuid}
person.age=${random.int}
person.birth=2017/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
# 使用默认值
person.dog.name=${person.hello:hello}_dog
person.dog.age=15
prefix、value:指定配置文件中 key 的前缀
@Value
@value 需要一个一个赋值#{...} 作为定界符 ,
yaml 配置文件定义类属性值
# 配置文件中定义 Person 类属性 使用 person 作为前缀
person: # 对象
boss: false
maps: # Map 集合
k1: v1
k2: 14
lists: # List 集合
- name: d1
age: ${demo.map.demo1:20}22 # demo1值存在时赋值,否则赋值20;追加默认值22
- name: d2
age: 3
- {name: d3,age: 4} # 行内写法
birth: 2017/12/15 # Date
dog: # 对象属性
name: p_dog
age: 15
age: 13
last-name: 张三${random.uuid} # 使用随机uuid,松散绑定属性
arr: [s1,s2,s3] # 数组,行内写法
实体类中引用配置文件中的定义
@Component
@Data //自动生成set、get、toString()、equals()、hashCode() 等 方法
@NoArgsConstructor //声明生成无参构造
@AllArgsConstructor //声明生成有参构造
@ConfigurationProperties(prefix = "person")
public class Person {
private String lastName;
private Integer age;
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Dog> lists;
private Dog dog;
private String[] arr;
}
@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "demo")
public class Dog {
private String name;
private Integer age;
}
Java Specification Requests,Java 规范提案
Bean Validation@Null:被注释的元素必须为 null@NotNull:被注释的元素必须不为 null
"" 字符串@NotBlank:被注释字符串必须不为 null 且被 trim() 后长度大于 0
@NotEmpty:被注释的字符串的必须非空@AssertTrue:被注释的元素必须为 true@AssertFalse:被注释的元素必须为 false@Size(max, min) :被注释的元素的长度必须在指定的范围内
@Length(min=, max=):被注释的字符串的长度必须在指定的范围内@Past:被注释的元素必须是一个过去的日期@Future:被注释的元素必须是一个将来的日期@Pattern:被注释的元素必须符合指定的正则表达式
regexp:正则表达式flags:指定 Pattern.Flag 的数组,表示正则表达式的相关选项Stirng、Integer 类型
int 类型
"" 时无法转换为intStirng 可为 "",Integer 可为 null@Min(value):被注释的元素必须是值大于等于指定的最小值的数字@Max(value):被注释的元素必须是值小于等于指定的最大值的数字@DecimalMin(value):被注释的元素必须是值大于等于指定的最小值的数字
@DecimalMax(value):被注释的元素必须是值小于等于指定的最大值的数字
@Digits:被注释的元素必须是一个数字,其值必须在可接受的范围内
interger:指定整数精度fraction:指定小数精度@Range(min=, max=) :被指定的元素必须在合适的范围内
@Range(min=10000, max=50000, "message=range.bean.wage")@Valid:递归的对关联对象进行校验
@CreditCardNumber:信用卡验证@Email:被注释的元素必须是电子邮箱地址
null,不进行验证,算通过验证@ScriptAssert(lang= ,script=, alias=) :JS 验证@URL(protocol=,host=, port=,regexp=, flags=):
需要校验的参数 Bean 前添加 @Valid 开启校验功能
校验的 Bean 后添加一个 BindingResult
BindingResult 封装了前面 Bean 的校验结果
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("")
public Result save (@Valid User user , BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
Map<String , String> map = new HashMap<>();
bindingResult.getFieldErrors().forEach( (item) -> {
String message = item.getDefaultMessage();
String field = item.getField();
map.put( field , message );
} );
return Result.build( 400 , "非法参数 !" , map);
}
return Result.ok();
}
}
异常的统一处理
参数校验不通过时,会抛出 BingBindException 异常
可以进行统一异常处理中,不用在每个需要参数校验的地方都用 BindingResult 获取校验结果
@Slf4j
@RestControllerAdvice(basePackages = "com.itwolfed.controller")
public class GlobalExceptionControllerAdvice {
@ExceptionHandler(value= {MethodArgumentNotValidException.class , BindException.class})
public Result handleVaildException(Exception e){
BindingResult bindingResult = null;
if (e instanceof MethodArgumentNotValidException) {
bindingResult = ((MethodArgumentNotValidException)e).getBindingResult();
} else if (e instanceof BindException) {
bindingResult = ((BindException)e).getBindingResult();
}
Map<String,String> errorMap = new HashMap<>(16);
bindingResult.getFieldErrors().forEach((fieldError)->
errorMap.put(fieldError.getField(),fieldError.getDefaultMessage())
);
return Result.build(400 , "非法参数 !" , errorMap);
}
}
分组解决校验
新增和修改对于实体的校验规则是不同的
校验注解都有一个 groups 属性,可将校验注解分组
groups 是 Class> 类型的数组,@NotNull 源码
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
@Documented
@Constraint(validatedBy = { })
public @interface NotNull {
String message() default "{javax.validation.constraints.NotNull.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@interface List {
NotNull[] value();
}
}
创建一个 Groups
public class Groups {
public interface Add{}
public interface Update{}
}
给参数对象的校验注解添加分组
@Data
public class User {
@Null(message = "新增不需要指定id" , groups = Groups.Add.class)
@NotNull(message = "修改需要指定id" , groups = Groups.Update.class)
private Integer id;
@NotBlank(message = "用户名不能为空")
@NotNull
private String username;
@Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$", message = "密码必须为8~16个字母和数字组合")
private String password;
@Email
private String email;
private Integer gender;
}
Controller 中原来的 @Valid 不能指定分组 ,需要替换成 @Validated
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("")
public Result save (@Validated(Groups.Add.class) User user) {
return Result.ok();
}
}