目录

SpringBoot介绍

创建一个最基础的springbooot项目

使用Spring Initializr创建springboot项目

Spring Boot 自动配置机制

SpringBoot常用注解

1.组件注册

2.条件注解

3.属性绑定

SpringBoot自动配置流程​编辑

学习SpringBoot的方法

​编辑

SpringBoot日志配置

日志格式:

自定义日志格式:

使用日志:

指定日志级别:

日志分组:​编辑

日志文件输出:

日志归档和切割:(默认开启)

自定义日志系统:​编辑

切换默认日志系统:

SpringBoot Web开发

静态资源

WebMvcAutoConfiguration自动配置类分析

默认配置

自定义静态资源规则

路径匹配

内容协商

自定义数据格式返回

WebMvcConfigurationSupport

模板引擎

Thymeleaf整合

使用​编辑

SpringBoot开发工具

国际化

错误处理

MVC处理机制:

boot机制:

最佳实战

​编辑

嵌入式容器

Web新特性

Problemdetails

函数式Web(估计用不到)


版本要求

SpringBoot介绍

SpringBoot 能够帮我们简单、快速地创建一个独立的、生产级别的Spring应用

特性:

  • 快速创建独立Spring应用
  • 直接嵌入tomcat、jetty或Undertow等Servlet容器,无需部署war包
  • 提供可选的starter,简化应用整合
  • 按需自动配置Spring以及第三方库
  • 提供生产级别特性:如 监控指标、健康检查(k8s)、外部化配置等
  • 无代码生成,无xml

创建一个最基础的springbooot项目

1.创建项目

2.将父工程设置为spring-boot-starter-parent,导入springboot web 开发的基础依赖:spring-boot-starter-web,设置springboot打包插件:spring-boot-maven-plugin

<?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.qiu</groupId>
    <artifactId>boot-1-project</artifactId>
    <version>1.0-SNAPSHOT</version>
<!--    springboot项目必须继承 spring-boot-starter-parent-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.5</version>
    </parent>
    <dependencies>
<!--        web开发的场景启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
<!--            springboot项目的打包插件-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3.编写启动类,springboot web项目可以直接运行该类来启动项目,不需要tomcat等服务器,因为springboot已经内置服务器。

//启动类注解
@SpringBootApplication
public class SpringMain {
    public static void main(String[] args) {
        //固定代码:SpringApplication.run(启动类的类对象,main函数的参数);
        SpringApplication.run(SpringMain.class,args);
    }
}

4.编写服务

@RestController
// ==  Controller(将该类放入ioc容器) + ResponseBody(以数据格式返回,不添加该注解会经过视图解析器)
public class HelloController {

    //请求映射:/hello的请求会调用该方法
    @RequestMapping("hello")
    public String hello(){
        //将数据返回
        return "hello spring boot3 !";
    }
}

5.启动服务

6.访问服务

7.将项目打包

8.运行项目:把jar包放到有java环境的服务器上就可以直接启动(记得把项目停掉)

9.springboot可以不在源码修改配置文件,在jar包目录下创建一个 .properties 配置文件就可以覆盖配置,还可以创建config文件夹,把配置文件放进去,优先级更高


使用Spring Initializr创建springboot项目

创建服务并启动项目:

@RestController
public class HelloController {
    
    @RequestMapping("hello")
    public String hello(){
        return "hello spring init";
    }
    
}


Spring Boot 自动配置机制

  • 自动配置的Tomcat,SpringMVC等
    • springboot自动配置DispatcherServlet、ViewResolver、CharacterEncodingFilter等组件
    • 如果需要哪些组件,只需要把启动器导入,就自动配置到ioc容器
    • 可以使用以下代码查看配置的组件
