avatar

SpringBoot2.X快速上手

概述

SpringBoot提供了一种快速使用Spring的方式,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率

SpringBoot功能

1自动配置

Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是SpringBoot自动完成的。

2起步依赖

起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。

简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。

3辅助功能

提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、安全、指标,健康检测、外部配置等。

注意:Spring Boot 并不是对 Spring 功能上的增强,而是提供了一种快速使用 Spring 的方式。

为什么要学习SpringBoot

Spring的缺点

配置文件繁琐

引入的依赖过多

配置文件和业务逻辑之间需要频繁的切换

SpringBoot的优点

提供了默认的最优配置

引入的依赖少

Spring可以不使用XML配置Bean,使用注解注解配置

核心功能

起步依赖

好处:导入一个依赖,这个依赖会引用其他依赖

自动配置

有默认的配置,启动的时候会使用默认的配置

包结构

Sping Boot 建议的包结构

root package 结构:cn.giftsstore.myProject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
myproject
-src
- main
- java
- cn.giftsstore.myProject
- comm
- domain
- repository
- service
- web
- Application.java
- resources
- static
- templates
- application.properties
- test
-pom.xml

各包名介绍

  • Application.java:建议放到根目录下面,是项目的启动类,Spring Boot 项目只能有一个 main() 方法。
  • comm:目录建议放置公共的类,如全局的配置文件、工具类等。
  • domain:目录主要用于实体(Entity)与数据访问层(Repository)。
  • repository:数据库访问层代码。
  • service:该层主要是业务类代码。
  • web:该层负责页面访问控制。
  • resources 目录下:
    • static:目录存放 Web 访问的静态资源,如 JS、CSS、图片等。
    • templates:目录存放页面模板(JSP,Thymeleaf)
    • application.properties:项目的配置信息。
    • test 目录存放单元测试的代码;pom.xml 用于配置项目依赖包,以及其他配置。

采用默认配置可以省去很多设置,当然也可以根据自己的喜好来进行更改。最后,启动 Application main 方法,至此一个 Java 项目搭建好了!

快速创建SpringBoot2.0工程

创建

测试

编写控制器

1
2
3
4
5
6
7
8
9
10
11
package com.itheima.controller;

import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;

@Controller public class QuickStartController {
@RequestMapping("/quick")
@ResponseBody
public String quick(){
return "springboot 访问成功!";
}
}

运行项目的启动类

1
2
3
4
5
6
7
8
9
10
11
12
package com.itheima;

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);
}

}

访问页面

打开浏览器访问url地址为:http://localhost:8080/quick

配置热部署

热启动会消耗系统性能,开启时慎重

我们在开发中反复修改类、页面等资源,每次修改后都是需要重新启动才生效,这样每次启动都很麻烦,浪费了大 量的时间,我们可以在修改代码后不重启就能生效,在 pom.xml 中添加如下配置就可以实现这样的功能,我们称 之为热部署

1
2
3
4
5
<!--热部署配置--> 
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

注意:IDEA进行SpringBoot热部署失败原因
出现这种情况,并不是热部署配置问题,其根本原因是因为Intellij IEDA默认情况下不会自动编译,需要对IDEA进 行自动编译的设置,如下

SpringBoot起步依赖原理分析

  • 在spring-boot-starter-parent中定义了各种技术的版本信息,组合了一套最优搭配的技术版本。

  • 在各种starter中,定义了完成该功能需要的坐标合集,其中大部分版本信息来自于父工程。

  • 我们的工程继承parent,引入starter后,通过依赖传递,就可以简单方便获得需要的jar包,并且不会存在版本冲突等问题。

application.yml配置文件

yml配置文件简介

SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用 application.properties或者application.yml(application.yaml)进行配置。

SpringBoot默认会从Resources目录下加载application.properties或application.yml(application.yaml)文件。其中,application.properties文件是键值对类型的文件,之前一直在使用,所以此处不在对properties文件的格式 进行阐述。除了properties文件外,SpringBoot还可以使用yml文件进行配置,下面对yml文件进行讲解。

YML文件格式是YAML (YAML Aint Markup Language)编写的文件格式,YAML是一种直观的能够被电脑识别的的数 据数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导 入,比如: C/C++, Ruby, Python, Java, Perl, C#, PHP等。YML文件是以数据为核心的,比传统的xml方式更加简 洁。
YML文件的扩展名可以使用.yml或者.yaml。

yml语法注意事项

  • 大小写敏感
  • 数据值前边必须有空格,作为分隔符
  • 使用缩进表示层级关系
  • 缩进时不允许使用Tab键,只允许使用空格(各个系统 Tab对应的 空格数目可能不同,导致层次混乱)。
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
  • ‘’#” 表示注释,从这个字符一直到行尾,都会被解析器忽略。

