什么是SpringBoot

Spring的发展史:Spring是2003年兴起的一个轻量级的Java开源框架,这个框架最初是为了解决企业级应用开发笨重臃肿的问题,宗旨就是简化开发; SpringBoot的诞生:随着Spring越来越火,Spring也慢慢从一个小而精的框架变成了一个覆盖面广又全的框架,大量繁琐的XML配置和第三方整合配置,让Spring使用者痛苦不已,这个时候急需一个解决方案来解决这些问题,故SpringBoot应运而生,2013年SpringBoot开始研发,2014年4月Spring Boot1.0正式发布

  • SpringBoot对于Spring来说是一套全新的框架,它来自于Spring大家族,因此Spring所有具备的功能它都有并且更容易使用;同时还简化了基于Spring的应用开发,通过少量的代码就能创建一个独立的、产品级别的Spring应用.
  • SpringBoot默认配置了很多框架的使用方式,就像Maven整合了所有的jar包,SpringBoot整合了所有的框架.它的核心设计思想是:约定优于配置,SpringBoot所有开发细节都是依据此思想进行实现的.

Springboot 特性

  • 搭建项目快,几秒钟就可以搭建完成
  • 没有冗余代码生成和XML配置的要求
  • 开箱即用,提供各种默认配置来简化项目配置
  • 内嵌容器,省去了配置Tomcat的繁琐
  • Starter自动依赖和版本控制
  • 方便监控,使用Spring Boot Actuator组件提供了应用的系统监控,可以查看应用配置的详细信息

单体架构与微服务架构

微服务是一种架构风格,它要求我们在开发一个应用的时候,这个应用必须构建成一系列小服务的组合;可以通过http的方式进行互通.

  • 什么是单体架构

    所谓单体应用架构(all in one)是指我们将一个应用的中的所有服务封装在一个应用中.无论是ERP、CRM或是其他什么系统,都把数据库访问、WEB访问,等等各个功能放到一个war包内.

  • 单体架构优缺点

    优点:易于开发和测试;十分方便部署;当需要扩展时,只需要将war复制多酚,然后放到多个服务器上,再做个负载均衡就可以了 缺点:项目过于臃肿;资源无法隔离;无法灵活扩展

  • 什么是微服务架构

    所谓微服务架构,就是打破之前all in one的架构方式,把每个功能元素独立出来.把独立出来的功能元素的动态组合,需要的功能元素才去拿来组合,需要多一些时可以整合多个功能元素.所以微服务架构是对功能元素进行复制,而没有对整个应用进行复制

  • 微服务架构优点

    节省了调用资源.每个功能元素的服务都是一个可以替换的、可独立升级的软件代码.

下图可以更好的来分辨单体架构和微服务架构 区别图:
左侧是单体架构,将所有的功能都放到一个容器里面;右侧是微服务架构将功能单独出来进行动态组合.
image.png
如何构建微服务

  • 一个大型系统的微服务架构,就像一个复杂交织的神经网络,每一个神经元就是一个功能元素,它们各自完成自己的功能,然后通过http或者RPC相互请求调用.但这种庞大但系统架构部署和运维带来很大的难度,于是Spring为我们带来了构建大型分布式微服务的全套、全程产品:

    • 构建一个个功能独立的微服务应用单元,可以使用Springboot 可以帮我们快速构建一个应用;
    • 大型分布式网络服务的调用,这部分由Spring cloud来完成,实现分布式.
    • 在分布式中间,进行流式数据计算、批处理,采用spring cloud data flow.

      快速入门SpringBoot

      Maven配置

      在下载的maven包中,找到/conf/setting.xml 进行配置localRepository:本地资源路径可以使用默认的也可以自己配置路径,然后配置jdk版本.
      1. <localRepository>/xx/path</localRepository>
      2. <profile>
      3. <id>JDK-1.8</id>
      4. <activation>
      5. <activeByDefault>true</activeByDefault>
      6. <jdk>1.8</jdk>
      7. </activation>
      8. <properties>
      9. <maven.compiler.source>1.8</maven.compiler.source>
      10. <maven.compiler.target>1.8</maven.compiler.target>
      11. <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
      12. </properties>
      13. </profile>
      然后在IDE中进行配置
      image.png

      创建Spring Boot项目

      创建Springboot的两种方式:
  • Spring 官网下载 https://start.spring.io/

  • IDEA 实现 springboot