public static void main(String[] args) {
		//获取ioc容器
		ConfigurableApplicationContext run = SpringApplication.run(Boot2ProjectApplication.class, args);
		//查看所有组件
        //springboot自动配置好核心组件
		for (String name : run.getBeanDefinitionNames()) {
			System.out.println(name);
		}
	}
  • 默认的包扫描规则
    • 默认扫描启动类的目录及子目录
    • 可以@SpringBootApplication(scanBasePackages="com.qiu")
    • 也可以@ComponentScan("com.qiu")
  • 配置默认值
    • 配置文件中的所有配置项都是跟某个类的对象值一一对应的。
    • 在application.properties中按住ctrl点击对应的配置项可以跳转到对应的类。
    • 这样的类叫做配置属性类。
    • 比如:ServerProperties包含所有Tomcat服务器相关的配置 , MultipartProperties包含所有文件上传相关的配置。
  • 按需加载自动配置
    • 当导入启动器,如:spring-boot-starter-web时,启动器除了会导入相关功能的依赖,还会导入一个spring-boot-starter
    • spring-boot-starter是所有启动器的启动器,是基础核心starter
    • spring-boot-starter导入了spring-boot-autoconfigure,这个包有所有启动器的AutoConfiguration(自动配置类)
    • 但不会全部开启,只有导入对应的启动器时才会开启相应的自动配置

SpringBoot常用注解

SpringBoot不再使用XML配置方式,使用全注解驱动

1.组件注册

@Configuration:在类上添加,表明是个配置类,替代配置文件。

@SpringBootConfiguration:与@Configuration功能相同,更见名知意。

@Bean:在配置类下的方法上添加,替代<Bean>标签。

@Controller、@Service、@Repository、@Component:在类上使用,表明把这个类放到ioc容器。

@Import:可以导入任意类,当我们需要把第三方的组件放到ioc容器中,除了使用@Bean,还可以直接在配置类上使用@Import( … .class) 将组件放到ioc容器中。

@ComponentScan:在配置类上使用@ComponentScan("路径"),来扫描路径下的组件放到ioc容器中。

2.条件注解

@ConditionalOnXxx:

@ConditionOnClass:如果类路径中存在这个类,则触发指定行为

@ConditionOnMissingClass:如果类路径中不存在这个类,则触发指定行为

@ConditionOnBean:如果容器中存在这个Bean,则触发指定行为

@ConditionOnMissingBean:如果容器中不存在这个Bean,则触发指定行为

解释:当ioc容器中有FastsqlException组件就把Cat类放到ioc容器,没有就把Dog类放到ioc容器中。

如果该注解放到配置类上,这个配置类才生效。

3.属性绑定

@ConfigurationProperties

@EnableConfigurationProperties

将容器的任意组件的属性值和配置文件的配置项的值进行绑定。

示例:编写application配置文件

student.id=1
student.name=qiu
student.age=22

创建pojo类并放到ioc容器


@Component
public class Student {
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

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

    Integer id;
    String name;
    Integer age;
}

只要类中属性与配置文件的配置项相同,就在类上添加注解(类属性要有set和get方法)

@ConfigurationProperties(prefix = "student")
@Component
public class Student {
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

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

    Integer id;
    String name;
    Integer age;
}

这样启动服务后,就会自动给组件赋值

EnableConfigurationProperties(Student.class)功能:(主要用在第三方)

1.开启Student组件的属性绑定

2.默认把该组件放到ioc容器中


SpringBoot自动配置流程


学习SpringBoot的方法

示例:

1、导入redis的启动器

        <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

2、导入启动器后就会有相应的自动配置类:RedisAutoConfiguration

     输入 ctrl + n 搜索可查看

3、在类上可以看到@EnableConfigurationProperties({RedisProperties.class}),这个注解开启了RedisProperties类的属性绑定,ctrl + 左键 查看

4、在类上看到@ConfigurationProperties( prefix = "spring.data.redis" ),就知道在配置文件对应配置项

5、在RedisAutoConfiguration中可以看到把哪些Bean放到ioc容器中,可以修改配置或覆盖


SpringBoot日志配置

日志接口日志实现类

JCL(Jakarta Commons Logging)

SLF4j(Simpple Logging Facade for Java)

jboss-logging

Log4j

JUL(java.util.logging)

Log4j2

Logback

Spring5以后把commons-logging作为内部日志,但支持jul,log4j2,logback。默认使用logback

日志格式:

