主要内容:
1.Spring Boot
基本应用
2.Spring Boot
原理深入及源码剖析
3.Spring Boot
数据访问
4.Spring Boot
视图技术
5.Spring Boot
实战演练
6.Spring Boot
项目部署
1. SpringBoot
基本应用
1.1
约定优于配置
Build Anything with Spring Boot : Spring Boot is the starting point forbuilding all Spring-based applications. Spring Boot is designed to get you up andrunning as quickly as possible, with minimal upfront configuration of Spring.
上面是引自官网的一段话,大概是说: Spring Boot 是所有基于 Spring 开发的项目的起点。Spring Boot 的设计是为了让你尽可能快的跑起来 Spring 应用程序并且尽可能减少你的配置文件。
约定优于配置(
Convention over Configuration
),又称按约定编程,是一种软件设计范式。
本质上是说,系统、类库或框架应该假定合理的默认值,而非要求提供不必要的配置。
比如说模型中有一个名为User
的类,那么数据库中对应的表就会默认命名为
user
。只有在偏离这一个约定的时候,例如想要将该表命名为person
,才需要写有关这个名字的配置。
比如平时架构师搭建项目就是限制软件开发随便写代码,制定出一套规范,让开发人员按统一的要求进行开发编码测试之类的,这样就加强了开发效率与审查代码效率。所以说写代码的时候就需要按要求命名,这样统一规范的代码就有良好的可读性与维护性了
约定优于配置简单来理解,就是遵循约定
1.2 SpringBoot
概念
1.2.1 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
整合包、数据库驱动,引入依赖的数量繁多、容易存在版本冲突。
1.2.2 Spring Boot
解决上述
spring
问题
SpringBoot
对上述
Spring
的缺点进行的改善和优化,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑 业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率,一定程度上缩短 了项目周期。
起步依赖
起步依赖本质上是一个
Maven
项目对象模型
(Project Object Model
,
POM)
,定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。
简单的说,起步依赖就是将具备某种功能的依赖坐标打包到一起,并提供一些默认的功能。
自动配置
springboot
的自动配置,指的是
springboot
,会自动将一些配置类的
bean
注册进
ioc
容器,我们可以需要的地方使用@autowired
或者
@resource
等注解来使用它。
“
自动
”
的表现形式就是我们只需要引我们想用功能的包,相关的配置我们完全不用管,
springboot
会自动注入这些配置bean
,我们直接使用这些
bean
即可springboot: 简单、快速、方便地搭建项目;对主流开发框架的无配置集成;极大提高了开发、部署效率
1.3 Spring Boot
入门案例
案例需求:请求
Controller
中的方法,并将返回值响应到页面
(
1
)依赖管理
<!--
所用的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.3.4.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)
启动类
/**
* SpringBoot的启动类通常放在二级包中,比如:com.lagou.SpringBootDemo1Application
* 因为SpringBoot项目在做包扫描,会扫描启动类所在的包及其子包下的所有内容。
*/
//标识当前类为SpringBoot项目的启动类
@SpringBootApplication
public class SpringBootDemo1Application {
public static void main(String[] args) {
//样板代码
SpringApplication.run(SpringBootDemo1Application.class,args);
}
}
(3)Controller
package com.lagou.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/boot")
public String helloBoot(){
return "Hello Spring Boot";
}
}
1.4 SpringBoot
快速构建
案例需求:请求
Controller
中的方法,并将返回值响应到页面
(
1
)使用
Spring Initializr
方式构建
Spring Boot
项目
本质上说,
Spring Initializr
是一个
Web
应用,它提供了一个基本的项目结构,能够帮助我们快速构
建一个基础的
Spring Boot
项目

Project SDK”
用于设置创建项目使用的
JDK
版本,这里,使用之前初始化设置好的
JDK
版本即可;在 “Choose Initializr Service URL(选择初始化服务地址)
”
下使用默认的初始化服务地址
“
https://start.spring.io
”
进行
Spring Boot
项目创建(注意使用快速方式创建
Spring Boot
项目时,所在主机须在联网状态下)

Spring Boot项目就创建好了。创建好的Spring Boot项目结构如图:
使用Spring Initializr方式构建的Spring Boot项目会默认生成项目启动类、存放前端静态资源和页
面的文件夹、编写项目配置的配置文件以及进行项目单元测试的测试类
(
2
) 创建一个用于
Web
访问的
Controller
com.lagou
包下创建名称为
controller
的包,在该包下创建一个请求处理控制类
HelloController
,
并编写一个请求处理方法
(
注意:将项目启动类
SpringBootDemoApplication
移动到
com.lagou
包下
)
@RestController // 该注解为组合注解,等同于Spring中@Controller+@ResponseBody注解
public class DemoController {
@RequestMapping("/demo")
public String demo(){
return "hello spring Boot";
}
}
(
3
) 运行项目
运行主程序启动类
SpringbootDemoApplication
,项目启动成功后,在控制台上会发现
Spring
Boot
项目默认启动的端口号为
8080
,此时,可以在浏览器上访问
“
http://localhost:8080/hello
”

页面输出的内容是“hello Spring Boot”,至此,构建Spring Boot项目就完成了
1.5
单元测试与热部署
1.5.1
单元测试
开发中,每当完成一个功能接口或业务方法的编写后,通常都会借助单元测试验证该功能是否正
确。
Spring Boot
对项目的单元测试提供了很好的支持,在使用时,需要提前在项目的
pom.xml
文件中添加spring-boot-starter-test
测试依赖启动器,可以通过相关注解实现单元测试
演示:
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>
</dependency>
注意:使用
Spring Initializr
方式搭建的
Spring Boot
项目,会自动加入
spring-boot-starter-test
测试依赖启动器,无需再手动添加
2
.编写单元测试类和测试方法
使用
Spring Initializr
方式搭建的
Spring Boot
项目,会在
src.test.java
测试目录下自动创建与项目主程序启动类对应的单元测试类
package com.lagou;
import com.lagou.controller.HelloController;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
/**
* SpringJUnit4ClassRunner.class:Spring运行环境
* JUnit4.class:JUnit运行环境
* SpringRunner.class:Spring Boot运行环境
*/
@RunWith(SpringRunner.class) //@RunWith:运行器
@SpringBootTest //标记为当前类为SpringBoot测试类,加载项目的ApplicationContext上下文环境
class Springbootdemo2ApplicationTests {
/**
* 需求:调用HelloController的hello方法
*/
@Autowired
private HelloController helloController;
@Test
void contextLoads() {
String result = helloController.hello();
System.out.println(result);
}
}
上述代码中,先使用
@Autowired
注解注入了
DemoController
实例对象,然后在
contextLoads()
方
法中调用了
DemoController
类中对应的请求控制方法
contextLoads()
,并输出打印结果

1.5.2
热部署
在开发过程中,通常会对一段业务代码不断地修改测试,在修改之后往往需要重启服务,有些服务
需要加载很久才能启动成功,这种不必要的重复操作极大的降低了程序开发效率。为此,
Spring Boot
框架专门提供了进行热部署的依赖启动器,用于进行项目热部署,而无需手动重启项目 。
热部署:在修改完代码之后,不需要重新启动容器,就可以实现更新。
使用步骤:
1
)添加
SpringBoot
的热部署依赖启动器
2
)开启
Idea
的自动编译
3
)开启
Idea
的在项目运行中自动编译的功能
演示:
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
】按钮保存设置
在项目任意页面中使用组合快捷键
“Ctrl+Shift+Alt+/”
打开
Maintenance
选项框,选中并打开
Registry
页面,具体如图
1-17
所示

