
[JavaEE进阶] SpringBoot 配置文件详解
- 1. 配置文件是干嘛的?
- 2. 快速入手:把 8080 改成 9090
- 3. SpringBoot 支持的三种配置文件格式
- 4. properties 配置文件说明
- 5. yml 配置文件说明
- 6. 综合练习:Hutool 图形验证码
- 7. 总结与速查清单
前言:
这里是小谢同学的 SpringBoot 配置文件学习记录,整理自 JavaEE 进阶相关内容。有错误欢迎大家指出,专栏还有 Java、网络、C 语言等系列笔记欢迎翻阅。如果整篇只记一句话,我希望是这句:配置文件的本质,就是“把会变的东西从代码里挪出来”。而 SpringBoot 给了你两套写法——老派的
properties和新潮的yml,选哪个、怎么写、怎么读,这篇一次说清。
1. 配置文件是干嘛的?
先说个大白话结论:配置文件就是“把写死在代码里的东西拿出来,放到一个集中的地方”。
先说说什么叫“写死”(硬编码)。硬编码就是把数据直接嵌到程序源代码里,说白了就是“代码写死”。
也就是不能根据用户的需求来进行调整,就好像手机的字体大小一样,每个人的喜好都各不一样,如果采取了硬编码的形式来编写代码,只有我们程序员来设置字体大小,写死了,有些用户视力,以及个人习惯都不一样,这样用户的体验感就非常不好~
如果采用配置文件:把字号放在配置文件里,程序启动时读一下用户设置,按用户的偏好显示。这样能有效加强用户的体验感~
同样的道理,配置文件能让程序完成用户与应用程序的交互,也能完成应用程序与其他程序的交互。
那 SpringBoot 里,什么东西需要放到配置文件里?其实也就这几类:
| 配置内容 | 为什么需要它 |
|---|---|
| 项目的启动端口 | SpringBoot 内置 Tomcat,默认 8080,但 8080 很可能被别的程序占了 |
| 数据库连接信息(url / 用户名 / 密码) | 每个项目连的数据库都不一样,持久层框架必须支持自定义 |
| 第三方系统的调用密钥 | 不同环境、不同客户,密钥肯定不同 |
| 普通日志和异常日志 | 用来发现和定位问题 |
顺便说一下 SpringBoot 在这件事上的另一层贡献:它定义并统一了配置文件的格式,其他框架想集成进 SpringBoot,必须得按它的规矩来。这就是“规范”带来的好处。
2. 快速入手:把 8080 改成 9090
前面说过,Tomcat默认的端口号是8080,例如,我们启动一个springboot项目:

如果当端口号被占用时,这时候程序启动就会失败,此时就需要修改启动时的端口号
spring项目在创建之初已经顺手帮我们建好了配置文件。打开 application.properties,改一行:
server.port=9090
重启程序观察日志:

端口号一定要选对。
8080常被 IDEA、其他 Java 进程、甚至微信开发者工具占着。启动报Port 8080 was already in use的时候,这时候不要急着怀疑代码,先去配置文件换个端口,或者改回来之前那个。
3. SpringBoot 支持的三种配置文件格式
SpringBoot 的配置文件一共有三种:
application.propertiesapplication.ymlapplication.yaml
yml 是 yaml 的简写,实际开发中出现频率最高。yaml 和 yml 的用法完全一样,所以这里只来讲解 yml。
程序启动时,SpringBoot 会自动从 classpath 路径找到并加载这几个文件(application.properties、application.yaml 或 application.yml)。当然,也可以自己指定,比如通过 spring.config.name 参数来改名字和路径。
这就像商品的包装:
properties:是老款的包装
yml: 则是新款的包装
spring默认创建时生成的是老款包装:properties
这从而衍生出了一个面试题:yml和properties有什么区别?
| 说明 | 内容 |
|---|---|
| ① 能共存吗? | 理论上 .properties 和 .yml 可以同时存在一个项目中,两个配置都会加载;如果内容冲突,以 .properties 为主,也就是 .properties 优先级更高 |
| ② 实际怎么用? | 虽然能共存,但真实业务里我们通常统一只用一种格式,这样更好维护,也能降低故障率 |
💡 一句话记住优先级:properties > yml > yaml(同名冲突时)。
4. properties 配置文件说明
properties是最早期的配置文件格式,也是创建 SpringBoot 项目时的默认格式。
4.1 基本语法
properties是以键值对的形式配置的,key和value之间用=连接:
例如:
# 配置项目端口号
server.port=8080
# 配置数据库连接信息
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
💡 小技巧:配置文件中用
#来添加注释信息。
4.2 读取配置:@Value
主动读取配置文件中的内容,可以用 @Value 注解。@Value 使用 ${} 的格式读取:
我们首先得在: application.properties 里先写一个自定义配置:
mykey.key1=helloWord
然后在 Controller 里读它:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PropertiesController {
@Value("${mykey.key1}")
private String key1;
@RequestMapping("/key")
public String key() {
return "读取到值:" + key1;
}
}
浏览器访问 /key,就能看到 读取到值:helloWord。