2024-03-23T01:01:09.925+08:00  INFO 27188 --- [boot-2-project] [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
  • 默认格式:
    • 时间和日期:毫秒级精度
    • 日志级别:ERROR,WARN,INFO,DEBUG ,TRACE
    • 进程ID
    • ---:信息分割符
    • 线程名:使用[]包含
    • Logger名:通常是产生日志的类名
    • 消息:日志记录的内容

自定义日志格式:

%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n

使用日志:

方法1:从日志工厂获得记录当前类的记录器(一个类可以有一个记录器),调用方法

方法2:在类使用@Slf4j注解(需要添加lombok依赖),它会在底层自动为这个类注入log属性,使用log打印日志。

指定日志级别:

Springboot默认所有日志只要没有指定日志级别就使用root的默认级别(info)或设置的级别:

logging.level.root = debug

日志内容可以使用占位符:

log.info("a:{},b:{}",a,b);

指定某个类或包的日志级别:

logging.level.com.qiu.boot2project.controller = info

日志分组:

日志文件输出:

指定文件名:只写名字生成到当前位置

logging.file.name=D:\\logging\\file.log

指定文件路径:日志文件名默认为spring.log

logging.file.path=D:\\logging\\

同时指定文件名和文件路径只看文件名

日志归档和切割:(默认开启)

# 归档    切割
# LOG_FILE 就是 自己配置的文件名      yyyy-MM-dd 时间       i 当天的第几个文件
# max-file-size 只要文件超过了1MB 切割下一个文件
logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz
logging.logback.rollingpolicy.max-file-size=1MB

只有logback才能直接配置,如果要使用其他日志系统,需要自行配置(log4j2需要添加log4j2.xml或log4j2-spring.xml)

自定义日志系统:

可以自行编写logback.xml或logback-spring.xml配置文件,这时springboot会读取这个配置文件,不使用默认的日志。

<?xml version="1.0" encoding="UTF-8"?>

<!-- 配置文件修改时重新加载,默认true -->
<configuration scan="true">
    
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="CATALINA_BASE" value="logs"></property>
    
    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder charset="UTF-8">
            <!-- 输出日志记录格式 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
 
    <!-- 第一个文件输出,每天产生一个文件 -->
    <appender name="FILE1" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 输出文件路径+文件名 -->
            <fileNamePattern>${CATALINA_BASE}/aa.%d{yyyyMMdd}.log</fileNamePattern>
            <!-- 保存30天的日志 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder charset="UTF-8">
            <!-- 输出日志记录格式 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
 
    <!-- 第二个文件输出,每天产生一个文件 -->
    <appender name="FILE2" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${CATALINA_BASE}/bb.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${CATALINA_BASE}/bb.%d{yyyyMMdd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder charset="UTF-8">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <appender name="CUSTOM" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${CATALINA_BASE}/custom.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- daily rollover -->
            <fileNamePattern>${CATALINA_BASE}/custom.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- keep 30 days' worth of history -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder charset="UTF-8">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <!-- 设置日志输出级别 -->
    <root level="ERROR">
        <appender-ref ref="CONSOLE" />
    </root>
    <logger name="file1" level="DEBUG">
        <appender-ref ref="FILE1" />
    </logger>
    <logger name="file1" level="INFO">
        <appender-ref ref="FILE2" />
    </logger>
    <!-- 自定义logger -->
    <logger name="custom" level="INFO">
        <appender-ref ref="CUSTOM" />
    </logger>
</configuration>

切换默认日志系统:

        <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
        <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j</artifactId>
		</dependency>

SpringBoot Web开发

依赖:


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

最佳实战:


静态资源

WebMvcAutoConfiguration自动配置类分析

1.生效条件:

@AutoConfiguration(
    after = {DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class}
)//在这三个自动配置类后面开始自动配置
@ConditionalOnWebApplication(
    type = Type.SERVLET
)//如果是web应用,并且还得是servlet类型(还有Reactive 响应式web应用)才能生效
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})//当存在这些Bean才生效
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})//当没有这个Bean才生效
@AutoConfigureOrder(-2147483638)//优先级
@ImportRuntimeHints({WebResourcesRuntimeHints.class})
public class WebMvcAutoConfiguration {

2.效果:

1.放了两个Bean:FormContentFilter 和 HiddenHttpMethodFilter

