最近更新于 2024-05-10 10:05
1 前言
去年接过一个 Java 的单子,现学了 Java(https://blog.iyatt.com/?p=11305 ),在之后都没碰过 Java 了。
前段时间又遇到一个 Spring Boot 的项目,因为时间比较紧只有三四天就要见初版,我也不能现学来做就推掉了。
现在抽空学一下,做个记录。
2 环境
- Java 21.0.2
- Maven 3.9.6
- Spring Boot 3.2.4
3 辅助
3.1 项目创建器
3.1.1 官方网站
Spring Boot 项目创建器:https://start.spring.io/
这个是官方提供的,而且是开源的,自己也可以部署这个网页
左侧配置基本信息,右侧添加其它依赖
3.1.2 VScode
如果像我一样是使用 VScode 开发,可以安装一个插件,实现项目创建(感觉应该也是基于上面的官方项目),可以不需要手动解包打开项目,这个直接跳转到创建好的项目
按F1
或者Ctrl
+Shift
+P
打开 VScode 的命令面板,搜索 Spring,开始创建一个 Maven 或 Gradle 项目,后续填的参数和网页一样
除了上面的项目创建插件,VScode 中进行 Spring Boot 开发可能用到的其它插件:
-
Java 插件集合:Extension Pack for Java
-
Spring Boot 仪表盘:Spring Boot Dashboard
在侧边栏会显示所有的 Spring Boot 项目,可以集中调试和运行管理
3.1.3 IDEA
如果用 IDEA(2023.1),也可以用同样的方法创建,这个默认就是调用官方的创建器网站
3.2 文档
官方文档:https://spring.io/projects/spring-boot#learn
中文文档:https://springdoc.cn/spring-boot/
4 “Hello world” 体验
创建一个 Spring Boot 项目,搜索添加 Spring Web 依赖
直接运行
浏览器访问本机 8080 端口,可以看到一个错误页面,但是确实运行起来了
一般的 Spring Boot 项目结构
myproject/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ ├── controllers/ # 存放控制器类
│ │ │ ├── models/ # 存放模型类
│ │ │ ├── repositories/ # 存放数据访问层接口
│ │ │ ├── services/ # 存放服务层接口和实现类
│ │ │ ├── utilities/ # 存放工具类
│ │ │ └── Application.java # 项目的入口类
│ │ ├── resources/
│ │ │ ├── application.properties # 应用程序配置文件
│ │ │ └── static/ # 存放静态资源文件
│ │ └── webapp/ # 存放Web应用程序资源(可选)
│ └── test/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── tests/ # 存放测试类
│ └── resources/ # 存放测试资源文件
└── pom.xml # Maven项目配置文件
- src/main/java:存放Java源代码的根目录。
- src/main/java/com/example/controllers:存放控制器类,处理HTTP请求和响应。
- src/main/java/com/example/models:存放模型类,表示应用程序的数据结构。
- src/main/java/com/example/repositories:存放数据访问层接口,用于与数据库或其他数据源进行交互。
- src/main/java/com/example/services:存放服务层接口和实现类,处理业务逻辑。
- src/main/java/com/example/utilities:存放工具类,提供辅助功能。
- src/main/resources:存放项目的资源文件,如应用程序配置文件、静态资源文件等。
- src/main/webapp:如果使用传统的Web应用程序部署方式,该目录存放Web应用程序资源(例如JSP文件)。
- src/test:存放测试代码和资源文件的目录。
- pom.xml:Maven项目的配置文件,用于定义项目的依赖和构建配置。
上面直接运行,访问页面是个错误页就是因为缺少 controller 来处理请求
现在创建一个
package com.iyatt.test1.controllers;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Test1Controller
{
@RequestMapping("/") // 处理 http://IP:8080/ 地址的请求
public String hello()
{
return "Hello World";
}
}
再运行 Test1Application 后访问可以看到 Hello world
5 配置文件
5.1 公共应用属性
application.properties 就是配置文件,另外支持用 yaml 格式配置,即命名为 application.yaml
官方文档有关于公共应用属性的说明:https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html
比如 server.port 设置端口,默认是 8080
我设置端口为 80,即 http 的默认端口,这样浏览器就可以不用指定端口进行访问
在 application.properties 中添加
这样就可以直接用 IP 访问了
把上面设置的端口注释掉,创建 application.yaml 文件,写入
现在可以通过 81 端口访问
那么如果两种格式的配置文件同时存在,且对同一个参数设置了不同值优先级如何?
把 properties 设置端口为 80,yaml 设置端口为 81,再运行
可以看到实际运行的是 80,代表 properties 的优先级更高
5.2 读取配置文件
这里以 YAML 格式的配置文件进行演示
YAML 的语法参考官方文档:https://yaml.org/spec/
目前最新的一版是 2021-10-01 的 1.2.2 版本
application.yaml 写入内容如下:
name: Xiao Qiang
# 对象
person:
name: ${name} # 引用
age: 18
adult: true
# 数组
address:
- Chong Qing
- Beijing
msg1: 'hello\n world' # 保留原始字符串
msg2: "hello\n world" # 特殊字符会转义
5.2.1 逐个读取
package com.iyatt.test1.controllers;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Test1Controller
{
@Value("${name}") // 读取application.yaml中的name属性
private String name;
@RequestMapping("/name") // 访问 http://localhost/name 获取name属性值
public String get_name()
{
return this.name;
}
@Value("${person.name}") // 读取application.yaml中的person.name属性
private String person_name;
@Value("${person.age}") // 读取application.yaml中的person.age属性
private Integer person_age;
@Value("${person.adult}") // 读取application.yaml中的person.adult属性
private boolean person_adult;
@RequestMapping("/person") // 访问 http://localhost/person 获取person对象
public String get_person()
{
return "Name: " + this.person_name + ", Age: " + this.person_age + ", Adult: " + this.person_adult;
}
@Value("${address[0]}") // 读取application.yaml中的address数组第一个元素
private String address1;
@Value("${address[1]}") // 读取application.yaml中的address数组第二个元素
private String address2;
@RequestMapping("/address") // 访问 http://localhost/address 获取address数组
public String get_address()
{
return "Address1: " + this.address1 + ", Address2: " + this.address2;
}
@Value("${msg1}") // 读取application.yaml中的msg1属性
private String msg1;
@Value("${msg2}") // 读取application.yaml中的msg2属性
private String msg2;
@RequestMapping("/msg") // 访问 http://localhost/msg 获取msg数组
public String get_msg()
{
return "msg1: " + this.msg1 + " msg2: " + this.msg2;
}
}
分别访问
5.2.2 按需获取
这种方式不需要像上面那种逐个读取值到变量中,可以整体加载,然后按需要获取属性值
package com.iyatt.test1.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Test1Controller
{
@Autowired
private Environment env;
@RequestMapping("/") // 访问 http://localhost
public String get_env()
{
return "name: " + env.getProperty("name") +
", person.name: " + env.getProperty("person.name") +
", person.age: " + env.getProperty("person.age") +
", person.adult: " + env.getProperty("person.adult") +
", adddress1: " + env.getProperty("address[0]") +
", address2: " + env.getProperty("address[1]") +
", msg1: " + env.getProperty("msg1") +
", msg2: " + env.getProperty("msg2");
}
}
5.2.3 反序列化
直接将配置文件中的内容加载到对象
Bean 通用方法自动生成,参考:https://blog.iyatt.com/?p=14637
application.yaml 改为
person:
name: Xiao Wang
age: 18
adult: true
address:
- Chong Qing
- Beijing
创建一个 Person.java
package com.iyatt.test1;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.Data;
@Component
@ConfigurationProperties(prefix = "person") // 读取 person 对象
@Data // 自动生成 Baen 通用方法
public class Person
{
private String name;
private Integer age;
private boolean adult;
private String[] address;
}
controller.java
package com.iyatt.test1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Test1Controller
{
@Autowired
private Person person;
@RequestMapping("/person")
public String get_person()
{
return person.toString();
}
}
运行访问
5.3 配置文件分类
5.3.1 多文件
application 作为主配置文件,一般测试环境的配置文件命名为 application-test,开发环境命名为 application-dev,生产环境命名为 application-pro。
比如我在 dev、pro、test 分别设置服务端口为80、81、82
在 application.properties 控制当前的激活环境(后缀)为 pro
spring.profiles.active=pro
运行服务就是 pro 配置的 81 端口启用了
5.3.2 单文件分段
application.yaml
---
Server:
port: 80
spring:
config:
activate:
on-profile: dev
---
Server:
port: 81
spring:
config:
activate:
on-profile: pro
---
Server:
port: 82
spring:
config:
activate:
on-profile: test
---
spring:
profiles:
active: test # 处于激活状态的配置
test 设置的 82 端口运行
5.3.3 运行时指定配置文件
执行命令打包
mvn package
运行在 target 目录下的 jar 文件,并在后方通过参数指定
java -jar .\target\test2-profile-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
比如我这里指定为 dev 运行,就会以 80 端口运行(即使文件里指定的是 test)
5.4 外部配置文件
前面说的 application 配置文件在打包的时候会一起打包,如果在运行的时候想要修改,可以按照同样的格式编辑作为外部配置文件,在运行的时候指定或者放置到默认自动加载的路径,会覆盖打包的配置文件起作用。可放置的位置挺多的,需要用的时候可以现查文档。