Springboot2

2023-04-25 23:35:57 浏览数 (1)

参考:https://www.yuque.com/leifengyang/springboot2

参考:https://www.bilibili.com/video/BV19K4y1L7MT?p=1&vd_source=0c3c1f43c75954a15fba4e42c1d7883e

1. HelloWorld

项目结构

1. pom.xml

代码语言:javascript复制
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>springboot-test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>springboot-01-hello</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

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

</project>

2. MainApplication

代码语言:javascript复制
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 主程序类
 * @SpringBootApplication:这是一个springboot应用
 */
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}

3. HelloController

代码语言:javascript复制
package com.example.controller;

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

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String home() {
        return "Hello world";
    }
}

4. 启动服务,浏览器访问

2. Springboot特点

2.1 依赖管理

2.1.1 父项目做依赖管理

代码语言:javascript复制
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
</parent>

点进spring-boot-starter-parent看到:
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.3.4.RELEASE</version>
</parent>

点进spring-boot-dependencies看到:
    几乎声明了所有开发中常用的依赖的版本号

2.1.2 开发导入starter场景启动器

  • 会见到很多spring-boot-starter-*: *就代表某种场景
  • 只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
  • SpringBoot所有支持的场景:https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
  • 见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
  • 所有场景启动器最底层的依赖
代码语言:javascript复制
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter</artifactId>
     <version>2.3.4.RELEASE</version>
     <scope>compile</scope>
</dependency>

2.1.3 无需关注版本号,自动版本仲裁

  • spring-boot-dependencies几乎声明了所有开发中常用的依赖的版本号,引入依赖默认都可以不写版本=>自动版本仲裁

2.1.4 可以修改版本号

  • 引入非版本仲裁的jar,要写版本号
  • 查看spring-boot-dependencies里面规定当前依赖的版本用的 key,版本不一致=>在当前项目里面重写配置
代码语言:javascript复制
<properties>
    <mysql.version>5.1.43</mysql.version>
</properties>

2.2 自动配置

2.2.1 自动配好Tomcat

  • 引入Tomcat依赖
代码语言:javascript复制
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.3.4.RELEASE</version>
      <scope>compile</scope>
</dependency>
  • 配置Tomcat ???

2.2.2 自动配好SpringMVC

  • 引入SpringMVC全套组件:spring-boot-starter-web引入
  • 自动配好SpringMVC常用组件(功能)

2.2.3 自动配好Web常见功能

SpringBoot帮我们配置好了所有web开发的常见场景

  • dispatcherServlet
  • 字符编码:characterEncodingFilter
  • 文件上传:multipartResolver

2.2.4 默认的包结构

  • 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
  • 无需以前的包扫描配置
  • 想要改变扫描路径,@SpringBootApplication(scanBasePackages="com.example")
    • 或者@ComponentScan 指定扫描路径
代码语言:javascript复制
@SpringBootApplication
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.example")

2.2.5 各种配置拥有默认值

  • application.properties:默认配置最终都是映射到某个类上,如:MultipartProperties
  • application.properties配置文件的值最终会绑定每个类上,这个类会在容器中创建对象

2.2.6 按需加载所有自动配置项

  • 非常多的starter
  • 引入了哪些场景这个场景的自动配置才会开启
  • SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
代码语言:javascript复制
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

/**
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.example")
等价于@SpringBootApplication(scanBasePackages="com.example")
 默认扫描主程序所在的包
*/
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        //1、返回我们IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        //2、查看容器里面的组件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println("组件:"   name);
        }
    }
}

3. 自动配置注解

3.1 @Configuration

  • Full模式与Lite模式
  • 项目结构
  • User
代码语言:javascript复制
package com.example.bean;

public class User {
    private String name;
    private int age;

    private Pet pet;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Pet getPet() {
        return pet;
    }

    public void setPet(Pet pet) {
        this.pet = pet;
    }

    @Override
    public String toString() {
        return "User{"  
                "name='"   name   '''  
                ", age="   age  
                ", pet="   pet  
                '}';
    }
}
  • Pet
代码语言:javascript复制
package com.example.bean;

public class Pet {
    private String name;

    public Pet() {
    }

    public Pet(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Pet{"  
                "name='"   name   '''  
                '}';
    }
}
  • MainConfig
代码语言:javascript复制
package com.example.config;

import com.example.bean.Pet;
import com.example.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods=true) // 告诉springboot这是一个配置类
public class MainConfig {
    @Bean
    public User userBean(){
        User u = new User("zhangsan", 18);
        u.setPet(petBean());
        return u;
    }

