文章目录
application.properties
-
SpringBoot 的核心配置文件
-
配置文件名:application.properties | yml
-
不能改变
-
-
扩展名
- properties;数据格式:
k=v
- yaml、yml;数据格式:
k: v
application.properties
或application.yml
- 当两种格式配置文件同时存在
properties
优先级最高- 在父工程中配置文件加载顺序
- yml → yaml → properties
- 后加载的配置文件会将先加载的配置覆盖掉
- properties;数据格式:
-
定义 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
可查看生效的配置
- 所有配置文件中能配置的属性都是在
yaml
语法格式
-
语法
-
大小写敏感
-
使用缩进表示层级关系
-
缩进时不允许使用 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
组 - 2.4 版本重命名
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 # 生产环境
- 使用
自定义K-V
-
配置文件中可以自定义 key
- 在赋值引用时可以引用框架的 key 或 自定义key
demo: name: 张三${random.uuid} age: 19 map: demo1: 18 demo2: 20 hobby: - 唱 - 跳 - rap
@Value
-
@Value(${key})
- key 来自配置文件
- 当指定使用了其他配置文件时
- 获取 key 优先从指定的配置文件搜索
- 若该文件没有定义此 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
@ConfigurationProperties
作用
- 将整个文件映射成一个对象
- 用于自定义配置较多的情况
- 同时将整个类中属性赋值
- 根据属性名和 key 一致进行赋值
- set 注入,类中必须存在 set 方法
- 会提示添加依赖项
- 添加后可以显示自定义 key 的引用信息
- 属性:
prefix
、value
:指定配置文件中 key 的前缀- 这两个属性作用一样
- 对比
@Value
- 可以批量注入对象属性,
@value
需要一个一个赋值 - 支持松散绑定,@Value 支持
- 配置文件中属性名和类属性名可不完全一致
- Java 中对于驼峰命名法,可用原名或使用 - 代替驼峰
- 如:lastName 属性,yml 中使用 lastName 或 last-name 都可正确映射
- 不支持SpEL,@Value 不支持
- SpEL 使用
#{...}
作为定界符 ,- 所有在大括号中的字符都将被认为是 SpEL
- 通过 SpEL
- 通过 bean 的 id 对 bean 进行引用
- 调用方式以及引用对象中的属性
- 计算表达式的值
- 正则表达式的匹配
- SpEL 使用
- 支持 JSR303 数据校验,@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;
}
JSP303
- JSR:
Java Specification Requests
,Java 规范提案- 指向JCP(Java Community Process) 提出新增一个标准化技术规范的正式请求
- 任何人都可以提交 JSR,以向 Java 平台增添新的 API 和服务
- JSR 已成为 Java 界的一个重要标准
- JSR-303 是JAVA EE 6 中的一项子规范
- 叫做
Bean Validation
- 叫做
@Validated
- 进行数据格式校验
- 空检查
@Null
:被注释的元素必须为null
@NotNull
:被注释的元素必须不为null
- 无法查验
""
字符串
- 无法查验
@NotBlank
:被注释字符串必须不为null
且被trim()
后长度大于 0- 只针对字符串且会去掉前后空格
@NotEmpty
:被注释的字符串的必须非空
- Booelan 检查
@AssertTrue
:被注释的元素必须为true
@AssertFalse
:被注释的元素必须为false
- 长度检查
@Size(max, min)
:被注释的元素的长度必须在指定的范围内- Array、Collection、Map、String 类型元素
@Length(min=, max=)
:被注释的字符串的长度必须在指定的范围内
- 日期检查
@Past
:被注释的元素必须是一个过去的日期@Future
:被注释的元素必须是一个将来的日期
- 正则验证
@Pattern
:被注释的元素必须符合指定的正则表达式regexp
:正则表达式flags
:指定Pattern.Flag
的数组,表示正则表达式的相关选项
- 数值检查
- 建议使用在
Stirng
、Integer
类型- 不建议使用在
int
类型- 表单值为
""
时无法转换为int
- 但
Stirng
可为""
,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
:递归的对关联对象进行校验- 如果关联对象是集合或者组
- 对其中的元素进行递归校验
- 如果是一个map
- 对其中的值部分进行校验
- 如果关联对象是集合或者组
- 建议使用在
- 特殊格式
@CreditCardNumber
:信用卡验证@Email
:被注释的元素必须是电子邮箱地址- 为
null
,不进行验证,算通过验证
- 为
@ScriptAssert(lang= ,script=, alias=)
:JS 验证@URL(protocol=,host=, port=,regexp=, flags=)
:- 被注解元素必须是 url
使用
-
需要校验的参数 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); } }
-
-
分组解决校验
-
新增和修改对于实体的校验规则是不同的
- 例:id 自增,新增时 id 要为空,修改则必须不为空
- 新增和修改若用的恰好是同一种实体就需要用到分组校验
- 例:id 自增,新增时 id 要为空,修改则必须不为空
-
校验注解都有一个
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(); } }
-
-