  • HiddenHttpMethodFilter:页面表单提交Rest请求(GET,POST,PUT,DELETE),不然表单只能发送GET和POST
  • FormContentFilter:表单内容Filter,不然只有GET(URL后面)和POST(请求体)能携带数据,PUT和DELETE请求体数据会被忽略。

2.给容器放了WebMvcConfigurer组件:给SpringMvc添加各种定制功能

 @Configuration(
        proxyBeanMethods = false
    )
    @Import({EnableWebMvcConfiguration.class})
    @EnableConfigurationProperties({WebMvcProperties.class, WebProperties.class})
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {

 3.WebMvcConfigurer


4.静态资源的规则源码addResourceHandlers


        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
            } else {
                //规则1
                this.addResourceHandler(registry, this.mvcProperties.getWebjarsPathPattern(), "classpath:/META-INF/resources/webjars/");
                //规则2
                this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
                    registration.addResourceLocations(this.resourceProperties.getStaticLocations());
                    if (this.servletContext != null) {
                        ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
                        registration.addResourceLocations(new Resource[]{resource});
                    }

                });
            }
        }

规则1:访问 /webjars/** 就到 classpath:/META-INF/resources/webjars/ 下找资源。

             maven导入依赖,依赖jar包下的静态资源可以通过/webjars/访问

规则2:访问 /** 就到 "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" 这些下找资源。

规则3:静态资源默认都有缓存规则的设置

  • 所有缓存的配置修改,在配置文件的 spring.web
  • cachePeriod:缓存周期:多久不用找服务器要新的,默认没有,以秒为单位
  • cacheControl:HTTP缓存控制
  • useLastModified:是否使用最后一次修改,配合http cache规则

                如果浏览器访问了一个静态资源,如果服务器这个资源没有发生变化,下次访问直接让浏览器用自己缓存中的东西,而不是给服务器发请求。

//addResourceHandler方法内部
registration.setCachePeriod(this.getSeconds(this.resourceProperties.getCache().getPeriod()));
registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified());

5.EnableWebMvcConfiguration源码

@Configuration(
        proxyBeanMethods = false
    )
    @EnableConfigurationProperties({WebProperties.class})
    public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {

 这个类继承了WebMvcConfigurationSupport,就是SpringBoot给容器中放了WebMvcConfigurationSupport组件。

如果我们自己放了这个组件,SpringBoot的WebMvcAutoConfiguration都不会生效;但他自己是在自动配置类生效后放的,不矛盾。

类下有方法WelcomePageHandlerMapping:只要静态资源路径内有index.html,项目启动就默认访问。


默认配置

静态资源映射

  • 访问 /webjars/** 就到 classpath:/META-INF/resources/webjars/ 下找资源。
    • maven导入依赖,依赖jar包下的静态资源可以通过/webjars/访问
  • 访问 /** 就到 "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" 这些下找资源。

静态资源缓存

静态资源默认都有缓存规则的设置

  • 所有缓存的配置修改,在配置文件的 spring.web
  • cachePeriod:缓存周期:多久不用找服务器要新的,默认没有,以秒为单位
  • cacheControl:HTTP缓存控制
  • useLastModified:是否使用最后一次修改,配合http cache规则

欢迎页

只要静态资源路径内有index.html,项目启动就默认访问。

Favicon

每次浏览器请求网站时,都会请求 /favicon.ico,只要静态资源路径下有该图标就会返回。

 缓存的一些配置


自定义静态资源规则

自定义静态资源路径,自定义缓存规则

1.配置方式

  • spring.mvc:
    • 静态资源访问前缀路径(你想要访问静态资源要在浏览器输入的路径的前缀)
  • spring.web:
    • 静态资源在服务器的位置前缀
    • 静态资源缓存策略

# 自定义webjars路径前缀
spring.mvc.webjars-path-pattern=/wj/**
# 静态资源访问路径前缀
spring.mvc.static-path-pattern=/static/**
# 自定义静态资源在服务器的位置
spring.web.resources.static-locations=classpath:/a/,classpath:/b/,classpath:/static/

2.代码方式

创建一个配置类,实现WebMvcConfigurer接口,不要添加@EnableWebMvc,它会禁用boot的springMvc自动配置。

@Configuration
public class MyConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //保留默认配置
        WebMvcConfigurer.super.addResourceHandlers(registry);
        //自己写
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/a/","classpath:/b/")
                .setCacheControl(CacheControl.maxAge(1180, TimeUnit.SECONDS));

    }
}

路径匹配

Spring5.3之前只支持AntPathMatcher,现在提供了PathPatternParser策略,并且可以指定使用哪种策略。默认使用新版策略。


内容协商

1.基于请求头:在请求头添加:Accept:application/数据格式(json,xml)

2.基于请求参数:在请求参数中添加format=数据格式(需要开启)

# 使用参数进行内容协商
spring.mvc.contentnegotiation.favor-parameter=true 
# 自定义参数名 ,默认为format
spring.mvc.contentnegotiation.parameter-name=myparam

SpringBoot会自动就数据转换为对应的数据格式

默认支持把数据对象写成json,因为web启动器默认导入了jackson处理json的包:jackcon-core。

jackson也支持把数据对象写成xml,要导入xml相关的处理依赖

        <dependency>
			<groupId>com.fasterxml.jackson.dataformat</groupId>
			<artifactId>jackson-dataformat-xml</artifactId>
		</dependency>

在对象上添加注解

这样就可以根据请求返回xml数据对象了。

@Data
@JacksonXmlRootElement
public class People {
    private String name;
    private Integer sex;
}
自定义数据格式返回

内容协商原理-HttpMessageConverter

1.@ResponseBody 由 HttpMessageConverter 处理

2.WebMvcAutoConfiguration提供几个默认HttpMessageConverters

系统里功能有限,只能返回json或普通数据,要返回新的类型需要增加新的HttpMessageConverter。


WebMvcConfigurationSupport

提供了很多的默认配置

如果手动把它放到ioc容器,SpringBoot关于web的自动配置就会失效

该类判断系统中是否有相应的包,如果有,就加入相应的HttpMessageConverter,但顶多也就json和xml等,向yaml等依然不支持。

static {
        ClassLoader classLoader = WebMvcConfigurationSupport.class.getClassLoader();
        romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
        jaxb2Present = ClassUtils.isPresent("jakarta.xml.bind.Binder", classLoader);
        jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
        jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
        jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
        jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
        gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
        jsonbPresent = ClassUtils.isPresent("jakarta.json.bind.Jsonb", classLoader);
        kotlinSerializationCborPresent = ClassUtils.isPresent("kotlinx.serialization.cbor.Cbor", classLoader);
        kotlinSerializationJsonPresent = ClassUtils.isPresent("kotlinx.serialization.json.Json", classLoader);
        kotlinSerializationProtobufPresent = ClassUtils.isPresent("kotlinx.serialization.protobuf.ProtoBuf", classLoader);
    }

操作

想要自定义数据格式,只需要编写WebMvcConfigurer接口的实现类提供的configureMessageConverters底层,修改底层的MessageConverter即可。

示例:yaml类型

添加依赖: 

<!--		支持返回yaml包-->
		<dependency>
			<groupId>com.fasterxml.jackson.dataformat</groupId>
			<artifactId>jackson-dataformat-yaml</artifactId>
		</dependency>

配置application文件:

# 增加一种新的内容类型
spring.mvc.contentnegotiation.media-types.yaml = application/yaml

编写一个格式转换器:

public class MyYamlHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
    private ObjectMapper objectMapper = null;//该属性就是来把对象转成yaml
    public MyYamlHttpMessageConverter(){
        YAMLFactory yamlFactory = new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER/*取消yaml的文档分隔符*/);
        this.objectMapper = new ObjectMapper(yamlFactory);
    }
    //支持把什么类型写成yaml格式
    @Override
    protected boolean supports(Class<?> clazz) {
        //可以在此判断
        return true;
    }

    @Override //@RequestBody
    protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }

    @Override //@ResponseBody 怎么把对象写成对应格式
    protected void writeInternal(Object methodReturnValue, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
//        OutputStream body = outputMessage.getBody();
//        try {
//            this.objectMapper.writeValue(body,methodReturnValue);
//        }finally {
//            body.close();
//        }
        //try-with写法,自动关流
        try (OutputStream os = outputMessage.getBody()){
            this.objectMapper.writeValue(os,methodReturnValue);
        }
    }
}