💡
${}里写的是配置文件的 key 全名,别写成 Java 字段名。字段叫key1,但配置里是mykey.key1,写错了启动就报Could not resolve placeholder。

4.3 properties 的缺点
properties 是 key-value 的形式,好处是简单,坏处是——冗余信息特别多。
当我们配置文件中写的特别多的时候,看起来就很冗余,让人看起来就不是特别的简洁明了,感觉看起来一坨一坨的,不方便程序员理解;
我们来看上面那段数据库配置,spring.datasource 被重复写了三遍:
spring.datasource.url=...
spring.datasource.username=...
spring.datasource.password=...
配置项一多,这种重复就爆炸式增长,我们想要去修改个前缀还得全局替换一遍。
此时yml就能很好的解决冗余的问题,yml天生就是树形结构有很强的可读性
5. yml 配置文件说明
yml是YAML的缩写,全称 Yet Another Markup Language,翻译过来就是“另一种标记语言”。名字很谦虚,格式很好用。
5.1 基本语法
yml是树形结构的配置文件,基础语法是key: value。
❤️ 注意:key 和 value 之间使用英文冒号加空格的方式组成,冒号后面的空格是一定不可以省略!
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/dbname?characterEncoding=utf8&useSSL=false
username: root
password: root
第一项(spring: 带空格)是正确写法,key 在 IDEA 里会高亮显示;如果写成 spring:datasource 少了空格,key 就不会高亮,配置也不会生效。
两者的对比:

| 对比项 | properties | yml |
|---|---|---|
| 写法 | spring.datasource.url=... 平铺 | spring: 换行缩进,树形 |
| 层级表达 | 靠 . 点号连接 | 靠换行 + 缩进 |
| 前缀重复 | 每行都要重复写 spring.datasource | 只写一次,子项缩进即可 |
| 可读性 | 一般 | 更好,一眼看出层级关系 |
❤️ 注意: yml 里
key:后面必须跟一个空格。server:port不会报错弹窗,但配置就是不生效,排查半天你才会发现少了个空格。->一个空格引发的惨案。

我们需要添加一个空格才能是yml文件进行生效:

5.2 使用进阶
yml 支持的数据类型比 properties 丰富,字符串、布尔、整数、浮点、null、空串都能写:
5.2.1 配置不同数据类型及 null
例如:
# 字符串
string.value: hello
# 布尔值,true 或 false
boolean.value: true
boolean.value1: false
# 整数
int.value: 10
# 浮点数
float.value: 3.14159
# Null,~ 代表 null
null.value: ~
# "" 空字符串
# 直接后面什么都不加也可以,但这种写法不直观,更推荐用引号括起来
empty.value: ''
| 类型 | 写法 | 备注 |
|---|---|---|
| 字符串 | string.value: Hello | 默认不用加引号 |
| 布尔值 | true / false | 只能小写 |
| 整数 | int.value: 10 | — |
| 浮点数 | float.value: 3.14159 | — |
| null | null.value: ~ | ~ 就是 null |
| 空字符串 | empty.value: '' | 推荐用引号,直观看得出来 |
读取方式和 properties 一模一样,还是 @Value:
@RestController
public class ReadYml {
@Value("${string.value}")
private String hello;
@RequestMapping("/ymlKey")
public String key() {
return "读取到值:" + hello;
}
}
访问
http://127.0.0.1:8080/ymlKey,输出读取到值:hello。