    @Bean
    public Pet petBean(){
        Pet p = new Pet("cat");
        return p;
    }
}
  • MainApplication
代码语言:javascript复制
package com.example;

import com.example.bean.Pet;
import com.example.bean.User;
import com.example.config.MainConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

/**
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.example")
等价于@SpringBootApplication(scanBasePackages="com.example")
 默认扫描主程序所在的包
*/
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        //1、返回我们IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        //2、查看容器里面的组件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println("组件:"   name);
        }

        // 3. 从容器中获取组件
        User user = (User) run.getBean("userBean");
        User user2 = (User) run.getBean("userBean");
        System.out.println("组件默认是单例的:"   (user==user2));

        // 4. 配置类也是组件
        MainConfig bean = run.getBean(MainConfig.class);
        System.out.println("配置类本身也是组件:"   bean);

        // 5. proxyBeanMethods = true, mainConfig就是被增强的代理对象
        // springboot总会检查组件是否在容器中存在
        // 保持组件单实例
        // 外部无论对配置类中的这个组件注册方法调用多少次,获取的都是之前注册容器中的单实例对象
        User user3 = bean.userBean();
        User user4 = bean.userBean();
        System.out.println("主配置是否为代理对象: " (user3==user4));

        // full: proxyBeanMethods=true  => 应用场景: 解决组件依赖
        // lite: proxyBeanMethods=false => 配置类在容器中不会保存代理对象,在外边调用方法,每次都会产生一个新对象

        // Full: 保证每个@Bean方法被调用多少次返回的组件都是单实例的。类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
        // Lite: 每个@Bean方法被调用多少次返回的组件都是新创建的。类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
        // 组件依赖必须使用Full模式默认。其他默认是否Lite模式
        Pet pet = (Pet) run.getBean("petBean");
        System.out.println("proxyBeanMethods组件依赖"   (user.getPet()==pet));
    }
}

3.2 @Bean、@Component、@Controller、@Service、@Repository

  • 项目结构
  • MainConfig
代码语言:javascript复制
package com.example.config;

import com.example.bean.Pet;
import com.example.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MainConfig {
}
  • User
代码语言:javascript复制
package com.example.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component("userBean")
public class User {
    private String name;
    private int age;

    @Autowired
    private Pet pet;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Pet getPet() {
        return pet;
    }

    public void setPet(Pet pet) {
        this.pet = pet;
    }

    @Override
    public String toString() {
        return "User{"  
                "name='"   name   '''  
                ", age="   age  
                ", pet="   pet  
                '}';
    }
}
  • Pet
代码语言:javascript复制
package com.example.bean;

import org.springframework.stereotype.Component;

@Component("petBean")
public class Pet {
    private String name;

    public Pet() {
    }

    public Pet(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Pet{"  
                "name='"   name   '''  
                '}';
    }
}
  • MainApplication
代码语言:javascript复制
package com.example;

import com.example.bean.Pet;
import com.example.bean.User;
import com.example.config.MainConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

/**
 * @SpringBootConfiguration
 * @EnableAutoConfiguration
 * @ComponentScan("com.example") 等价于@SpringBootApplication(scanBasePackages="com.example")
 * 默认扫描主程序所在的包
 */
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        //1、返回我们IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        //2、查看容器里面的组件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println("组件:"   name);
        }

        // 3. 从容器中获取组件
        User user = (User) run.getBean("userBean");
        User user2 = (User) run.getBean("userBean");
        System.out.println("组件默认是单例的:"   (user == user2));

        // 4. 配置类也是组件
        MainConfig bean = run.getBean(MainConfig.class);
        System.out.println("配置类本身也是组件:"   bean);

        // 5. 组件依赖
        Pet pet = (Pet) run.getBean("petBean");
        System.out.println("组件依赖"   (user.getPet() == pet));
    }
}

3.3 @Import、@Conditional、@ImportResource、@ConfigurationProperties

@Import:给容器中自动创建出指定类型的组件、默认组件的名字就是全类名

@Conditional:条件装配,满足Conditional指定的条件,则进行组件注入

@ImportResource:原生配置文件引入

@ConfigurationProperties:配置文件中的配置项绑定给组件的属性

  • 项目结构
  • MainApplication
代码语言:javascript复制
package com.example;

import ch.qos.logback.core.db.DBHelper;
import com.example.bean.Pet;
import com.example.bean.User;
import com.example.config.MainConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import java.util.Arrays;