把转换器和配置文件设置的类型关联起来:

转换器类继承的抽象类的构造方法可以传入mediatype,在传入的mediatype可以配置和配置文件设置的媒体类型一样的属性,这样两者就关联起来了。

在转换器的构造方法修改:

public MyYamlHttpMessageConverter(){
        //告诉springboot这个类型转换器支持哪种媒体类型
        super( new MediaType("application", "yaml", Charset.forName("UTF-8")));
        YAMLFactory yamlFactory = new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER/*取消yaml的文档分隔符*/);
        this.objectMapper = new ObjectMapper(yamlFactory);
    }

 把转换器配置到springboot:

@Configuration
public class MyConfig implements WebMvcConfigurer {
    @Override   //配置一个能把对象转换为yaml的messageConverter
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MyYamlHttpMessageConverter());
    }
}

模板引擎

由于SpringBoot使用嵌入式Servlet容器,默认不能使用JSP。需要服务器页面渲染,优先考虑使用模板引擎。

模板引擎默认放到 /src/main/resources/templates

SpringBoot包含以下模板引擎的自动配置:

  • FreeMarker
  • Groovy
  • Thymeleaf(推荐)官网:Thymeleaf
  • Mustache 
Thymeleaf整合

导入启动器:

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

自动配置原理:

在ThymeleafAutoConfiguration下:

  • 将属性与配置文件下 spring.thymeleaf 绑定
  • 设置前缀 classpath:/templates/ 
  • 设置后缀 .html 

SpringBoot如果整合了Thymeleaf,默认是到 classpath:/templates/下找文件

编写服务:

//这时要返回页面,不能使用RestController
@Controller
public class WelcomeController {
    //请求路径:localhost:8080/welcome?name=qiu
    //就是name参数来填写到要返回的页面上
    @GetMapping("welcome")
    public String welcome(String name, Model model){
        //将msg:name放到model中,在模板引擎中就可以直接使用msg映射name的值
        model.addAttribute("msg",name);
        //返回页面的话,由于整合了Thymeleaf,将返回的字符串与设置的前后缀拼接在访问器中搜索并返回
        //    前缀(默认:classpath:/templates/) + welcome(返回字符串) + 后缀(默认:.html)
        return "welcome";
    }
}

在 \src\main\resources\templates 下创建文件 welcome.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--                th:... 是 Thymeleaf -->
    <h1>你好:<span th:text="${msg}"></span></h1>
</body>
</html>

启动服务访问:localhost:8080/welcome?name=qiu


使用

 


SpringBoot开发工具

导入SpringBoot提供的依赖

<!--		热启动功能-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>

修改代码或页面后按 ctrl + f9, 项目就热启动了。

如果修改的是java代码,最好重启项目,不然可能有一些bug。


国际化

 在resources下创建文件:messages.properties,messages_zh_CN.properties,messages_en_US.properties。

idea会自动识别形成以下目录:

国际化要成功使用,项目编码要是UTF-8:File->Settings->搜索 file encodings

messages.properties:

login=Login
sign=Sign-Up

messages_zh_CN.properties:

login=登录
sign=注册

messages_en_US.properties:

login=Login
sign=Sign-Up-US

在模板中:

<!--    会根据当前状态使用中文或者英文-->
    <button th:text="#{login}"></button>
    <button th:text="#{sign}"></button>


错误处理

错误处理的自动化配置在ErrorMvcAutoConfiguration中,两大核心机制:

1.SpringBoot会自适应处理错误,响应页面或JSON数据

