文章目录
- 一、为什么需要配置文件?
- 二、SpringBoot两种配置文件
-
- [2.1 文件存放位置与加载规则](#2.1 文件存放位置与加载规则)
- [2.2 application.propertie 键值对格式](#2.2 application.propertie 键值对格式)
-
- [1. 基础语法](#1. 基础语法)
- [2. 读取配置:@Value](#2. 读取配置:@Value)
- [3. properties缺点](#3. properties缺点)
- [三、application.yml YAML树形配置](#三、application.yml YAML树形配置)
-
- [3.1 语法](#3.1 语法)
- [3.2 yml支持全类型数据配置](#3.2 yml支持全类型数据配置)
-
- [1. 基础数据类型](#1. 基础数据类型)
- [2. 字符串单双引号特殊规则](#2. 字符串单双引号特殊规则)
- [3. 配置对象](#3. 配置对象)
- [4. 配置 List & Map](#4. 配置 List & Map)
- [3.3 两种读取配置注解对比](#3.3 两种读取配置注解对比)
- [3.4 yml优缺点](#3.4 yml优缺点)
- [四、yml配置 + Hutool图形验证码案例](#四、yml配置 + Hutool图形验证码案例)
-
- [4.1 需求说明](#4.1 需求说明)
- [4.2 引入Hutool验证码依赖](#4.2 引入Hutool验证码依赖)
- [4.3 yml配置验证码参数](#4.3 yml配置验证码参数)
- [4.4 创建配置映射实体CaptchaProperties](#4.4 创建配置映射实体CaptchaProperties)
- [4.5 后端Controller 生成校验验证码](#4.5 后端Controller 生成校验验证码)
- [4.6 前端页面](#4.6 前端页面)
一、为什么需要配置文件?
开发中如果把端口、数据库账号、第三方密钥直接写死在代码里,也就是硬编码,会带来极大维护问题:
- 环境切换(本地/测试/生产)需要反复改代码、重新打包;
- 敏感信息暴露在源码中,存在安全风险;
- 统一参数修改需要全局检索代码,效率极低。
配置文件的作用:把可变参数抽离到独立文件,程序启动自动读取,统一管理所有外部配置。
SpringBoot内置两套主流配置文件:application.properties、application.yml(yaml),可以维护端口、数据库、日志、自定义业务参数等配置。
二、SpringBoot两种配置文件
2.1 文件存放位置与加载规则
配置文件统一放在 src/main/resources 目录,项目启动自动加载:
application.properties:SpringBoot创建项目默认生成,键值对格式;application.yml/application.yaml:新式树形层级格式,是开发主流;
两者同时存在时,二者取并集,properties优先级更高,同名配置会覆盖yml;但是项目最好统一只用一种格式,避免两套配置造成维护混乱。
2.2 application.propertie 键值对格式
1. 基础语法
key=value,# 单行注释,层级通过.分隔。
properties
# 修改Tomcat端口
server.port = 9090
# MySQL数据库配置
spring.datasource.url = jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding = utf8&useSSL=false
spring.datasource.username = root
spring.datasource.password = root
# 自定义业务配置
my.test.key=demo123
2. 读取配置:@Value
使用 ${配置key} 读取参数,适合零散、独立的配置,仅支持单个简单值
java
@RestController
@RequestMapping("/prop")
public class PropController {
// 读取properties自定义参数
@Value("${my.test.key}")
private String testKey;
@RequestMapping("/get")
public String getConfig() {
return "读取properties配置:" + testKey;
}
}
3. properties缺点
多层级配置存在大量重复前缀:
properties
spring.datasource.url=xxx
spring.datasource.username=root
spring.datasource.password=root
每一行都要重复写spring.datasource,层级越深冗余越严重
三、application.yml YAML树形配置
YAML全称Yet Another Markup Language(另一种标记语言),树形缩进结构,可读性更强,支持对象、集合、Map等复杂数据。
3.1 语法
- 基础格式:
key: value冒号后必须加英文空格,缺少空格直接解析报错; - 层级区分:使用缩进(2个空格) 代表父子层级;
- 注释:
#单行注释; - 行内写法:大括号
{}简化单层对象/Map,短横线-代表集合元素。
数据库配置
yaml
# application.yml
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding=utf8&useSSL=false
username: root
password: root
对比properties,yml消除重复前缀,层级更清晰。
3.2 yml支持全类型数据配置
1. 基础数据类型
yaml
# 字符串
str: Hello SpringBoot
# 布尔值
bool: true
# 数字
num: 666
floatNum: 3.14
# null:~代表空值
empty: ~
# 空字符串
emptyStr: ''
2. 字符串单双引号特殊规则
yaml
string:
str1: Hello \n Boot # 无引号:\n 原样输出,不换行
str2: 'Hello \n Boot' # 单引号:转义所有特殊字符,\n仅作为文本
str3: "Hello \n Boot" # 双引号:保留转义字符,\n会自动换行
3. 配置对象
yaml
# 标准缩进写法
person:
id: 1
name: daisy
age: 10
# 行内简写,效果完全一致
person: {id: 1, name: daisy, age: 10}
注意 :对象不能用@Value读取 ,必须使用@ConfigurationProperties批量绑定。
java
@ConfigurationProperties(prefix = "person")
@Configuration
@Data
public class Person {
private int id ;
private String name;
private int age;
}
4. 配置 List & Map
- List集合
yaml
db-types:
name:
- mysql
- sqlserver
- db2
List和数组的配置完全相同,可以使用List接收,也可以使用数组接收
- Map键值对集合
yaml
map-demo:
map:
k1: v1
k2: v2
# 行内简写
map-demo: {map: {k1: v1, k2: v2}}
java
@Data
@Component
@ConfigurationProperties(prefix = "dbtypes")
public class DBTypes {
private List<String> name;
private Map<String,String> ball;
}
3.3 两种读取配置注解对比
| 特性 | @Value | @ConfigurationProperties |
|---|---|---|
| 适用场景 | 单个简单参数、零散配置 | 批量绑定一组配置、对象/List/Map |
| 复杂类型 | 不支持对象、集合、Map | 完美支持嵌套对象、List、Map |
| 松散绑定 | 严格匹配key名称 | 支持驼峰、短横线、下划线自动映射 |
不论使用application.properties还是application.yml,二者的读取方式都是通过这两个注解来完成,因此读取方式基本相同
3.4 yml优缺点
✅ 优点:
- 树形层级清晰,消除重复配置,可读性极高;
- 原生支持对象、数组、Map等复杂数据结构;
- 跨语言通用,Java、Go、Python、前端均可使用。
❌ 缺点: 格式要求严苛,缩进、空格错误直接启动失败;
四、yml配置 + Hutool图形验证码案例
4.1 需求说明
- 访问接口返回图形验证码图片;
- 验证码存入Session,有效期1分钟;
- 前端输入验证码提交,后端校验是否匹配、是否过期;
- 验证码宽高、Session键名全部抽离到yml配置,统一管理。
4.2 引入Hutool验证码依赖
pom.xml
xml
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
<version>5.8.22</version>
</dependency>
4.3 yml配置验证码参数
application.yml
yaml
captcha:
width: 150
height: 50
session:
key: CAPTCHA_SESSION_KEY
date: CAPTCHA_SESSION_DATE
4.4 创建配置映射实体CaptchaProperties
java
@Data
@Configuration
@ConfigurationProperties(prefix = "captcha")
public class CaptchaProperties {
private Integer width;
private Integer height;
private Session session;
@Data
public static class Session{
private String key;
private String date;
}
}
注意: 普通的内部类不能交给Spring管理,因为要依托外内部类存在,改成静态内部类就不再依托外部类,可以交给Spring管理
4.5 后端Controller 生成校验验证码
java
@RestController
@RequestMapping("/captcha")
public class CaptchaController {
@Autowired
CaptchaProperties captchaProperties;
private final static Long VALID_TIME = 60*1000L;
@RequestMapping("/getCaptcha")
public void getCaptcha(HttpServletResponse response, HttpSession session) throws IOException {
response.setContentType("image/jpeg");
//理论上由前端处理浏览器缓存问题
response.setHeader("Pragma", "No-cache");
//生成验证码
ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(captchaProperties.getWidth(), captchaProperties.getHeight());
String code = shearCaptcha.getCode();
session.setAttribute(captchaProperties.getSession().getKey(), code);
session.setAttribute(captchaProperties.getSession().getDate(), System.currentTimeMillis());
shearCaptcha.write(response.getOutputStream());
response.getOutputStream().close();
}
@RequestMapping("/check")
public boolean check(String captcha, HttpSession session){
//判空
if(!StringUtils.hasLength(captcha))
return false;
//验证
Object codeAttr = session.getAttribute(captchaProperties.getSession().getKey());
Object dateAttr = session.getAttribute(captchaProperties.getSession().getDate());
if(codeAttr == null || dateAttr == null)
return false;
String code = codeAttr.toString();
long date = (long) dateAttr;
boolean isValid = System.currentTimeMillis() - date <= VALID_TIME;
return captcha.equalsIgnoreCase(code) && isValid;
}
}
4.6 前端页面
- index.html 验证码输入页
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>验证码</title>
<style> #inputCaptcha {
height: 30px;
vertical-align: middle;
}
#verificationCodeImg{
vertical-align: middle;
}
#checkCaptcha{
height: 40px;
width: 100px;
}
</style>
</head>
<body>
<h1>输入验证码</h1>
<div id="confirm">
<input type="text" name="inputCaptcha" id="inputCaptcha">
<img id="verificationCodeImg" src="/captcha/getCaptcha" style="cursor: pointer;" title="看不清?换一张" />
<input type="button" value="提交" id="checkCaptcha">
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script> $("#verificationCodeImg").click(function(){
$(this).hide().attr('src', '/captcha/getCaptcha?dt=' + new Date().getTime()).fadeIn();
});
$("#checkCaptcha").click(function () {
$.ajax({
type: "post",
url: "/captcha/check",
data:{
captcha: $("#inputCaptcha").val()
},
success: function (result) {
if(result)
location.href = "success.html";
else
alert("验证码错误,请重新输入");
}
})
});
</script></body>
</html>