文章目录
- 一、为什么需要配置文件?
- 二、SpringBoot两种配置文件
- 2.1 文件存放位置与加载规则
- 2.2 application.propertie 键值对格式
- 1. 基础语法
- 2. 读取配置:@Value
- 3. properties缺点
- 三、application.yml YAML树形配置
- 3.1 语法
- 3.2 yml支持全类型数据配置
- 1. 基础数据类型
- 2. 字符串单双引号特殊规则
- 3. 配置对象
- 4. 配置 List & Map
- 3.3 两种读取配置注解对比
- 3.4 yml优缺点
- 四、yml配置 + Hutool图形验证码案例
- 4.1 需求说明
- 4.2 引入Hutool验证码依赖
- 4.3 yml配置验证码参数
- 4.4 创建配置映射实体CaptchaProperties
- 4.5 后端Controller 生成校验验证码
- 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,#单行注释,层级通过.分隔。
# 修改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=demo1232. 读取配置:@Value
使用${配置key}读取参数,适合零散、独立的配置,仅支持单个简单值
@RestController@RequestMapping("/prop")publicclassPropController{// 读取properties自定义参数@Value("${my.test.key}")privateStringtestKey;@RequestMapping("/get")publicStringgetConfig(){return"读取properties配置:"+testKey;}}3. 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,短横线-代表集合元素。
数据库配置
# application.ymlspring:datasource:url:jdbc:mysql://127.0.0.1:3306/testdb?characterEncoding=utf8&useSSL=falseusername:rootpassword:root对比properties,yml消除重复前缀,层级更清晰。
3.2 yml支持全类型数据配置
1. 基础数据类型
# 字符串str:Hello SpringBoot# 布尔值bool:true# 数字num:666floatNum:3.14# null:~代表空值empty:~# 空字符串emptyStr:''2. 字符串单双引号特殊规则
string:str1:Hello \n Boot# 无引号:\n 原样输出,不换行str2:'Hello \n Boot'# 单引号:转义所有特殊字符,\n仅作为文本str3:"Hello \n Boot"# 双引号:保留转义字符,\n会自动换行3. 配置对象
# 标准缩进写法person:id:1name:daisyage:10# 行内简写,效果完全一致person:{id:1,name:daisy,age:10}注意:对象不能用@Value读取,必须使用@ConfigurationProperties批量绑定。
@ConfigurationProperties(prefix="person")@Configuration@DatapublicclassPerson{privateintid;privateStringname;privateintage;}4. 配置 List & Map
- List集合
db-types:name:-mysql-sqlserver-db2List和数组的配置完全相同,可以使用List接收,也可以使用数组接收
- Map键值对集合
map-demo:map:k1:v1k2:v2# 行内简写map-demo:{map:{k1:v1,k2:v2}}@Data@Component@ConfigurationProperties(prefix="dbtypes")publicclassDBTypes{privateList<String>name;privateMap<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
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-captcha</artifactId><version>5.8.22</version></dependency>4.3 yml配置验证码参数
application.yml
captcha:width:150height:50session:key:CAPTCHA_SESSION_KEYdate:CAPTCHA_SESSION_DATE4.4 创建配置映射实体CaptchaProperties
@Data@Configuration@ConfigurationProperties(prefix="captcha")publicclassCaptchaProperties{privateIntegerwidth;privateIntegerheight;privateSessionsession;@DatapublicstaticclassSession{privateStringkey;privateStringdate;}}注意:普通的内部类不能交给Spring管理,因为要依托外内部类存在,改成静态内部类就不再依托外部类,可以交给Spring管理
4.5 后端Controller 生成校验验证码
@RestController@RequestMapping("/captcha")publicclassCaptchaController{@AutowiredCaptchaPropertiescaptchaProperties;privatefinalstaticLongVALID_TIME=60*1000L;@RequestMapping("/getCaptcha")publicvoidgetCaptcha(HttpServletResponseresponse,HttpSessionsession)throwsIOException{response.setContentType("image/jpeg");//理论上由前端处理浏览器缓存问题response.setHeader("Pragma","No-cache");//生成验证码ShearCaptchashearCaptcha=CaptchaUtil.createShearCaptcha(captchaProperties.getWidth(),captchaProperties.getHeight());Stringcode=shearCaptcha.getCode();session.setAttribute(captchaProperties.getSession().getKey(),code);session.setAttribute(captchaProperties.getSession().getDate(),System.currentTimeMillis());shearCaptcha.write(response.getOutputStream());response.getOutputStream().close();}@RequestMapping("/check")publicbooleancheck(Stringcaptcha,HttpSessionsession){//判空if(!StringUtils.hasLength(captcha))returnfalse;//验证ObjectcodeAttr=session.getAttribute(captchaProperties.getSession().getKey());ObjectdateAttr=session.getAttribute(captchaProperties.getSession().getDate());if(codeAttr==null||dateAttr==null)returnfalse;Stringcode=codeAttr.toString();longdate=(long)dateAttr;booleanisValid=System.currentTimeMillis()-date<=VALID_TIME;returncaptcha.equalsIgnoreCase(code)&&isValid;}}4.6 前端页面
- index.html 验证码输入页
<!DOCTYPEhtml><htmllang="en"><head><metacharset="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><divid="confirm"><inputtype="text"name="inputCaptcha"id="inputCaptcha"><imgid="verificationCodeImg"src="/captcha/getCaptcha"style="cursor:pointer;"title="看不清?换一张"/><inputtype="button"value="提交"id="checkCaptcha"></div><scriptsrc="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='+newDate().getTime()).fadeIn();});$("#checkCaptcha").click(function(){$.ajax({type:"post",url:"/captcha/check",data:{captcha:$("#inputCaptcha").val()},success:function(result){if(result)location.href="success.html";elsealert("验证码错误,请重新输入");}})});</script></body></html>