参考: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: 第三方为我们提供的简化开发的场景启动器。
- 所有场景启动器最底层的依赖
<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,版本不一致=>在当前项目里面重写配置
<properties>
<mysql.version>5.1.43</mysql.version>
</properties>
2.2 自动配置
2.2.1 自动配好Tomcat
- 引入Tomcat依赖
<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 指定扫描路径
@SpringBootApplication
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.example")
2.2.5 各种配置拥有默认值
- application.properties:默认配置最终都是映射到某个类上,如:MultipartProperties
- application.properties配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
2.2.6 按需加载所有自动配置项
- 非常多的starter
- 引入了哪些场景这个场景的自动配置才会开启
- SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
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
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
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
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
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
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
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
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
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
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
<?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
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
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
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
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
@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
@Import({AutoConfigurationPackages.Registrar.class})
// 给容器中导入一个组件
// 指定了默认的包规则
public @interface AutoConfigurationPackage {}
// 利用Registrar给容器中导入一系列组件
// 将指定的MainApplication所在包下的所有组件导入进来
- @Import({AutoConfigurationImportSelector.class})
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
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图片
- 配置文件中添加配置项:
spring.banner.image.location=classpath:timg.jpg
4.5 简化开发
4.5.1 lombok
- 引入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
- idea安装插件
- 使用
@ToString // toString
@Data // getter、setter
@AllArgsConstructor // 全参构造器
@NoArgsConstructor // 无参构造器
@Slf4j // 日志
- 例子
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
- 重新加载项目
- 引入依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
- 添加配置
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
k: v
- 对象:键值对的集合。map、hash、set、object
行内写法: k: {k1:v1,k2:v2,k3:v3}
#或
k:
k1: v1
k2: v2
k3: v3
- 数组:一组按次序排列的值。array、list、queue
行内写法: k: [v1,v2,v3]
#或者
k:
- v1
- v2
- v3
5.3 配置提示
- 自定义的类和配置文件绑定一般没有提示
<!-- 配置提示 -->
<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
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
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
package com.example.bean;
import lombok.Data;
@Data
public class Pet {
private String name;
private Double weight;
}
- PersonController
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
server.port=9991
- application.yml
- application.properties和application.yml配置了相同项,以application.properties配的为准
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 静态资源访问前缀
- 默认无前缀
- 改变默认的静态资源路径
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/
<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不能被默认访问
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 放在静态资源目录下即可
spring:
# mvc:
# static-path-pattern: /res/** 这个会导致 Favicon 功能失效
重启服务,浏览器