列表中找到
“compiler.automake.allow.when.app.running”
,将该选项后的
Value
值勾选,用于指
定
IDEA
工具在程序运行过程中自动编译,最后单击【
Close
】按钮完成设置
3
.热部署效果测试
启动
chapter01
http://localhost:8080/hello

页面原始输出的内容是
“hello Spring Boot”
。
为了测试配置的热部署是否有效,接下来,在不关闭当前项目的情况下,将
DemoController
类中的请求处理方法hello()
的返回值修改为
“
你好,
Spring Boot”
并保存,查看控制台信息会发现项目能够自动构建和编译,说明项目热部署生效

可以看出,浏览器输出了“你好,Spring Boot”,说明项目热部署配置成功
1.6
全局配置文件
全局配置文件能够对一些默认配置值进行修改。
Spring Boot
使用一个
application.properties
或者
application.yaml
的文件作为全局配置文件,该文件存放在
src/main/resource
目录或者类路径
的
/config
,一般会选择
resource
目录。接下来,将针对这两种全局配置文件进行讲解 :
Spring Boot
配置文件的命名及其格式:
application.properties
application.yaml
application.yml
1.6.1 application.properties
配置文件
使用
Spring Initializr
方式构建
Spring Boot
项目时,会在
resource
目录下自动生成一个空的
application.properties
文件,
Spring Boot
项目启动时会自动加载
application.properties
文件。
我们可以在
application.properties
文件中定义
Spring Boot
项目的相关属性,当然,这些相关属性可以是系统属性、环境变量、命令参数等信息,也可以是自定义配置文件名称和位置
#修改tomcat的版本号
server.port=8888
#定义数据库的连接信息 JdbcTemplate
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/lagou
spring.datasource.username=root
spring.datasource.password=wu7787879
接下来,通过一个案例对
Spring Boot
项目中
application.properties
配置文件的具体使用进行讲解
演示:
预先准备了两个实体类文件,后续会演示将
application.properties
配置文件中的自定义配置属性注入到Person实体类的对应属性中
(1)先在项目的
com.lagou
包下创建一个
pojo
包,并在该包下创建两个实体类
Pet
和
Person
public class Pet {
private String type;
private String name;
}
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private int id; //id
private String name; //名称
private List hobby; //爱好
private String[] family; //家庭成员
private Map map;
private Pet pet; //宠物
}
@ConfigurationProperties(prefix = "person")
注解的作用是将配置文件中以
person
开头的属性值通过setXX()方法注入到实体类对应属性中
@Component
注解的作用是将当前注入属性值的
Person
类对象作为
Bean
组件放到
Spring
容器中,只有这样才能被@ConfigurationProperties
注解进行赋值
(2)打开项目的
resources
目录下的
application.properties
配置文件,在该配置文件中编写需要对
Person
类设置的配置属性
#自定义配置信息
person.id=1
person.name=王二麻子
person.hobby=read,write
person.family=father,mather
person.map.key1=value1
person.map.key2=value2
person.pet.type=dog
person.pet.name=哈士奇
(3)查看
application.properties
配置文件是否正确,同时查看属性配置效果,打开通过
IDEA
工具创建的项目测试类,在该测试类中引入Person
实体类
Bean
,并进行输出测试
@RunWith(SpringRunner.class) // 测试启动器,并加载Spring Boot测试注解
@SpringBootTest // 标记为Spring Boot单元测试类,并加载项目的ApplicationContext上下文环
境
class SpringbootDemoApplicationTests {
// 配置测试
@Autowired
private Person person;
@Test
void configurationTest() {
System.out.println(person);
}
}
打印结果:

可以看出,测试方法
configurationTest()
运行成功,同时正确打印出了
Person
实体类对象。至此,说明application.properties配置文件属性配置正确,并通过相关注解自动完成了属性注入
(4)中文乱码问题解决
调整文件编码格式:

设置Tomcat及Http编码
#解决中文乱码
server.tomcat.uri-encoding=UTF-8
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
1.6.2 application.yaml
配置文件
YAML
文件格式是
Spring Boot
支持的一种
JSON
文件格式,相较于传统的
Properties
配置文件,
YAML
文件以数据为核心,是一种更为直观且容易被电脑识别的数据序列化格式。application.yaml
配置文件的工作原理和application.properties
是一样的,只不过
yaml
格式配置文件看起来更简洁一些。
YAML
文件的扩展名可以使用
.yml
或者
.yaml
。
application.yml
文件使用
“key:
(空格)
value”
格式配置属性,使用缩进控制
层级关系
。
SpringBoot
的三种配置文件是可以共存的:

这里,针对不同数据类型的属性值,介绍一下
YAML
(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
配置文件演示案例基础上,通过配置
application.yaml
配置文件对
Person
对象进行赋值,具体使用如下
(1)在项目的
resources
目录下,新建一个
application.yaml
配置文件,在该配置文件中编写为
Person类设置的配置属性
#对实体类对象Person进行属性配置
person:
id: 1
name: 王二麻子
family:
- 妻
- 妾
hobby:
- play
- read
- sleep
map:
k1: value1
k2: value2
pet:
type: 狗
name: 哈士奇
(
2
)再次执行测试
Person{id=1, name='
王二麻子
', hobby=[play, read, sleep], family=[
妻
,
妾
], map={k1=value1,
k2=value2}, pet=Pet{type='
狗
', name='
哈士奇
'}}
可以看出,测试方法
configurationTest()
同样运行成功,并正确打印出了
Person
实体类对象。
需要
说明
的是,本次使用
application.yaml
配置文件进行测试时需要提前将
application.properties
配置文件中编写的配置注释,这是因为application.properties
配置文件会覆盖
application.yaml
配置文件
1.7
配置文件属性值的注入
配置文件的优先级如下: 从低到高
<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
注入属性
1.7.1
使用
@ConfigurationProperties
注入属性
Spring Boot
提供的
@ConfigurationProperties
注解用来快速、方便地将配置文件中的自定义属性值批量注入到某个Bean
对象的多个对应属性中。假设现在有一个配置文件,如果使用
@ConfigurationProperties
注入配置文件的属性,示例代码如下:
@Component
//将配置文件中所有以person开头的配置信息注入当前类中
//前提1:必须保证配置文件中person.xx与当前Person类的属性名一致
//前提2:必须保证当前Person中的属性都具有set方法
@ConfigurationProperties(prefix = "person")
public class Person {
private int id; //id
private String name; //名称
private List hobby; //爱好
private String[] family; //家庭成员
private Map map;
private Pet pet; //宠物
}
上述代码使用
@Component
和
@ConfigurationProperties(prefix = “person”)
将配置文件中的每个属性映射到person
类组件中。
1.7.2
使用
@Value
注入属性
@Value
注解是
Spring
框架提供的,用来读取配置文件中的属性值并逐个注入到
Bean
对象的对应属性中,Spring Boot
框架从
Spring
框架中对
@Value
注解进行了默认继承,所以在
Spring Boot
框架中还可以使用该注解读取和注入配置文件属性值。使用@Value
注入属性的示例代码如下
@Component
public class Person {
@Value("${person.id}")
private int id;
}
上述代码中,使用
@Component
和
@Value
注入
Person
实体类的
id
属性。其中,
@Value
不仅可以
将配置文件的属性注入
Person
的
id
属性,还可以直接给
id
属性赋值,这点是
@ConfigurationProperties
不支持的
演示@Value
注解读取并注入配置文件属性的使用
:
(1)在
com.lagou.pojo
包下新创建一个实体类
Student
,并使用
@Value
注解注入属性
@Component
public class Student {
@Value("${person.id}")
private int id;
@Value("${person.name}")
private String name; //名称
//省略toString
}
Student
类使用
@Value
注解将配置文件的属性值读取和注入。
从上述示例代码可以看出,使用
@Value
注解方式需要对每一个属性注入设置,同时又免去了属性的 setXX()方法
(2)再次打开测试类进行测试
@Autowired
private Student student;
@Test
public void studentTest() {
System.out.println(student);
}
打印结果:

可以看出,测试方法
studentTest()
运行成功,同时正确打印出了
Student
实体类对象。需要说明的
是,本示例中只是使用
@Value
注解对实例中
Student
对象的普通类型属性进行了赋值演示,而
@Value
注解对于包含Map
集合、对象以及
YAML
文件格式的行内式写法的配置文件的属性注入都不支持,如果赋值会出现错误
1.8
自定义配置
spring Boot
免除了项目中大部分的手动配置,对于一些特定情况,我们可以通过修改全局配置文
件以适应具体生产环境,可以说,几乎所有的配置都可以写在
application.yml
文件中,
Spring Boot
会自动加载全局配置文件从而免除我们手动加载的烦恼。但是,如果我们自定义配置文件,Spring Boot
是无法识别这些配置文件的,此时就需要我们手动加载。接下来,将针对Spring Boot
的自定义配置文件及其加载方式进行讲解
1.8.1
使用
@PropertySource
加载配置文件
对于这种加载自定义配置文件的需求,可以使用
@PropertySource
注解来实现。
@PropertySource
注解用于指定自定义配置文件的具体位置和名称
当然,如果需要将自定义配置文件中的属性值注入到对应类的属性中,可以使用
@ConfigurationProperties
或者
@Value
注解进行属性值注入
演示:
(1)打开
Spring Boot
项目的
resources
目录,在项目的类路径下新建一个
test.properties
自定义配
置文件,在该配置文件中编写需要设置的配置属性
#对实体类对象MyProperties进行属性配置
test.id=110
test.name=test
(2)在
com.lagou.pojo
包下新创建一个配置类
MyProperties
,提供
test.properties
自定义配置文件
中对应的属性,并根据
@PropertySource
注解的使用进行相关配置
@Component // 自定义配置类
@PropertySource("classpath:test.properties") // 指定自定义配置文件位置和名称
@ConfigurationProperties(prefix = "test") // 指定配置文件注入属性前缀
public class MyProperties {
private int id;
private String name;
// 省略属性getXX()和setXX()方法
// 省略toString()方法
}
主要是一个自定义配置类,通过相关注解引入了自定义的配置文件,并完成了自定义属性值的注
入。针对示例中的几个注解,具体说明如下
@PropertySource("classpath:test.properties")
注解指定了自定义配置文件的位置和名称,此示例
表示自定义配置文件为
classpath
类路径下的
test.properties
文件;
@ConfigurationProperties(prefix = "test")
注解将上述自定义配置文件
test.properties
中以
test
开
头的属性值注入到该配置类属性中。
(3)进行测试
@Autowired
private MyProperties myProperties;
@Test
public void myPropertiesTest() {
System.out.println(myProperties);
}
打印结果:

1.8.2
使用
@Configuration
编写自定义配置类
在
Spring Boot
框架中,推荐使用配置类的方式向容器中添加和配置组件
在
Spring Boot
框架中,通常使用
@Configuration
注解定义一个配置类,
Spring Boot
会自动扫描和识别配置类,从而替换传统Spring
框架中的
XML
配置文件。
当定义一个配置类后,还需要在类中的方法上使用
@Bean
注解进行组件配置,将方法的返回对象注入到Spring容器中,并且组件名称默认使用的是方法名,当然也可以使用
@Bean
注解的
name
或
value
属性自定义组件的名称
演示:
(1)在项目下新建一个
com.lagou.config
包,并在该包下新创建一个类
MyService
,该类中不需要编写任何代码
public class MyService {
}
创建了一个空的
MyService
类,而该类目前没有添加任何配置和注解,因此还无法正常被
Spring Boot
扫描和识别
(2) 在项目的
com.lagou.config
包下,新建一个类
MyConfig
,并使用
@Configuration
注解将该类声明一个配置类,内容如下:
@Configuration // 定义该类是一个配置类````
public class MyConfig {
@Bean // 将返回值对象作为组件添加到Spring容器中,该组件id默认为方法名
public MyService myService(){
return new MyService();
}
}
MyConfig
是
@Configuration
注解声明的配置类(类似于声明了一个
XML
配置文件),该配置类会
被
Spring Boot
自动扫描识别;使用
@Bean
注解的
myService()
方法,其返回值对象会作为组件添加到了Spring容器中(类似于
XML
配置文件中的标签配置),并且该组件的
id
默认是方法名
myService
(3)测试类
@Autowired
private ApplicationContext applicationContext;
@Test
public void iocTest() {
System.out.println(applicationContext.containsBean("myService"));
}
上述代码中,先通过
@Autowired
注解引入了
Spring
容器实例
ApplicationContext
,然后在测试方法
iocTest()
中测试查看该容器中是否包括
id
为
myService
的组件。
执行测试方法
iocTest()
,查看控制台输出效果,结果如下:

从测试结果可以看出,测试方法
iocTest()
运行成功,显示运行结果为
true
,表示
Spirng
的
IOC
容器中也已经包含了id
为
myService
的实例对象组件,说明使用自定义配置类的形式完成了向
Spring
容器进行组件的添加和配置
2. SpringBoot
原理深入及源码剖析
传统的
Spring
框架实现一个
Web
服务,需要导入各种依赖
JAR
包,然后编写对应的
XML
配置文件
等,相较而言,
Spring Boot
显得更加方便、快捷和高效。那么,
Spring Boot
究竟如何做到这些的呢?
接下来分别针对
Spring Boot
框架的依赖管理、自动配置通过源码进行深入分析
2.1
依赖管理
问题:(1)为什么导入
dependency
时不需要指定版本?
在
Spring Boot
入门程序中,项目
pom.xml
文件有两个核心依赖,分别是
spring-boot-starter
parent
和
spring-boot-starter-web
,关于这两个依赖的相关介绍具体如下:
1
.
spring-boot-starter-parent
依赖
在
chapter01
项目中的
pom.xml
文件中找到
spring-boot-starter-parent
依赖,示例代码如下
:
<!-- Spring Boot父项目依赖管理 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent<11./artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
上述代码中,将
spring-boot-starter-parent
依赖作为
Spring Boot
项目的统一父项目依赖管理,并将项目版本号统一为2.2.2.RELEASE
,该版本号根据实际开发需求是可以修改的
使用
“Ctrl+
鼠标左键
”
进入并查看
spring-boot-starter-parent
底层源文件,发现
spring-boot
starter-parent
的底层有一个父依赖
spring-boot-dependencies
,核心代码具体如下
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
继续查看
spring-boot-dependencies
底层源文件,核心代码具体如下:
<properties>
<activemq.version>5.15.11</activemq.version>
...
<solr.version>8.2.0</solr.version>
<mysql.version>8.0.18</mysql.version>
<kafka.version>2.3.1</kafka.version>
<properties>
<activemq.version>5.15.11</activemq.version>
...
<solr.version>8.2.0</solr.version>
<mysql.version>8.0.18</mysql.version>
<kafka.version>2.3.1</kafka.version>
从
spring-boot-dependencies
底层源文件可以看出,该文件通过标签对一些常用技术框架的依赖文件进行了统一版本号管理,例如activemq
、
spring
、
tomcat
等,都有与
Spring Boot 2.2.2
版本相匹配的版本,这也是pom.xml
引入依赖文件不需要标注依赖文件版本号的原因。
需要说明的是,如果
pom.xml
引入的依赖文件不是
spring-boot-starter-parent
管理的,那么在
pom.xml
引入依赖文件时,需要使用标签指定依赖文件的版本号。
(2)问题
2
:
spring-boot-starter-parent
父依赖启动器的主要作用是进行版本统一管理,那么项目运行依赖的JAR
包是从何而来的?
2. spring-boot-starter-web
依赖
查看
spring-boot-starter-web
依赖文件源码,核心代码具体如下
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.2.2.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.2.2.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.2.2.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.2.2.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>tomcat-embed-el</artifactId>
<groupId>org.apache.tomcat.embed</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.2.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.2.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
从上述代码可以发现,
spring-boot-starter-web
依赖启动器的主要作用是提供
Web
开发场景所需的底层所有依赖
正是如此,在
pom.xml
中引入
spring-boot-starter-web
依赖启动器时,就可以实现
Web
场景开发,而不需要额外导入Tomcat
服务器以及其他
Web
依赖文件等。当然,这些引入的依赖文件的版本号还是由 spring-boot-starter-parent父依赖进行的统一管理。
有哪些
starter
:
https://github.com/spring-projects/spring-boot/tree/v2.1.0.RELEASE/spring-boot-project/spring-bo
ot-starters
https://mvnrepository.com/search?q=starter
Spring Boot
除了提供有上述介绍的
Web
依赖启动器外,还提供了其他许多开发场景的相关依赖,
我们可以打开
Spring Boot
官方文档,搜索
“Starters”
关键字查询场景依赖启动器

列出了
Spring Boot
官方提供的部分场景依赖启动器,这些依赖启动器适用于不同的场景开发,使用时只需要在pox.xml
文件中导入对应的依赖启动器即可。
需要说明的是,
Spring Boot
官方并不是针对所有场景开发的技术框架都提供了场景启动器,例如数据库操作框架MyBatis
、阿里巴巴的
Druid
数据源等,
Spring Boot
官方就没有提供对应的依赖启动器。为了充分利用Spring Boot
框架的优势,在
Spring Boot
官方没有整合这些技术框架的情况下,
MyBatis
、Druid等技术框架所在的开发团队主动与
Spring Boot
框架进行了整合,实现了各自的依赖启动器,例如mybatis-spring-boot-starter、
druid-spring-boot-starter
等。我们在
pom.xml
文件中引入这些第三方的依赖启动器时,切记要配置对应的版本号
2.2
自动配置
概念:能够在我们添加
jar
包依赖的时候,自动为我们配置一些组件的相关配置,我们无需配置或者只需要少量配置就能运行编写的项目
问题:
Spring Boot
到底是如何进行自动配置的,都把哪些组件进行了自动配置?
Spring Boot
应用的启动入口是
@SpringBootApplication
注解标注类中的
main()
方法,
@SpringBootApplication
:
SpringBoot
应用标注在某个类上说明这个类是
SpringBoot
的主配置
类,
SpringBoot
就应该运行这个类的
main()
方法启动
SpringBoot
应用。
下面,查看
@SpringBootApplication
内部源码进行分析 ,核心代码具体如下
@SpringBootApplication
public class SpringbootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
}
进入到
@SpringBootApplication
内,观察其做了哪些工作:
@Target({ElementType.TYPE}) //注解的适用范围,Type表示注解可以描述在类、接口、注解或枚举中
@Retention(RetentionPolicy.RUNTIME) //表示注解的生命周期,Runtime运行时
@Documented //表示注解可以记录在javadoc中
@Inherited //表示可以被子类继承该注解
@SpringBootConfiguration // 标明该类为配置类
@EnableAutoConfiguration // 启动自动配置功能
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes =
TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes =
AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
// 根据class来排除特定的类,使其不能加入spring容器,传入参数value类型是class类型。
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
// 根据classname 来排除特定的类,使其不能加入spring容器,传入参数value类型是class的全
类名字符串数组。
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
// 指定扫描包,参数是包名的字符串数组。
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
// 扫描特定的包,参数类似是Class类型数组。
@AliasFor(annotation = ComponentScan.class, attribute =
"basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
从上述源码可以看出,
@SpringBootApplication
注解是一个组合注解,前面
4
个是注解的元数据
信息, 我们主要看后面
3
个注解:
@SpringBootConfiguration
、
@EnableAutoConfiguration
、
@ComponentScan
三个核心注解,关于这三个核心注解的相关说明具体如下:
1
.
@SpringBootConfiguration
注解
@SpringBootConfiguration
:
SpringBoot
的配置类,标注在某个类上,表示这是一个
SpringBoot
的配置类。
查看
@SpringBootConfiguration
注解源码,核心代码具体如下。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration // 配置类的作用等同于配置文件,配置类也是容器中的一个对象
public @interface SpringBootConfiguration {
}
从上述源码可以看出,
@SpringBootConfiguration
注解内部有一个核心注解
@Configuration
,该
注解是
Spring
框架提供的,表示当前类为一个配置类(
XML
配置文件的注解表现形式),并可以被组件扫描器扫描。由此可见,@SpringBootConfiguration
注解的作用与
@Configuration
注解相同,都是
标识一个可以被组件扫描器扫描的配置类,只不过
@SpringBootConfiguration
是被
Spring Boot
进行
了重新封装命名而已
2
.
@EnableAutoConfiguration
注解
@EnableAutoConfiguration
:开启自动配置功能,以前由我们需要配置的东西,现在由
SpringBoot 帮我们自动配置,这个注解就是 Springboot
能实现自动配置的关键。
同样,查看该注解内部查看源码信息,核心代码具体如下
// 自动配置包
@AutoConfigurationPackage
// Spring的底层注解@Import,给容器中导入一个组件;
// 导入的组件是AutoConfigurationPackages.Registrar.class
@Import(AutoConfigurationImportSelector.class)
// 告诉SpringBoot开启自动配置功能,这样自动配置才能生效。
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
// 返回不会被导入到 Spring 容器中的类
Class<?>[] exclude() default {};
// 返回不会被导入到 Spring 容器中的类名
String[] excludeName() default {};
}
可以发现它是一个组合注解,
Spring
中有很多以
Enable
开头的注解,其作用就是借助
@Import
来收集并注册特定场景相关的
Bean
,并加载到
IOC
容器。
@EnableAutoConfiguration
就是借助
@Import
来收集所有符合自动配置条件的
bean
定义,并加载到
IoC
容器。
下面,对这两个核心注解分别讲解
:
(
1
)
@AutoConfigurationPackage
注解
查看
@AutoConfigurationPackage
注解内部源码信息,核心代码具体如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class}) // 导入Registrar中注册的组件
public @interface AutoConfigurationPackage {
}
从上述源码可以看出,
@AutoConfigurationPackage
注解的功能是由
@Import
注解实现的,它是
spring
框架的底层注解,它的作用就是给容器中导入某个组件类,例如
@Import(AutoConfigurationPackages.Registrar.class)
,它就是将
Registrar
这个组件类导入到容器
中,可查看
Registrar
类中
registerBeanDefinitions
方法,这个方法就是导入组件类的具体实现
:

从上述源码可以看出,在
Registrar
类中有一个
registerBeanDefinitions()
方法,使用
Debug
模式启
动项目,可以看到选中的部分就是
com.lagou
。也就是说,
@AutoConfigurationPackage
注解的主要作用就是将主程序类所在包及所有子包下的组件到扫描到spring
容器中。
因此 在定义项目包结构时,要求定义的包结构非常规范,项目主程序启动类要定义在最外层的根目录位置,然后在根目录位置内部建立子包和类进行业务开发,这样才能够保证定义的类能够被组件扫描器扫描
(2)
@Import({AutoConfigurationImportSelector.class})
注解
将
AutoConfigurationImportSelector
这个类导入到
Spring
容器中,
AutoConfigurationImportSelector
可以帮助
Springboot
应用将所有符合条件的
@Configuration
配置都加载到当前
SpringBoot
创建并使用的
IOC
容器
(
ApplicationContext
)
中。
继续研究
AutoConfigurationImportSelector
这个类,通过源码分析这个类中是通过
selectImports
这个方法告诉springboot
都需要导入那些组件:

深入研究loadMetadata方法
AutoConfigurationImportSelector类 getAutoConfigurationEntry方法
protected AutoConfigurationEntry
getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
//判断EnabledAutoConfiguration注解有没有开启,默认开启
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
//获得注解的属性信息
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获取默认支持的自动配置类列表
List<String> configurations =
getCandidateConfigurations(annotationMetadata, attributes);
//去重
configurations = removeDuplicates(configurations);
//去除一些多余的配置类,根据EnabledAutoConfiguratio的exclusions属性进行排除
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//根据pom文件中加入的依赖文件筛选中最终符合当前项目运行环境对应的自动配置类
configurations = filter(configurations, autoConfigurationMetadata);
//触发自动配置导入监听事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
深入
getCandidateConfigurations
方法
这个方法中有一个重要方法
loadFactoryNames
,这个方法是让
SpringFactoryLoader
去加载一些组件的名字。

