SpringBoot详解

SpringBoot 详解

一、进入微服务阶段

javase :OOP

mysql : 持久化

html+css+js+jquery+框架 :视图,框架不熟练,css不好

javaweb:独立开发MVC三层架构的网站:原始

ssm:框架:简化了我们的开发流程,配置也开始较为复杂

war包:Tomcat运行

微服务阶段:

spring再简化:SpringBoot ,jar‘包:内嵌tomcat; 微服务架构

服务越来越多:springcloud

二、什么是SpringBoot

  1. 什么是Spring

Spring是一个开源框架,Spirng是为了解决企业级应用开发的复杂性而创建的,简化开发。

  1. Spring是如何简化Java开发的

为了降低Java开发的复杂性,Spring采用了以下4种关键策略:

  • 基于POJO的轻量级和最小侵入性编程
  • 通过IOC,依赖注入(DI)和面向接口实现松耦合
  • 基于切面(AOP)和惯例进行声明式编程
  • 通过切面和模板减少样式代码
  1. 什么是SpringBoot

SpringBoot ,就是一个javaweb的开发框架,简化开发,约定大于配置,能迅速的开发web应用。

随着Spring不断的发展,涉及的领域越来越多,项目整合开发需要配合各种各样的文件,慢慢变得不那么易用简单,人称配置地域。Spring Boot 正是在这样的一个背景下被抽象出来的开发框架,目的为了让大家更容易的使用Spring、更容易集成各种常用的中间件、开源软件;

Spring Boot 基于Spring开发,SpringBoot 本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷的开发新一代基于Spring框架的应用程序,也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发体验的工具。

Spring Boot的主要优点:

  • 为所有Spring开发者更快的入门
  • 开箱即用 ,提供各种默认配置来简化项目配置
  • 内嵌式容器简化Web项目
  • 没有冗余代码生成和XML配置的要求

三、什么是微服务架构

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

是指,我们将一个应用中的所有应用服务都封装在一个应用中

  • 这样做的好处是,易于测试和开发;也十分方便部署;当需要扩展时,只需要将war复制多份,然后放到多个服务器上,再做个负载均衡就可以了
  • 单体应用架构的缺点是,哪怕我要修改一个非常小的地方,我都需要停掉整个服务,重新打包、部署这个应用war包。特别是对于一个大型应用,我们不可能把所有内容都放在一个应用里面,我们如何维护、如何分工合作都是问题
  1. 微服务架构

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

这样做的好处是:

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

这种庞大的系统架构给部署和运维带来很大的难度,于是Spring为我们带来了构建大型分布式微服务的全套、全程产品:

  • 构建一个个独立的微服务应用单元,可以使用springboot,可以帮我们快速构建一个应用
  • 大型分布式网络服务的调用,这部分由spring cloud 来完成,实现分布式
  • 在分布式中间,进行流式数据计算、批处理 ,我们有spring cloud data flow
  • spring 为我们想清楚了整个从开始构建应用到大型分布式应用全流程方案

四、学习SpringBoot

1)第一个SpringBoot程序

  1. 环境:
  • jdk1.8
  • maven3.6.1
  • springboot :最新版
  • IDEA
  1. 创建
  • 可以在官网直接下载后,导入idea开发
  • 直接使用idea创建一个springboot项目(一般开发直接在idea中创建)
  1. 核心文件
  • application
package com.example.springboot01;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//本身就是spring的一个组件
//程序的主入口
@SpringBootApplication
public class Springboot01Application {

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

}

  • properties

是springboot的核心配置文件

  • ApplicationTest
package com.example.springboot01;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

//单元测试
@SpringBootTest
class Springboot01ApplicationTests {

    @Test
    void contextLoads() {
    }

}

  • pom.xml

<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.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.7.2version>
        <relativePath/> 
    parent>
    <groupId>com.examplegroupId>
    <artifactId>springboot-01artifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>springboot-01name>
    <description>springboot-01description>
    <properties>
        <java.version>1.8java.version>
    properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    dependencies>

    <build>

        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