这里通过IDEA来创建Spring Boot项目,其实IDEA创建Springboot项目就是使用Spring Initializr
image.png
之后选择,要集成的框架即可
image.png

Spring Boot结构说明

项目结构如下:Application类为Spring Boot项目的启动类.resources/static 静态资源文件 resources/templates html模版 application.properties或者application.yml 项目的配置文件.target目录会生成class文件和jar/war包
image.png
pom文件说明

  • 项目元数据信息:创建时候输入的Project Metadata部分,也就是Maven项目的基本元素,包括:groupId、artifactId、version、name、description等
  • parent:集成spring-boot-starter-parent的依赖管理,控制版本与打包依赖等功能
  • dependencies:项目具体依赖
  • build:构建配置部分.默认使用了spring-boot-maven-plugin,配合spring-boot-starter-parent就可以把Spring Boot应用打成JAR来直接运行 ```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

    1. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    4.0.0

      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.2.6.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
    

    com.example.springboot.hello springboot-hello 0.0.1-SNAPSHOT springboot-hello

    Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine org.springframework.boot spring-boot-maven-plugin

点击右侧的Maven,显示如下:点击package即可进行打包<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/375694/1588922045743-0b0ff26b-a96f-4ac0-9a88-9abacf0bde6a.png#align=left&display=inline&height=273&margin=%5Bobject%20Object%5D&name=image.png&originHeight=546&originWidth=364&size=39581&status=done&style=none&width=182)<br />使用Springboot plugin打包 java -jar xxxxx.jar 直接运行Springboot的jar包即可访问

<a name="eTx0c"></a>
### Spring Boot 启动原理分析
如下代码,是Spring Boot的启动类,关键地方在@SpringBootApplication注解,如果去掉这个注解就无法启动项目
```java
@SpringBootApplication //Spring boot 启动类注解
    //如果去掉注解 则无法启动
public class SpringbootHelloApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootHelloApplication.class, args);
    }

}

在这个注解上,还有着其他注解分别是:@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {.....}

@SpringBootConfiguration :Springboot的配置类 -》 @Configuration :标明这是一个配置类 @EnableAutoConfiguration:开启自动配置功能 -> @AutoConfigurationPackage:自动配置包:在当前类的约定的包下进行扫描 如果不是约定的基础包那么无法加载Spring容器中 @Import(AutoConfigurationPackages.Registrar.class):包启动类所在的包进行默认扫描,该包下的所有的类都会被扫描到Spring容器中进行管理 @Import({AutoConfigurationImportSelector.class}):加载指定的类到Spring容器中去 AutoConfigurationImportSelector:自动配置导入选择器 根据项目来判断你的项目需要哪些配置信息,然后把默认的配置内容导入Spring容器进行管理 @ComponentScan:组件扫描和自动装配,用来指定扫描容器的范围

如下图所示: 目前先了解大体的流程即可,知道Springboot启动的时候做了什么,后续会进行详细的讲解,不要一下深入源码无法自拔了
image.png

Spring Boot 配置说明

Springboot 配置文件

  • Springboot为什么还需要配置文件

    1. 方便修改默认配置
    2. 其他信息保存在配置文件中
  • Springboot配置文件有哪些

    1. properties配置文件
    2. yml配置文件
    3. 如果同时存在properties和yml同时存在,优先properties生效 yml不生效
  • Springboot配置文件

    1. 文件放在src/main/resources/目录或者类路径/config目录下(不推荐)
    2. Springboot默认读取application开头的配置文件

如下默认的application.properties的配置文件,修改默认的端口号

#如果同时存在properties和yml同时存在,优先properties生效 yml不生效
# 优先级 properties > yml
#修改默认端口号 8080
server.port=8088

yml 配置文件