5.2.2 单引号与双引号
字符串默认不用加单引号或双引号,但如果加了英文的单双引号,就表示特殊的含义。我们在
application.yml里配置三段:
string:
str1: Hello \n Spring Boot.
str2: 'Hello \n Spring Boot.'
str3: "Hello \n Spring Boot."
读取代码:
@RestController
public class ReadYml {
@Value("${string.str1}")
private String str1;
@Value("${string.str2}")
private String str2;
@Value("${string.str3}")
private String str3;
@RequestMapping("/yml")
public String readYml() {
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
return "yml";
}
}
我们能观察到一下结果:

详细:
Hello \n Spring Boot. ← str1:不加引号,\n 就是个普通字符
Hello \n Spring Boot. ← str2:单引号,\n 被转义,还是普通字符
Hello ← str3:双引号,\n 保持本意,真的换行
Spring Boot.
结论整理成一句话:单引号会把 \n 转义掉(变成普通字符串,不换行),双引号不转义(\n 表示它本身的含义,也就是换行)。
| 写法 | \n 的表现 | 结果 |
|---|---|---|
| 不加引号 | 按普通字符处理 | 原样输出 Hello \n Spring Boot. |
单引号 '...' | 转义,失去特殊功能 | 原样输出 Hello \n Spring Boot. |
双引号 "..." | 不转义,保留本意 | 真的换行 |
这里的“转义”确实拗口,但记住一句话就行:单引号是“保护套”,把特殊字符保护起来当普通人;双引号是“放大器”,让特殊字符继续发挥它的特殊能力。
5.2.3 配置对象
yml 里还可以直接配置一个对象,接下来我们来看一看如何来配置对象:
我们首先定义好对象的属性:
@Data
public class Student {
private int id;
private String name;
private int age;
}
@Data注解,在之前的文章中我们谈到过,这是一个工具类,方便我们程序员的开发,我们不需要自己写get和set方法等
student:
id: 1
name: Java
age: 18
或者用行内写法(和上面作用一致):
student: {id: 1,name: Java,age: 18}
注意:这个时候我们就不能再去使用 @Value 去读了(一个个字段读太麻烦),要用@ConfigurationProperties:而不是使用@Value注解
@ConfigurationProperties(prefix = "student")
@Component
@Data
public class Student {
private int id;
private String name;
private int age;
}
调用类:
@RestController
public class StudentController {
@Autowired
private Student student;
@RequestMapping("/readStudent")
public String readStudent() {
return student.toString();
}
}
访问 http://127.0.0.1:8080/readStudent,就能看到 Student(id=1, name=Java, age=18)。

@ConfigurationProperties只是“说明怎么绑定”,这个类必须被 Spring 管理才会生效,所以要加@Component(或者在启动类上加@EnableConfigurationProperties)。prefix的值要跟配置文件的第一层 key 完全一致,而且建议全小写。写成prefix = "Student"或者prefix = "student.id"都会绑定失败,字段全是默认值。
5.2.4 配置集合 List
配置文件里当然也能配 List:
例如:
dbtypes:
name:
- hello
- word
- hi
集合的读取和对象一样,还是使用 @ConfigurationProperties注解:
@Component
@ConfigurationProperties("dbtypes")
@Data
public class ListConfig {
private List<String> name;
}
访问的方式:
@RestController
public class ReadYml2 {
@Autowired
private ListConfig listConfig;
@RequestMapping("/readList")
public String readList() {
return listConfig.toString();
}
}
访问 http://127.0.0.1:8080/readList

5.2.5 配置 Map
同理,配置文件中Map 也能够配置:
例如:
maptypes:
map:
k1: hello
k2: word
k3: hi
map在配置文件中是使用键值对形似的,前面是key,后面为value
或者行内写法(作用一致):
maptypes: {map: {k1: kk1,k2: kk2, k3: kk3}}
Map 的读取还是同样用 @ConfigurationProperties 注解:
@Data
@ConfigurationProperties(prefix = "maptypes")
@Component
public class MapConfig {
private HashMap<String, String> map;
}
浏览器获取结果:
@Data
@ConfigurationProperties(prefix = "maptypes")
@Component
public class MapConfig {
private HashMap<String, String> map;
}
访问 http://127.0.0.1:8080/readMap