project>

parent:继承spring-boot-starter-parent的依赖管理,控制版本与打包等内容

dependencies:项目具体依赖 spring-boot-starter-web 用于实现HTTP接口,该依赖中包含了springMVC,即“使用SpringMVC构建WEB应用程序,使用Tomcat作为默认嵌入式容器”

  1. 编写Http接口
  • 在于Application同级目录下创建controller层、dao层、pojo层、service层
  • 写HelloController.java
package com.example.springboot01.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

//自动装配
@RestController
public class HelloController {
    //接口:http://localhost:8080/hello
    @RequestMapping("/hello")
    public String hello(){
        //调用业务,接收前端的参数!
        return "hello,World";
    }
}

  • 启动测试
  1. 修改端口号

在配置文件中application.properties

server.port=8081

即可修改当前程序端口号

  1. 修改banner ,就是运行程序下面弹出来的图片
  • 网上搜修改springboot banner的网站
  • 拿到自己想要的图片对应的ascii码
  • 在resource文件夹下创建banner.txt,将其复制进去,重启,即可看到banner变成了自己喜欢的

2)原理初探

自动配置

  1. pom.xml
  • 继承spring-boot-starter-parent,而spring-boot-starter-parent又继承spring-boot-dependencies,spring-boot-dependencies是核心依赖
  • 我们在写或者引入一些springbboot依赖的时候不需要指定版本号,因为有这些版本仓库
  • 启动器
 <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
  • 启动器:说白了就是springboot的启动场景
  • 比如spring-boot-starter-web,它会自动导入web环境所有的依赖
  • springboot会将所有的功能场景,都变成一个个的启动器
  • 我们要使用说明功能,就只需要找到对应的启动器就行 starter
  1. 主程序
  • @SpringBootApplication:标注这个类是一个springboot的应用:启动类下的所有资源被导入

  • 点进去@SpringBootApplication:

    • @SpringBootConfiguration:springboot的配置:

      • @configuration:是spring的一个配置---->@component :说明这也是spring的一个组件
    • @EnableAutoConfiguration:自动导入包

      • @AutoConfigurationPackage:自动配置包,>@Import({AutoConfigurationPackages.Registrar.class}):导入选择器:自动配置‘包注册’

      • @Import({AutoConfigurationImportSelector.class}):导入选择器:自动配置选择器

      • protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
                List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
                ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
                Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
                return configurations;
            }
        //获取候选的配置
        
    • @ComponentScan :扫描当前主启动类同级的包

  • 结论:springboot所有自动配置都是在启动的时候扫描并加载:所有的自动配置类都在spring.factories里面,但是不一定生效,要判断条件是否成立----只有导入了对应的start,有对应的启动器,我们的自动装配才会生效,然后才配置成功。

  1. 过程:
  • springboot在启动的时候,从类路径下\META-INF\spring.factories获取指定的值
  • 将这些自动配置的类导入容器,自动配置就会生效,帮我们进行自动配置
  • 以前我们需要自动配置的东西,现在springboot帮我们做了
  • 整合javaee,解决方案和自动配置的东西都在\spring-boot-autoconfigure\2.7.2\spring-boot-autoconfigure-2.7.2.jar这个包下
  • 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
  • 容器中也会存在非常多的xxxAutoConfiguration的文件(@Bean),就是这些类个容器中导入了这个场景需要的所有组件;并自动配置,@Configuration -----JavaConfig
  • 有了自动配置;类,免去了我们手动编写配置文件的工作!

3)了解主启动类怎么运行

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

}

   
  • 该方法返回一个ConfigurableApplicationContext对象
  1. SpringApplication.run
  • SpringApplication的实例化

这个类主要做了以下四件事

1)推断应用的类型是普通的项目还是Web项目

2)查找并加载所有可用初始化器,设置到initializers属性中

3)找出所有的应用程序监听器,设置到listeners属性中

4)推断并设置main方法的定义类,找到运行的主类

  • run()方法

