## 1. 配置文件快速上手
我们在前面讲解Tomcat的时候,默认的端口号是8080,如果我们有的程序访问的端口号也是8080的时候,这时候就会发生端口号冲突,所以我们需要通过配置文件来修改程序运行时的端口号 .在项目创建的时候,就帮我们自动创建了一个配置文件.他的后缀是.properties.

我们点开配置文件修改程序的端口号:
ini
spring.application.name=demo
server.port=9090
AI写代码
12
运行程序:我们可以发现程序的端口号变成了9090.

这时候我们通过8080端口号访问其中的html页面的时候,就无法访问了.

2. 配置文件的格式
SpringBoot的配置文件有以下三种:
• application.properties
• application.yml
• application.yaml
其中yml格式和yaml格式其实是等同的.yml是yaml的缩写.
需要注意的一点是,配置文件的文件名只能是以上三个,文件名一旦修改,配置文件就会变成无效配置文件.
-
特殊说明:
- 如果properties和yml存在于同一个项目的时候,两个配置都会加载,但是如果配置文件内容有冲突的时候,.properties文件的优先级更高.
- 虽然他们可以共存,但是我们在实际的也业务当中,我们一般只使用一个文件来配置,这样可以更好的维护.
3. properties配置文件的说明
properties配置文件是最早期的配置文件格式,也是创建SpringBoot项目默认的配置文件
3.1 properties基本语法
properties是以键值的形式配置 的,单词和单词之间用.分割,就像导包一样.key和value之间是以=连接的.比如:
ini
spring.application.name=demo
server.port=9090
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8&useSSL=false
spring.datasource.name=root
spring.datasource.password=qwe123524
AI写代码
12345
提示 配置文件中可以通过在前面加#来注释信息.
3.2 读取配置文件
如果在项目中,想要读取配置文件中的内容,可以使用@Value注解来实现.@Value注解在后面的参数中使用${}的格式来读取,代码如下:
kotlin
@RestController
@RequestMapping("/demo")
public class PropertiesController {
@Value("${mykey.key}")
private String key;
@RequestMapping("/key")
public String key(){
return key;
}
}
AI写代码java
运行
12345678910
运行结果:

3.3 properties的缺点
properties配置文件是以key-Value的形式来配置的,但是有的时候,配置文件中的信息有些赘余,比如下面的配置,spring.datasource这个内容就是赘余的:
ini
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8&useSSL=false
spring.datasource.name=root
spring.datasource.password=qwe123524
AI写代码
123
要想解决这个问题,我们需要引入yml配置文件的格式了.
4.yml配置文件说明
4.1 yml基本语法
yml是树形结构的配置文件,他的基础语法是:key: value,需要注意的一点是,key和value之间的空格不可以省略 .
基础语法如下:

我们看到,要是yml的键值对中间没有空格的话,key是没有语法高亮的,语法就是错误的.
下面我们就把上面连接数据库的案例改写为yml的格式.
yaml
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8&useSSL=false
name: root
password: qwe123524
AI写代码yml
12345
我们看到,前面我们所说的"赘余"的信息,在yml下可以合并到一起写了 .这里行与行之间的缩进一般是两个空格.
4.2 yml使用进阶
4.2.1 yml配置不同的数据类型及其null
php
# 字符串
string.value: Hello
# 布尔值,true或false
boolean.value: true
boolean.value1: false
# 整数
int.value: 10
# 浮点数
float.value: 3.14159
# Null,~代表null
null.value: ~
# "" 空字符串
#, 直接后⾯什么都不加就可以了, 但这种⽅式不直观, 更多的表⽰是使⽤引号括起来
empty.value: ''
AI写代码yml
1234567891011121314
这里需要注意的地方只有两点,第一就是空字符串是一个单引号,第二就是null用一个波浪号来表示.
4.2.2 yml配置读取
yml读取配置的方法和properties相同,使用@Value注解即可,实现代码如下:
yaml
string:
hello: bite
AI写代码yml
12
kotlin
@RequestMapping("/demo")
@RestController
public class YmlController {
@Value("${string.hello}")
public String hello;
@RequestMapping("/hello99")
public String hello(){
return this.hello;
}
}
AI写代码java
运行
12345678910
运行结果:

4.2.3 注意事项:value值佳单引号和双引号
字符串默认不用加上单引号或者是双引号,如果加了的话,有的情况下又会表示特殊含义.
比如在yml文件中配置如下信息:
yaml
string:
str1: Hello \n Spring Boot.
str2: 'Hello \n Spring Boot.'
str3: "Hello \n Spring Boot."
AI写代码yml
1234
kotlin
@RestController
public class ReadYml {
@Value("${string.str1}")
private String str1;
@Value("${string.str2}")
private String str2;
@Value("${string.str3}")
private String str3;
@PostConstruct
public String readYml(){
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
return "yml";
}
}
AI写代码java
运行
12345678910111213141516

在这里我们可以看到:
- 字符串默认不用加上单引号或者双引号
- 加了单引号之后,特殊字符会被转义,只表示的是一个普通的字符串,加了双引号之后,特殊字符不会被转义.
注意:这里的转义说起来可能会有些拗口,\n本来表示的是换行,使用单引号发生了转义,也就是说,\n不再表示换行了,表示的是一个普通的字符串,而加了双引号之后就表示的是特殊字符的本意,没有发生转义.
我们来说明一下@PostConstruct这个注解,这个注解表示的是,在服务启动之后,这个方法会变为初始化方法 ,这个方法在后端立即就会执行,如果有打印信息的话,会立即打印在后端的控制台上.相比于使用@RequestMapping注解,我们就不需要通过浏览器来访问最终结果了,我们只需要在后端的控制台上看最终的结果即可.
4.2.4 配置对象
我们还可以在yml中配置对象.如下配置:
yaml
student:
id: 1
name: java
age: 20
AI写代码yml
1234
这个时候我们就不可以用@Value来配置对象了,此时就要使用到另一个注解:@ConfigurationProperties来读取.具体实现如下:
less
@Component
@ConfigurationProperties(prefix = "student")
@Data
public class Student {
public Integer id;
public String name;
public Integer age;
}
AI写代码java
运行
12345678
typescript
@RestController
public class StudentController {
@Autowired
private Student student;
@PostConstruct
public void readStudent(){
System.out.println(student);
}
}
AI写代码java
运行
123456789
运行结果:

注意事项
- 在一个类中给对象中的属性赋值的时候,这个类必须有Set方法 ,所以我们才要在类的头上加上
@Data注解,我们下面不引入注解,手动写入Set方法,来验证这种说法的可靠性.
typescript
@Component
@ConfigurationProperties(prefix = "student")
public class Student {
public Integer id;
public String name;
public Integer age;
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + ''' +
", age=" + age +
'}';
}
}
AI写代码java
运行
12345678910111213141516171819202122232425262728
运行结果:

- 在类的属性中,属性名必须和yml中的字段名是一致的.否则无法对应的上.
4.2.5 配置集合
配置文件还可以配置List集合,(包括数组,Set在内都是如下的方法)如下所示:
markdown
dbtypes:
name:
- mysql
- sqlserver
- db2
AI写代码yml
12345
就是在每一个字符串的前面加上一个横杠,就表示的是列表,和md的语法非常相似.
java
import java.util.List;
@Component
@Data
@ConfigurationProperties(prefix = "dbtypes")
public class ListConfig {
public List<String> name;//对应name字段
}
AI写代码java
运行
1234567
typescript
@RestController
public class ReadYml2 {
@Autowired
public ListConfig listConfig;
@PostConstruct
public void readList(){
System.out.println(listConfig);
}
}
AI写代码java
运行
123456789
运行结果:

在配置集合的时候,上述代码实际上也是在配置一个对象,所以仍然使用@ConfigurationProperties注解.
4.2.6 配置map
配置文件也可以配置map,如下所示:
yaml
maptypes:
map:
k1: v1
k2: v2
k3: v3
AI写代码yml
12345
less
@Component
@Data
@ConfigurationProperties(prefix = "maptypes")
public class MapConfig {
//注意字段名的一致性
public Map<String,String> map;
}
AI写代码java
运行
1234567
kotlin
@RestController
public class ReadYml3 {
@Autowired
public MapConfig mapConfig;
@PostConstruct
public void mapReader(){
System.out.println(this.mapConfig);
}
}
AI写代码java
运行
123456789
运行结果:

5. 综合性练习:验证码案例
5.1 接口文档
-
需求分析
- 生成验证码,并返回验证码
- 校验验证码是否正确:校验验证码是否正确.
-
生成验证码:
- 请求
javascript请求url: /captcha/getCaptcha 请求参数: 无 AI写代码 12- 响应
验证码内容的图片.浏览器给服务器发送⼀个/captcha/getCaptcha 这样的请求,服务器返回⼀个图片,浏览器显显示在页面上.
-
校验验证码是否正确
- 请求
ini请求url: /captcha/check 请求参数: captcha=用户输入的验证码 AI写代码 12- 响应
true or false,验证成功,返回true,验证失败,返回false.
5.2 Hutool工具介绍
5.3 后端代码
- 引入Hutool依赖
xml
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
<version>5.8.22</version>
</dependency>
AI写代码xml
12345
- 写出验证码的配置项与验证码配置项所对应的类.并注入IoC容器.
yaml
captcha:
width: 100
height: 40
session:
key: CAPTCHA_SESSION_KEY
date: KAPTCHA_SESSION_DATE
AI写代码yml
123456
配置项中对应的分别是验证码的长和宽,还有用于存储验证码和过期时间.
less
@Component
@ConfigurationProperties(prefix = "captcha")
@Data
public class CaptchaProperties {
public Integer width;
public Integer height;
public Session session;
public static class Session{
public String key;
public String date;
}
}
AI写代码java
运行
123456789101112
- 调整生成验证码的Controller代码
less
@RestController
@RequestMapping("/captcha")
public class CaptchaController {
@Autowired
public CaptchaProperties captchaProperties;
@RequestMapping("/getCaptcha")
public void getCaptcha(HttpServletResponse response, HttpSession session) throws IOException {//可以通过这个参数拿到响应中的所有信息
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(captchaProperties.getWidth(),captchaProperties.getHeight());//创建线条干扰验证码
//图形验证码写出,可以写出到文件,也可以写出到流
response.setContentType("image/jpeg");//从响应中获取到类型信息,设置为图片格式
response.setHeader("Pragma","No-cache");//从响应中获取到Header,把Pragma键值对设置为没有缓存.
try {
lineCaptcha.write(response.getOutputStream());
//把验证码放入session中
session.setAttribute(captchaProperties.getSession().getKey(),lineCaptcha.getCode());
//把过期时间放入session中
session.setAttribute(captchaProperties.getSession().getDate(),System.currentTimeMillis());
response.getOutputStream().close();//关闭输出流
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
AI写代码java
运行
1234567891011121314151617181920212223
接下来我们来访问网页来观察验证码是否生成成功.

验证码生成成功.
- 校验验证码
java
public static final Integer MAX_WAIT_MILLS = 60*1000;
@RequestMapping("/check")
public boolean checkCaptcha(HttpSession session,String captcha){
if (!StringUtils.hasLength(captcha)){//判断验证码是否有长度
return false;
}
String sessionCode = (String) session.getAttribute(captchaProperties.getSession().getKey());
Long sessionDate = (Long) session.getAttribute(captchaProperties.getSession().getDate());
if (captcha.equalsIgnoreCase(sessionCode) &&
System.currentTimeMillis()-sessionDate < MAX_WAIT_MILLS){
return true;//验证码和用户输入的等同且
}
return false;
}
AI写代码java
运行
1234567891011121314
5.4 前端代码
xml
<!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({
url: "/captcha/check",
type: "post",
data: { captcha: $("#inputCaptcha").val() },
success: function (result) {
if (result) {
location.href = "success.html";
} else {
alert("验证码错误");
$("#inputCaptcha").val("");
}
}
});
});
</script>
</body>
</html>
AI写代码html
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
xml
<!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>
AI写代码html
1234567891011
测试运行:

