Spring Boot基础
学习目标:
- 能够理解
Spring
的优缺点
- 能够理解
Spring Boot
的特点
- 能够理解
Spring Boot
的核心功能
- 能够搭建
Spring Boot
的环境
- 能够完成
application.properties
配置文件的配置
- 能够完成
application.yml
配置文件的配置
- 能够使用
Spring Boot
集成 Mybatis
- 能够使用
Spring Boot
集成 Junit
- 能够使用
Spring Boot
集成 Spring Data JPA
一、Spring Boot 简介
1.1 原有 Spring 优缺点分析
1.1.1 Spring 的优点分析
Spring
是Java企业版(Java Enterprise Edition 也称J2EE)的轻量级替代品,无需开发重量级的Enterprise JavaBean(EJB),Spring
为企业版Java开发提供了一种相对简单的方法,通过依赖注入和面向切面编程,用简单的Java对象(Plain Old Java Object POJO)实现了 EJB
的功能
1.1.2 Spring 的缺点分析
Spring
的组件代码是轻量级的,但它的配置确实重量级的。Spring1.0
使用的是XML配置,而且是很多的XML配置;Spring2.0
引入了基于注解的组件扫描,这消除了大量针对应用程序自身组建的显式XML配置;Spring3.0
引入了基于Java的配置,这是一种类型安全的可重构配置方式,可以完全代替XML。
Spring
开发过程中,由于思考 Spring
特性配置和解决业务问题之间的思维切换,导致开发时间的损耗。
- 项目依赖的管理,在项目环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导入与之有依赖关系的其他库坐标,一旦选错了依赖的版本,那随之而来的不兼容问题会严重阻碍项目的开发进度。
1.2 Spring Boot 的概述
1.2.1 Spring Boot 解决上述 Spring 的缺点
Spring Boot
是对 Spring
缺点进行的改善和优化,基于约定优于配置的思想。
1.2.2 Spring Boot 的特点
- 为基于
Spring
的开发提供更快的入门体验
- 开箱即用,没有代码生成,也无需XML配置,同时也可以修改默认值来满足特定的需求
- 提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、安全指标、健康检测、外部配置等
Spring Boot
不是对 Spring
功能上的增强,而是提供了一种更快速的使用 Spring
的方式
1.2.3 Spring Boot 的核心功能
- 起步依赖
- 简单来说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。
- 自动配置
Spring Boot
的自动配置是一个运行时(更准确的说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring
配置应该用哪个,不应该用哪个。该过程是 Spring
自动完成的。
二、Spring Boot 快速入门
2.1 代码实现
2.1.1 创建 Maven 工程
- 使用IDEA创建一个 Maven 工程,该工程为普通的 java 工程即可。
2.1.2 添加Spring Boot的起步依赖
Spring Boot
要求,项目要继承 Spring Boot
的起步依赖 spring-boot-starter-parent
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.0.RELEASEversion>
parent>
Spring Boot
要集成 SpringMVC
的 Controller 进行开发,所以项目要导入 web 的启动依赖
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
2.1.3 编写 Spring Boot 的引导类
- 要通过
Spring Boot
提供的引导类起步 Spring Boot
才可以进行访问
package com.guojh;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class);
}
}
2.1.4 编写 Controller
- 在引导类
SpringBootApplication
同级包或者子级包中创建类 QuickController
package com.guojh.Controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/")
public class QuickController {
@RequestMapping("quick")
@ResponseBody
public String quick() {
return "Hello SpringBoot!";
}
}
2.1.5 测试
- 地址栏输入:http://localhost:8080/quick 访问
2.2 快速入门解析
2.2.1 Spring Boot 代码解析
- Spring Boot的常用注解:https://www.cnblogs.com/tanwei81/p/6814022.html
2.2.2 Spring Boot 工程热部署
- 在 pom.xml 中添加如下代码,在进行
Spring Boot
开发时候可以实现热部署
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
dependency>
- 注意:IDEA进行
Spring Boot
热部署失败的原因
- 出现这种情况并不是热部署配置的问题,其原因使
Spring Boot
不自动编译的问题,需要对IDEA进行自动编译的设置
- 按住Ctrl+Shift+Alt+/ 选择Registry
2.2.3 使用IDEA快速创建 Spring Boot 项目
三、Spring Boot 原理分析
3.1 起步依赖原理分析
3.1.1 分析 spring-boot-starter-parent
- 按住Ctrl点击 pom.xml 中的
spring-boot-starter-parent
,跳转到了 spring-boot-starter-parent
的 pom.xml 中,XML配置如下:
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.1.0.RELEASEversion>
<relativePath>../../spring-boot-dependenciesrelativePath>
parent>
- 按住Ctrl点击 pom.xml 中的
spring-boot-dependencies
,跳转到了 spring-boot-dependencies
的 pom.xml 中,XML配置如下:
<properties>
<activemq.version>5.15.7activemq.version>
<antlr2.version>2.7.7antlr2.version>
<appengine-sdk.version>1.9.67appengine-sdk.version>
<artemis.version>2.6.3artemis.version>
<aspectj.version>1.9.2aspectj.version>
<assertj.version>3.11.1assertj.version>
<atomikos.version>4.0.6atomikos.version>
.......
properties>
3.1.2 分析 spring-boot-starter-web
- 查看 pom.xml 中的 web 起步依赖
spring-boot-starter-web
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
- 依赖中包含
spring-boot-starter
、spring-boot-starter-json
、spring-web
、spring-webmvc
等,查看 json 依赖,如下(部分信息):
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>5.1.2.RELEASEversion>
<scope>compilescope>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.7version>
<scope>compilescope>
dependency>
3.2 自动配置原理解析
- 查看
Spring Boot
引导类中的注解:@SpringBootApplication
@SpringBootApplication
注解包括 @SpringBootConfiguration
(其注解为 @Configuration 等同于 spring 的XML配置文件)、@EnableAutoConfiguration
(表示开启自动化配置)、@ComponentScan
(用于组件扫描)
Spring Boot
常用注解:Spring Boot 常用注解解析
四、Spring Boot 配置文件
4.1 Spring Boot 配置文件类型
4.1.1 Spring Boot 配置文件类型和作用
Spring Boot
是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用 application.properties
或者 application.yml
(application.yaml
) 进行配置。
Spring Boot
默认会从 Resources
目录下加载 application.properties
或者 application.yml
(application.yaml
) 文件
- 其中
application.properties
文件是键值对类型的文件。
4.1.2 application.yml 配置文件
4.1.2.1 yml 配置文件简介
- YML 文件格式是 YAML(YAML Aint Markup Language) 编写的文件格式,YAML 是一种直观的能够被电脑识别的数据序列化格式,并且容易被人阅读,容易和脚本语言交互,可以被支持 YAML 库的不同的编程语言程序导入,如:C/C++、Ruby、Python、Java、Perl、C#、PHP等,YML 文件是以数据为核心的,比传统的 XML 方式更加简洁。
- (注:YML 文件的扩展名可以使用
.yml
和 .yaml
)
<resource>
<filtering>truefiltering>
<directory>${basedir}/src/main/resourcesdirectory>
<includes>
<include>**/application*.ymlinclude>
<include>**/application*.yamlinclude>
<include>**/application*.propertiesinclude>
includes>
resource>
4.1.2.2 yml 配置文件的语法(用缩进/空格方式来代替层级关系)
4.1.2.2.1 配置普通数据
name: huasir
- (注:name:+空格 value之前有一个空格)
4.1.2.2.2 配置对象数据
- 语法:
- key:
- key1: value1
- key2: value2
- key3: value3
- 或者:key: {key1: value1,key2: value2,key3: value3}
- 示例代码:
person:
name: huasir
age: 18
addr: shanxi
person: {name: huasir,age: 18,addr: shanxi}
4.1.2.2.3 配置Map数据
4.1.2.2.4 配置数组(List、Set)数据
- 语法:
- key:
- 或者:key: [value1, value2, value3]
- 示例代码:
city:
- beijing
- shanghai
- chongqing
city: [beijing, shanghai, chongqing]
student:
- name: zhangsan
age: 18
addr: shanxi
- name: lisi
age: 19
addr: beijing
student: [{name: zhangsan, age: 18, addr: shanxi},{name: lisi, age: 19, addr: beijing}]
4.2 配置文件与配置类的属性映射方式
4.2.1 使用注解 @Value 映射
- 我们可以通过
@Value
注解将配置文件中的值映射到一个 Spring
管理的 Bean
字段上
- 例如:
application.yml
配置如下:
name: huasir
person:
name: huasir
age: 18
addr: shanxi
package com.guojh.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/")
public class Quick2Controller {
@Value("${name}")
public String name;
@Value("${person.addr}")
public String addr;
@RequestMapping("quick2")
@ResponseBody
public String quick2() {
return "yml获取普通数据的配置name:" + name + "——addr:" + addr;
}
}
4.2.2 使用注解 @ConfigurationProperties
映射
- 我们通过注解 @ConfigurationProperties(prefix=“配置文件中的key的前缀”) 可以将配置文件中的配置自动与实体进行映射
- 例如:
application.yml
配置如下:
person:
name: huasir
age: 18
addr: shanxi
package com.guojh.controller;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/")
@ConfigurationProperties(prefix = "person")
public class Quick3Controller {
private String name;
private Integer age;
private String addr;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
@RequestMapping("quick3")
@ResponseBody
public String quick3() {
return "yml对象数据的配置结果如下:name: " + name + "...age: " + age + "...addr: " + addr;
}
}
- 配置注解
@ConfigurationProperties
的执行器
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
五、Spring Boot 整合其他技术
5.1 Spring Boot 整合 Mybatis
5.1.1 添加 Mybatis 起步依赖
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.3.1version>
dependency>
5.1.2 添加数据库驱动坐标
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.4.RELEASEversion>
<relativePath/>
parent>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.25version>
dependency>
- 此处如果本机使用的是 Mysql8,在添加 MySQL 依赖的时候不需要添加版本号 5.1.25
- 解决:添加 MySQL 版本号,或者降低 Spring Boot 的版本号
5.1.3 添加数据库连接信息
- 在
application.properties
中配置数据库的连接信息
# 数据库连接信息
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
5.1.4 创建user表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`password` varchar(50) DEFAULT NULL,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
insert into `user`(`id`,`username`,`password`,`name`)
values (1,'zhangsan','zs123','张三'),
(2,'lisi','ls123','李四'),
(3,'wangwu','ww123','王五'),
(4,'zhaoliu','zl123','赵六');
5.1.5 创建实体 Bean
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
package com.guojh.springbootmybatis.domain;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Data
@Getter
@Setter
public class User {
private Integer id;
private String username;
private String password;
private String name;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", name='" + name + '\'' +
'}';
}
}
5.1.6 编写Mapper
package com.guojh.springbootmybatis.mapper;
import com.guojh.springbootmybatis.domain.User;
import java.util.List;
@Mapper
public interface UserMapper {
public List<User> queryUserList();
}
5.1.7 配置Mapper映射文件
<mapper namespace="com.guojh.springbootmybatis.mapper.UserMapper">
<select id="queryUserList" resultType="user">
select * from user
select>
mapper>
5.1.8 在application.properties中添加mybatis的信息
# 配置Mybatis中的信息
# pojo别名扫描包
mybatis.type-aliases-package=com.guojh.springbootmybatis.domain
# 加载Mybatis映射文件
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
5.1.9 编写测试类Controller
package com.guojh.springbootmybatis.controller;
import com.guojh.springbootmybatis.domain.User;
import com.guojh.springbootmybatis.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("/")
public class MybatisController {
@Autowired
private UserMapper userMapper;
@RequestMapping("queryUserList")
@ResponseBody
public List<User> queryUserList() {
List<User> userList = userMapper.queryUserList();
return userList;
}
}
- 注解
@Autowired
与 @Resource
的区别 参考博客:参考博客1,参考博客2
- @Resource 的作用相当于 @Autowired,只不过 @Autowired 按照 byType 自动注入,@Resource 按照 byName 自动注入。
5.2 Spring Boot 整合 Junit
5.2.1 添加 Junit 起步依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
5.2.2 编写测试类
package com.guojh.springbootmybatis;
import com.guojh.springbootmybatis.domain.User;
import com.guojh.springbootmybatis.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootMybatisApplication.class)
public class MybatisTest {
@Resource
private UserMapper userMapper;
@Test
public void test() {
List<User> userList = userMapper.queryUserList();
System.out.println(userList);
}
}
5.3 Spring Boot 整合 Spring Data JPA
5.3.1 添加 Spring Data JPA 起步依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
5.3.2 添加数据库驱动依赖
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.25version>
dependency>
5.3.3 在application.properties中配置数据库和jpa的相关属性
# 数据库连接信息
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
# JPA 的相关配置信息
spring.jpa.database=mysql
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
5.3.4 创建实体配置实体
package com.guojh.domain;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Data
@Getter
@Setter
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
private String password;
private String name;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", name='" + name + '\'' +
'}';
}
}
5.3.5 编写UserRepository
package com.guojh.repository;
import com.guojh.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface UserRepository extends JpaRepository<User, Integer> {
@Override
public List<User> findAll();
}
5.3.6 编写测试类
package com.guojh;
import com.guojh.domain.User;
import com.guojh.repository.UserRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootJpaApplication.class)
public class JPATest {
@Autowired
private UserRepository userRepository;
@Test
public void test() {
List<User> userList = userRepository.findAll();
System.out.println(userList);
}
}
- 注意:使用 jdk9 会提示:NoClassDefFoundError: javax/xml/bind/JAXBException
- 解决办法:添加如下依赖
<dependency>
<groupId>javax.xml.bindgroupId>
<artifactId>jaxb-apiartifactId>
<version>2.3.0version>
dependency>
5.4 Spring Boot 整合 Redis
5.4.1 添加 Redis 起步依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
5.4.2 配置 Redis 的连接信息
# redis 配置信息
spring.redis.host=192.168.38.144
spring.redis.port=6379
- 在Linux中安装Redis参考博客:Linux安装Redis
5.4.3 注入 RedisTemplate 测试 Redis 操作
package com.guojh;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.guojh.domain.User;
import com.guojh.repository.UserRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootJpaApplication.class)
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private UserRepository userRepository;
@Test
public void test() throws JsonProcessingException {
Object userList = redisTemplate.boundValueOps("user.findAll").get();
if (null == userList) {
List<User> all = userRepository.findAll();
ObjectMapper objectMapper = new ObjectMapper();
userList = objectMapper.writeValueAsString(all);
redisTemplate.boundValueOps("user.findAll").set(userList);
System.out.println("======== 从数据库中获得user数据 ========");
} else {
System.out.println("======== 从Redis缓存中获得user数据 ========");
}
System.out.println(userList);
}
}