【Java EE】Spring Boot配置文件

文章目录

  • 一、为什么需要配置文件?
  • 二、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 前端页面)

一、为什么需要配置文件?

开发中如果把端口、数据库账号、第三方密钥直接写死在代码里,也就是硬编码,会带来极大维护问题:

  1. 环境切换(本地/测试/生产)需要反复改代码、重新打包;
  2. 敏感信息暴露在源码中,存在安全风险;
  3. 统一参数修改需要全局检索代码,效率极低。

配置文件的作用:把可变参数抽离到独立文件,程序启动自动读取,统一管理所有外部配置。

SpringBoot内置两套主流配置文件:application.propertiesapplication.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 语法

  1. 基础格式:key: value 冒号后必须加英文空格,缺少空格直接解析报错
  2. 层级区分:使用缩进(2个空格) 代表父子层级;
  3. 注释:# 单行注释;
  4. 行内写法:大括号{}简化单层对象/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优缺点

✅ 优点:

  1. 树形层级清晰,消除重复配置,可读性极高;
  2. 原生支持对象、数组、Map等复杂数据结构;
  3. 跨语言通用,Java、Go、Python、前端均可使用。

❌ 缺点: 格式要求严苛,缩进、空格错误直接启动失败;

四、yml配置 + Hutool图形验证码案例

4.1 需求说明

  1. 访问接口返回图形验证码图片;
  2. 验证码存入Session,有效期1分钟;
  3. 前端输入验证码提交,后端校验是否匹配、是否过期;
  4. 验证码宽高、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>
相关推荐
Tim_101 小时前
【C++】019、内存泄漏
java·开发语言
咖啡八杯2 小时前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法
要开心吖ZSH4 小时前
一文搞懂:JDK 21 虚拟线程 vs N种异步方案,到底该怎么选?
java·数据库·jdk·虚拟线程
guodingdingh8 小时前
软件开发工作问题总结0718
java·开发语言·数据库
咖啡八杯10 小时前
GoF设计模式——解释器模式
java·后端·spring·设计模式
优橙教育10 小时前
5G网优培训 vs Java开发:转行选哪个?
java·开发语言·5g
糖果店的幽灵10 小时前
【DeepAgents 从入门到精通】Context Management 上下文管理
java·人工智能·后端·spring·中间件·langgraph·deepagents
腻害兔12 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
碎光拾影12 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库