SpringBoot 基本应用
约定优于配置
约定优于配置(Convention over Configuration),又称按约定编程,是一种软件设计范式。
本质上是说,系统、类库或框架应该假定合理的默认值,而非要求提供不必要的配置。比如说模型中有一个名为 User 的类,那么数据库中对应的表就会默认命名为 User。只有在偏离这一个约定的时候,例如想要将该表命名为 person,才需要写有关这个名字的配置。
比如平时架构师搭建项目就是限制软件开发随便写代码,制定出一套规范,让开发人员按统一的要求进行开发编码测试之类的,这样就加强了开发效率与审查代码效率。所以说写代码的时候就需要按要求命名,这样统一规范的代码就有良好的可读性与维护性了。
约定优于配置简单来理解,就是遵循约定。
Spring Boot 是所有基于 Spring 开发的项目的起点。Spring Boot 的设计是为了尽可能快的跑起来 Spring 应用程序并且尽可能减少配置文件。
SpringBoot 概念
Spring 优缺点分析
优点:Spring 是 Java 企业版(Java Enterprise Edition,JEE,也称 J2EE)的轻量级代替品。无需开发重量级的 Enterprise Java Bean - EJB,Spring 为企业级 Java 开发提供了一种相对简单的方法,通过依赖注入和面向切面编程,用简单的 Java 对象(Plain Old Java Object,POJO)实现了 EJB 的功能。
缺点:虽然 Spring 的组件代码是轻量级的,但它的配置却是重量级的。一开始,Spring 用 XML 配置,而且是很多 XML 配 置。Spring 2.5 引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式 XML 配置。Spring 3.0 引入 了基于 Java 的配置,这是一种类型安全的可重构配置方式,可以代替 XML。
所有这些配置都代表了开发时的损耗。因为在思考 Spring 特性配置和解决业务问题之间需要进行思维切换,所以编写配置挤占了编写应用程序逻辑的时间。和所有框架一样,Spring 实用,但与此同时它要求的回报也不少。
除此之外,项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。SSM 整合:Spring、Spring MVC、Mybatis、Spring-Mybatis 整合包、数据库驱动,引入依赖的数量繁多、容易存在版本冲突。
Spring Boot 解决上述 Spring 的问题
SpringBoot 对上述 Spring 的缺点进行的改善和优化,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率,一定程度上缩短了项目周期。
起步依赖:
起步依赖本质上是一个 Maven 项目对象模型 (Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。
简单的说,起步依赖就是将具备某种功能的依赖坐标打包到一起,并提供一些默认的功能。
自动配置:
springboot 的自动配置,指的是 springboot 会自动将一些配置类的 bean 注册进 ioc 容器,在需要的地方使用 @autowired 或者 @resource 等注解来使用它。
“自动”的表现形式就是只需要引想用功能的包,相关的配置完全不用管,springboot 会自动注入这些配置 bean,直接使用这些 bean 即可。
Springboot 可以简单、快速、方便地搭建项目;对主流开发框架的无配置集成;极大提高了开发、部署效率。
SpringBoot 入门案例
案例需求:请求 Controller 中的方法,并将返回值响应到页面。
1) 依赖管理
pom.xml
<!--
所用的 springBoot 项目都会直接或者间接的继承 spring-boot-starter-parent
1.指定项目的编码格式为 UTF-8
2.指定 JDK 版本为 1.8
3.对项目依赖的版本进行管理,当前项目再引入其他常用的依赖时就需要再指定版本号,避免版本冲突的问题
4.默认的资源过滤和插件管理
-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
<dependencies>
<!-- 引入 Spring Web 及 Spring MVC 相关的依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<!-- 可以将 project 打包为一个可以执行的 jar -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2) 启动类
com.renda.SpringBootDemo1Application
/**
* SpringBoot 的启动类通常放在二级包中,
* 比如:com.renda.SpringBootDemo1Application。
* 因为 SpringBoot 项目在做包扫描,
* 会扫描启动类所在的包及其子包下的所有内容。
*
* @author Renda Zhang
* @since 2020-10-28 23:11
*/
@SpringBootApplication // 标识当前类为 SpringBoot 项目的启动类
public class SpringBootDemo1Application {
public static void main(String[] args) {
// 样板代码
SpringApplication.run(SpringBootDemo1Application.class, args);
}
}
3) Controller
com.renda.controller.HelloController
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/boot")
public String helloSpringBoot() {
return "Hello Spring Boot";
}
}
SpringBoot 快速构建
案例需求:请求 Controller 中的方法,并将返回值响应到页面。
1)使用 Spring Initializr 方式构建 Spring Boot 项目
本质上说,Spring Initializr 是一个 Web 应用,它提供了一个基本的项目结构,能够快速构建一个基础的 Spring Boot 项目。
注意使用快速方式创建 Spring Boot 项目时,所在主机须在联网状态下;本质上是在开发工具执行各项参数后,由 Spring 提供的 URL 所对应的服务器生成, IDEA 将服务器生成的 SpringBoot 项目下载到本地的工作空间中。
Project SDK 用于设置创建项目使用的 JDK 版本,这里,使用之前初始化设置好的 JDK 版本即可;在 Choose Initializr Service URL 下使用默认的初始化服务地址 https://start.spring.io 进行 Spring Boot 项目创建。
创建完成后的 pom 文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.renda</groupId>
<artifactId>springbootdemo2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootdemo2</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
创建完成后,可以删除自动生成的 .mvn
、.gitignore
、HELP.md
、mvnw
、mvnw.cmd
。
创建好的 Spring Boot 项目结构如图:
/src/main/java/
com.renda.Springbootdemo2Application - 项目主程序启动类
/src/main/resources/
static - 静态资源文件夹
templates - 模板页面文件夹
application.properties - 全网配置文件
/src/test/java/
com.renda.Springbootdemo2ApplicationTests - 项目测试类
使用 Spring Initializr 方式构建的 Spring Boot 项目会默认生成项目启动类、存放前端静态资源和页面的文件夹、编写项目配置的配置文件以及进行项目单元测试的测试类。
2)创建一个用于 Web 访问的 Controller
注意:确保项目启动类 Springbootdemo2Application 在 com.renda 包下。
com.renda.controller.HelloController
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/boot")
public String hello() {
return "What's up! Spring Boot!";
}
}
3) 运行项目
在 application.properties
中修改 tomcat 的默认端口号:
server.port=8888
运行主程序启动类 Springbootdemo2Application,项目启动成功后,在控制台上会发现 Spring Boot 项目默认启动的端口号为 8888,此时,可以在浏览器上访问 http://localhost:8888/hello/boot。
页面输出的内容是 “What’s up! Spring Boot!”,至此,构建 Spring Boot 项目就完成了。
单元测试与热部署
单元测试
开发中,每当完成一个功能接口或业务方法的编写后,通常都会借助单元测试验证该功能是否正确。
1)添加 spring-boot-starter-test 测试依赖启动器,在项目的 pom.xml 文件中添加 spring-boot-starter-test 测试依赖启动器,示例代码如下 :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
注意:使用 Spring Initializr 方式搭建的 Spring Boot 项目,会自动加入 spring-boot-starter-test 测试依赖启动器,无需再手动添加。
2)编写单元测试类和测试方法:
/**
* SpringJUnit4ClassRunner.class: Spring 运行环境
* JUnit4.class: JUnit 运行环境
* SpringRunner.class: Spring Boot 运行环境
*/
@RunWith(SpringRunner.class) // @RunWith: 运行器
@SpringBootTest // 标记为当前类为 SpringBoot 测试类,加载项目的 ApplicationContext 上下文环境
class Springbootdemo2ApplicationTests {
@Autowired
private HelloController helloController;
@Test
void contextLoads() {
String result = helloController.hello();
System.out.println(result);
}
}
上述代码中,先使用 @Autowired
注解注入了 HelloController 实例对象,然后在 contextLoads()
方法中调用了 HelloController 类中对应的请求控制方法 hello()
,并输出打印结果。
热部署
在开发过程中,通常会对一段业务代码不断地修改测试,在修改之后往往需要重启服务,有些服务需要加载很久才能启动成功,这种不必要的重复操作极大的降低了程序开发效率。为此,Spring Boot 框架专门提供了进行热部署的依赖启动器,用于进行项目热部署,而无需手动重启项目 。
热部署:在修改完代码之后,不需要重新启动容器,就可以实现更新。
使用步骤:
1)添加 spring-boot-devtools 热部署依赖启动器。
在 Spring Boot 项目进行热部署测试之前,需要先在项目的 pom.xml 文件中添加 spring-boot-devtools 热部署依赖启动器:
<!-- 引入热部署依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
由于使用的是 IDEA 开发工具,添加热部署依赖后可能没有任何效果,接下来还需要针对 IDEA 开发工具进行热部署相关的功能设置。
2)开启 IDEA 的自动编译。
选择 IDEA 工具界面的 【File】->【Settings】 选项,打开 Compiler 面板设置页面。
选择 Build 下的 Compiler 选项,在右侧勾选 “Build project automatically” 选项将项目设置为自动编译,单击 【Apply】->【OK】 按钮保存设置。
3)开启 IDEA 的在项目运行中自动编译的功能。
在项目任意页面中使用组合快捷键 “Ctrl+Shift+Alt+/” 打开 Maintenance 选项框,选中并打开 Registry 页面。
列表中找到 “compiler.automake.allow.when.app.running”,将该选项后的 Value 值勾选,用于指定 IDEA 工具在程序运行过程中自动编译,最后单击 【Close】 按钮完成设置。
热部署效果测试
启动 Springbootdemo2Application http://localhost:8888/hello/boot
页面原始输出的内容是 “What’s up! Spring Boot!”。
为了测试配置的热部署是否有效,接下来,在不关闭当前项目的情况下,将 HelloController 类中的请求处理方法 hello() 的返回值修改为 “Hello! Spring Boot!” 并保存,查看控制台信息会发现项目能够自动构建和编译,说明项目热部署生效。
再次刷新浏览器,输出了 “Hello! Spring Boot!”,说明项目热部署配置成功。
全局配置文件
全局配置文件能够对一些默认配置值进行修改。Spring Boot 使用一个 application.properties
或者 application.yaml
的文件作为全局配置文件,该文件存放在 src/main/resource
目录或者类路径的 /config
,一般会选择 resource 目录。
Spring Boot 配置文件的命名及其格式:
application.properties
application.yaml
application.yml
application.properties
配置文件
引入相关依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
使用 Spring Initializr 方式构建 Spring Boot 项目时,会在 resource 目录下自动生成一个空的 application.properties
文件,Spring Boot 项目启动时会自动加载 application.properties
文件。
# 修改 tomcat 的版本号
server.port=8080
# 定义数据库的连接信息 JdbcTemplate
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/renda01
spring.datasource.username=root
spring.datasource.password=password
可以在 application.properties
文件中定义 Spring Boot 项目的相关属性,当然,这些相关属性可以是系统属性、环境变量、命令参数等信息,也可以是自定义配置文件名称和位置。
预先准备了两个实体类文件,后续会演示将 application.properties
配置文件中的自定义配置属性注入到 Person 实体类的对应属性中。
1)先在项目的 com.renda 包下创建一个 pojo 包,并在该包下创建两个实体类 Pet 和 Person。
/**
* 宠物类
*
* @author Renda Zhang
* @since 2020-10-29 1:03
*/
public class Pet {
// 品种
private String type;
// 名称
private String name;
// setter and getter, toString ...
}
/**
* 人类
*
* @author Renda Zhang
* @since 2020-10-29 1:04
*/
@Component
/**
* 将配置文件中所有以 person 开头的配置信息注入当前类中
* 前提 1:必须保证配置文件中 person.xx 与当前 Person 类的属性名一致
* 前提 2:必须保证当前 Person 中的属性都具有 set 方法
*/
@ConfigurationProperties(prefix = "person")
public class Person {
// id
private int id;
// 名称
private String name;
// 爱好
private List hobby;
// 家庭成员
private String[] family;
private Map map;
// 宠物
private Pet pet;
// setter and getter, toString ...
}
@ConfigurationProperties(prefix = "person")
注解的作用是将配置文件中以 person 开头的属性值通过 setXX()
方法注入到实体类对应属性中。
@Component
注解的作用是将当前注入属性值的 Person 类对象作为 Bean 组件放到 Spring 容器中,只有这样才能被 @ConfigurationProperties
注解进行赋值。
2)打开项目的 resources 目录下的 application.properties
配置文件,在该配置文件中编写需要对 Person 类设置的配置属性。
# 自定义配置信息注入到 Person 对象中
person.id=100
person.name=张人大
## list
person.hobby=看书,写代码,吃饭
## String[]
person.family=兄弟,父母
## map
person.map.k1=v1
person.map.k2=v2
## pet 对象
person.pet.type=dog
person.pet.name=旺财
3)查看 application.properties
配置文件是否正确,同时查看属性配置效果,打开通过 IDEA 工具创建的项目测试类,在该测试类中引入 Person 实体类 Bean,并进行输出测试。
@RunWith(SpringRunner.class)
@SpringBootTest
class Springbootdemo2ApplicationTests {
@Autowired
private Person person;
@Test
void showPersonInfo() {
System.out.println(person);
}
}
可以看出,测试方法 showPersonInfo()
运行成功,同时正确打印出了 Person 实体类对象。至此,说明 application.properties
配置文件属性配置正确,并通过相关注解自动完成了属性注入。
4)解决浏览器请求出现中文乱码问题。
调整文件编码格式:Settings -> Editor -> File Encodings -> 确保 Global Encoding 和 Project Encoding 为 UTF-8,修改 Default ecoding for properties files 为 UTF-8 并勾选 Transparent native-to-ascii conversion。
application.properties
文件中增加配置:
# 解决中文乱码
server.tomcat.uri-encoding=UTF-8
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
application.yaml
配置文件
YAML 文件格式是 Spring Boot 支持的一种 JSON 文件格式,相较于传统的 Properties 配置文件,YAML 文件以数据为核心,是一种更为直观且容易被电脑识别的数据序列化格式。application.yaml
配置文件的工作原理和 application.properties
是一样的,只不过 yaml 格式配置文件看起来更简洁一些。
- YAML 文件的扩展名可以使用
.yml
或者.yaml
。 application.yml
文件使用key: value
格式配置属性,使用缩进控制层级关系。
SpringBoot 的三种配置文件是可以共存的:application.properties
、application.yaml
、application.yml
。
1)value 值为普通数据类型(例如数字、字符串、布尔等)
当 YAML 配置文件中配置的属性值为普通数据类型时,可以直接配置对应的属性值,同时对于字符串类型的属性值,不需要额外添加引号,示例代码如下:
server:
port: 8080
servlet:
context-path: /hello
2)value 值为数组和单列集合
当 YAML 配置文件中配置的属性值为数组或单列集合类型时,主要有两种书写方式:缩进式写法和行内式写法。
其中,缩进式写法还有两种表示形式,示例代码如下:
person:
hobby:
- play
- read
- sleep
或者使用如下示例形式:
person:
hobby:
play,
read,
sleep
上述代码中,在 YAML 配置文件中通过两种缩进式写法对 person 对象的单列集合(或数组)类型的爱好 hobby 赋值为 play、read 和 sleep。其中一种形式为 “- 属性值”,另一种形式为多个属性值之前加英文逗号分隔;注意,最后一个属性值后不要加逗号。
person:
hobby: [play,read,sleep]
通过上述示例对比发现,YAML 配置文件的行内式写法更加简明、方便。另外,包含属性值的中括号 “[]” 还可以进一步省略,在进行属性赋值时,程序会自动匹配和校对。
3)value 值为 Map 集合和对象
当 YAML 配置文件中配置的属性值为 Map 集合或对象类型时,YAML 配置文件格式同样可以分为两种书写方式 - 缩进式写法和行内式写法。
其中,缩进式写法的示例代码如下:
person:
map:
k1: v1
k2: v2
对应的行内式写法示例代码如下:
person:
map: {
k1: v1,k2: v2}
在YAML配置文件中,配置的属性值为Map集合或对象类型时,缩进式写法的形式按照YAML文件格式编写即可,而行内式写法的属性值要用大括号“{}”包含。
接下来,在 Properties 配置文件演示案例基础上,注释掉 Properties 中跟 Person 相关的注入,然后通过配置 application.yaml 配置文件对 Person 对象进行赋值,具体使用如下。
在项目的 resources 目录下,新建一个 application.yaml 配置文件,在该配置文件中编写为 Person 类设置的配置属性:
person:
id: 1000
name: 张人大
hobby:
- 跑步
- 瑜伽
- 游泳
family:
- 张小明
- 李小红
map:
k1: 这是 k1 对应的 value
k2: 这是 k2 对应的 value
pet:
type: dog
name: 金毛
再次执行测试。
可以看出,测试方法 showPersonInfo()
同样运行成功,并正确打印出了 Person 实体类对象。
需要说明的是,本次使用 application.yaml
配置文件进行测试时需要提前将 application.properties
配置文件中编写的配置注释,这是因为 application.properties
配置文件会覆盖 application.yaml
配置文件。
配置文件属性值的注入
从 spring-boot-starter-parent
的 pom 文件可以知道配置文件的优先级从低到高如下:
<includes>
<include>**/application*.yml</include>
<include>**/application*.yaml</include>
<include>**/application*.properties</include>
</includes>
使用 Spring Boot 全局配置文件设置属性时:
如果配置属性是 Spring Boot 已有属性,例如服务端口 server.port,那么 Spring Boot 内部会自动扫描并读取这些配置文件中的属性值并覆盖默认属性。
如果配置的属性是用户自定义属性,例如刚刚自定义的 Person 实体类属性,还必须在程序中注入这些配置属性方可生效。
Spring Boot 支持多种注入配置文件属性的方式,下面来介绍如何使用注解 @ConfigurationProperties
和 @Value
注入属性。
使用 @ConfigurationProperties
注入属性
Spring Boot 提供的 @ConfigurationProperties
注解用来快速、方便地将配置文件中的自定义属性值批量注入到某个 Bean 对象的多个对应属性中。假设现在有一个配置文件,如果使用 @ConfigurationProperties
注入配置文件的属性,示例代码如下:
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private int id;
private String name;
private List hobby;
private String[] family;
private Map map;
private Pet pet;
// setter and getter, toString ...
}
上述代码使用 @Component
和 @ConfigurationProperties(prefix = “person”)
将配置文件中的每个属性映射到 person 类组件中。
使用 @Value
注入属性
@Value
注解是 Spring 框架提供的,用来读取配置文件中的属性值并逐个注入到 Bean 对象的对应属性中,Spring Boot 框架从 Spring 框架中对 @Value
注解进行了默认继承,所以在 Spring Boot 框架中还可以使用该注解读取和注入配置文件属性值。使用 @Value
注入属性的示例代码如下:
@Component
public class Student {
@Value("${person.id}")
private int number;
// getter setter toString ...
}
上述代码中,使用 @Component
和 @Value
注入 Person 实体类的id属性。其中,@Value
不仅可以将配置文件的属性注入 Person 的 id 属性,还可以直接给 id 属性赋值,这点是@ConfigurationProperties
不支持的。
1)在 com.renda.pojo
包下新创建一个实体类 Student,并使用 @Value
注解注入属性:
@Component
public class Student {
@Value("${pers