1. 什么是SpringBoot
1.1 说明
SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来==简化Spring应用的初始搭建以及开发过程(因为大部分会使用的配置都默认配置好了,因此可以简化大部分开发,即约定大于配置)==
Spring程序缺点:
-
依赖设置繁琐
-
配置繁琐
SpringBoot程序优点:
-
起步依赖(简化依赖配置)
-
自动配置(简化常用工程相关配置)
-
辅助功能(内置服务器,……)
看了上面的说明之后相信大部分人应该还是不理解到底什么是SpringBoot,SpringBoot是干什么用的,所以下面就让我们做一个简单的SpringBootDemo小案例:
1.2 SpringBootDemo小案例
-
创建新模块,选择Spring Initializr,并配置模块相关基础信息
基于阿里云创建项目,地址:https://start.aliyun.com
- 选择当前模块需要使用的技术集
- 编写Controller类测试:
//Rest模式
@RestController
@RequestMapping("/test")
public class testController {
@GetMapping
public String testDemo1(){
System.out.println("Spring Boot ....");
return "Spring Boot ....";
}
}
- 运行创建项目时自动生成的Application引导类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootDemo1Application {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemo1Application.class, args);
}
}
1.3 上述Demo简单分析
注意:
- 阿里云提供的坐标版本较低,如果需要使用高版本,进入工程后手工切换SpringBoot版本(但是目前2.3.7也可以了)
- 阿里云提供的工程模板与Spring官网提供的工程模板略有不同
- SpringBoot程序需要基于JDK8进行制作
- SpringBoot程序中需要使用何种功能通过勾选选择技术
- 运行SpringBoot程序通过运行Application程序入口进行
- Boot默认的应用程序的上下文路径为"/"
最简SpringBoot程序所包含的基础文件:
-
pom.xml文件
使用阿里云网站创建出来的pom.xml:
<?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>
<groupId>com.ahua</groupId>
<artifactId>springboot_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.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>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.ahua.SpringbootDemoApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
使用原生的start.spring.io网站创建出来的pom.xml文件:
<?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.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ahua</groupId>
<artifactId>springboot_01_01_quickstart</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- Application引导类
1.4 原生Spring与SpringBoot程序对比:
1.5 手工创建SpringBoot工程步骤
当你电脑里有SpringBoot的jar包又没有联网时,就可以通过手工创建SpringBoot工程,步骤如下:
-
创建普通Maven工程
-
继承spring-boot-starter-parent
-
添加依赖spring-boot-starter-web
-
制作引导类Application
2. SpringBoot哪里好
2.1 parent标签与dependencyManagement标签
SpringBoot定义一系列的常用坐标版本,并且定义了一系列的常用坐标组合, 我们开发时只需要通过<parent>标签继承这些配置即可大大的降低我们做配置文件的操作
例如我们在pom.xml中导入坐标时不需要写版本号, SpringBoot会默认将版本号设置为Spring测试过的最好用的版本(通过<project>标签与<dependencyManagement>标签)
因此使用SpringBoot可以避免多个依赖使用相同技术时出现依赖版本冲突
源码部分:
我们创建的项目继承了spring-boot-starter-parent, 而spring-boot-starter-parent继承了spring-boot-dependencies, 在spring-boot-dependencies中通过<project>定义了若干坐标的版本号
而在使用阿里云创建的项目中则是通过<dependencyManagement>标签引用了spring-boot-dependencies
也就是说因为在spring-boot-dependencies中定义了常用的坐标版本并且定义了一系列的常用坐标,并在这些常用坐标中引用了定义的版本信息, 所以我们才可以在开发的时候引用坐标时不需要写版本信息
并且对于常用坐标版本的区别仅取决于SpringBoot的版本(通过选中俩个文件右键比较文件看出区别)
补充:dependencyManagement标签说明
使用dependencyManagement可以统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,不用每个模块项目都弄一个版本号,不利于管理,当需要变更版本号的时候只需要在父类容器里更新,不需要任何一个子项目的修改;如果某个子项目需要另外一个特殊的版本号时,只需要在自己的模块dependencies中声明一个版本号即可。子类就会使用子类声明的版本号,不继承于父类版本号
与dependencies区别:
1)dependencies相对于dependencyManagement,所有生命在dependencies里的依赖都会自动引入,并默认被所有的子项目继承
2)dependencyManagement里只是声明依赖,并不自动实现引入(只是创建了依赖管理),因此子项目需要显示的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本
因此dependencyManagement标签主要用于管理依赖关系和各种依赖包冲突(版本号)
使用parent可以做到坐标依赖管理
但是注意:<parent>继承之后, 只是定义了依赖,而没有使用这些依赖, 我们导入了starter相关的包后, 由于starter相关的包集成了这个技术中要用的几乎所有的坐标, 这时才使用了这些依赖
2.2 starter
在SpringBoot中有很多名字与starter相关的依赖, 其实这些与starter相关的依赖都集成了这个技术中要用的几乎所有的坐标, 因此我们需要一种技术时(例如web与test)只需要导入相关的starter包即可, 简化了我们导包与配置的工作, 达到减少依赖配置的目的
而<parent>标签只是所有SpringBoot项目要继承的项目,定义了若干个坐标版本号(依赖管理,而非依赖),以达到减少依赖冲突的目的, 因此<parent>标签并没有使用这些依赖
因此我们实际开发时往往只需要导入starter相关的坐标, 其他坐标除非SpringBoot没有不然不导入. 并且使用任意坐标时,仅书写GAV中的G和A,V由SpringBoot提供,除非SpringBoot未提供对应版本V, 此时我们再去指定V
使用starter可以做到快速配置依赖
2.3 引导类Application
首先看引导类中的这句代码:
SpringApplication.run(SpringbootDemoApplication.class, args);
其实这句话运行之后会生成一个应用上下文对象:ConfigurableApplicationContext
, 即Spring容器对象
也就是说引导类其实就是启动了一个Spring容器
再看看引导类上的注解:
@SpringBootApplication
观察源码后发现这个注解其实就是一个配置类的注解(@Configuration), 同时这个注解也是一个扫描当前所在包下的所有注解的注解(@ComponentScan), 因此所有bean都必须在引导类所在包下, 当然这个注解不仅仅于此
总结:
- SpringBoot的引导类是Boot工程的执行入口,运行main方法就可以启动项目(而能启动web项目是因为SpringBoot内嵌了tomcat服务器)
- SpringBoot工程运行后初始化Spring容器,扫描引导类所在包加载bean
2.4 内嵌tomcat
在spring-boot-starter-web依赖中还内置依赖了spring-boot-starter-tomcat, 而在spring-boot-starter-tomcat内还依赖了tomcat-embed-core
而tomcat-embed-core, 顾名思义即内嵌的tomcat核心, 这就是SpringBoot能直接运行web项目的原因
而tomcat为什么可以内嵌到程序中呢?我们平时使用不都是将程序内嵌到tomcat中吗?
其实, tomcat不就是用java写的, 既然是用Java写的自然就可以有对象, 而对象不就可以交给Spring容器管理吗, 因此导入依赖后在Spring容器中就有一个tomcat对象了, 也就可以运行web项目了
而当我们不使用tomcat服务器时只需要在导入spring-boot-starter-web时移除spring-boot-starter-tomcat即可:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
接着我们就可以导入其他的web服务器使用了, 在SpringBoot中支持三种web服务器(即有starter的), 分别是tomcat, jetty(轻量级服务器, 相较于tomcat可拓展性更强, 但负载性能比不上tomcat)与undertow(并发负载勉强跑赢tomcat)
导入jetty:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
除了上述四点之外, Boot之所以好用还因为他将所有配置都设置了默认最常用的配置等等
3. REST风格
3.1 REST风格简介
REST风格其实就是一种访问资源的风格
Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等
并且REST风格中描述模块的名称通常使用复数, 例如users, books, 表示此类资源, 而非单个资源
优点:
- 隐藏资源的访问方式, 无法从地址得知对资源是何种操作
- 书写简化
但也由于隐藏资源的访问方式与书写简化导致可能添加操作的访问写法与删除操作的访问资源写法一模一样, 此时就需要引入REST的行为来区分对资源进行何种操作:
RESTful风格的请求是使用**“url+请求方式”**表示一次请求目的的,HTTP 协议里面四个表示操作方式的动词如下(其实SpringMVC支持的是八个, 但我们常用的只有四个):
-
GET:用于获取资源
-
POST:用于新建资源
-
PUT:用于更新资源
-
DELETE:用于删除资源
例如:
- /users/1 GET : 查询id = 1 的 user
- /users/1 DELETE: 删除 id = 1 的 user
- /users/1 PUT: 更新 id = 1 的 user
- /users POST: 新增 user
- /users GET : 查询所有user
也就是说REST风格将HTTP协议里的四个请求方式变成了自己的新的意思
而使用REST风格对资源进行访问称为RESTful
3.2 REST开发步骤
- 将@RequestMapping中的value参数值改为REST风格的, 并且对method属性进行赋值, 赋的值就是上面说的四个动词, 并且已经内部提供了常量供我们使用了, 示例:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@RequestMapping
public class UserController {
@RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)
- 对于参数需要使用@PathVariable注解:
@PathVariable("id")int id
但实际开发中,只有参数较少时才会使用@PathVariable接收参数
如果参数较多时,并且数据以JSON格式为主则使用@RequestBody注解
如果非JSON格式, 则选用@RequestParam接收
3.3 REST快速开发
其实是SpringMVC提供的简化REST风格开发的注解:
- 首先可以将users等带复数的写到类的@RequestMapping中, 此时方法的@RequestMapping只需要写method属性, 除非需要接受参数, 不然不需要写value属性
- 使用@RestController, @GetMapping, @PostMapping等注解
4. 基础配置
4.1 属性配置
-
修改服务器端口:8080–>80
在application.properties中修改:
server.port=80
- 修改banner:
# 修改banner, 将logo打到日志里
spring.main.banner-mode=log
# 将banner修改为你选择的图片, 会通过图片识别技术识别图片并打印
spring.banner.image.location=地址
- 控制日志(输入log所有和日志相关的配置都会跳出来)
# 修改root时的最低日志打印级别, 默认为info
# root还可以修改为sql与web或者你写的包
logging.level.root=info
logging.level.com.ahua=debug
具体还有什么配置都可以去官网看文档, 但具体配置是和你导入的依赖有关的, 如果没有导相关依赖是配不了相关信息的, 即配置对应相关技术
4.2配置方式(配置文件类型)
-
SpringBoot默认配置文件application.properties(必须是这名), 创建过程时会自动创建该文件, 该文件通过键值对设置配置信息
-
application.yml格式, 最主流,示例:
server:
port: 81
- application.yaml格式,示例:
server:
port: 81
当三种文件共存时, 配置文件优先级:
application.properties > application.yml > application.yaml
但是如果是配置相同属性, 则按照优先级选择, 如果是不同属性 ,则都会留下来
4.2.1 yaml数据格式
YAML(YAML Ain’t Markup Language),一种数据序列化格式
优点:
-
容易阅读
-
容易与脚本语言交互
-
以数据为核心,重数据轻格式
YAML文件扩展名
- .yml(主流)
- .yaml
yaml语法规则
-
大小写敏感
-
属性层级关系使用多行描述,每行结尾使用冒号结束(多层级之间相当于用点隔开)
-
使用缩进表示层级关系,同层级左侧对齐,只允许使用空格(不允许使用Tab键)
-
属性值前面添加空格(属性名与属性值之间使用冒号+空格作为分隔)
-
# 表示注释
-
核心规则:数据前面要加空格与冒号隔开
因为其他的IDEA都可以给你提示出来或者自动补全
-
不管写数字还是字符串都不需要"", 并且数据后面不能写空格, 但有特殊字符如空格时需要用双引号, 同时加上引号之后变成字符串, 里面的内容就会被解析, 例如写了"\n"则会解析出回车来, 但如果不写双引号直接写\n则不会被解析
日期必须使用yyyy-MM-dd格式
-
同名属性不允许重复
-
数组表示方式:在属性名书写位置的下方使用减号作为数据开始符号,每行书写一个数据,减号与数据间空格分隔:
subject:
- Java
- 前端
- 大数据
enterprise:
name: itcast
age: 16
subject: - Java
- 前端
- 大数据
likes: [王者荣耀,刺激战场] #数组书写缩略格式
user: # 对象数据格式
name: zhangsan
age: 20
users: #对象数组格式
- name: Tom
age: 4
- name: Jerry
age: 5
users: #对象数组格式二
-
name: Tom
age: 4
-
name: Jerry
age: 5
#对象数组缩略格式,类似JSON
users2: [ { name: Tom , age: 4 } , { name: Jerry , age: 5 } ]
4.2.2 yaml数据读取
4.2.2.1 一次读取一个属性
对于简单数据类型, 直接通过==@Value("${一级属性名.二级属性名……}")==进行注入:
@Value("${user.name}")
private String username;
对于数组数据类型, 直接通过==@Value("${一级属性名[索引]}")==进行注入
@Value("${subject[2]}")
private String subject;
上面俩个混着使用基本上所有东西都可以读取到了:
@Value("${users[0].age}")
private int age;
4.2.2.2 一次读取全部属性
Boot提供一个Environment对象(org.springframework.core.env), 能够将yaml中的全部属性都加载进来
创建Environment对象变量:
// 使用自动装配将yaml中的所有数据封装到一个对象中
@Autowired
private Environment env;
接着通过Environment对象的getProperty(“属性名”)方法获取相对应的属性, 其中属性名写法与上述EL表达式写法一致:
System.out.println(env.getProperty("enterprise.subject[0]"));
通过这种方式可以节约对变量的定义
4.2.2.3 读取引用类型数据主流
对于下述数据:
enterprise:
name: zhangsan
age: 16
tel: 1535262
我们在获取时肯定不希望Boot将全部属性封装, 而是希望封装成一个实体类对象给我们
步骤:
-
定义实体类来封装yaml中的对应数据, 属性名需要与yaml的一致, 例如上面的name, age与tel
并且将这个实体类定义为Spring管控的类:@Component
-
使用@ConfigurationProperties注解绑定配置信息到封装类中, 即指定要加载的数据
该注解中的value属性值与prefix(前缀)绑定在一起了, 用于指定yaml中的对应数据前缀(一级名字):
@ConfigurationProperties(prefix="enterprise")
- 接着之间创建这个实体类对象(使用注解自动装配即可)
4.2.3 yaml文件中的变量引用
在yaml文件中可能存在这种问题:
center:
dataDir: D:/usr/local/fire/data
tmpDir: D:/usr/local/fire/tmp
logDir: D:/usr/local/fire/log
msgDir: D:/usr/local/fire/msgDir
即大量重复内容, 此时如果我们要修改就会很麻烦
此时就需要在yaml中定义一个属性名配置重复部分
然后通过${属性名}的EL表达式方式引用数据:
baseDir: D:/usr/local/fire
center:
dataDir: ${baseDir}/data
tmpDir: ${baseDir}/tmp
logDir: ${baseDir}/log
msgDir: ${baseDir}/msgDir
4.3 不同环境配置
通常我们在application.yml中加载application-dev.yml(开发环境配置)
一个项目有很多环境:开发环境,测试环境,准生产环境,生产环境
每个环境的参数不同,我们就可以把每个环境的参数配置到yml文件中,这样在想用哪个环境的时候只需要在主配置文件中将用的配置文件写上就行如application.ym
在Spring Boot中多环境配置文件名需要满足application-{profile}.yml的格式,其中{profile}对应环境标识,比如:
application-dev.yml:开发环境
application-test.yml:测试环境
application-prod.yml:生产环境
至于哪个具体的配置文件会被加载,需要在application.yml文件中通过spring.profiles.active属性来设置,其值对应{profile}值
示例:
spring:
profiles:
active: dev
5. Boot整合第三方技术
5.1 整合Mybatis
首先创建项目时勾选SQL下的Mybatis framework与MySQL Driver, 这样子就不用手写依赖了
发现导入的依赖为:mybatis-spring-boot-starter, 而之前的依赖都是spring-boot-starter-*
其实, spring-boot-starter-*都是Spring自己官方的整合
而*-spring-boot-starter则是Spring整合第三方的技术
注意:
- 使用MySQL8开始的驱动一定要设置时区参数:serverTimezone, 例如可以设置为UTC等, 或者在数据库中已经设置好了则不用
- 数据库Driver最好使用:com.mysql.cj.jdbc.Driver, 因为之前那个过时了, 使用的话会产生警告
Mybatis需要的配置:
spring:
# 应用名称
application:
name: springboot_demo
# 配置数据库连接信息:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=UTC
username: root
password: "root"
接着可以在mapper包下创建映射文件
再在启动类或者配置类上加上@MapperScan(“包名”)配置包扫描, 并在mapper接口上加@Repository注解, 也可以在每个mapper类上都加入@Mapper注解实现扫描
@Mapper与@Repository区别:@Mapper不需要配置包扫描, 会通过xml文件中的namespace找到接口自动注入
5.2 整合druid
Spring并没有提供整合的Druid的starter给我们勾选, 因此我们需要手工添加:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
接着修改配置:
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=UTC
username: root
password: "root
5.3 整合Mybatis-puls
MyBatis-Plus与MyBatis区别
-
导入坐标不同
-
数据层实现简化
因此整合MyBatis-Plus步骤几乎与上述一致
但是注意:创建Boot工程时, 由于MyBatis-Plus是国人开发的, Spring并没有将他整合进去,此时有俩种解决方法:
- 使用阿里云创建工程, 勾选SQL下的Mybatis Plus framework与MySQL Driver
- 使用官方提供的创建工程, 只勾选MySQL Driver, 再自己手动导入坐标:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
接着的配置与MyBatis一致, 但还需要增加与MP相关的配置, 例如:
#设置Mp相关的配置
mybatis-plus:
global-config:
db-config:
# 设置表的前缀名
table-prefix: sys_
5.4 总结:整合思想
- 导入相关starter, 需要使用的第三方技术无法通过勾选确定时,需要手工添加坐标
- 配置相关信息