【JavaEE进阶】Spring Boot配置文件

欢迎关注个人主页:逸狼


创造不易,可以点点赞吗

如有错误,欢迎指出~

目录

SpringBoot配置⽂件

[举例: 通过配置文件修改端口号](#举例: 通过配置文件修改端口号)

配置⽂件的格式

properties基本语法

读取配置⽂件

properties配置文件的缺点

yml配置⽂件

yml基本语法

yml和properties连接数据库的配置对⽐

yml的使用

yml配置读取

配置对象

读取yml配置文件中的对象

配置集合

读取yml配置文件中的集合

配置Map

[​编辑 yml优缺点](#编辑 yml优缺点)

验证码案例

需求

约定前后端交互接⼝

接⼝定义

[1. ⽣成验证码](#1. ⽣成验证码)

[2. 校验验证码是否正确](#2. 校验验证码是否正确)

Hutool⼯具介绍

yml文件配置项

验证码配置项对应的Java对象

后端代码实现

前端代码实现

index.html

success.html

测试

总结



配置⽂件主要是为了解决硬编码带来的问题 ,把可能会发⽣改变的信息,放在⼀个集中的地⽅, 当我们启 动某个程序时,应⽤程序从配置⽂件中读取数据,并加载运⾏.

硬编码是将数据直接嵌⼊到程序或其他可执⾏对象的源代码中,也就是我们常说的"代码写死"

使⽤配置⽂件,可以使程序完成⽤⼾和应⽤程序的交互,或者应⽤程序与其他应⽤程序的交互

SpringBoot配置⽂件

SpringBoot⽀持并定义了配置⽂件的格式,也在另⼀个层⾯达到了规范其他框架集成到SpringBoot的 ⽬的.

很多项⽬或者框架的配置信息也放在配置⽂件中,⽐如:

• 项⽬的启动端⼝

• 数据库的连接信息(包含⽤⼾名和密码的设置)

• 第三⽅系统的调⽤密钥等信息

• ⽤于发现和定位问题的普通⽇志和异常⽇志等.

举例: 通过配置文件修改端口号

Tocmat默认端⼝号是8080,所以我们程序访问时的端⼝号也是8080 但是如果8080端⼝号已经被其他进程使⽤ ,我们可以通过配置⽂件来修改服务的端⼝号 SpringBoot在创建项⽬时,就已经帮我们创建了配置⽂件

修改 application.properties ⽂件 加上server.port=9090

配置⽂件的格式

SpringBoot配置⽂件有以下三种:

  1. application.properties
  2. application.yml
  3. application.yaml

yml 为yaml的简写,实际开发中出现频率最⾼ .yaml和yml的使⽤⽅式⼀样, 当应⽤程序启动时,SpringBoot会**⾃动从classpath路径找到并加载** application.properties 和application.yaml 或者application.yml ⽂件.

  1. 理论上讲**.properties 和.yml 可以并存** 在于⼀个项⽬中,当.properties 和.yml 并存时,两个配置都会加载 .如果配置⽂件内容有冲突,则以.properties 为主,也就是 .properties 优先级更⾼.( properties配置⽂件是最早期的配置⽂件格式,也是创建SpringBoot项⽬默认的配置⽂件 )
  2. 虽然理论上来讲.properties 可以和.yml 共存,但实际的业务 当中,我们通常会采取⼀种 统⼀的配置 ⽂件格式,这样可以更好的维护(降低故障率).

properties基本语法

properties是以键值的形式配置的,key和value之间是以"="连接的,如: # 配置项⽬端⼝号 server.port=8080

配置⽂件中使⽤"#"来添加注释信息。

读取配置⽂件

如果在项⽬中,想要主动的读取配置⽂件 中的内容,可以使⽤@Value 注解来实现。 @Value 注解使⽤" ${} "的格式读取,如下代码所⽰:

properties配置如下:

复制代码
m.k=do

package com.example.demo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
//@RequestMapping("/p1")
public class PropertiesController {
    @Value("${m.k}")
    private String k;

    @RequestMapping("/v1")
    public String key(String input){//参数名 input 与成员变量 k 同名,否则可能会读取失败
        System.out.println("注入后的key值为: " + k);
        if (k == null) {
            System.out.println("key的值为null");
        }
        return "读取到properties文件中的k的值: "+ k;
    }
}

properties配置文件的缺点

properties配置⽂件中会有很多的冗余的信息,⽐如

yml配置文件可以解决以上问题

yml配置⽂件

yml是YAML是缩写,它的全称YetAnotherMarkupLanguage翻译成中⽂就是"另⼀种标记语⾔.

yml基本语法

yml是树形结构的配置⽂件,它的基础语法是**"key:value".** key和value之间使⽤英⽂冒号加空格 的⽅式组成,空格不可省略

正确配置 会有高亮提示

yml和properties连接数据库的配置对⽐

yml的使用

复制代码
# 字符串 
string.value: Hello
# 布尔值,true或false 
boolean.value: true
boolean.value1: false
# 整数 
int.value: 10
# 浮点数 
float.value: 3.14159
# Null,~代表null 
null.value: ~
# "" 空字符串 
#, 直接后⾯什么都不加就可以了, 但这种⽅式不直观, 更多的表⽰是使⽤引号括起来 
empty.value: ''

yml配置读取

yml读取配置的⽅式和properties 相同,使⽤@Value注解即可,实现代码如下:

复制代码
    @Value("${code.java}")
    private String java;
    @RequestMapping("/v2")
    public String v2(){
        return "读取yml配置文件code.java的值: "+ java;
    }

注意事项:value值加单双引号 字符串默认不⽤加上单引号或者双引号,如果加英⽂的单双引号可以表⽰特殊的含义。

尝试在application.yml中配置如下信息:

复制代码
String:
  str1: hello \n yml
  str2: 'hello \n yml'
  str3: "hello \n yml"

    @RequestMapping("/v3")
    public String v3(){
        System.out.println(str1);
        System.out.println(str2);
        System.out.println(str3);
        return "yml";
    }

从上述结果可以看出:

  • • 字符串默认不⽤加上单引号或者双引号。
  • 单引号会转义特殊字符,使其失去特殊功能,始终是⼀个普通的字符串.
  • 双引号不会转义字符串⾥⾯的特殊字符,特殊字符会表⽰本⾝的含义.

配置对象

我们还可以在yml中配置对象,如下配置:以下两者写法都行

复制代码
Student:
  id: 1
  name: zhangsan
  age: 21
Student2: {id: 2, name: lisi, age: 18}
读取yml配置文件中的对象

这个时候就不能⽤@Value来读取配置中的对象了,此时要使⽤另⼀个注解**@ConfigurationProperties (prefix = "对应的是配置文件中的对象")**来读取,具体实现如下:

复制代码
package com.example.demo;


import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@ConfigurationProperties(prefix = "student")//注意对象名称
@Data
@Component
public class Student {
    public int id;
    public String name;
    public int age;
}

    @Autowired
    private Student student;
    @RequestMapping("/v4")
    public String v4(){
        return student.toString();
    }

配置集合

复制代码
2022:
  name:
    - zhangsan
    - lisi
    - wangwu
读取yml配置文件中的集合

集合的读取和对象⼀样,也是使⽤@ConfigurationProperties 来读取的,具体实现如下:

复制代码
package com.example.demo;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.List;

@Data
@Component
@ConfigurationProperties(prefix = "2022")
public class List2020 {
    private List<String> name;
}

    @Autowired
    private List2020 list2020;

    @RequestMapping("/v5")
    public String v5(){
        return list2020.toString();
    }

配置Map

配置⽂件也可以配置map,如下所⽰

复制代码
maptypes:
  map:
    k1: 111
    k2: 222
    k3: 333

行内写法作用相同

复制代码
maptypes2: {map2: {k1: 1, k2: 2, k3: 3}}

Map的读取和对象⼀样,也是使⽤@ConfigurationProperties 来读取的,具体实现如下:

复制代码
package com.example.demo;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.HashMap;

@Data
@Component
@ConfigurationProperties(prefix = "maptypes")
public class MapTypes {
    public HashMap<String, String> map;
}

    @Autowired
    private MapTypes mapTypes;

    @RequestMapping("/v6")
    public String v6(){
        return mapTypes.toString();
    }

yml优缺点

优点:

  1. 可读性⾼,写法简单,易于理解

  2. ⽀持更多的数据类型,可以简单表达对象,数组,List,Map等数据形态.

  3. ⽀持更多的编程语⾔,不⽌是Java中可以使⽤,在Golang,Python,Ruby,JavaScript中也可以使⽤

缺点:

  1. 不适合写复杂的配置⽂件

转换的过程也⽐较花费精⼒,如果配置更复杂⼀点,可读性会更差,代码也会更难写

  1. 对格式有较强的要求(⼀个空格可能会引起⼀场⾎案)

验证码案例

验证码的实现⽅式很多,可以前端实现,也可以后端实现.⽹上也有⽐较多的插件或者⼯具包可以使⽤, 咱们选择使⽤Hutool提供的⼩⼯具来实现

需求

界⾯如下图所⽰

  1. ⻚⾯⽣成验证码

  2. 输⼊验证码,点击提交,验证⽤⼾输⼊验证码是否正确,正确则进⾏⻚⾯跳转

约定前后端交互接⼝

需求分析 后端需要提供两个服务

  1. ⽣成验证码,并返回验证码

  2. 校验验证码是否正确:校验验证码是否正确.

接⼝定义

1. ⽣成验证码

请求: 请求URL: /captcha/getCaptcha

响应:验证码图⽚内容

浏览器给服务器发送⼀个 /captcha/getCaptcha 这样的请求,服务器返回⼀个图⽚,浏览器显 ⽰在⻚⾯上

2. 校验验证码是否正确

请求:/captcha/check 请求URL: /captcha/check 请求参数: captcha=xn8d

captcha:⽤⼾输⼊的验证码

响应: true 根据⽤⼾输⼊的验证码,校验验证码是否正确.

true:验证成功.false:验证失败.

Hutool⼯具介绍

这里验证码的实现,使⽤Hutool提供的⼩⼯具来实现 Hutool是⼀个Java⼯具包类库,对⽂件、流、加密解密、转码、正则、线程、XML等JDK⽅法进⾏封 装,组成各种Util⼯具类. Hutool是⼀个⼩⽽全的Java⼯具类库,通过静态⽅法封装,降低相关API的学习成本,提⾼⼯作效 率,使Java拥有函数式语⾔般的优雅,让Java语⾔也可以"甜甜的".

引入依赖

复制代码
<dependency> 
 <groupId>cn.hutool</groupId>
 <artifactId>hutool-captcha</artifactId>
 <version>5.8.22</version>
</dependency>

1.获取和验证验证码

复制代码
package com.example.demo.captcha;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

@RequestMapping("/captcha")
@RestController
public class HuToolCaptchaController {

    @GetMapping("/getCaptcha")
    public void getCaptcha(HttpServletResponse response, HttpSession session){
        //定义图形验证码的长和宽
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(100, 40, 4, 150);

        String code = lineCaptcha.getCode();
        //存储session
        session.setAttribute("CAPTCHA_KEY",code);

        //获取当前时间, 验证码的时效性
        session.setAttribute("CAPTCHA_Date",new Date());

        
        //验证码写出,可以写到文件,也可以写到流里
        try {
            lineCaptcha.write(response.getOutputStream());
            //输出
            System.out.println("生成的验证码: "+ lineCaptcha.getCode());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    @RequestMapping("/check")
    public boolean check(HttpSession session, String captcha){
        //captcha为空,直接返回false;
        if(!StringUtils.hasLength(captcha)){
            return false;
        }
        String code = (String) session.getAttribute("CAPTCHA_KEY");
        return captcha.equals(code);
    }
}

对程序进⾏调整

1)把配置项挪到配置⽂件中

2)把⽣成的验证码存储在Session中,校验时使⽤

yml文件配置项

复制代码
captcha:
  height: 40
  width: 100
  session:
    key: CAPTCHA_SESSION_KEY
    date: KAPTCHA_SESSION_DATE

验证码配置项对应的Java对象

复制代码
package com.example.demo.captcha;


import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Data
@Configuration
@ConfigurationProperties(prefix = "captcha")
public class Captcha {
    private Integer width;
    private Integer height;
    private Session session;

    @Data
    public static class Session{//要使用公开的 静态内部类,
        // 否则session拿不到值(要先有外部类的对象,然后才能拿到内部类,静态内部类就不用), 或者不要写内部类
        private String date;
        private String key;
    }
}

后端代码实现

复制代码
package com.example.demo.captcha;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.Date;

@RequestMapping("/captcha")
@RestController
public class HuToolCaptchaController {
    //注入配置文件对应对象
    @Autowired
    private Captcha captcha;

    //过期时间1分钟 = 60秒 * 1000毫秒
    private static long VALID_TIME_OUT  = 60 * 1000;

    @GetMapping("/getCaptcha")
    public void getCaptcha(HttpServletResponse response, HttpSession session){


        //定义图形验证码的长和宽
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(captcha.getWidth(), captcha.getHeight());

        String code = lineCaptcha.getCode();
        //存储session
        session.setAttribute(captcha.getSession().getKey(),code);
        //当前时间
        session.setAttribute(captcha.getSession().getDate(),new Date());

        //验证码写出,可以写到文件,也可以写到流里
        try {
            lineCaptcha.write(response.getOutputStream());
            response.setContentType("image/jpeg");
            response.setCharacterEncoding("utf-8");
            //防止缓存
            response.setHeader("Pragma", "No-cache");

            //输出
            System.out.println("生成的验证码: "+ lineCaptcha.getCode());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    @RequestMapping("/check")
    public boolean check(HttpSession session, String captcha1){
        System.out.println("用户输入验证码: "+ captcha1);
        //captcha为空,直接返回false;
        if(!StringUtils.hasLength(captcha1)){
            return false;
        }

        String code = (String) session.getAttribute(captcha.getSession().getKey());
        Date date = (Date) session.getAttribute(captcha.getSession().getDate());
        if(date == null || (System.currentTimeMillis() - date.getTime()) > VALID_TIME_OUT){
            return false;
        }
        //验证码不区分大小写验证验证码是否正确
        return captcha1.equalsIgnoreCase(code);
    }
}

前端代码实现

index.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: {
          captcha1: $("#inputCaptcha").val()
        },
        success: function(result){
          if(result){
            location.href = "success.html"
          }else{
            alert("验证码错误");
          }
        }
      });
    });

  </script>
</body>

</html>

success.html

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>验证成功页</title>
</head>
<body>
    <h1>验证成功</h1>
</body>
</html>

测试

总结

  1. properties是以 key=value 的形式配置的键值类型的配置⽂件,yml使⽤的是树形配置⽅式.
  2. 读取配置⽂件内容,使⽤@Value 注解,注解内使⽤**" ${} "**的格式读取.
  3. yml层级之间使⽤换⾏缩进的⽅式配置,key和value之间使⽤":"(英⽂冒号)加空格的⽅式设置,并 且空格不可省略.
  4. properties为早期并且默认 的配置⽂件格式,其配置存在⼀定的冗余数据,使⽤yml可以很好的解决 数据冗余的问题,但不适合复杂配置
  5. yml可以和properties共存,但⼀个项⽬中建议使⽤⼀种配置类型⽂件.
相关推荐
JosieBook1 分钟前
【web应用】前后端分离项目基本框架组成:Vue + Spring Boot 最佳实践指南
前端·vue.js·spring boot
用户4976360000605 分钟前
内部类不能bean注入
后端
Code blocks22 分钟前
SpringBoot中策略模式使用
java·spring boot·后端·mybatis·策略模式
污领巾30 分钟前
虚幻GAS底层原理解剖三 (GA)
java·游戏引擎·虚幻
C4程序员37 分钟前
北京JAVA基础面试30天打卡02
java·开发语言·面试
ん贤44 分钟前
面向对象的七大设计原则
前端·后端·go
好好研究1 小时前
Java基础学习(一):类名规范、返回值、注释、数据类型
java·学习·算法
_码农121381 小时前
java web 未完成项目,本来想做个超市管理系统,前端技术还没学。前端是个简单的html。后端接口比较完善。
java·前端·html
coding随想1 小时前
深入浅出数据库管理系统DBMS
后端
jack_yin1 小时前
颠覆写作流程!AI 3 分钟自动在掘金写完并保存《小红帽》
后端