/**
 @SpringBootConfiguration
 @EnableAutoConfiguration
 @ComponentScan("com.example")
 等价于@SpringBootApplication(scanBasePackages="com.example")
 默认扫描主程序所在的包
 */


/**
 * @Import:给容器中自动创建出指定类型的组件、默认组件的名字就是全类名
 * @Conditional:条件装配,满足Conditional指定的条件,则进行组件注入
 * @ImportResource:原生配置文件引入
 * @ConfigurationProperties:配置文件中的配置项绑定给组件的属性
 */
@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        //1、返回我们IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

        //2、查看容器里面的组件
        String[] names = run.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println("组件:"   name);
        }

        // 3. 获取组件
        Boolean flag = run.containsBean("petBean");
        System.out.println("容器中是否存在petBean组件:"   flag);

        Boolean flag2 = run.containsBean("userBean");
        System.out.println("容器中是否存在userBean组件:"   flag2);
        
        // 4. 容器中组件数量
        System.out.println("组件数量:"   run.getBeanDefinitionCount()); // 167
    }
}
  • mainApplication.xml
代码语言:javascript复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="petBeanXml" class="com.example.bean.Pet">
        <property name="name" value="cat"></property>
    </bean>

    <bean id="userBeanXml" class="com.example.bean.User">
        <property name="pet" ref="petBeanXml"></property>
        <property name="name" value="zhangsan"></property>
        <property name="age" value="18"></property>
    </bean>
</beans>
  • User
代码语言:javascript复制
package com.example.bean;

public class User {
    private String name;
    private int age;

    private Pet pet;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Pet getPet() {
        return pet;
    }

    public void setPet(Pet pet) {
        this.pet = pet;
    }

    @Override
    public String toString() {
        return "User{"  
                "name='"   name   '''  
                ", age="   age  
                ", pet="   pet  
                '}';
    }
}
  • Pet
代码语言:javascript复制
package com.example.bean;

public class Pet {
    private String name;

    public Pet() {
    }

    public Pet(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Pet{"  
                "name='"   name   '''  
                '}';
    }
}
  • Car
代码语言:javascript复制
package com.example.bean;

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

// @Component 
// MainConfig中使用了@EnableConfigurationProperties(Car.class),则不用@Component
@ConfigurationProperties(prefix = "car")
public class Car {
    private String brand;
    private double price;

    public Car() {
    }