yml的全称为YAML(YAML Ain’t Markup Language) 它是一种标记语言,它是一种直观的被电脑识别的数据序列化格式,并且容易被人类阅读,这种标记语言与其他标记语言不同的地方是,它是以数据为中心,比json、xml等更适合做配置文件.

如下书写格式: 新建application.yml

server:
  port: 8089 #yml 修改端口号
person:
  name: zhangsan
  age: 19
  sex: nan
  isMerried: false
#  friend:
#    name: lisi
#    sex: nv
  friend: {name: lisi,sex: nv}
#  pets:
#    - 小狗
#    - 小猫
#    - 小驴
  pets: [小猫,小狗,小驴]
  friends: [{name: lisi,sex: nv},{name: wangwu,sex: nan}]

yml文件的语法说明:

  • yml的基本语法
    • key: value的格式(value前面的空格不能少,可以有多个,不能用tab替代);
    • 大小写敏感
    • 字符串默认不需要使用引号,单引号和双引号的区别在于是否能用转义字符;
    • 注释方式:#
  • yml支持的三种数据类型
    • 字面量:直接量,单个不能被拆分的值(数字、字符串、布尔)
    • 对象: 键值对形式存在
    • 数组:字面量/对象的集合

读取yml文件的配置信息
如下核心代码,这里省去了setter/getter 和toString 这些重复的代码,加载配置文件主要时配置@ConfigurationProperties 注解,perfix是配置文件的前缀名

@Component
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    private String sex;
    private boolean isMerried;
    private Friend friend;
    private String[] pets;
    private List<Friend> friends;
}

测试:
@SpringBootTest
class SpringbootHelloApplicationTests {

    @Autowired
    private Person person;

    @Test
    void contextLoads() {
        System.out.println(person);
    }

}

输出如下:

Person{name=’zhangsan’, age=19, sex=’nan’, isMerried=false, friend=Friend{name=’lisi’, sex=’nv’}, pets=[小猫, 小狗, 小驴], friends=[Friend{name=’lisi’, sex=’nv’}, Friend{name=’万物’, sex=’nan’}]}

读取properties文件配置信息,如下properties要比yml复杂的多

person1.name=zhangsan
person1.age=19
person1.sex=nan
person1.isMerried:false
person1.pets[0]=小猫
person1.pets[1]=小狗
person1.pets[2]=小驴
person1.friends[0].name=lisi
person1.friends[0].sex=nv
person1.friends[1].name=万物
person1.friends[1].sex=nan
person1.friend.name=lisi
person1.friend.sex=nv

只需要将Person类的注解ConfigurationProperties进行修改即可

@ConfigurationProperties(prefix = "person1")

输出结果:

Person{name=’zhangsan’, age=19, sex=’nan’, isMerried=false, friend=Friend{name=’lisi’, sex=’nv’}, pets=[小猫, 小狗, 小驴], friends=[Friend{name=’lisi’, sex=’nv’}, Friend{name=’万物’, sex=’nan’}]}

如果遇到中文没有显示出来多问题修改:
image.png
如果我们想只读取某一个属性如何呢? 通过@Value可以更加灵活多获取配置信息

只读取配置文件某些属性

实现如下,这时候就不需要使用@ConfigurationProperties注解了,在类中哪个属性需要通过@Value灵活的获取配置信息

@Component
//@ConfigurationProperties(prefix = "person1")
public class Person {
    @Value("${person.name}")
    private String name;
    @Value("${person.age}")
    private Integer age;
    @Value("#{11*2}")
    private String sex;
    private boolean isMerried;
    private Friend friend;
    private String[] pets;
    private List<Friend> friends;
}

输出结果如下:

Person{name=’zhangsan’, age=19, sex=’22’, isMerried=false, friend=null, pets=null, friends=null}

无论是@Value还是@ConfigurationProperties可以根据编码的实际情况进行使用.

如何读取自定义的properties文件配置信息呢?

首先在resources目录下创建person2.properties文件

person2.name=zhangsan
person2.age=19
person2.sex=nan
person2.isMerried:false
person2.pets[0]=小猫
person2.pets[1]=小狗
person2.pets[2]=小驴
person1.friends[0].name=lisi
person1.friends[0].sex=nv
person1.friends[1].name=万物
person1.friends[1].sex=nan
person1.friend.name=lisi
person1.friend.sex=nv