yml配置文件的语法

配置普通数据(纯量)

语法: key: value 示例代码

1
2
3
name: haohao
msg1: 'hello \n world' # 单引忽略转义字符
msg2: "hello \n world" # 双引识别转义字符

注意:value之前有一个空格

配置对象或者Map数据

语法:
key:
key1: value1
key2: value2
或者:
key: {key1: value1,key2: value2} 示例代码

1
2
3
4
5
6
person:  
name: haohao
age: 31
addr: beijing
#或者
person: {name: haohao,age: 31,addr: beijing}

注意:key1前面的空格个数不限定,在yml语法中,相同缩进代表同一个级别

配置数组、List、Set数据

语法:

1
2
3
4
5
key:
- value1
- value2
# 或者:
key: [value1,value2]

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
city:  
- beijing
- tianjin
- shanghai
- chongqing
# 或者
city: [beijing,tianjin,shanghai,chongqing]

# 集合中的元素是对象形式
student:
- name: zhangsan
age: 18
score: 100
- name: lisi
age: 28
score: 88
- name: wangwu
age: 38
score: 90

注意:value1与之间的 - 之间存在一个空格

参数引用

1
2
3
name: lisi 
person:
name: ${name} # 引用上边定义的name值

获取yml文件中的数据

方式1:使用@Value

我们可以通过@Value注解将配置文件中的值映射到一个Spring管理的Bean的字段上
例如:

application.yml配置

1
2
3
person:  
name: zhangsan
age: 18

java代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller 
public class QuickStartController {

@Value("${person.name}")
private String name;
@Value("${person.age}")
private Integer age;

@RequestMapping("/quick")
@ResponseBody
public String quick(){
return "springboot 访问成功! name="+name+",age="+age;
}
}

方式2:使用Evironment

application.yml配置

1
2
3
person:
name: tom
age: 23

java代码

1
2
3
4
5
6
7
8
9
10
@RestController
public class QuickController {
@Autowired
private Environment env;

@GetMapping("/getPropInfo")
public String getPropInfo(){
return "查询结果:"+env.getProperty("person.name");
}
}

方式3:使用@ConfigurationProperties

通过注解@ConfigurationProperties(prefix=”配置文件中的key的前缀”)可以将配置文件中的配置自动与实体进行映 射

application.yml配置

1
2
3
person:  
name: zhangsan
age: 18

java代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Controller 
@ConfigurationProperties(prefix = "person")
public class QuickStartController {
private String name;
private Integer age;
@RequestMapping("/quick")
@ResponseBody
public String quick(){
return "springboot 访问成功! name="+name+",age="+age;
}

public void setName(String name) {
this.name = name;
}

public void setAge(Integer age) {
this.age = age;
}
}

注意:使用@ConfigurationProperties方式可以进行配置文件与实体字段的自动映射,但需要字段必须提供set方 法才可以,而使用@Value注解修饰的字段不需要提供set方法

约定优于配置怎么体现的

SpringBoot解决了配置文件和业务逻辑不停切换的问题

使用SrpingBoot就不需要配置文件了,直接使用JAVA文件+注解开发

使用注解(约定)作为配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Configuration

public class MyFilterConfiguration {

@Bean

public FilterRegistrationBean myFilterRegistration() {

FilterRegistrationBean registration = new FilterRegistrationBean();

registration.setFilter(new MyFilter());//添加过滤器

registration.addUrlPatterns("/");//设置过滤路径,/所有路径

registration.addInitParameter("name", "alue");//添加默认参数

registration.setName("MyFilter");//设置优先级

registration.setOrder(1);//设置优先级

return registration;

}

}

使用xml(配置文件) 作为配置文件

  1. @Configuration和@Bean注解说明:

  2. @Configuration 标注在类上,相当于把该类作为spring的xml配置文件中的 <beans>,作用为:配置spring容器(应用上下文),上文中在MyFilterConfiguration类上添加了该注解,相当于创建了一个beans.xml配置文件里面的内容是

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd" default-lazy-init="false" >


    </beans>
  1. @Bean标注在方法上(返回某个实例的方法),等价于spring的xml配置文件中的<bean>,作用为:注册bean对象。
  • @Bean注解在返回实例的方法上,如果未通过@Bean指定bean的名称,则默认与标注的方法名相同。

  • @Bean注解默认作用域为单例singleton作用域,可通过@Scope(“prototype”)设置为原型作用域

    上文中在myFilterRegistration()方法上加了@Bean注解,表示在spring启动的时候会执行该方法并将结果作为一个bean注册到容器中,该bean的名字是”myFilterRegistration”