小结:
@Value只能读“单个值”,一旦遇到**对象 / List / Map 这种复杂结需要使用@ConfigurationProperties。
5.3 yml 的优缺点
我们先来看看yml文件的优点:
- 可读性高,写法简单,易于理解;
- 支持更多的数据类型,可以简洁地表达对象、数组、List、Map 等数据形态;
- 支持更多的编程语言,不止 Java,Golang、Python、Ruby、JavaScript 里也能用。
缺点:
- 不适合写复杂的配置文件。
例如我们先来看看这段配置文件:
keycloak.realm = demo
keycloak.resource = fm-cache-cloud
keycloak.credentials.secret = d4589683-Oce7-4982-bcd3
keycloak.security[0].authRoles[0]= user
keycloak.security[0].collections[0].name = ssologinurl
keycloak.security[0].collections[0].patterns[0] = /login/*
转成 yml 就变成这样:
keycloak:
realm: demo
resource: fm-cache-cloud
credentials:
secret: d4589683-Oce7-4982-bcd3
security:
- authRoles:
- user
collections:
- name: ssologinurl
patterns:
- /login/*
转换过程本身就挺费精力,如果我们的配置再复杂一点,可读性会变得更差,代码也更难写。
- 对格式有很强的要求,一个空格可能会引起一场血案。
排查半天发现少写了一个空格~
6. 综合练习:Hutool 图形验证码
学完语法,来一个真实场景来练手——图形验证码。随着安全要求越来越高,现在项目里基本都有验证码,而且越来越复杂(图形验证码、行为验证码都成了趋势)。
图形验证码,手机验证码,还有能滑动的验证码等等各种各样的验证码
验证码可以使用前端来实现,也可以使用后端实现,网上插件也很多
文章中使用:Hutool。来实现图形验证码,并且使用后端来进行实现:
需求:
- 页面生成验证码;
- 输入验证码,点击提交,验证用户输入是否正确,正确则跳转页面。
准备工作: 创建项目 → 引入 Spring MVC 依赖 → 把前端页面放进项目的 static 目录。
前后端交互接口约定:
| 接口 | 请求方式 | URL | 参数 | 响应 |
|---|---|---|---|---|
| 生成验证码 | GET | /captcha/getCaptcha | 无 | 验证码图片内容 |
| 校验验证码 | POST | /captcha/check | captcha(用户输入) | true 成功 / false 失败 |
也就是说:浏览器发一个 /captcha/getCaptcha 请求,服务器返回一张图片,浏览器显示在页面上。
我们先来了解了解Hutool :
Hutool 是什么? 它是一个 Java 工具包类库,对文件、流、加密解密、转码、正则、线程、XML 等 JDK 方法做了封装,组成各种 Util 工具类。小而全,用静态方法封装,能降低 API 学习成本,让 Java 也能“甜甜的”,也就是如何生成一些东西不需要我们程序员来进行编写,直接使用别人早已写好的代码。
首先第一步我们得先引入他给我们的依赖:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.48</version>
</dependency>
第二步:先把配置项挪到配置文件里
注意,这才是文章的重点!把会变的东西(宽、高、Session 的 key 名)抽离出来,不写在代码里:
captcha:
width: 100
height: 40
session:
key: CAPTCHA_SESSION_KEY
date: KAPTCHA_SESSION_DATE
第三步:把配置项映射成 Java 对象
@Data
@Component
@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;
}
}
💡 这里演示了 yml 里的嵌套结构:
captcha.session.key对应 Java 里的静态内部类Session的key字段,层级一一对应。
第四步:生成验证码的接口
@RequestMapping("/captcha")
@RestController
public class HuToolCaptchaController {
@Autowired
private CaptchaProperties captchaProperties;
@RequestMapping("/getCaptcha")
public void getCode(HttpSession session, HttpServletResponse response) throws IOException {
// 定义图形验证码的长和宽(从配置文件读取)
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(
captchaProperties.getWidth(),
captchaProperties.getHeight());
response.setContentType("image/jpeg");
// 禁止使用缓存
response.setHeader("Pragma", "No-cache");
// 输出到页面
lineCaptcha.write(response.getOutputStream());
// 存储在 Session 中,校验时使用
session.setAttribute(captchaProperties.getSession().getKey(), lineCaptcha.getCode());
session.setAttribute(captchaProperties.getSession().getDate(), new Date());
// 打印日志
System.out.println("生成的验证码:" + lineCaptcha.getCode());
// 关闭流
response.getOutputStream().close();
}
}
启动项目,访问 http://127.0.0.1:8080/captcha/getCaptcha,就能看到验证码图片了。

💡 如果你的项目是 SpringBoot 2.x,把
jakarta.servlet.*换成javax.servlet.*即可;3.x 及以上用jakarta。
第五步:校验验证码
```java
import org.springframework.util.StringUtils;
private final static long VALID_MILLIS_TIME = 60 * 1000;
@RequestMapping("/check")
public boolean checkHomeCaptcha(String captcha, HttpSession session) {
if (!StringUtils.hasLength(captcha)) {
return false;
}
String savedCaptcha = (String) session.getAttribute(captchaProperties.getSession().getKey());
Date sessionDate = (Date) session.getAttribute(captchaProperties.getSession().getDate());
if (captcha.equalsIgnoreCase(savedCaptcha)) {
// 校验时间:一分钟以内有效
if (sessionDate == null
|| System.currentTimeMillis() - sessionDate.getTime() < VALID_MILLIS_TIME) {
return true;
}
return false;
}
return false;
}
逻辑就是:比对 Session 中存储的验证码和用户输入的是否一致;如果一致,并且时间在一分钟以内,就认为验证成功。注意
equalsIgnoreCase——验证码是不区分大小写的。
第六步:前端 ajax
<!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 () {
alert("验证码校验");
});
</script>
</body>
</html>
大概就是这样的一个外形;

我们需要修改这一部分代码:
$("#checkCaptcha").click(function () {
alert("验证码校验");
});
修改后的代码:
$("#checkCaptcha").click(function () {
$.ajax({
url: "/captcha/check",
type: "post",
data: { captcha: $("#inputCaptcha").val() },
success: function (result) {
if (result) {
location.href = "success.html";
} else {
alert("验证码错误");
$("#inputCaptcha").val("");
}
}
});
});
第七步:运行测试



访问 http://127.0.0.1:8080/index.html,输入验证码,验证成功即可跳转。
💡 回头看这个案例:宽、高、Session 的 key 名全部来自配置文件,以后想让验证码变宽一点,改 yml 就行,一行 Java 代码都不用动。这就是配置文件最朴素也最核心的价值。
7. 总结与速查清单
核心三句话:
- 配置文件 = 把会变的信息从代码里挪出来,解决硬编码问题;
properties是key=value的键值形式,yml是树形结构,靠缩进表达层级;- 单个值用
@Value,对象 / List / Map 用@ConfigurationProperties。
properties vs yml 速查
| 对比项 | properties | yml |
|---|---|---|
| 语法 | key=value | key: value(冒号后必须有空格) |
| 结构 | 平铺,靠 . 连接 | 树形,靠换行缩进 |
| 注释 | # | # |
| 冗余 | 多(前缀重复写) | 少(同层只写一次) |
| 数据类型 | 基本类型 | 字符串/布尔/数字/null/对象/List/Map |
| 适用场景 | 简单配置、老项目 | 日常开发首选 |
| 复杂度容忍度 | 高(复杂配置更清楚) | 低(复杂配置可读性差) |
Value 与ConfigurationProperties应该选哪一个?
| 注解 | 写法 | 能读什么 | 备注 |
|---|---|---|---|
@Value | @Value("${key}") | 单个值(String、int…) | 读不了对象 / List / Map |
@ConfigurationProperties | @ConfigurationProperties(prefix = "xxx") | 对象、List、Map、嵌套结构 | 类必须被 Spring 管理(加 @Component) |
注意事项:
| 坑 | 表现 | 解决 |
|---|---|---|
| yml 冒号后漏空格 | 配置不生效,key 不高亮 | 写成 port: 9090 这种“冒号 + 空格”的形式 |
@Value 里写字段名 | Could not resolve placeholder | 写配置里的 key 全名,如 ${mykey.key1} |
@ConfigurationProperties 类没被管理 | 字段全是默认值(0 / null) | 加 @Component |
prefix 大小写不对 | 绑定失败 | 建议全小写,和 yml 第一层 key 一致 |
| properties 和 yml 冲突 | 生效的是 properties | 只用一种格式,别两个都留 |
单引号里的 \n | 不换行 | 想要换行就用双引号 |
以上就是 SpringBoot 配置文件的全部内容啦,从“为什么要有配置文件”一直写到“验证码实战”
如果这篇笔记对你有帮助,欢迎点赞 👍 + 收藏 ⭐ + 留言 📝,你的支持是我持续更新的最大动力!笔记中有任何错误或者表述不清的地方,也欢迎在评论区指出,我们一起进步 🚀

转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/2502_93799892/article/details/167911835