2.SpringMVC的错误处理机制仍然保留,MVC处理不了才会交给boot处理

MVC处理机制:

可以在当前controller上添加处理方法:

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public String handlerException(Exception e){
        System.out.println("异常处理代码");
        return e.getMessage();
    }

也可以创建一个异常处理类:

@ControllerAdvice   //这个类集中处理所有controller发生的错误
public class GlobaExceptionHandler {
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public String handlerException(Exception e){
        System.out.println("异常处理");
        return e.getMessage();
    }
}

如果MVC机制无法解决,就提交boot机制处理。

boot机制:

boot会默认将MVC无法处理的异常转发到项目路径为: /error 下 ,boot底层设计了一个BasicErrorController 处理请求,server.error.path不修改默认为 /error 。

@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"})
public class BasicErrorController extends AbstractErrorController {

在该controller下,会先判断请求的是页面和JSON数据

如果是JSON:

  • boot封装了JSON格式的错误信息:DefaultErrorAttributes
  • 当发生JSON请求错误时,将错误信息放到DefaultErrorAttributes中并返回

如果是页面:

  • 如果发生了500,404,503等错误
    • 如果有模板引擎,默认返回classpath:/templates/error/错误码.html
    • 如果没有,默认返回 静态资源下的错误码.html
  • 如果没有匹配到错误码,就模糊匹配(4xx.html或5xx.html)
    • 如果有模板引擎,默认返回classpath:/templates/error/5xx.html(还真是5xx.html或4xx.html)
    • 如果没有,默认返回 静态资源下的5xx.html
  • 否则返回templates下的error.html(templates/error.html)
  • 如果templates没有error.html,返回SpringBoot自己的默认error页面
最佳实战

嵌入式容器

SpringBoot关于嵌入式容器的自动化配置为:ServletWebServerFactoryAutoConfiguration

SpringBoot默认使用Tomcat为内置Servlet容器。

SpringBoot支持3种Servlet容器:

  • Tomcat(默认)
  • Jetty
  • Undertow

SpringBoot关于各个容器的配置类以 server.容器 为前缀:

server.tomcat.accept-count=100
server.jetty.accesslog.append=false

要替换SpringBoot的Servlet容器方法:

  • 在导入web启动器时手动切换:
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-tomcat</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jetty</artifactId>
		</dependency>

Web新特性

Problemdetails

错误信息返回新格式

在web自动化配置中将 ProblemDetailsExceptionHandler 放到ioc容器中:

    //web自动化配置类
    static class ProblemDetailsErrorHandlingConfiguration {
        ProblemDetailsErrorHandlingConfiguration() {
        }

        @Bean
        @ConditionalOnMissingBean({ResponseEntityExceptionHandler.class})
        @Order(0)
        ProblemDetailsExceptionHandler problemDetailsExceptionHandler() {
            return new ProblemDetailsExceptionHandler();
        }
    }
    //ProblemDetailsExceptionHandler源码
    @ControllerAdvice//异常处理类
    final class ProblemDetailsExceptionHandler extends ResponseEntityExceptionHandler {
        ProblemDetailsExceptionHandler() {
        }
    }

它来处理以下异常:

    @ExceptionHandler(
            HttpRequestMethodNotSupportedException.class, 
            HttpMediaTypeNotSupportedException.class, 
            HttpMediaTypeNotAcceptableException.class, 
            MissingPathVariableException.class, 
            MissingServletRequestParameterException.class, 
            MissingServletRequestPartException.class, 
            ServletRequestBindingException.class, 
            MethodArgumentNotValidException.class, 
            NoHandlerFoundException.class, 
            AsyncRequestTimeoutException.class, 
            ErrorResponseException.class, 
            ConversionNotSupportedException.class, 
            TypeMismatchException.class, 
            HttpMessageNotReadableException.class, 
            HttpMessageNotWritableException.class, 
            BindException.class})

如果系统出现这些异常,SpringBoot以 RFC 7807 规范方式返回数据。

不过该功能默认关闭,需要在配置文件中手动开启:

spring.mvc.problemdetails.enabled=true

函数式Web(估计用不到)
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