自动配置原理

  • META-INF\spring.fatories文件中定义了很多自动配置类;可以根据在pom.xml文件中添加的 启动器依赖自动配置组件 ctrl+shift+n 搜索spring.factories

  • 通过如下流程可以去修改application配置文件,改变自动配置的组件默认参数

使用Profile配置多种开发环境

我们在开发Spring Boot应用时,通常同一套程序会被安装到不同环境,比如 开发、测试、生产等。其中数据库地址、服务器端口等等配置都不同,如果每次打包时,都要修改配置文件,那么非常麻烦。profile功能就是来进行动态配置切换的。

功能

profile是用来完成不同环境下,配置动态切换功能

配置方式1

创建多个配置文件,在主配置文件中激活要使用的配置文件

​ application-dev.properties/yml 开发环境

​ application-test.properties/yml 测试环境

​ application-pro.properties/yml 生产环境

12

配置方式2

将不同环境的配置同时配置到一个yml文档中,称为(yml多文档方式).不同环境的配置使用—分割

13

profile激活方式

方式1

配置文件: 再配置文件中配置:spring.profiles.active=dev

请看配置方式1和配置方式2

方式2

虚拟机参数:在VM options 指定:-Dspring.profiles.active=dev

14

方式3

命令行参数:java –jar xxx.jar –spring.profiles.active=dev

15

SpringBoot与整合其他技术

整合SpringMVC以及配置

修改Tomcat端口号

1
2
3
#tomcat端口
server:
port: 80

静态资源存放目录

整合Mybatis

添加Mybatis的起步依

1
2
3
4
5
6
<!--mybatis起步依赖--> 
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>

添加数据库驱动坐标

1
2
3
4
5
<!-- MySQL连接驱动 --> 
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

添加数据库连接信息

在application.properties中添加数据量的连接信息

1
2
3
4
5
#DB Configuration: 
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

创建user表

1
2
3
4
5
6
7
8
9
10
11
12
-- ----------------------------- Table structure for `user` -- ---------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) 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=10 DEFAULT CHARSET=utf8;

-- ----------------------------- Records of user -- ---------------------------
INSERT INTO `user` VALUES ('1', 'zhangsan', '123', '张三');
INSERT INTO `user` VALUES ('2', 'lisi', '123', '李四');

创建实体Bean

1
2
3
4
5
6
7
8
9
10
11
public class User {    
// 主键
private Long id;
// 用户名
private String username;
// 密码
private String password;
// 姓名
private String name;
//此处省略getter和setter方法 .. ..
}

编写Mapper

1
2
3
4
@Mapper 
public interface UserMapper {
public List<User> queryUserList();
}

注意:@Mapper标记该类是一个mybatis的mapper接口,可以被spring boot自动扫描到spring上下文中

配置Mapper映射文件

在src\main\resources\mapper路径下加入UserMapper.xml配置文件”

1
2
3
4
5
6
7
<?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.itheima.mapper.UserMapper">
<select id="queryUserList" resultType="user">
select * from user
</select>
</mapper>

配置包扫描和配置文件映射

1
2
3
4
#spring集成Mybatis环境 #pojo别名扫描包 
mybatis.type-aliases-package=com.itheima.domain
#加载Mybatis映射文件
mybatis.mapper-locations=classpath:mapper/*Mapper.xml

编写测试Controller

1
2
3
4
5
6
7
8
9
10
11
12
@Controller 
public class MapperController {
@Autowired
private UserMapper userMapper;

@RequestMapping("/queryUser")
@ResponseBody
public List<User> queryUser(){
List<User> users = userMapper.queryUserList();
return users;
}
}

测试

8

集成MyBatis时遇到的问题

1.每一个Mapper类都需要写@Mapper注解,比较麻烦

​ 解决办法

​ 在启动类上加@MapperScan(“cn.itcast.demo.mapper”)//新增

​ 表示启动的时候会扫描该包下面所有的mapper.java文件,这样就不需要在为每一个XXXMpaer.java文件添加注解@Mapper了

2.The server time zone异常

​ 在配置文件的URL末尾追加参数&serverTimezone=UTC

3.报错:user找不到

​ 问题原因:程序启动的时候没有扫描到User类

​ 解决方案:修改配置文件type-aliases-package: cn.itcast.demo.domain

4.错误

​ maven错误

​ 修改mavent的setting.xml 修改仓库的地址

整合Junit

添加Junit的起步依赖

1
2
3
4
5
6
<!--测试的起步依赖--> 
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

编写测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.itheima.test;

import com.itheima.MySpringBootApplication;
import com.itheima.domain.User;
import com.itheima.mapper.UserMapper;
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 = MySpringBootApplication.class)
public class MapperTest {
@Autowired
private UserMapper userMapper;

@Test
public void test() {
List<User> users = userMapper.queryUserList();
System.out.println(users);
}
}

其中,SpringRunner继承自SpringJUnit4ClassRunner,使用哪一个Spring提供的测试测试引擎都可以

1
public final class SpringRunner extends SpringJUnit4ClassRunner

@SpringBootTest的属性指定的是引导类的字节码对象

整合Redis

添加redis的起步依赖

1
2
3
4
5
<!-- 配置使用redis启动器 --> 
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置redis的连接信息

1
2
3
#Redis 
spring.redis.host=127.0.0.1
spring.redis.port=6379

注入RedisTemplate测试redis操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@RunWith(SpringRunner.class) 
@SpringBootTest(classes = SpringbootJpaApplication.class)
public class RedisTest {

@Autowired
private UserRepository userRepository;

@Autowired
private RedisTemplate<String, String> redisTemplate;

@Test
public void test() throws JsonProcessingException {
//从redis缓存中获得指定的数据
String userListData = redisTemplate.boundValueOps("user.findAll").get(); //如果redis中没有数据的话
if(null==userListData){
//查询数据库获得数据
List<User> all = userRepository.findAll();
//转换成json格式字符串
ObjectMapper om = new ObjectMapper();
userListData = om.writeValueAsString(all);
//将数据存储到redis中,下次在查询直接从redis中获得数据,不用在查询数据库
redisTemplate.boundValueOps("user.findAll").set(userListData);
System.out.println("===============从数据库获得数据===============");
}else{
System.out.println("===============从redis缓存中获得数据===============");
}
System.out.println(userListData);
}

}

整合SpringDataJpa

添加Spring Data JPA的起步依赖

1
2
3
4
5
<!-- springBoot JPA的起步依赖 --> 
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

添加数据库驱动依赖

1
2
3
4
5
<!-- MySQL连接驱动 --> 
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

在application.properties中配置数据库和jpa的相关属性

1
2
3
4
5
6
7
8
9
10
11
#DB Configuration: 
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 Configuration:
spring.jpa.database=MySQL
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy

创建实体配置实体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Entity
public class User {
// 主键
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 用户名
private String username;
// 密码
private String password;
// 姓名
private String name;

//此处省略setter和getter方法... ...
}

编写UserRepository

1
2
3
public interface UserRepository extends JpaRepository<User,Long>{    
public List<User> findAll();
}

编写测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith(SpringRunner.class) 
@SpringBootTest(classes=MySpringBootApplication.class)
public class JpaTest {

@Autowired
private UserRepository userRepository;

@Test
public void test(){
List<User> users = userRepository.findAll();
System.out.println(users);
}
}

控制台打印信息

如果使用JDK1.9 会报异常ClassNotFoundException:javax.xml.bind.JAXBException

原因缺少jar

解决办法导入依赖

1
2
3
4
5
6
<!--jdk9需要导入如下坐标--> 
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>

SpringBoot启动流程

核心分为2个步骤

第一步: 创建SpringApplication对象

第二步: 调用SpringApplication对象的run方法启动同时返回当前容器上下文

分析流程

1.创建SpringApplication对象时会初始化Springboot容器

2.获取当前应用启动类型。原理:判断当前classpath是否有加载我们的servlet类返回servlet web启动方式

​ WebApplicationType有三种类型

​ a) REACTIVE 响应式WEB启动(Spring5.0新特性,基于NETTY)

​ b) NONE 不会嵌入WEB容器启动,如果需要将springboot项目放入外部服务器,则使用该种方式启动

​ c) SERVLET 基于WEB容器启动

3.setInitializers()方法读取SpringBoot包下麦呢的META-INF/spring.factories,获取到对应ApplicationContextInitializer装配到集合

4.setListeners()方法读取SpringBoot包下麦呢的META-INF/spring.factories,获取到对应ApplicationListiner装配到集合

5.mainApplicationClass获取当前运行的主函数。

6.调用SpringApplication的run方法实现启动

7.StopWatch stopWatch = new StopWatch(); 记录SpringBoot项目启动时间

文章作者: 微信:hao_yongliang
文章链接: https://haoyongliang.gitee.io/2019/07/13/SpringBoot/SpringBoot2.X%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 郝永亮的主页
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论