4)yaml语法讲解

ps:创建springboot项目时,url报错,解决方案:

  • 改成阿里云镜像:https://start.aliyun.com/ (推荐好用)
  • 降springboot版本
  1. 配置文件

Springboot使用一个全局的配置文件,配置文件名称是固定的

  • application.properties

    • 语法结构: key=value
  • application.yml

    • 语法结构: key:空格 value
  • 配置文件的作用:修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了

  1. YAML
  • 标记语言

以前的配置文件,大多数都是使用xml来配置,比如一个简单的端口配置,对比xml和yaml

xml:

<server>
	<port>8081port>
server>

yaml:

server:
	port: 8080
  1. YAML语法
  • key:空格 value (一定要有空格)
  • 对象

基础语法

server:
  port: 8081
#对空格的要求很严格
  # 对象
  student:
    name: xqh
    age: 3
    
    
  # 行内写法
  
  person: {name:xqh,age:3}
  
  #数组
  pets:
    - cat
    - dog
    - pig
    
  pets1: [cat,dog,pig]

5)给属性赋值的几种方法

  • 通过@Value

实体类Dog.java

package com.example.pojo;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

//成为spring的组件
@Component
public class Dog {
    @Value("旺财")
    private String name;
    @Value("3")
    private Integer age;


    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试类

package com.example;

import com.example.pojo.Dog;
import com.example.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Springboot02ApplicationTests {
    @Autowired
    private Dog dog;

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

}

//输出结果:Dog{name=‘旺财’, age=3}

  • 通过配置文件.yml

实体类Person.java

package com.example.pojo;


import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Component  //注册bean
@ConfigurationProperties(prefix = "person")
//@ConfigurationProperties作用:
//将配置文件中的每一个属性的值,映射到这个组件中;告诉springboot将本类中的所有属性和配置文件中相关的配置进行绑定;
//参数prefix=“person” :将配置文件中的person下面的的所有属性一一对应
//只有这个组件是容器中的组件,才能使用@ConfigurationProperties,所以要先@Component,让它成为spring的组件
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object>maps;
    private List<Object>lists;
    private Dog dog;