继续点开loadFactory方法
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable
ClassLoader classLoader) {
//获取出入的键
String factoryClassName = factoryClass.getName();
return
(List)loadSpringFactories(classLoader).getOrDefault(factoryClassName,
Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable
ClassLoader classLoader) {
MultiValueMap<String, String> result =
(MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
//如果类加载器不为null,则加载类路径下spring.factories文件,将其中设置的
配置类的全路径信息封装 为Enumeration类对象
Enumeration<URL> urls = classLoader != null ?
classLoader.getResources("META-INF/spring.factories") :
ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
//循环Enumeration类对象,根据相应的节点信息生成Properties对象,通过传入的
键获取值,在将值切割为一个个小的字符串转化为Array,方法result集合中
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties =
PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryClassName =
((String)entry.getKey()).trim();
String[] var9 =
StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName = var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
会去读取一个
spring.factories
的文件,读取不到会表这个错误,我们继续根据会看到,最终路径的长这样,而这个是spring
提供的一个工具类
public final class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "METAINF/spring.factories";
}
它其实是去加载一个外部的文件,而这文件是在

@EnableAutoConfiguration
就是从
classpath
中搜寻
META-INF/spring.factories
配置文件,并将其中
org.springframework.boot.autoconfigure.EnableutoConfiguration
对应的配置项通过反射(
Java
Refletion
)实例化为对应的标注了
@Configuration
的
JavaConfig
形式的配置类,并加载到
IOC
容器中
以刚刚的项目为例,在项目中加入了
Web
环境依赖启动器,对应的
WebMvcAutoConfiguration
自动配置类就会生效,打开该自动配置类会发现,在该配置类中通过全注解配置类的方式对Spring MVC
运行所需环境进行了默认配置,包括默认前缀、默认后缀、视图解析器、MVC
校验器等。而这些自动配置类的本质是传统Spring MVC
框架中对应的
XML
配置文件,只不过在
Spring Boot
中以自动配置类的形式进行了预先配置。因此,在Spring Boot
项目中加入相关依赖启动器后,基本上不需要任何配置就可以运行程序,当然,我们也可以对这些自动配置类中默认的配置进行更改
总结
因此
springboot
底层实现自动配置的步骤是:
1. springboot
应用启动;
2. @SpringBootApplication
起作用;
3. @EnableAutoConfiguration
;
4. @AutoConfigurationPackage
:这个组合注解主要是
@Import(AutoConfigurationPackages.Registrar.class)
,它通过将
Registrar
类导入到容器中,而
Registrar
类作用是扫描主配置类同级目录以及子包,并将相应的组件导入到
springboot
创建管理的
容器中;
5. @Import(AutoConfigurationImportSelector.class)
:它通过将
AutoConfigurationImportSelector
类导入到容器中,
AutoConfigurationImportSelector
类作用是通过
selectImports
方法执行的过程
中,会使用内部工具类
SpringFactoriesLoader
,查找
classpath
上所有
jar
包中的
META
INF/spring.factories
进行加载,实现将配置类信息交给
SpringFactory
加载器进行一系列的容器创
建过程
3. @ComponentScan
注解
@ComponentScan
注解具体扫描的包的根路径由
Spring Boot
项目主程序启动类所在包位置决定,
在扫描过程中由前面介绍的
@AutoConfigurationPackage
注解进行解析,从而得到
Spring Boot
项目主程序启动类所在包的具体位置
总结:
@SpringBootApplication
的注解的功能就分析差不多了, 简单来说就是
3
个注解的组合注解:
|- @SpringBootConfiguration
|- @Configuration //通过javaConfig的方式来添加组件到IOC容器中
|- @EnableAutoConfiguration
|- @AutoConfigurationPackage //自动配置包,与@ComponentScan扫描到的添加到IOC
|- @Import(AutoConfigurationImportSelector.class) //到METAINF/spring.factories中定义的bean添加到IOC容器中
|- @ComponentScan //包扫描
3. SpringBoot
数据访问
3.1 Spring Boot
整合
MyBatis
MyBatis
是一款优秀的持久层框架,
Spring Boot
官方虽然没有对
MyBatis
进行整合,但是
MyBatis
团队自行适配了对应的启动器,进一步简化了使用
MyBatis
进行数据的操作
因为
Spring Boot
框架开发的便利性,所以实现
Spring Boot
与数据访问层框架(例如
MyBatis
)的
整合非常简单,主要是引入对应的依赖启动器,并进行数据库相关参数设置即可
基础环境搭建:
(
1
)数据准备
在
MySQL
中,先创建了一个数据库
springbootdata
,然后创建了两个表
t_article
和
t_comment
并
向表中插入数据。其中评论表
t_comment
的
a_id
与文章表
t_article
的主键
id
相关联
# 创建数据库
CREATE DATABASE springbootdata;
# 选择使用数据库
USE springbootdata;
# 创建表t_article并插入相关数据
DROP TABLE IF EXISTS t_article;
CREATE TABLE t_article (
id int(20) NOT NULL AUTO_INCREMENT COMMENT '文章id',
title varchar(200) DEFAULT NULL COMMENT '文章标题',
content longtext COMMENT '文章内容',
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO t_article VALUES ('1', 'Spring Boot基础入门', '从入门到精通讲解...');
INSERT INTO t_article VALUES ('2', 'Spring Cloud基础入门', '从入门到精通讲
解...');
# 创建表t_comment并插入相关数据
DROP TABLE IF EXISTS t_comment;
CREATE TABLE t_comment (
id int(20) NOT NULL AUTO_INCREMENT COMMENT '评论id',
content longtext COMMENT '评论内容',
author varchar(200) DEFAULT NULL COMMENT '评论作者',
a_id int(20) DEFAULT NULL COMMENT '关联的文章id',
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO t_comment VALUES ('1', '很全、很详细', 'lucy', '1');
INSERT INTO t_comment VALUES ('2', '赞一个', 'tom', '1');
INSERT INTO t_comment VALUES ('3', '很详细', 'eric', '1');
INSERT INTO t_comment VALUES ('4', '很好,非常详细', '张三', '1');
INSERT INTO t_comment VALUES ('5', '很不错', '李四', '2');
(
2
)创建项目,引入相应的启动器

(
3
)编写与数据库表
t_comment
和
t_article
对应的实体类
Comment
和
Article
public class Comment {
private Integer id;
private String content;
private String author;
private Integer aId;
}
public class Article {
private Integer id;
private String title;
private String content;
}
(
4
)编写配置文件
(1)在application.properties
配置文件中进行数据库连接配置
# MySQL数据库连接配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/springbootdata?
serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: wu7787879
注解方式整合
Mybatis
需求:实现通过
ID
查询
Comment
信息
(
1
)创建一个对
t_comment
表数据操作的接口
CommentMapper
public interface CommentMapper {
@Select("SELECT * FROM t_comment WHERE id =#{id}")
public Comment findById(Integer id);
}
(
2
)在
Spring Boot
项目启动类上添加
@MapperScan("xxx")
注解
@SpringBootApplication
@MapperScan("com.lagou.mapper")
public class Springboot02MybatisApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot02MybatisApplication.class, args);
}
}
(
3
)编写测试方法
@RunWith(SpringRunner.class)
@SpringBootTest
class SpringbootPersistenceApplicationTests {
@Autowired
private CommentMapper commentMapper;
@Test
void contextLoads() {
Comment comment = commentMapper.findById(1);
System.out.println(comment);
}
}
打印结果:

控制台中查询的
Comment
的
aId
属性值为
null
,没有映射成功。这是因为编写的实体类
Comment
中使用了驼峰命名方式将
t_comment
表中的
a_id
字段设计成了
aId
属性,所以无法正确映射查询结果。
为了解决上述由于驼峰命名方式造成的表字段值无法正确映射到类属性的情况,可以在
Spring Boot
全局 配置文件application.properties
中添加开启驼峰命名匹配映射配置,示例代码如下
#开启驼峰命名匹配映射
mybatis:
configuration:
map-underscore-to-camel-case: true
打印结果:

配置文件的方式整合
MyBatis
第一、二步骤使用
Free Mybatis plugin
插件生成

(
1
)创建一个用于对数据库表
t_article
数据操作的接口
ArticleMapper
@Mapper
public interface ArticleMapper {
public Article selectArticle(Integer id);
}
(
2
)创建
XML
映射文件
resources
目录下创建一个统一管理映射文件的包
mapper
,并在该包下编写与
ArticleMapper
接口方
应的映射文件
ArticleMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lagou.mapper.ArticleMapper">
<select id="selectArticle" resultType="Article">
select * from Article
</select>
</mapper>
(
3
)配置
XML
映射文件路径
在项目中编写的
XML
映射文件,
Spring Boot
并无从知晓,所以无法扫描到该自定义编写的
XML
配置文 件,还必须在全局配置文件application.properties
中添加
MyBatis
映射文件路径的配置,同时需要添加实体类别名映射路径,示例代码如下
mybatis:
#配置MyBatis的xml配置文件路径
mapper-locations: classpath:mapper/*.xml
#配置XML映射文件中指定的实体类别名路径
type-aliases-package: com.lagou.base.pojo
(
4
)编写单元测试进行接口方法测试
@Autowired
private ArticleMapper articleMapper;
@Test
void contextLoads2() {
Article article = articleMapper.selectByPrimaryKey(1);
System.out.println(article);
}
打印结果:

3.2 Spring Boot
整合
Redis
(
1
)添加
Redis
依赖包
在项目的
pom.xml
中添加如下:
<!-- redis依赖包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
(
2
)配置
Redis
数据库连接
在
application.properties
中配置
redis
数据库连接信息,如下:
#redis配置
#Redis服务器地址
spring.redis.host=127.0.0.1
#Redis服务器连接端口
spring.redis.port=6379
#Redis数据库索引(默认为0)
spring.redis.database=0
#连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=50
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=3000
#连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=20
#连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=2
#连接超时时间(毫秒)
spring.redis.timeout=5000
(
3
)编写
Redis
操作工具类
将
RedisTemplate
实例包装成一个工具类,便于对
redis
进行数据操作。
package com.lagou.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class RedisUtils {
@Autowired
private RedisTemplate redisTemplate;
/**
* 读取缓存
*
* @param key
* @return
*/
public Object get(final String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* 写入缓存
*/
public boolean set( String key, Object value) {
boolean result = false;
try {
redisTemplate.opsForValue().set(key, value,1, TimeUnit.DAYS);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 更新缓存
*/
public boolean getAndSet(final String key, String value) {
boolean result = false;
try {
redisTemplate.opsForValue().getAndSet(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 删除缓存
*/
public boolean delete(final String key) {
boolean result = false;
try {
redisTemplate.delete(key);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
(
4
)测试
写一个测试用例类来完成对
redis
的整合
@RunWith(SpringRunner.class)
@SpringBootTest
class Springboot02MybatisApplicationTests {
@Autowired
private RedisUtils redisUtils;
@Autowired
private CommentMapper commentMapper;
@Test
public void setRedisData() {
redisUtils.set("article_1",articleMapper.selectByPrimaryKey(1));
System.out.println("success");
}
@Test
public void getRedisData() {
Article article = (Article) redisUtils.get("article_1");
System.out.println(article);
}
4. SpringBoot
视图技术
4.1
支持的视图技术
前端模板引擎技术的出现,使前端开发人员无需关注后端业务的具体实现,只关注自己页面的呈现效果即可,并且解决了前端代码错综复杂的问题、实现了前后端分离开发。Spring Boot
框架对很多常用的模板引擎技术(如:FreeMarker
、
Thymeleaf
、
Mustache
等)提供了整合支持
Spring Boot
不太支持常用的
JSP
模板,并且没有提供对应的整合配置,这是因为使用嵌入式
Servlet
容器的Spring Boot
应用程序对于
JSP
模板存在一些限制 :
在
Jetty
和
Tomcat
容器中,
Spring Boot
应用被打包成
war
文件可以支持
JSP
。但
Spring Boot
默认使
用嵌入式
Servlet
容器以
JAR
包方式进行项目打包部署,这种
JAR
包方式不支持
JSP
。
如果使用
Undertow
嵌入式容器部署
Spring Boot
项目,也不支持
JSP
模板。(
Undertow
是红帽公
司开发的一款基于
NIO
的高性能
Web
嵌入式服务器)
Spring Boot
默认提供了一个处理请求路径
“/error”
的统一错误处理器,返回具体的异常信息。使用
JSP
模板时,无法对默认的错误处理器进行覆盖,只能根据
Spring Boot
要求在指定位置定制错误页
面。
上面对
Spring Boot
支持的模板引擎进行了介绍,并指出了整合
JSP
模板的一些限制。接下来,对其
中常用的
Thymeleaf
模板引擎进行介绍,并完成与
Spring Boot
框架的整合实现
4.2 Thymeleaf
Thymeleaf
是一种现代的基于服务器端的
Java
模板引擎技术,也是一个优秀的面向
Java
的
XML
、
XHTML
、
HTML5
页面模板,它具有丰富的标签语言、函数和表达式,在使用
Spring Boot
框架进行页面设计时,一般会选择Thymeleaf
模板
4.2.1 Thymeleaf
语法
常用标签
在
HTML
页面上使用
Thymeleaf
标签,
Thymeleaf
标签能够动态地替换掉静态内容,使页面动态展示。
为了大家更直观的认识
Thymeleaf
,下面展示一个在
HTML
文件中嵌入了
Thymeleaf
的页面文件,示例代码如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" media="all"
href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
<title>Title</title>
</head>
<body>
<p th:text="${hello}">欢迎进入Thymeleaf的学习</p>
</body>
</html>
上述代码中,
“xmlns:th="
http://www.thymeleaf.org
"“
用于引入
Thymeleaf
模板引擎标签,使用关键字 “th”标注标签是
Thymeleaf
模板提供的标签,其中,
“th:href”
用于引入外联样式文件,
“th:text”
用于动态显示标签文本内容。
除此之外,
Thymeleaf
模板提供了很多标签,接下来,通过一张表罗列
Thymeleaf
的常用标签
th
:标签
|
说明
|
th:insert
|
布局标签,替换内容到引入的文件
|
th:replace
|
页面片段包含(类似
JSP
中的
include
标签)
|
th:each
|
元素遍历(类似
JSP
中的
c:forEach
标签)
|
th:if
|
条件判断,如果为真
|
th:unless
|
条件判断,如果为假
|
th:switch
|
条件判断,进行选择性匹配
|
th:case
|
条件判断,进行选择性匹配
|
th:value
|
属性值修改,指定标签属性值
|
th:href
|
用于设定链接地址
|
th:src
|
用于设定链接地址
|
th:text
|
用于指定标签显示的文本内容
|
标准表达式
Thymeleaf
模板引擎提供了多种标准表达式语法,在正式学习之前,先通过一张表来展示其主要语法及说明
说明
|
表达式语法
|
变量表达式
|
${...}
|
选择变量表达式
|
*{...}
|
消息表达式
|
#{...}
|
链接
URL
表达式
|
@{...}
|
片段表达式
|
~{...}
|
1
.变量表达式
${...}
变量表达式
${...}
主要用于获取上下文中的变量值,示例代码如下:
<p th:text="${title}">这是标题</p>
示例使用了
Thymeleaf
模板的变量表达式
${...}
用来动态获取
P
标签中的内容,如果当前程序没有启动或者当前上下文中不存在title
变量,该片段会显示标签默认值
“
这是标题
”
;如果当前上下文中存在
title
变量并且程序已经启动,当前P
标签中的默认文本内容将会被
title
变量的值所替换,从而达到模板引擎页面数据动态替换的效果
同时,
Thymeleaf
为变量所在域提供了一些内置对象,具体如下所示
# ctx:上下文对象
# vars:上下文变量
# locale:上下文区域设置
# request:(仅限Web Context)HttpServletRequest对象
# response:(仅限Web Context)HttpServletResponse对象
# session:(仅限Web Context)HttpSession对象
# servletContext:(仅限Web Context)ServletContext对象
结合上述内置对象的说明,假设要在
Thymeleaf
模板引擎页面中动态获取当前国家信息,可以使用
#locale
内置对象,示例代码如下
The locale country is: <span th:text="${#locale.country}">US</span>.
上述代码中,使用
th:text="${#locale.country}"
动态获取当前用户所在国家信息,其中标签内默认
内容为
US
(美国),程序启动后通过浏览器查看当前页面时,
Thymeleaf
会通过浏览器语言设置来识别当前用户所在国家信息,从而实现动态替换
2
.选择变量表达式
*{...}
选择变量表达式和变量表达式用法类似,一般用于从被选定对象而不是上下文中获取属性值,如果
没有选定对象,则和变量表达式一样,示例代码如下
<div th:object="${book}">
<p>titile: <span th:text="*{title}">标题</span>.</p>
</div>
*{title}
选择变量表达式获取当前指定对象
book
的
title
属性值。
3
.消息表达式
#{...}
消息表达式
#{...}
主要用于
Thymeleaf
模板页面国际化内容的动态替换和展示,使用消息表达式
#{...}
进行国际化设置时,还需要提供一些国际化配置文件。
4
.链接表达式
@{...}
链接表达式
@{...}
一般用于页面跳转或者资源的引入,在
Web
开发中占据着非常重要的地位,并且使用也非常频繁,示例代码如下:
<a th:href="@{http://localhost:8080/order/details(orderId=${o.id})}">view</a>
<a th:href="@{/order/details(orderId=${o.id},pid=${p.id})}">view</a>
上述代码中,链接表达式
@{...}
分别编写了绝对链接地址和相对链接地址。在有参表达式中,需要
按照
@{
路径
(
参数名称
=
参数值,参数名称
=
参数值
...)}
的形式编写,同时该参数的值可以使用变量表达式来传递动态参数值
5
.片段表达式
~{...}
片段表达式
~{...}
用来标记一个片段模板,并根据需要移动或传递给其他模板。其中,最常见的用法是使用th:insert
或
th:replace
属性插入片段,示例代码如下:
<div th:insert="~{thymeleafDemo::title}"></div>
上述代码中,使用
th:insert
属性将
title片段模板引用到该
标签中。
thymeleafDemo
为模板名称,
Thymeleaf
会自动查找
“/resources/templates/”
目录下的
thymeleafDemo
模板,
title
为片段名称
4.2.2
基本使用
(1)
Thymeleaf
模板基本配置
首先 在
Spring Boot
项目中使用
Thymeleaf
模板,首先必须保证引入
Thymeleaf
依赖,示例代码如
下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
其次,在全局配置文件中配置
Thymeleaf
模板的一些参数。一般
Web
项目都会使用下列配置,示例代码如:
spring.thymeleaf.cache = true #启用模板缓存
spring.thymeleaf.encoding = UTF_8 #模板编码
spring.thymeleaf.mode = HTML5 #应用于模板的模板模式
spring.thymeleaf.prefix = classpath:/templates/ #指定模板页面存放路径
spring.thymeleaf.suffix = .html #指定模板页面名称的后缀
上述配置中,
spring.thymeleaf.cache
表示是否开启
Thymeleaf
模板缓存,默认为
true
,在开发过
程中通常会关闭缓存,保证项目调试过程中数据能够及时响应;
spring.thymeleaf.prefix
指定了
Thymeleaf
模板页面的存放路径,默认为
classpath:/templates/
;
spring.thymeleaf.suffix
指定了
Thymeleaf
模板页面的名称后缀,默认为
.html
(2)静态资源的访问
开发
Web
应用时,难免需要使用静态资源。
Spring boot
默认设置了静态资源的访问路径。
使用
Spring Initializr
方式创建的
Spring Boot
项目,默认生成了一个
resources
目录,在
resources
目录中新建public
、
resources
、
static
三个子目录下,
Spring boot
默认会挨个从
public
、
resources
、
static
里面查找静态资源
4.2.3
完成数据的页面展示
1.
创建
Spring Boot
项目,引入
Thymeleaf
依赖

2.
编写配置文件
打开
application.properties
全局配置文件,在该文件中对
Thymeleaf
模板页面的数据缓存进行设置
# thymeleaf页面缓存设置(默认为true),开发中方便调试应设置为false,上线稳定后应保持默认
true
spring.thymeleaf.cache=false
使用
“spring.thymeleaf.cache=false”
将
Thymeleaf
默认开启的缓存设置为了
false
,用来关闭模板页面缓存
3.
创建
web
控制类
在项目中创建名为
com.lagou.controller
的包,并在该包下创建一个用于前端模板页面动态数据替
换效果测试的访问实体类
LoginController
@Controller
public class LoginController {
/**
* 获取并封装当前年份跳转到登录页login.html
*/
@RequestMapping("/toLoginPage")
public String toLoginPage(Model model){
model.addAttribute("currentYear",
Calendar.getInstance().get(Calendar.YEAR));
return "login";
}
toLoginPage()
方法用于向登录页面
login.html
跳转,同时携带了当前年份信息
currentYear
。
4
.创建模板页面并引入静态资源文件
在
“classpath:/templates/”
目录下引入一个用户登录的模板页面
login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1,shrinkto-fit=no">
<title>用户登录界面</title>
<link th:href="@{/login/css/bootstrap.min.css}" rel="stylesheet">
<link th:href="@{/login/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<!-- 用户登录form表单 -->
<form class="form-signin">
<img class="mb-4" th:src="@{/login/img/login.jpg}" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal">请登录</h1>
<input type="text" class="form-control"
th:placeholder="用户名" required="" autofocus="">
<input type="password" class="form-control"
th:placeholder="密码" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> 记住我
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" >登录</button>
<p class="mt-5 mb-3 text-muted">© <span
th:text="${currentYear}">2019</span>-<span
th:text="${currentYear}+1">2020</span></p>
</form>
</body>
</html>
通过
“xmlns:th="
http://www.thymeleaf.org
"”
引入了
Thymeleaf
模板标签;
使用
“th:href”
和
“th:src”
分别引入了两个外联的样式文件和一个图片;
使用
“th:text”
引入了后台动态传递过来的当前年份
currentYear
5
.效果测试

可以看出,登录页面
login.html
显示正常,在文件
4-3
中使用
“th:*”
相关属性引入的静态文件生效,
并且在页面底部动态显示了当前日期
2019-2020
,而不是文件中的静态数字
2019-2020
。这进一步说明了Spring Boot
与
Thymeleaf
整合成功,完成了静态资源的引入和动态数据的显示
5. SpringBoot
实战演练
实战技能补充:
lombok
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<!--只在编译阶段生效-->
<scope>provided</scope>
</dependency>
需求:实现用户的
CRUD
功能
(
1
)创建
springboot
工程

(
2
)导入
pom.xml
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.3</version>
</dependency>
(
3
)
User
实体类编写
@Data
public class User implements Serializable {
private Integer id;
private String username;
private String password;
private String birthday;
private static final long serialVersionUID = 1L;
}
(
4
)
UserMapper
编写及
Mapper
文件
public interface UserMapper {
int deleteByPrimaryKey(Integer id);
int insert(User record);
int insertSelective(User record);
User selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(User record);
int updateByPrimaryKey(User record);
List<User> queryAll();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.base.mapper.UserMapper">
<resultMap id="BaseResultMap" type="com.example.base.pojo.User">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="username" jdbcType="VARCHAR" property="username" />
<result column="password" jdbcType="VARCHAR" property="password" />
<result column="birthday" jdbcType="VARCHAR" property="birthday" />
</resultMap>
<sql id="Base_Column_List">
id, username, password, birthday
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer"
resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user
where id = #{id,jdbcType=INTEGER}
</select>
<select id="queryAll" resultType="com.example.base.pojo.User">
select <include refid="Base_Column_List" />
from user
</select>
.......
</mapper>
(
5
)
UserService
接口及实现类编写
package com.lagou.service.impl;
import com.lagou.mapper.UserMapper;
import com.lagou.pojo.User;
import com.lagou.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> queryAll() {
return userMapper.queryAll();
}
@Override
public User findById(Integer id) {
return userMapper.selectByPrimaryKey(id);
}
@Override
public void insert(User user) {
//userMapper.insert(user); //将除id所有的列都拼SQL
userMapper.insertSelective(user); //只是将不为空的列才拼SQL
}
@Override
public void deleteById(Integer id) {
userMapper.deleteByPrimaryKey(id);
}
@Override
public void update(User user) {
userMapper.updateByPrimaryKeySelective(user);
}
}
(
6
)
UserController
编写
package com.lagou.controller;
import com.lagou.pojo.User;
import com.lagou.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.yaml.snakeyaml.events.Event;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
/**
* restful格式进行访问
* 查询:GET
* 新增: POST
* 更新:PUT
* 删除: DELETE
*/
/**
* 查询所有
* @return
*/
@GetMapping("/query")
public List<User> queryAll(){
return userService.queryAll();
}
/**
* 通过ID查询
*/
@GetMapping("/query/{id}")
public User queryById(@PathVariable Integer id){
return userService.findById(id);
}
/**
* 删除
* @param id
* @return
*/
@DeleteMapping("/delete/{id}")
public String delete(@PathVariable Integer id){
userService.deleteById(id);
return "删除成功";
}
/**
* 新增
* @param user
* @return
*/
@PostMapping("/insert")
public String insert(User user){
userService.insert(user);
return "新增成功";
}
/**
* 修改
* @param user
* @return
*/
@PutMapping("/update")
public String update(User user){
userService.update(user);
return "修改成功";
}
}
(
8
)
application.yml
##服务器配置
server:
port: 8090
servlet:
context-path: /
##数据源配置
spring:
datasource:
name: druid
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/springbootdata?characterEncoding=utf-
8&serverTimezone=UTC
username: root
password: wu7787879
#整合mybatis
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml #声明Mybatis映射文件所在的位置
(
9
)启动类
@SpringBootApplication
//使用的Mybatis,扫描com.lagou.mapper
@MapperScan("com.lagou.mapper")
public class Springbootdemo5Application {
public static void main(String[] args) {
SpringApplication.run(Springbootdemo5Application.class, args);
}
}
(
10
)使用
Postman
测试

6. Spring Boot
项目部署
需求:将
Spring Boot
项目使用
maven
指令打成
jar
包并运行测试
分析:
1.
需要添加打包组件将项目中的资源、配置、依赖包打到一个
jar
包中;可以使用
maven
的
package
;
2.
部署:
java -jar
包名
步骤实现:
添加打包组件
<build>
<plugins>
<!-- 打jar包时如果不配置该插件,打出来的jar包没有清单文件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
部署运行
java -jar 包名