SpringBoot系列—配置文件

上篇文章:

SpringBoot系列---入门https://blog.csdn.net/sniper_fandc/article/details/148977345?fromshare=blogdetail&sharetype=blogdetail&sharerId=148977345&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link

目录

[1 application.properties](#1 application.properties)

[2 application.yml](#2 application.yml)

[2.1 语法格式](#2.1 语法格式)

[2.2 读取配置](#2.2 读取配置)

[2.3 application.properties和application.yml优缺点对比](#2.3 application.properties和application.yml优缺点对比)

[2.4 常用配置application.yml文件](#2.4 常用配置application.yml文件)

[3 验证码](#3 验证码)

[3.1 pom.xml依赖管理](#3.1 pom.xml依赖管理)

[3.2 yml配置文件](#3.2 yml配置文件)

[3.3 前端代码](#3.3 前端代码)

[3.4 后端代码](#3.4 后端代码)

[3.5 结果](#3.5 结果)


SpringBoot的配置文件有3种:application.properties、application.yaml和application.yml。其中yml是yaml的简写,这是一种标记语言。这些配置文件可以共存在一个项目中,而application.properties优先级最高,即其中的内容优先生效。

注意:配置文件必须放在resources目录下。

1 application.properties

学习配置文件,对于常见的配置不需要记忆,用的时候查就行,主要学习语法和使用方法。

properties文件以键值对组织内容,格式为key=value,可以添加空格(对空格不敏感)。如果key有多级,就用.分隔。

除了官方配置信息外,我们也可以自定义一些配置。读取配置文件的内容需要用到@Value注解(Spring会自动进行类型转换):

java 复制代码
@Controller

public class UserController {

    @Value("${key}")

    public String key;

    public void hello(){

        System.out.println("hello userController");

        System.out.println("获取配置文件信息:key=" + key);

    }

}

注意:如果@Value中不加${},则该注解会把字符串的内容赋值给属性。

2 application.yml

2.1 语法格式

key: value:以:分隔键和值,注意:后必须有空格。多级key也需要用:分隔(也可以用.分隔表示,但结构不清晰),并且换行表示,换行表示前必须有空格缩进,建议2个空格。

比如MySQL数据库的连接配置:

java 复制代码
spring:

  datasource:

    url: jdbc:mysql://127.0.0.1:3306/mydb?characterEncoding=utf8&useSSL=false

    username: root

    password: root

driver-class-name: com.mysql.cj.jdbc.Driver

2.2 读取配置

java 复制代码
#  字符串

string:

  value: user

#  整数

int:

  value: 10

#  表示Null:注意这里的键名不能为null,否则键名就会被Spring解析为Null导致读取时空值异常

#  注意:不能使用String来接收,因为会被认为字符串的值是"~"

nulltype:

  value: ~

#  表示空,比如MySQL没有设置密码,就什么都不写或用引号括起来

empty:

  value: ''

#  字符串值:什么都不加、加单引号、加双引号区别

string1:

  value1: hello \n user

  value2: 'hello \n user'

  value3: "hello \n user"

#  对象

userinfo:

  id: 102

  name: wangwu

  age: 22

#  集合:需要用一个类的属性来接收这个集合(-与元素之间空格不能省略,否则这几个元素就会被当做一个字符串处理)

collectiontype:

  list:

    - 1

    - 2

    - 3

#  map:需要用一个类的属性来接收这个map

maptype:

  map:

    key1: 1

    key2: 2

    key3: 3

读取基本数据类型,也是使用@Value注解读取

java 复制代码
@Controller

public class UserController {

    @Value("${string.value}")

    public String str1;

    @Value("${int.value}")

    public Integer num;

    @Value("${nulltype.value:#{null}}")

    public String str2;

    @Value("${empty.value:#{null}}")

    public String str3;

    public void hello(){

        System.out.println("hello userController");

        System.out.println("获取配置文件信息:");

        System.out.println("string.value:" + str1);

        System.out.println("int.value:" + num);

        System.out.println("null.value:" + str2);

        System.out.println("empty.value:" + str3);

    }

}

注意yml表示字符串时,什么都不加表示字符串原本的内容。'' 表示将特殊字符转义为普通字符(/n不会进行换行)。 "" 表示对特殊字符不转义(/n就会进行换行):

java 复制代码
@Controller

public class UserController {

    @Value("${string1.value1}")

    public String str1;

    @Value("${string1.value2}")

    public String str2;

    @Value("${string1.value3}")

    public String str3;

    public void hello(){

        System.out.println("hello userController");

        System.out.println("获取配置文件信息:");

        System.out.println("string1.value1:" + str1);

        System.out.println("string1.value2:" + str2);

        System.out.println("string1.value3:" + str3);

    }

}

读取对象,需要在要转换的对象类型前加@ConfigurationProperties(prefix = "userinfo") 注解,prefix的值是yml文件中要读取的key。同时需要注意,使用@Autowired注入对象:

java 复制代码
@Data

@Repository

@ConfigurationProperties(prefix = "userinfo")

public class UserInfo {

    private Integer id;

    private String name;

    private Integer age;

    public UserInfo() {

    }

    public UserInfo(Integer id, String name, Integer age) {

        this.id = id;

        this.name = name;

        this.age = age;

    }

}

@Controller

public class UserController {

    @Autowired

    public UserInfo userInfo;

    public void hello(){

        System.out.println("hello userController");

        System.out.println("获取配置文件信息:");

        System.out.println("object.value:" + userInfo);

    }

}

读取集合,和读取对象方式类似,也需要在要转换的对象类型前加@ConfigurationProperties(prefix = "collectiontype") 注解,prefix的值是yml文件中要读取的key。同时需要注意,使用@Autowired注入对象:

java 复制代码
@Controller

@Data

@ConfigurationProperties(prefix = "collectiontype")

public class CollectiontypeController {

    public List<Integer> list;

}

@Controller

public class UserController {

    @Autowired

    public CollectiontypeController collectiontypeController;

    public void hello(){

        System.out.println("hello userController");

        System.out.println("获取配置文件信息:");

        System.out.println("collectiontype.list:" + collectiontypeController);

    }

}

读取Map,和读取对象方式类似:

java 复制代码
@Controller

@Data

@ConfigurationProperties(prefix = "maptype")

public class MaptypeController {

    public HashMap<String,Integer> map;

}

@Controller

public class UserController {

    @Autowired

    public MaptypeController maptypeController;

    public void hello(){

        System.out.println("hello userController");

        System.out.println("获取配置文件信息:");

        System.out.println("collectiontype.list:" + maptypeController);

    }

}

2.3 application.properties和application.yml优缺点对比

****(1)application.properties:****优点:易于表示复杂的配置结构。缺点:配置信息冗余,多个key前缀一致,但是需要多次写。

****(2)application.yml:****优点:1.可读性高,易理解。2.支持更多的数据类型:数组、对象、集合等等。3.通用性好,不止适用于Java,Python、JavaScript等也适用。缺点:不适合写复杂的配置结构,并且对空格非常敏感。

2.4 常用配置application.yml文件

XML 复制代码
spring:

  datasource:

    url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8&useSSL=false

    username: root

    password: root

    driver-class-name: com.mysql.cj.jdbc.Driver

  mvc:

    favicon:

      enable: false

  profiles:  #多平台配置

    active: dev

# 设置 Mybatis 的 xml 保存路径

mybatis:

  mapper-locations: classpath:mapper/*Mapper.xml

  configuration: # 配置打印 MyBatis 执行的 SQL

    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

    map-underscore-to-camel-case: true  #自动驼峰转换

# 配置打印 MyBatis 执行的 SQL

logging:

  file:

    name: logs/springboot.log

  logback:

    rollingpolicy:

      max-file-size: 1KB

      file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i

  level:

    com:

      example:

        demo: debug

3 验证码

验证码的本质是:验证码+背景图片+干扰项。当然种类也是很多,可以是经典的数字字母类型的,也可以是滑动拼图(滑动拼图块拼成完整的图形)的,还有点击字符(依次点击某些字符或形状)的。

验证码校验是否正确就是要验证值是否正确。比如数字字母序列的验证码,就是验证用户输入的序列和保存的验证码的值是否一致。滑动拼图的验证码则是把整个图片的长视为[0,1],选取一个值作为拼图块的中心(比如0.5),拖动拼图块则是判断用户拖拽的当前拼图块的中心的值是否位于选择的值的位置。点击字符验证码就是xy两个坐标的验证码,判断坐标是否正确。

下面给出了基于SpringBoot配置文件的验证码实现方案。使用到插件是基于谷歌的Kaptcha验证码插件(http://code.google.com/p/kaptcha/)封装的一个插件:[https://github.com/oopsguy/kaptcha-spring-boot。](https://github.com/oopsguy/kaptcha-spring-boot。 "https://github.com/oopsguy/kaptcha-spring-boot。")

验证码可以由后端生成,也可以由前端生成。而该插件是基于后端生成的,把验证码的内容存储在Session中。

3.1 pom.xml依赖管理

XML 复制代码
        <dependency>

            <groupId>com.oopsguy.kaptcha</groupId>

            <artifactId>kaptcha-spring-boot-starter</artifactId>

            <version>1.0.0-beta-2</version>

        </dependency>

3.2 yml配置文件

在com.oopsguy.kaptcha.KaptchaProperties的源码中可以发现,作者实现了自动配置,让我们只用在配置文件中写验证码的配置,无需在自己写验证码生成的代码,即可自动生成验证码(底层还是基于Servlet,使用HttpServletRequest req来进行session的存储)。

XML 复制代码
kaptcha:

  border:

    enbaled: true

  image:

    height: 50

    width: 160

  text-producer:

    character:

      length: 4

    font:

      color: blue

  items:

    home:

      path: /admin/captcha

      session:

        key: KAPTCHA_SESSION_KEY

        date: KAPTCHA_SESSION_DATE

其中kaptcha则是对应了源码中@ConfigurationProperties注解的prefix的值。也就是说通过配置文件读取map,map用对象items接收,作为kaptcha对象的属性。

map的键是字符串,值是单个验证码类型SingleKaptchaProperties,包含session(存储验证码的session)和path(验证码的访问路径)。

在session中存储key和date字段,key存储的是验证码的值,date存储的是验证码生成的时间(防止过期验证码)。

而对于验证码也可以修改相关属性,查看kaptcha插件的源码,在com.oopsguy.kaptcha.

autoconfigure.BaseProperties中:

注意KaptchaProperties继承BaseProperties,因此也可以以上属性在配置文件中修改,只不过配置文件的键的第一级都是kaptcha。

3.3 前端代码

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="/admin/captcha" 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', '/admin/captcha?dt=' + new Date().getTime()).fadeIn();

    });

    $("#checkCaptcha").click(function () {

        $.ajax({

            type: "get",

            url: "/admin/check",

            data: {

                captcha: $("#inputCaptcha").val()

            },

            success:function(result){

                if(result){

                    location.href = "success.html";

                }else{

                    alert("验证码错误");

                }

            }

        });

    });

  </script>

</body>

</html>

在img标签中,src路径放的是网络路径,即服务器配置文件中验证码的path。而在请求中拼接了dt=new Date().getTime()是因为浏览器URL请求是GET请求,如果反复请求相同的路径(用户刷新验证码)会被缓存(GET请求的幂等性)导致验证码不变化,new Date().getTime()会获得当前的时间戳,因此用户每次刷新时URL都不一样,于是GET请求就不会被缓存。

3.4 后端代码

java 复制代码
@RequestMapping("/admin")

@RestController

public class KaptchaController {

    private final static String KAPTCHA_SESSION_KEY = "KAPTCHA_SESSION_KEY";

    private final static String KAPTCHA_SESSION_DATE = "KAPTCHA_SESSION_DATE";

    private final static long VALID_MILLIS_TIME = 60 * 1000;// 过期时间1分钟

    @RequestMapping("/check")

    public boolean checkHomeCaptcha(String captcha, HttpSession session) {

        // 如果输入验证码为空,返回false

        if (!StringUtils.hasLength(captcha)) {

            return false;

        }

        // 从session中取出验证码和生成时间

        String savedCaptcha = (String) session.getAttribute(KAPTCHA_SESSION_KEY);

        Date sessionDate = (Date) session.getAttribute(KAPTCHA_SESSION_DATE);

        // 不区分大小写判断是否正确

        if (captcha.equalsIgnoreCase(savedCaptcha)) {

            // 判断是否过期

            if (sessionDate != null && System.currentTimeMillis() - sessionDate.getTime() < VALID_MILLIS_TIME) {

                return true;

            }

        }

        return false;

    }

}

3.5 结果

如果输入错误的验证码,则弹出提示"验证码错误"。

如果输入正确的验证码,则跳转到成功页面。

下篇文章:

SpringBoot系列---日志https://blog.csdn.net/sniper_fandc/article/details/148978087?fromshare=blogdetail&sharetype=blogdetail&sharerId=148978087&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link