    public Person() {
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public Boolean getHappy() {
        return happy;
    }

    public void setHappy(Boolean happy) {
        this.happy = happy;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public List<Object> getLists() {
        return lists;
    }

    public void setLists(List<Object> lists) {
        this.lists = lists;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", happy=" + happy +
                ", birth=" + birth +
                ", maps=" + maps +
                ", lists=" + lists +
                ", dog=" + dog +
                '}';
    }
}

配置文件 application.yml

person:
  name: qinjiang
  age: 3
  happy: false
  birth: 2019/11/2
  maps: {k1: v1,k2: v2}
  lists:
    - code
    - music
    - girl

  dog:
    name: 旺财
    age: 3

测试:

package com.example;

import com.example.pojo.Dog;
import com.example.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Springboot02ApplicationTests {
    @Autowired
    private Person person;

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

}

//结果:Person{name=‘qinjiang’, age=3, happy=false, birth=Sat Nov 02 00:00:00 CST 2019, maps={k1=v1, k2=v2}, lists=[code, music, girl], dog=Dog{name=‘旺财’, age=3}}

  • 通过配置文件.properties

实体类Person.java

package com.example.pojo;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

@Component  //注册bean
//加载指定的配置文件
@PropertySource(value = "classpath:person.properties")
public class Person {
    @Value("${name}")
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object>maps;
    private List<Object>lists;
    private Dog dog;

    public Person() {
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public Boolean getHappy() {
        return happy;
    }

    public void setHappy(Boolean happy) {
        this.happy = happy;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    public List<Object> getLists() {
        return lists;
    }

    public void setLists(List<Object> lists) {
        this.lists = lists;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", happy=" + happy +
                ", birth=" + birth +
                ", maps=" + maps +
                ", lists=" + lists +
                ", dog=" + dog +
                '}';
    }
}

配置文件.properties

name=xqh

测试

package com.example;

import com.example.pojo.Dog;
import com.example.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Springboot02ApplicationTests {
    @Autowired
    private Person person;

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

}

  • 推荐使用yaml配置文件来给属性赋值,更方便。
  1. @ConfigurationProperties 和 @Value 对比
  • 前者支持批量注入配置文件的属性,而后者只能一个一个指定
  • 前者支持松散绑定,后者不支持

松散绑定:即便是实体类中属性名为firstName,而配置文件中写的first-name,一样可以进行绑定

  • 前者支持JSR303数据校验,后者不支持

  • 前者支持复杂类型封装,后者不支持。如yaml中可以封装对象,而@value就不行

  1. 结论:
  • 配置yml和配置properties都可以获取到值,强烈推荐使用yaml
  • 如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下@value
  • 如果我们专门编写了一个JavaBean来和配置文件进行映射,就直接使用@ConfigurationProperties

6)JSR303数据校验

JSR303数据校验:我们可以在字段增加一层过滤器验证,可以保证数据的合法性

@Validated //数据校验
public class Person {
    @Email(message="邮箱格式错误")  //这样后,如果配置文件中对应的属性赋值不是email的话,就会报错

    private String name;

常用校验注解:

1、空检查

Constraint 详细信息
@Null 验证对象是否为null
@NotNull 验证对象是否不为null,无法检查长度为0的字符串
@NotBlank 检查约束字符串是不是NULL还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格。
@NotEmpty 检查约束元素是否为NULL或者EMPTY.

2、Boolean检查

Constraint 详细信息
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false

3、长度检查

Constraint 详细信息
@Size(min=,max=) 验证对象(Array,Collection,Map,String) 长度是否在给定方位之内
@Length(min=,max=) Validates that the annotated string is between min and max included.

4、日期检查

Constraint 详细信息
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern 验证 String 对象是否符号正则表达式的规则 : 正则表达式

7)多环境配置及配置文件位置

  1. 配置文件位置:
  • 项目根目录下建config文件夹(与src同级),在config文件夹内写配置文件
  • 在项目根目录下直接写配置文件
  • 在resource文件夹下建config文件夹,再在config文件夹下写配置文件
  • 直接在resource文件夹里写配置文件(一创建好springboot项目的默认配置文件位置)
  1. 不同配置文件位置的优先级:

项目下config文件夹内的配置文件 > 项目下的配置文件 > resource文件夹下的config文件夹内的配置文件 >resource文件夹下的配置文件

  1. 多环境配置
  • 可以选择激活哪一个配置文件

第一种方法分开文件写

真实开发环境中,比如有application.yml , application-dev.yml , application-test.yml三个不同环境下的配置文件

application.yml

spring.profiles.active: dev

即可切换到使用application-dev.yml配置文件

第二种方法,在一个文件中写(因为yaml可以模块化配置)

application.yml

server:
  port: 8080
spring:
  profiles:
    active: dev

---
server:
  port: 8082
spring:
  profiles: dev

---
server:
  port: 8081
spring:
  profiles: test

用—分隔开不同环境下

8)自动配置原理再理解

配置文件到底能写什么-----联系------spring.factories(在spring-boot-autoconfigure\2.3.7.RELEASE\spring-boot-autoconfigure-2.3.7.RELEASE.jar!\META-INF\spring.factories)

  1. 点开spring.factories,比如在spring.factories中的一条配置代码,org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,点开HttpEncodingAutoConfiguration
  2. HttpEncodingAutoConfiguration
//表示这是一个配置类
@Configuration(
    proxyBeanMethods = false
)
//自动装配属性:ServerProperties
@EnableConfigurationProperties({ServerProperties.class})

//spring的底层注解:根据不同的条件,来判断当前配置或者类是否生效
@ConditionalOnWebApplication(
    type = Type.SERVLET
)//是不是这个类型
@ConditionalOnClass({CharacterEncodingFilter.class}) //是否存在这个字符编码过滤器
@ConditionalOnProperty(
    prefix = "server.servlet.encoding",
    value = {"enabled"},
    matchIfMissing = true
)//是否存在这些配置
  1. 点进ServerProperties
@ConfigurationProperties(
//配置前缀是server
    prefix = "server",
    ignoreUnknownFields = true

)

public class ServerProperties {
//这些属性就是配置文件中能配置的属性
    private Integer port;
    private InetAddress address;
    @NestedConfigurationProperty
    private final ErrorProperties error = new ErrorProperties();
    private ForwardHeadersStrategy forwardHeadersStrategy;
    private String serverHeader;
    private DataSize maxHttpHeaderSize = DataSize.ofKilobytes(8L);
    private Shutdown shutdown;
    @NestedConfigurationProperty
    private Ssl ssl;
    @NestedConfigurationProperty
    private final Compression compression;
    @NestedConfigurationProperty
    private final Http2 http2;
    private final Servlet servlet;
    private final Tomcat tomcat;
    private final Jetty jetty;
    private final Netty netty;
    private final Undertow undertow;
...


  1. 对应着application.yml中能够配置的东西,对应着server前缀下的能配置的所有属性
server:
  port:
  server-header:
  address:
  forward-headers-strategy: 
  
  ...
  1. @Conditional扩展注解

作用:判断是否满足当前指定条件,后缀不同对应着不同条件

  1. 在我们这配置文件中能配置的东西,都存在一个固有规律,对应着 xxxAutoConfiguration中的xxxProperties中的属性,配置文件绑定。

  2. 自动装配原理再总结

  • SpringBoot启动会加载大量的自动装配类
  • 我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中(spring.factories)
  • 我们再来看springboot写好的这个自动配置类到底配置了哪些组件(xxxAutoConfiguration中)(只要我们要用的组件存在其中,我们就不需要再手动配置了)
  • 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们只需要在配置文件中指定这些属性的值即可

xxxAutoConfiguration:自动配置类;给容器中添加组件

xxxProperties:封装配置文件中相关属性

  1. 查看哪些配置属性生效,通过debug: true
debug: true

五、SpringBoot Web开发

1)web开发探究

jar:webapp

自动装配

要解决的问题:

  • 导入静态资源
  • 首页
  • jsp,模板引擎 Thymeleaf
  • 装配扩展SpringMVC
  • 数据库增删改查
  • 拦截器
  • 国际化

2)静态资源导入