使用@PropertySource注解指定自定义的properties文件

@Component
@ConfigurationProperties(prefix = "person2")
@PropertySource("classpath:person2.properties")
public class Person {
    private String name;
    private Integer age;
    private String sex;
    private boolean isMerried;
    private Friend friend;
    private String[] pets;
    private List<Friend> friends;

结果如下,成功读取到了自定义的配置文件

Person{name=’zhangsan’, age=19, sex=’nan’, isMerried=false, friend=Friend{name=’lisi’, sex=’nv’}, pets=[小猫, 小狗, 小驴], friends=[Friend{name=’lisi’, sex=’nv’}, Friend{name=’万物’, sex=’nan’}]}

Spring Boot 进行Web开发

RESTful

image.png

使用JPA

Spring DATA REST

http://localhost:8080/ 请求项目就会返回如下信息
image.png
请求 : http://localhost:8080/users 会返回如下的信息,用户的所有信息
image.png

自动实现的分页请求

同时可以去请求分页:http://localhost:8080/users?page=1&size=2 会自动帮我们进行分页
image.png
还可以对分页的数据进行排序:http://localhost:8080/users?page=1&size=3&sort=id,desc
image.png

根据条件进行查询

包括查询某一条的用户信息: http://localhost:8080/users/1 默认支持ID的查找
image.png

如果要通过username进行查找需要进行配置:

@RepositoryRestResource(path = "users")
public interface UserRepository extends JpaRepository<User, Integer> {
    User findByUsername(@Param("username") String username);
}

http://localhost:8080/users/search 可以查询你自己定义的请求,如下就可以进行使用,它会告诉你如何进行请求
image.png
http://localhost:8080/users/search/findByUsername?username=张三

{
    "username": "张三",
    "password": "aaaaa",
    "name": "zzsaan",
    "_links": {
        "self": {
            "href": "http://localhost:8080/users/1"
        },
        "user": {
            "href": "http://localhost:8080/users/1"
        }
    }
}

POST请求

当我们发送post请求:http://localhost:8080/users?username=张三&password=111111&name=zhangsan 去向数据库添加一条记录
会报400的错误这是为什么呢?

{
    "cause": {
        "cause": null,
        "message": "No content to map due to end-of-input\n at [Source: (org.apache.catalina.connector.CoyoteInputStream); line: 1, column: 0]"
    },
    "message": "JSON parse error: No content to map due to end-of-input; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input\n at [Source: (org.apache.catalina.connector.CoyoteInputStream); line: 1, column: 0]"
}

header 需要设置:Content-Type:application/json;charset=UTF-8
发送body:

{"username":"张三","password":"aaaaa","name":"zzsaan"}

这样就请求成功了

{
    "username": "张三",
    "password": "aaaaa",
    "name": "zzsaan",
    "_links": {
        "self": {
            "href": "http://localhost:8080/users/0"
        },
        "user": {
            "href": "http://localhost:8080/users/0"
        }
    }
}

添加ID 进行修改数据

{"id":8,"username":"长瘤","password":"bbbbbb","name":"zhangliu"}

如下数据修改成功了
image.png

PUT请求

put请求:http://localhost:8080/users/8 后面必须要加上主键ID

{"username":"长瘤1","password":"bbbbbb1"}

如下,如果我们只想要修改username和password,但是put进行了全局的修改包括post
image.png

PATCH请求

patch请求:http://localhost:8080/users/8 同样还是只修改用户名和密码,在数据库中加上name

{"username":"长瘤1","password":"bbbbbb1"}

运行结果如下: 可见patch请求可以实现对小范围的修改

{
    "username": "长瘤1",
    "password": "bbbbbb1",
    "name": "sjdsj",
    "_links": {
        "self": {
            "href": "http://localhost:8080/users/8"
        },
        "user": {
            "href": "http://localhost:8080/users/8"
        }
    }
}

:::tips post和put都会进行全局修改而patch可以进行指定的字段修改 :::