您现在的位置是:首页 >技术交流 >Spring Boot相关概念、创建与运行网站首页技术交流
Spring Boot相关概念、创建与运行
一、Spring Boot的创建与使用
(一)为什么要学习 Spring Boot?
Spring 是为了简化 Java 开发而诞生的,SpringBoot 是为了简化 Spring 程序开发的
(二)Spring Boot的优势
- 快速集成框架,Spring Boot提供了启动添加依赖的功能,用于秒级集成各种框架
- 内置运行容器,无需配置 Tomcat 等 Web 容器,直接运行和部署程序
- 快速部署项目,无需外部容器即可启动并运行项目
- 可以完全抛弃繁琐的 XML,使用注解和配置的方式进行开发
- ⽀持更多的监控的指标,可以更好的了解项⽬的运⾏情况
(三)Spring Boot的创建
Spring Boot可以使用 IDEA 来创建,也可以使用 Spring 官方提供的网页版来创建,在这里只介绍使用 IDEA 创建的Spring Boot 的方式
1. 安装插件
由于作者使用的是 IDEA 社区版,因此先要安装 Spring Assistant 插件,才能创建 Spring Boot 项目,如下图:
注意:IDEA2022版本的可能没有这个插件,作者也是又下载了一个2020.3版本的才安装上插件(幸好一台电脑能装多个IDEA)
2. 创建项目
- 在我们装好插件之后,New Project 页面上就会出现 Spring Assistant,选中。Spring Boot2支持的最低 JDK 版本是Java8,但是Spring Boot3支持的最低 JDK 版本是Java17,大家可以看自己的环境进行配置,点击下一步
- 确定创建项目需要的各种环境
- 确定项目版本和需要的各种框架支持
需要的框架
(1)Developer Tools:Spring Booot DevTools(开发阶段需要用到的工具包)
(2)Developer Tools:Lombok
(3)Web:Spring Web(为了支持 HTTP 协议) - 确定项目名称和保存的文件路径,最后点击finish
- 打开项目后,需要对项目进行加载
加载完成前:
加载完成后:
如果在加载完成之后有的地方报红,那么下面的操作就需要重点关注
3. 配置国内源
这么做的目的是为了快速创建 Spring Boot 项目,不用每次都去访问国外官网的源
-
先将当前项目的源设置为国内源
注意下面的两个文件,以及两个文件后面都需要打√
第一个 settings.xml 需要做如下配置
第二个文件夹中的文件会在我们进行加载时自动下载,如果加载完之后发现还有报错,那么删除该文件夹下的全部文件,并点击 Maven 中的刷新进行重新加载,如下图:
-
将以后创建的新项目的源也设置为国内源
4. 删除无效目录
- .mvn文件,该文件的作用是让我们通过命令行对maven项目进行打包等等操作,但是我们已经集成了插件,因此不需要这么麻烦了
- HELP.md文件,该文件就是项目的帮助文档
- mvnw文件以及mvnw.cmd文件,与maven有关的文件,都可以删除掉
(四)项目目录介绍和运行
经过上述操作,我们就得到了 Spring Boot 的项目目录,如下图:
Spring Boot项目有两个主要的目录:
- src/main/java 为 Java 源代码
- src/main/resources 为静态资源或配置文件
- /static:静态资源文件夹(包括html/js/css/img等等)
- /templates:模板资源文件夹(通用资源,比如通用的css文件/js文件等等)
- /application.properties:配置文件
- src/test/java 为 Java 单元测试文件
- target 为经过编译后的可执行 .class 文件
- .gitignore:git的忽略文件,里面存放了不提交的文件有哪些
- pom.xml:Maven项目必须要有的文件,Spring Boot不是必须要有的
1. 启动 Spring Boot
2. 输出 Hello World
我们学习 Spring Boot 是为了更方便的实现 Web 项目的,因此接下来我们就要用 Spring Boot 来实现和浏览器及用户的交互,实现代码及路径如下:
运行结果:
(五)注意事项
1. 正确的包路径
正确路径:我们只有把要注入的容器类(包)和启动类放到同一级目录下时,Spring Boot 项目才能正常的将 bean 注入到容器中,如上面的输出 Hello World 示例以及下方的示例:
2. 五大注解URL的区别
Spring Boot 对于五大注解也做了特殊的约定,由于 @Controller 就是我们规定的控制器类,因此 Spring Boot 官方设定被 @Controller 修饰的类不需要在类上加 @RequestMapping,只需要对方法修饰 @RequestMapping 即可,此时方法上的路径就是一级路径,也可以给类上加 @RequestMapping,那么类上的就是一级路由,方法上就是二级路由
其他注解不是控制器注解,所以如果也想要通过浏览器访问,那么就必须既在类上添加 @RequestMapping,也在方法上添加 @RequestMapping,通过二级路由才能访问到具体的方法,不过为了项目规范,不建议这样做
注意:约定大于配置
我们注意到,我们在运行项目前,并没有对 Spring Boot 项目进行什么配置,比如在 Spring 中配置 Bean 的扫描路径。但是仍然可以运行,因为 Spring Boot 不需要,官方已经约定好了,用户创建了容器类之后必须放到和启动类同级目录或者同级目录的包下面,等到运行时,Spring Boot 自然会对那些类进行扫描,但是当我们把容器类放到其他目录下时,就无法被框架识别。因此我们说,Spring Boot 配置比较少,就是因为 Spring Boot 的设计思想是:约定大于配置
二、配置文件
(一)配置文件作用
整个项目中所有重要的数据都是在配置文件中配置的,比如:
- 数据库的连接信息(包含用户名和密码的设置)
- 项目的启动端口
- 第三方系统的调用密钥等信息
- 用于发现和定位问题的普通日志和异常日志等
配置文件包括两类,一种是系统的配置文件,比如连接字符串、日志的相关设置,这是系统定义好的;另一种就是用户自定义的配置文件
(二)配置文件的格式
Spring Boot 的配置文件主要分为以下两种格式:
- *.properties
- *.yml
如下图所示:
上述两种格式的作用一样,只不过是两种时期的产物,.properties是创建 Spring Boot 项目时默认的文件格式,而 .yml 则需要自己创建
说明:
- 理论上两种文件可以同时存在在同一个 Spring Boot 项目中,此时如果配置文件中出现了同样的配置,那么就会以 properties 中的配置为主,就是说properties 配置文件的优先级最高,但加载完 .properties 文件之后,也会加载 .yml 文件的配置信息
- 虽然理论上两种文件可以共存,但是我们在实际使用时,我们会采用统一的配置文件格式,这样可以更好的维护
- Spring Boot 由于约定大于配置的特点,因此只有application.properties文件可以被识别,其他名字的properties文件都没用
(三)properties 配置文件说明
properties 配置文件是最早期的配置文件格式,也是创建 Spring Boot 项目默认的配置文件
1. 为 properties 配置文件安装提示插件
properties 配置文件默认情况下配置时不会有提示信息,对我们不太友好,因此我们可以安装一个插件来辅助我们编写配置文件代码
2. properties 基本语法
properties 是以键值对的形式配置的, key 和 value 之间是以"="连接的,注意:不能加空格,包括键值对的前后,中间,如:
# 系统的配置文件
# 服务器端口
server.port=9090
# 数据库连接
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/Test?characterEncoding=utf8&useSSL=false
spring.datasource.name=root
spring.datasource.password=xxx
# 自定义配置项,举例
qq.test=xxx
properties如果不经过配置可能会出现乱码,因为它是早期的配置文件,默认编码格式不是 utf8,接下来我们对它进行配置一下
- 给当前项目处理中文乱码问题
- 给以后的项目处理中文乱码问题
- 注意:设置完之后可能当前文件仍然是中文乱码,接下来我们需要做的就是删除 application.properties 文件,重新创建一个就可以正常使用了
3. 读取配置文件
在项目中,想要主动的读取配置文件中的内容,可以使用 @Value 注解来实现。@Value 注解使用”${}“的格式读取,如下代码所示:
@Controller
public class UserController {
// 获取配置文件中的端口号
@Value("${server.port}")
private Integer port;
@ResponseBody // 告诉服务器返回一个非静态页面的数据
@RequestMapping("/hello") //设置路由地址,路由地址尽量不要大写混小写
public String hello() {
return "Hello World! port: " + port;
}
}
运行结果:
4. properties 缺点分析
properties 配置是以 key-value 的形式配置的,从下面的配置 key 就能看出,properties 配置文件中会有很多的冗余的信息,想要解决这个问题,就可以使用 yml 配置文件的格式化了
(四)yml 配置文件说明
yml是 YAML 的缩写,它的全称 Yet Another Markup Language 翻译成中文就是“另一种标记语言”
yml优点分析:
- yml 是一个可读性高,写法简单、易于理解的标记语言,它的语法和 JSON 语言类似
- yml 支持更多的数据类型,它可以简单表达数组、散列表、标量等数据形态。它使用空白符号缩进和大量依赖外观的特色,特别适合同来表达或编辑数据结构、各种配置文件等
- yml 支持更多的编程语言,它不止是 Java 中可以使用,在 Golang、PHP、Python等等中同样可以
1. yml 基本语法
yml 是树形结构的配置文件,它的基础语法是“key: value”,注意 key 和 value 之间使用英文冒号加空格的方式组成,其中的空格不可省略,基础语法如下:
使用 yml 连接数据库
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/Test?characterEncoding=utf8&useSSL=false
name: root
password: 000000
2. yml 进阶用法
(1)yml 配置不同数据类型及 null
# 字符串
string.value: Hello
# 布尔值,true或false
boolean.value: true
boolean.value1: false
# 整数
int.value: 10
int.value1: 0000_0000_0000_0000_0000_0000_0000_1010 # 二进制
# 浮点数
float.value: 3.14
float.value1: 314e-2 # 科学计数法
# NULL,~表示null
null.value: ~
(2)yml配置读取
yml 读取配置的方式和 properties 相同,使用 @Value 注解即可
(3)注意事项:value 值加单双引号
规则:
- 字符串默认不⽤加上单引号或者双引号
- 单引号会转义特殊字符,特殊字符最终只是⼀个普通的字符串数据
- 双引号不会转义字符串⾥⾯的特殊字符;特殊字符会作为本身想表示的意思
示例:
# yml文件配置
string:
str1: hello
world
str2: 'hello
world'
str3: "hello
world"
// 测试
@Controller
public class UserController {
@Value("${string.str1}")
private String str1;
@Value("${string.str2}")
private String str2;
@Value("${string.str3}")
private String str3;
@ResponseBody // 告诉服务器返回一个非静态页面的数据
@RequestMapping("/hello") //设置路由地址,路由地址尽量不要大写混小写
public String hello() {
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
return "Hello World! port: " + port;
}
}
结果:
3. 配置对象
我们除了上述的功能之外,还可以在 yml 中配置对象,如下配置:
student:
id: 1
name: zhangsan
age: 12
或者行内写法:
student1: {id: 2, name: lisi, age: 18}
此时就不能用 @Value 来读取配置中的对象,要使用另一个注解 @ConfigurationProperties 来读取,具体实现如下:
注意,在上述代码中,@Data是不可省略的,因为 @ConfigurationProperties 需要通过 set 和 get 方法将配置文件中的属性一一匹配并注入到对应的 Bean 属性上,然后在其他地方进行读取
4. 配置集合
配置文件也可以配置 list 集合,也有两种写法,如下所示:
# 配置文件名
dbtypes:
# 配置文件名中的集合名
name:
# 集合中的内容
- mysql
- server
- db
dbtypes2: {name: [mysql, server, db1]}
集合的读取和对象一样,也是使用 @ConfigurationProperties 来读取,具体实现如下:
@Data
@ConfigurationProperties("dbtypes")
@Component
public class ListConfig {
private List<String> name;
}
打印类的实现
@Controller
public class UserController {
@Autowired
private ListConfig listConfig;
@ResponseBody // 告诉服务器返回一个非静态页面的数据
@RequestMapping("/hello") //设置路由地址,路由地址尽量不要大写混小写
public String hello() {
return "ListConfig : " + listConfig.getName();
}
}
运行结果:
5. 不同的环境设置不同的配置文件
通常情况下,我们的开发环境和测试环境都是不一致的,因此如果我们只有一个配置文件,在项目发布时将配置文件中开发环境的配置项注释掉,这种做法无疑是很麻烦的,因此我们可以采用更简单的做法,直接创建多个配置文件,分别保存开发环境、生产环境和公共的配置信息
我们以设置保存图片路径为例,对于配置文件来说,我们要求文件名必须是 application 或者 application-自定义名,后缀名为properties或者yml,我们选择设置三个配置文件,分别作为公共、开发环境、生产环境的配置文件,如下图所示:
通过设置,让我们改变环境时,只需要改变一个配置即可
公共配置:
# 选择配置文件是开发环境还是生产环境
# 由于前面的名字都一样,因此这里只需要写自定义的名字即可
spring:
profiles:
# 这里表明当前是使用开发环境的配置文件
active: dev
开发环境的配置:
# 保存文件的路径
img:
path: D:/Data/
生产环境的配置:
# 保存文件的路径
img:
path: /root/img/
测试代码:
@Value("${img.path}")
private String imgPath;
@RequestMapping("/imgpath")
public String img() {
return "图片保存路径:" + imgPath;
}
测试结果:
修改公共配置文件中的值为prod
,再观察运行结果:
(五)properties VS yml
- properties 是以 key=value 的形式配置的键值类型的配置⽂件,⽽ yml 使⽤的是类似 json 格式的树形配置⽅式进⾏配置的,yml 层级之间使⽤换⾏缩进的⽅式配置,key 和 value 之间使⽤" : "英⽂冒号加空格的⽅式设置,并且空格不可省略
- properties 为早期并且默认的配置⽂件格式,但其配置存在⼀定的冗余数据,使⽤ yml 可以很好的解决数据冗余的问题
- yml 通⽤性更好,⽀持更多语⾔,如 Java、Go、Python 等,如果是云服务器开发,可以使⽤⼀份配置⽂件作为 Java 和 Go 的共同配置⽂件
- yml ⽀持更多的数据类型
要说明的是,Spring Boot 读取配置文件的方法一共有五种,这里只是介绍了其中的两种,要想了解的更多,可以参考这篇文章:https://juejin.cn/post/7132641888166739982
三、日志文件
(一)日志的作用
日志也是我们程序的重要组成部分,无论是调试代码,查看修改记录等等操作,查看日志都是一个很好的定位和排除问题的途径
除了发现和定位问题,我们还可以通过日志实现以下功能:
- 记录用户登录日志,方便分析用户是正常登录还是恶意破解用户
- 记录系统的操作日志,方便数据恢复和定位操作人
- 记录程序的执行时间,方便为以后优化程序提供数据支持
(二)日志打印
1. 项目自动打印的日志
Spring Boot 项⽬在启动的时候默认就有⽇志输出,如下图所示:
通过上述日志信息我们能发现三个问题:
- Spring Boot 内置了日志框架
- 默认情况下,输出的日志不是开发者定义和打印的
- 日志默认是打印在控制台上,但控制台上的日志不能被保存
2. 自定义日志打印
开发者自定义打印日志的实现步骤:
- 在程序中得到日志对象
在程序中获取⽇志对象需要使⽤⽇志⼯⼚ LoggerFactory(日志框架),如下代码所示:
@Controller
@ResponseBody
public class LoggerController {
// 1. 获取日志对象(来自 slf4j)
private final static Logger log =
LoggerFactory.getLogger(LoggerController.class);
}
注意:Logger 对象是属于 org.slf4j 包下的,不要导错包。日志工厂需要将每个类的类型传递进去,这样我们才知道⽇志的归属类,才能更⽅便、更直观的定位到问题类
Spring Boot 中内置了日志框架 Slf4j,所以咱们可以直接在程序中调用 Slf4j 来输出日志,Slf4j 和 JDBC 类似,我们并不是直接控制工具,而是通过框架来控制工具,至于底层工具是什么,我们并不关心,这样的结果就是如果当前工具不好用了,我们可以很容易的就换一个工具
- 使用日志对象的相关语法输出要打印的内容
@Controller
@ResponseBody
public class LoggerController {
// 1. 获取日志对象(来自 slf4j)
private final static Logger log =
LoggerFactory.getLogger(LoggerController.class);
@RequestMapping("/logger")
public void logger() {
// 2. 使用日志对象提供的打印方法进行日志打印
// 从上到下日志级别逐渐提高
log.trace("trace 方法");
log.debug("debug 方法");
log.info("info 方法");
log.warn("warn 方法");
log.error("error 方法");
}
}
运行结果:
关于为什么我们写了五条日志语句结果只打印了三条的原因将在下面说明
3. 日志格式
(三)日志级别
1. 作用
- ⽇志级别可以帮助我们筛选出重要的信息,⽐如设置⽇志级别为 error,那么就可以只看程序的报错⽇志了,对于普通的调试⽇志和业务⽇志就可以忽略了,从⽽节省开发者信息筛选的时间
- ⽇志级别可以控制不同环境下,⼀个程序是否需要打印⽇志,如开发环境我们需要很详细的信息,⽽⽣产环境为了保证性能和安全性就会输⼊尽量少的⽇志,⽽通过⽇志的级别就可以实现此需求
2. 分类与使用
日志级别分为:
- trace:微量的意思,级别最低;
- debug:需要调试时候的关键信息打印;
- info:普通的打印信息(默认日志级别);
- warn:警告,不影响使用,但需要注意的问题;
- error:错误信息,级别较高的错误日志信息
- fatal:致命,因为代码异常导致程序退出执行的事件(这个级别用户无法自定义,只能系统输出)
日志级别设置
日志级别配置只需要在配置文件中设置“logging.level”配置项即可,如下所示:
logging:
level:
# 设置全局默认的日志级别
root: info
运行结果:
由上述日志打印可知,越往上接收到的消息就越少,如设置了 warn 就只能收到 warn、error、fatal 级别的⽇志了,又由我们上面日志打印示例可知,日志的输出级别,默认是info
局部文件设置日志级别
logging:
level:
# 设置全局默认的日志级别
root: info
# 设置局部文件夹的日志级别,从java文件夹的下一级别开始算起
# 精确到文件夹级别
com.example.demo.controller: trace
运行结果:
局部日志级别优先级 > 全局日志级别
(四)日志持久化
以上的日志输出都是在控制台输出,无法长久保存,然而在生产环境上我们需要将日志保存下来,以便出现问题之后追溯问题,把日志保存下来的过程就叫做持久化
想要将⽇志进⾏持久化,只需要在配置⽂件中指定⽇志的存储⽬录或者是指定⽇志保存⽂件名之后,
Spring Boot 就会将控制台的⽇志写到相应的⽬录或⽂件下
配置日志文件的保存路径:
# 设置日志的保存目录
logging:
file:
# 注意,由于windows系统地址使用的是反斜杠,地址可能会出现d或者D等转义字符
# 在这种情况下,spring boot 无法正确识别保存路径,日志无法正确保存
# 因此我们可以采用下面几种方式避免问题
# 1. 按照 linux 的地址形式,使用斜杠(推荐,以后 linux 系统上部署起来也方便)
# 2. 使用两个反斜杠进行转义
path: D:studyloggingData
运行结果:
配置日志文件的文件名:
logging:
file:
# 设置日志的保存文件名,这里写成 linux 的格式
name: D:/study/loggingData/spring-boot.log
运行结果:
关于上述持久化日志保存会出现几个问题:
- 如果我们重启服务器,文件中的日志是否会重新写入,将之前的日志覆盖掉
解答:通过下方文件日志记录表示,可以看出,重启服务器时并不会将之前的日志进行覆盖,而是接着往下写
- 如果我们的日志内容很多并且不进行处理的话,随着时间的推移,这个日志文件将会非常非常大,我们打开文件也要等很长时间
解答:由下图可知,Spring Boot 一个日志文件默认最大容量是10MB,而如果超过最大容量,之后就会创建一个新的文件并在后面加上编号
- 最长保存时间,保存格式等等一系列的操作我们都可以通过配置来手动设置
练习题:
将 controller 包下 error 级别以上的⽇志保存到 log_all.log 下,将 service 下 warn 级别以上的⽇志保存到 log_all.log 下
代码示例:
logging:
level:
com.example.demo.controller: error
com.example.demo.service: warn
file:
name: D:/study/loggingData/log_all.log
运行结果:
(五)更简单的日志输出——lombok
每次都使⽤ LoggerFactory.getLogger(xxx.class) 且每个类都添加⼀遍,很麻烦,还有⼀种更好⽤的⽇志输出⽅式,使⽤ lombok 来更简单的输出
- 添加 lombok 框架支持
- 添加 @slf4j 注解输出日志
0. 添加插件
这步属于前置工作,需要安装 EditsStarters 插件,该插件是为了让我们在已经创建完项目之后,如果想要再给项目添加框架提供帮助的,添加步骤仍然是在file目录下 Settings 中,选择 Plugins
1. 引入依赖 lombok
这步是针对我们在创建项目时没有引入插件,此时还想引入时,就需要我们在 pom.xml 文件中借助 EditStarters 插件来引入
- 在 pom.xml 文件中选中 Generate
- 选中 Edit Starters
- 就会进入我们熟悉的 Spring Boot 引入框架界面,选择搜索 lombok,进行添加,最后注意一定要点OK
2. 使用 @Slf4j 注解
如下示例:
@Controller
@ResponseBody
@Slf4j
public class LoggerController {
// 1. 获取日志对象(来自 slf4j)
// private final static Logger log =
// LoggerFactory.getLogger(LoggerController.class);
@RequestMapping("/logger")
public void logger() {
// 2. 使用日志对象提供的打印方法进行日志打印
// 从上到下日志级别逐渐提高
log.trace("trace 方法");
log.debug("debug 方法");
// 等于 info 或者高于 info 的日志等级可以打印
log.info("info 方法");
log.warn("warn 方法");
log.error("error 方法");
}
}
注意:加入注解后,日志对象名是 log,这里也体现了约定大于配置的特点
3. lombok 原理解释
根据java文件经过编译后生成的class文件,我们就可以明白 lombok 的原理
由上图可知,lombok 利用的就是 java 文件编译成 class 文件的间隙,不用我们再手写,而是它替我们写出来,实际实现效果和我们自己创建对象一模一样
4. lombok 更多注解说明
基本注解
注解 | 说明 |
---|---|
@Getter | 自动添加 getter 方法 |
@Setter | 自动添加 setter 方法 |
@ToString | 自动添加 toString 方法 |
@EqualsAndHashCode | 自动添加 equals 和 hashCode 方法 |
@NoArgsConstructor | 自动添加无参构造方法 |
@AllArgsConstructor | 自动添加全属性构造方法,顺序按照属性的定义顺序 |
@NonNull | 属性不能为null |
@RequiredArgsConstructor | 自动添加必需属性的构造方法,final + @NonNull 的属性为必须 |
组合注解
注解 | 说明 |
---|---|
@Data | @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor + @NoArgsConstructor |
@Slf4j | 添加一个名为 log 的日志对象 |