  1. 分析源码 WebMvcAutoConfiguration.class 里面
public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
            } else {
                Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
                CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
                if (!registry.hasMappingForPattern("/webjars/**")) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                }

                String staticPathPattern = this.mvcProperties.getStaticPathPattern();
                if (!registry.hasMappingForPattern(staticPathPattern)) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                }

            }
        }
  • 第一种方式webjars,通过maven导入,在classpath:/META-INF/resources/webjars/可以找到
  • staticPathPattern

在resources下建文件夹public、static、resource,springboot会自动扫描这些文件内的静态资源,且优先级是:

resources>static>public

  • if (!this.resourceProperties.isAddMappings()) {

​ logger.debug(“Default resource handling disabled”);意思是如果自己在配置文件中配置了静态资源路径,那么前面的默认的配置就不生效

  1. 总结
  • 在springboot,我们可以使用一下方式处理静态资源

    • webjars localhost:8080/webjars/
    • public , static , resources , /** localhost:8080/
  • 优先级:

resources>static(默认)>public

3)首页如何定制

  1. 相关源码
@Bean
        public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
            WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
            welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
            welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());
            return welcomePageHandlerMapping;
        }

        private Optional<Resource> getWelcomePage() {
            String[] locations = WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations());
            return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
        }

        private Resource getIndexHtml(String location) {
            return this.resourceLoader.getResource(location + "index.html");
        }

springboot会自动识别resource下的index.html,并把它设置为首页

4)thymeleaf模板引擎

  1. springboot这个项目以jar的方式,默认是不支持jsp的,不支持jsp,如果我们直接用静态页面的方式,那给我们开发会带来非常大的麻烦,所以SpringBoot推荐使用模板引擎

  2. jsp其实就是一个模板引擎,还有用的比较多的freemarker,包括springboot给我们推荐的Thymeleaf

  3. 导入依赖

    <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-thymeleafartifactId>
            <version>2.2.1.RELEASEversion>
        dependency>

  1. 将html页面放在我们的templates文件夹下,就可以实现直接跳转。
package com.example.controller;

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

//在templates目录下的所有页面,只能通过controller来跳转
@Controller
public class IndexController {
    @RequestMapping("/test")
    public String test(){
        return "test";
    }
}

test.html在templates下

doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
head>
<body>
<h1>testh1>
body>
html>

测试,可以跳转到test页面

  1. 编写thymeleaf页面
  • 加入标签 xmlns:th="http://www.w3.org/1999/xhtml“

  • doctype html>
    <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Documenttitle>
    head>
    <body>
    
    <div th:text="${msg}">div>
    body>
    html>
    
  • 取文本内容

package com.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

//在templates目录下的所有页面,只能通过controller来跳转
@Controller
public class IndexController {
    @RequestMapping("/test")
    public String test(Model model){
        model.addAttribute("msg","hello,springboot");
        return "test";
    }
}

这样就可以取到了!

  1. thymeleaf 常用语法

常用标签

标签 作用 示例
th:text 替换文本 th:text="${title}"
th:value 替换值 th:value="${user.name}"
th:each 迭代 th:each="stu:${user}"
th:href 替换链接 th:href="@{/index.html}"
th:src 替换资源 th:src="@{/img/Wechat.jpg}"
th:if 条件判断 th:if="${isVip}"
th:switch th:case 条件判断 th:switch="${sex}" th:case="'man'"
th:insert 插入 th:insert="footer :: copy"
th:replace 替换 th:replace="footer :: copy"
th:fragment 定义片段 th:fragment="frag (onevar,twovar)"
  • th:test 和th:utext
<body>


<div th:text="${msg}">div>

<div th:utext="${msg}">div>   
body>
  • 遍历 th:each

后端输入数据

  model.addAttribute("users", Arrays.asList("java","python"));

页面中获取数据



<h3 th:each="user:${users}" >[[${user}]]h3>

推荐使用第一种

5)SpringMVC自动配置原理 和 扩展

  1. MVC自动配置原理(举例扩展视图解析器)
package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.Locale;
//如果你想diy一些定制化的功能,只要写这个组件,然后将它交给springboot,springboot就会帮我们自动装配
//写组件(@Configuration),自定义(继承这个功能的接口类)---->注入到springboot(@Bean) ---->springboot会帮我们自动装配
//扩展mvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    // public interface ViewResolver 实现了视图解析器接口的类,我们就可以把它看做视图解析器(现在默认是springboot自动装配的)
    @Bean
    public ViewResolver myViewResolver(){
        return new MyViewResolver();
    }
    //自定义一个自己的视图解析器MyViewResolver
    public static class MyViewResolver implements ViewResolver{
        @Override
        public View resolveViewName(String s, Locale locale) throws Exception {
            return null;
        }
    }
}

  • SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(用户自己配置@Bean),如果有就用用户配置的,如果没有就用自动配置的;如果有些组件可以存在多个,比如我们的视图解析器,就将用户配置的和自己默认的组合起来!
  1. 扩展SpringMvc
package com.example.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//如果我们要扩展springmvc,官方建议我们这样去做,@Configuration成为组件,然后继承类,然后重写方法
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    //视图跳转
  //实现重命名,从/view也可以跳转到test
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/view").setViewName("test");
    }
}

  • 在SpringBoot中,有非常多的xxx Configuration帮助我们进行扩展配置,只要看见了这个东西,我们就要注意了!

你可能感兴趣的:(springboot,spring,boot,java,spring)