    public Car(String brand, double price) {
        this.brand = brand;
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{"  
                "brand='"   brand   '''  
                ", price="   price  
                '}';
    }
}
  • MainConfig
代码语言:javascript复制
package com.example.config;

import ch.qos.logback.core.db.DBHelper;
import com.example.bean.Car;
import com.example.bean.Pet;
import com.example.bean.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.*;

// @ConditionalOnBean(name="petBean") // 有petBean类里的组件注册才生效,否则都不生效
@EnableConfigurationProperties(Car.class)
// @EnableConfigurationProperties(Car.class)的作用:
// 1. 开启Car配置绑定功能
// 2. 把这个Car这个组件自动注册到容器中
@ImportResource("classpath:mainApplication.xml")
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods=true) // 告诉springboot这是一个配置类
public class MainConfig {
    @ConditionalOnBean(name="petBean") // 容器中存在petBean才执行userBean的组件注册
    @Bean
    public User userBean(){
        User u = new User("zhangsan", 18);
        u.setPet(petBean());
        return u;
    }

    // @Bean
    public Pet petBean(){
        Pet p = new Pet("cat");
        return p;
    }
}

4. 自动配置原理

4.1 引导加载自动配置类

  • @SpringBootApplication主要组成:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
代码语言:javascript复制
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {}

4.1.1 @SpringBootConfiguration

代码语言:javascript复制
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration 
// SpringBootConfiguration用来注解 配置类 => MainApplication是一个配置类(核心配置类)
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

4.1.2 @ComponentScan:包扫描,指定要扫描哪些

  • 两个自定义扫描器

4.1.3 @EnableAutoConfiguration

代码语言:javascript复制
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}
  • @AutoConfigurationPackage
代码语言:javascript复制
@Import({AutoConfigurationPackages.Registrar.class}) 
// 给容器中导入一个组件
// 指定了默认的包规则
public @interface AutoConfigurationPackage {}

// 利用Registrar给容器中导入一系列组件
// 将指定的MainApplication所在包下的所有组件导入进来
  • @Import({AutoConfigurationImportSelector.class})
代码语言:javascript复制
1. 利用getAutoConfigurationEntry(annotationMetadata)给容器中批量导入一些组件
2. 调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
3. 利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader)得到所有的组件
4. 从META-INF/spring.factories位置来加载一个文件。
    默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
    spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
    文件里面写死了spring-boot一启动就要给容器中加载的所有配置类

4.2 按需开启自动配置项

  • spring.factories
  • @Conditional
代码语言:javascript复制
1. 虽然我们127个场景的所有自动配置启动的时候默认全部加载。
    META-INF/spring.factories文件中:xxxxAutoConfiguration
2. 按照条件装配规则(@Conditional),最终会按需配置。
    eg. @ConditionalOnClass({Gson.class})

4.3 修改默认配置

代码语言:javascript复制
@Bean
@ConditionalOnBean(MultipartResolver.class)  //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {
    //给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
    //SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
	// Detect if the user has created a MultipartResolver but named it incorrectly
	return resolver;
}

SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先

代码语言:javascript复制
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {}

总结:

  • SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
  • 生效的配置类就会给容器中装配很多组件(pom.xml配置了)
  • 只要容器中有这些组件,相当于这些功能就有了
  • 定制化配置
    • 用户直接自己@Bean替换底层的组件
    • 用户去看这个组件是获取的配置文件什么值就去修改

xxxxxAutoConfiguration ---> 组件 ---> xxxxProperties里面拿值 ----> application.properties

4,4 最佳实践

  • 引入场景依赖
    • https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
  • 查看自动配置了哪些(选做)
    • 自己分析,引入场景对应的自动配置一般都生效了
    • 配置文件中debug=true开启自动配置报告。Negative(不生效)Positive(生效)
  • 是否需要修改
    • 参照文档修改配置项
      • https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties
      • 自己分析。xxxxProperties绑定了配置文件的哪些。
    • 自定义加入或者替换组件
      • @Bean、@Component。。。
    • 自定义器 XXXXXCustomizer
  • 例子
    • resources目录下放一张jpg图片
    • 配置文件中添加配置项:
代码语言:javascript复制
spring.banner.image.location=classpath:timg.jpg

4.5 简化开发

4.5.1 lombok

  • 引入依赖
代码语言:javascript复制
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
  • idea安装插件
  • 使用
代码语言:javascript复制
@ToString // toString
@Data // getter、setter
@AllArgsConstructor // 全参构造器
@NoArgsConstructor // 无参构造器
@Slf4j // 日志
  • 例子
代码语言:javascript复制
package com.example.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@ToString // toString
@Data // getter、setter
@AllArgsConstructor // 全参构造器
@NoArgsConstructor // 无参构造器
public class LombokBean {
    private String str;
    private int i;
}

代码语言:javascript复制
import com.example.bean.LombokBean;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

@Slf4j
public class LombokBeanTest {
    @Test
    public void testLombokBean(){
        LombokBean o = new LombokBean();
        o.setStr("abc");
        o.setI(10);
        System.out.println(o);
        log.info(o.toString());
    }
}

4.5.2 dev-tools

代码语言:javascript复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>
  • CTRL F9: 自动重启
  • SHIFT F10: 重启
  • JREBEL:IDEA 安装插件 热更新

4.5.3 Spring Initailizr(项目初始化向导)

  • 新建项目
  • 下一步(aliyun仓库没有这个版本的spring-boot-starter-parent,换成了2.7.8版本)
  • 新窗口打开项目,项目结构,可以删除不相关的文件&文件夹
  • 配置maven
  • 重新加载项目
  • 引入依赖
代码语言:javascript复制
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
  • 添加配置
代码语言:javascript复制
server.port=9999

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=redis
spring.redis.database=0
  • 测试项目

5. 配置文件

5.1 SpringBoot2核心技术-核心功能

5.2 文件类型

5.2.1 properties

  • 同以前的properties用法

5.2.2 yaml

  • YAML 是 "YAML Ain't Markup Language"(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)。 非常适合用来做以数据为中心的配置文件
  • 基本语法
    • key: value;kv之间有空格
    • 大小写敏感
    • 使用缩进表示层级关系
    • 缩进不允许使用tab,只允许空格
    • 缩进的空格数不重要,只要相同层级的元素左对齐即可
    • #表示注释
    • 字符串无需加引号,如果要加,单引号('')与双引号("")表示字符串内容=>会被 转义/不转义

5.2.3 数据类型

  • 字面量:单个的、不可再分的值。date、boolean、string、number、null
代码语言:javascript复制
k: v
  • 对象:键值对的集合。map、hash、set、object
代码语言:javascript复制
行内写法:  k: {k1:v1,k2:v2,k3:v3}
#或
k: 
  k1: v1
  k2: v2
  k3: v3
  • 数组:一组按次序排列的值。array、list、queue
代码语言:javascript复制
行内写法:  k: [v1,v2,v3]
#或者
k:
 - v1
 - v2
 - v3

5.3 配置提示

  • 自定义的类和配置文件绑定一般没有提示
代码语言:javascript复制
<!-- 配置提示 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-configuration-processor</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

5.4 例子

  • 新建模块
  • MainApplication
代码语言:javascript复制
package com.example;

import com.example.bean.Person;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;


/**
 * yaml
 */


@SpringBootApplication
@EnableConfigurationProperties(Person.class)
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);

    }
}
  • Person
代码语言:javascript复制
package com.example.bean;

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

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

@Data
@Component
@ConfigurationProperties(prefix = "person")
public class Person {

    private String userName;
    private Boolean boss;
    private Date birth;
    private Integer age;
    private Pet pet;
    private String[] interests;
    private List<String> animal;
    private Map<String, Object> score;
    private Set<Double> salarys;
    private Map<String, List<Pet>> allPets;
}
  • Pet
代码语言:javascript复制
package com.example.bean;


import lombok.Data;

@Data
public class Pet {
    private String name;
    private Double weight;
}
  • PersonController
代码语言:javascript复制
package com.example.controller;

import com.example.bean.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PersonController {
    @Autowired
    Person person;

    @RequestMapping("person")
    public String getPerson(){
        return person.toString();
    }
}
  • application.properties
代码语言:javascript复制
server.port=9991
  • application.yml
    • application.properties和application.yml配置了相同项,以application.properties配的为准
代码语言:javascript复制
server:
  port: 9999

# yaml表示以上对象
person:
  userName: zhangsan
  boss: false
  birth: 2019/12/12 20:12:33
  age: 18
  pet:
    name: tomcat
    weight: 23.4
  interests: [篮球,游泳]
  animal:
    - jerry
    - mario
  score:
    english:
      first: 30
      second: 40
      third: 50
    math: [131,140,148]  # { 0 = 131, 1 = 140, 2 = 148 }
    chinese: {first: 128,second: 136}
  salarys: [3999,4999.98,5999.99]
  allPets:
    sick:
      - {name: tom,weight: 10.1}
      - {name: jerry,weight: 47.0}
    health: [{name: mario,weight: 47.1}]

6. Web开发

6.1 静态资源访问

6.1.1 静态资源目录

  • 只要静态资源放在类路径下:/static (or /public or /resources or /META-INF/resources
  • 访问 : 当前项目根路径/ 静态资源名
  • 原理: 静态映射 /**。
  • 请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面

6.1.2 静态资源访问前缀

  • 默认无前缀
  • 改变默认的静态资源路径
代码语言:javascript复制
spring:
  mvc:
    static-path-pattern: /res/**
  • 当前项目 static-path-pattern 静态资源名 = 静态资源文件夹下找

6.1.3 静态资源保存目录

代码语言:javascript复制
spring:
  resources:
    static-locations: [classpath:/haha/]

6.1.4 webjar

  • 自动映射 /webjars/**
  • https://www.webjars.org/
代码语言:javascript复制
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>3.5.1</version>
</dependency>
  • 访问地址:http://localhost:9991/webjars/jquery/3.5.1/jquery.js后面地址要按照依赖里面的包路径

6.2 欢迎页

  • 静态资源路径下 index.html
    • 可以配置静态资源路径
    • 但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问
代码语言:javascript复制
spring:
#  mvc:
#    static-path-pattern: /res/**   这个会导致welcome page功能失效

  resources:
    static-locations: [classpath:/haha/]
  • controller能处理/index
  • 操作
    • 静态资源路径下,新增index.html文件
    • 启动服务,静态资源路径访问前缀/index.html,可以访问index.html文件
    • 直接访问根路径,404
    • 注释配置静态资源的访问前缀
    • 重启服务,访问根路径

6.3 自定义 Favicon

  • favicon.ico 放在静态资源目录下即可
代码语言:javascript复制
spring:
#  mvc:
#    static-path-pattern: /res/**   这个会导致 Favicon 功能失效

重启服务,浏览器

0 人点赞