Spring Boot “How-to“ 指南中文文档-上

本文为官方文档直译版本。原文链接

篇幅较长,遂分两篇

Spring Boot "How-to" 指南中文文档-上

  • 引言
  • [Spring Boot Application](#Spring Boot Application)
  • 属性和配置
  • [嵌入式 Web 服务器](#嵌入式 Web 服务器)
    • 使用其他网络服务器
    • [禁用 Web 服务器](#禁用 Web 服务器)
    • [修改 HTTP 端口](#修改 HTTP 端口)
    • [使用随机的未分配 HTTP 端口](#使用随机的未分配 HTTP 端口)
    • [在运行时发现 HTTP 端口](#在运行时发现 HTTP 端口)
    • [启用 HTTP 响应压缩](#启用 HTTP 响应压缩)
    • [配置 SSL](#配置 SSL)
      • [使用 PEM 编码文件](#使用 PEM 编码文件)
    • [配置 HTTP/2](#配置 HTTP/2)
      • [使用 Tomcat 实现 HTTP/2](#使用 Tomcat 实现 HTTP/2)
      • [使用 Jetty 实现 HTTP/2](#使用 Jetty 实现 HTTP/2)
      • [使用 Reactor Netty 实现 HTTP/2](#使用 Reactor Netty 实现 HTTP/2)
      • [使用 Undertow 实现 HTTP/2](#使用 Undertow 实现 HTTP/2)
    • [配置 Web 服务器](#配置 Web 服务器)
    • [向应用程序添加 Servlet、Filter或Listener](#向应用程序添加 Servlet、Filter或Listener)
      • [使用 Spring Bean 添加 Servlet、Filter或Listener](#使用 Spring Bean 添加 Servlet、Filter或Listener)
        • [禁用 Servlet 或 Filter 的注册](#禁用 Servlet 或 Filter 的注册)
      • [使用类路径扫描添加 Servlet、Filter和Listener](#使用类路径扫描添加 Servlet、Filter和Listener)
    • 配置访问日志
    • 在前端代理服务器后运行
      • [自定义 Tomcat 的代理配置](#自定义 Tomcat 的代理配置)
    • [通过 Tomcat 启用多个连接器](#通过 Tomcat 启用多个连接器)
    • [启用 Tomcat 的 MBean 注册表](#启用 Tomcat 的 MBean 注册表)
    • [使用 Undertow 启用多个监听器](#使用 Undertow 启用多个监听器)
    • [使用 @ServerEndpoint 创建 WebSocket 端点](#使用 @ServerEndpoint 创建 WebSocket 端点)
  • [Spring MVC](#Spring MVC)
    • [编写 JSON REST 服务](#编写 JSON REST 服务)
  • [编写 XML REST 服务](#编写 XML REST 服务)
    • [自定义 Jackson ObjectMapper](#自定义 Jackson ObjectMapper)
    • [自定义 @ResponseBody 渲染](#自定义 @ResponseBody 渲染)
    • 处理多文件上传
    • [关闭 Spring MVC DispatcherServlet](#关闭 Spring MVC DispatcherServlet)
    • [关闭默认 MVC 配置](#关闭默认 MVC 配置)
    • [自定义 ViewResolvers](#自定义 ViewResolvers)

引言

本节解答了在使用 Spring Boot 时经常出现的 "我该怎么做... "的问题。虽然没有面面俱到,但也涵盖了不少内容。

如果您遇到的具体问题我们在此未涉及,您可能需要查看 stackoverflow.com,看看是否有人已经提供了答案。这里也是提出新问题的好地方(请使用 spring-boot 标签)。

我们也非常乐意扩展本部分。如果你想添加 "如何做",请向我们发送拉取请求

Spring Boot Application

本节包括与 Spring Boot 应用程序直接相关的主题。

创建自己的FailureAnalyzer(故障分析器)

FailureAnalyzer 是在启动时拦截异常并将其转化为人类可读的消息(封装在 FailureAnalysis 中)的好方法。Spring Boot 为应用程序上下文相关异常、JSR-303 验证等提供了这种分析器。您也可以创建自己的分析器。
AbstractFailureAnalyzerFailureAnalyzer 的便捷扩展,它可以检查要处理的异常中是否存在指定的异常类型。您可以对其进行扩展,这样只有当异常实际存在时,您的实现才有机会处理异常。如果由于某种原因无法处理异常,则返回 null,给其他实现处理异常的机会。
FailureAnalyzer 实现必须在 META-INF/spring.factories 中注册。下面的示例注册了 ProjectConstraintViolationFailureAnalyzer

properties 复制代码
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer

如果您需要访问 BeanFactoryEnvironment,您的 FailureAnalyzer 可以分别实现 BeanFactoryAwareEnvironmentAware

自动配置故障诊断

Spring Boot 自动配置会尽力 "做正确的事",但有时也会失败,而且很难说清原因。

在任何 Spring Boot ApplicationContext 中都有一个非常有用的 ConditionEvaluationReport。如果启用 DEBUG 日志输出,就能看到它。如果使用 spring-boot-actuator(请参阅 Actuator 章节),还有一个以 JSON 格式呈现报告的条件端点。使用该端点可以调试程序,并查看 Spring Boot 在运行时添加了哪些功能(哪些功能未添加)。

通过查看源代码和 Javadoc,还可以回答更多问题。阅读代码时,请记住以下经验法则:

  • 查找名为 *AutoConfiguration 的类并阅读它们的源代码。特别注意 @Conditional* 注解,了解它们启用了哪些功能以及何时启用。在命令行中添加 --debug 或系统属性 -Ddebug,以便在控制台上获取应用程序中所有自动配置决定的日志。在启用了Actuator的运行中应用程序中,查看条件端点(/actuator/conditions 或 JMX 对应端点)以获取相同信息。
  • 查找 @ConfigurationProperties 的类(如 ServerProperties),从中读取可用的外部配置选项。@ConfigurationProperties 注解有一个 name 属性,作为外部属性的前缀。因此,ServerProperties 的前缀为 "server",其配置属性包括 server.portserver.address 等。在启用了Actuator的运行应用程序中,查看 configprops 端点。
  • 查找 Binder 上的 bind 方法,以轻松的方式从Environment中显式提取配置值。该方法通常带有前缀。
  • 查找直接绑定到Environment@Value 注解。
  • 查找 @ConditionalOnExpression 注解,该注解可根据 SpEL 表达式开关功能,通常使用从Environment中解析的占位符进行评估。

启动前自定义环境或应用程序上下文

SpringApplication 具有 ApplicationListenersApplicationContextInitializers,用于将自定义应用到上下文或环境中。Spring Boot 会从 META-INF/spring.factories 中加载大量此类自定义,供内部使用。注册其他自定义的方法不止一种:

  • 以编程方式,针对每个应用程序,在运行 SpringApplication 前调用其 addListenersaddInitializers 方法。
  • 对于所有应用程序,可通过添加 META-INF/spring.factories,并打包一个 jar 文件,让所有应用程序都将其作为一个库来使用。

SpringApplication 会向监听器发送一些特殊的 ApplicationEvents(有些甚至在上下文创建之前),然后也会为 ApplicationContext 发布的事件注册监听器。有关完整列表,请参阅 "Spring Boot 功能" 部分中的 "应用程序事件和监听器"。

还可以使用 EnvironmentPostProcessor 在应用上下文刷新之前自定义环境。每个实现都应在 META-INF/spring.factories 中注册,如下例所示:

properties 复制代码
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor

执行程序可以加载任意文件并将其添加到Environment中。例如,下面的示例从类路径加载了一个 YAML 配置文件:

java 复制代码
import java.io.IOException;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;

public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {

    private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        Resource path = new ClassPathResource("com/example/myapp/config.yml");
        PropertySource<?> propertySource = loadYaml(path);
        environment.getPropertySources().addLast(propertySource);
    }

    private PropertySource<?> loadYaml(Resource path) {
        Assert.isTrue(path.exists(), () -> "Resource " + path + " does not exist");
        try {
            return this.loader.load("custom-resource", path).get(0);
        }
        catch (IOException ex) {
            throw new IllegalStateException("Failed to load yaml configuration from " + path, ex);
        }
    }

}

Environment已包含 Spring Boot 默认加载的所有常用属性源。因此,可以从环境中获取文件的位置。前面的示例在列表末尾添加了自定义资源属性源,因此在任何其他位置定义的键都会优先。自定义实现可以定义其他顺序。
@SpringBootApplication 中使用 @PropertySource 似乎是在环境中加载自定义资源的便捷方法,但我们并不推荐这样做。在应用程序上下文被刷新之前,此类属性源不会被添加到环境中。这对于配置某些属性(如在刷新开始前读取的 logging.*spring.main.*)来说为时已晚。

构建 ApplicationContext 层次结构(添加父上下文或根上下文)

您可以使用 ApplicationBuilder 类创建parent/child ApplicationContext 层次结构。有关详细信息,请参阅 "Spring Boot 功能" 部分中的 "features.html"。

创建非 Web 应用程序

并非所有 Spring 应用程序都必须是网络应用程序(或网络服务)。如果您既想在mian方法中执行一些代码,又想引导一个 Spring 应用程序来设置要使用的基础架构,您可以使用 Spring Boot 的 SpringApplication 功能。SpringApplication 会根据是否需要网络应用程序来更改其 ApplicationContext 类。要帮助它,首先要做的就是将与服务器相关的依赖项(如 servlet API)从类路径中删除。如果做不到这一点(例如,你从同一个代码库中运行两个应用程序),那么你可以在 SpringApplication 实例上显式调用 setWebApplicationType(WebApplicationType.NONE) 或设置 applicationContextClass 属性(通过 Java API 或使用外部属性)。您希望作为业务逻辑运行的应用代码可作为 CommandLineRunner 实现,并作为 @Bean 定义放入上下文中。

属性和配置

本节包括有关设置和读取属性以及配置设置及其与 Spring Boot 应用程序交互的主题。

构建时自动扩展属性

与其硬编码项目构建配置中指定的某些属性,不如使用现有的构建配置自动扩展这些属性。这在 Maven 和 Gradle 中都可以实现。

使用 Maven 自动扩展属性

通过使用资源过滤,你可以从 Maven 项目中自动扩展属性。如果使用 spring-boot-starter-parent,就可以用 @..@ 占位符引用 Maven "项目属性",如下例所示:

yaml 复制代码
app:
  encoding: "@project.build.sourceEncoding@"
  java:
    version: "@java.version@"

只有生产配置才会以这种方式进行过滤(换句话说,src/test/resources 上不会进行过滤)。
如果启用 addResources 标志,spring-boot:run 目标就可以直接将 src/main/resources 添加到类路径中(用于热重载)。这样做可以规避资源过滤和此功能。相反,你可以使用 exec:java 目标或自定义插件配置。更多详情,请参阅插件使用页面

如果不使用spring-boot-starter-parent,则需要在 pom.xml<build/> 元素中包含以下元素:

xml 复制代码
<resources>
  <resource>
    <directory>src/main/resources</directory>
    <filtering>true</filtering>
  </resource>
</resources>

您还需要在 <plugins/> 中包含以下元素:

xml 复制代码
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <version>2.7</version>
    <configuration>
        <delimiters>
            <delimiter>@</delimiter>
        </delimiters>
        <useDefaultDelimiters>false</useDefaultDelimiters>
    </configuration>
</plugin>

如果在配置中使用标准 Spring 占位符(如 ${placeholder}),则 useDefaultDelimiters 属性非常重要。如果未将该属性设置为 false,则构建时可能会扩展这些占位符。

使用 Gradle 自动扩展属性

通过配置 Java 插件的 processResources 任务,可以自动展开 Gradle 项目中的属性,如下例所示:

groovy 复制代码
tasks.named('processResources') {
    expand(project.properties)
}

然后,你就可以使用占位符来引用 Gradle 项目的属性了,如下例所示:

yaml 复制代码
app:
  name: "${name}"
  description: "${description}"

Gradle 的展开方法使用 Groovy 的 SimpleTemplateEngine,它可以转换 ${..} 标记。${..} 风格与 Spring 自己的属性占位符机制相冲突。要同时使用 Spring 属性占位符和自动扩展,请按如下方式转义 Spring 属性占位符: \${..}.

将 SpringApplication 的配置外部化

SpringApplication 具有 bean 属性设置器,因此您可以在创建应用程序时使用其 Java API 来修改其行为。或者,你也可以通过在 spring.main.* 中设置属性来将配置外部化。例如,在 application.properties 中可能有以下设置:

yaml 复制代码
spring:
  main:
    web-application-type: "none"
    banner-mode: "off"

这样,启动时就不会打印 Spring Boot 横幅,应用程序也不会启动嵌入式 Web 服务器。

外部配置中定义的属性会覆盖并取代 Java API 中指定的值,但主源是个明显的例外。主要源是提供给 SpringApplication 构造函数的那些源:

java 复制代码
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MyApplication.class);
        application.setBannerMode(Banner.Mode.OFF);
        application.run(args);
    }

}

SpringApplicationBuildersources(...) 方法:

java 复制代码
import org.springframework.boot.Banner;
import org.springframework.boot.builder.SpringApplicationBuilder;

public class MyApplication {

    public static void main(String[] args) {
        new SpringApplicationBuilder()
            .bannerMode(Banner.Mode.OFF)
            .sources(MyApplication.class)
            .run(args);
    }

}

鉴于上述例子,如果我们有以下配置:

yaml 复制代码
spring:
  main:
    sources: "com.example.MyDatabaseConfig,com.example.MyJmsConfig"
    banner-mode: "console"

实际应用程序将显示横幅(由配置重载),并使用三个 ApplicationContext 源。应用程序源是:

  1. MyApplication(来自代码)
  2. MyDatabaseConfig(来自外部配置)
  3. MyJmsConfig(来自外部配置)

更改应用程序外部属性的位置

默认情况下,不同来源的属性会按照定义的顺序添加到 Spring Environment 中(具体顺序请参见 "Spring Boot 功能 "部分中的 "features.html")。

您还可以提供以下系统属性(或环境变量)来改变行为:

  • spring.config.name (SPRING_CONFIG_NAME): 默认以application作为文件名的根。
  • spring.config.location (SPRING_CONFIG_LOCATION): 要加载的文件(如类路径资源或 URL)。为该文件设置了一个单独的环境属性源,它可以被系统属性、环境变量或命令行覆盖。

无论您在环境中设置了什么,Spring Boot 都会如上所述加载 application.properties。默认情况下,如果使用 YAML,那么扩展名为".yml "和".yml "的文件也会被添加到列表中。

如果您想了解加载文件的详细信息,可以将 org.springframework.boot.context.config日志级别设置trace

使用 "短 "命令行参数

有些人喜欢使用(例如)--port=9000 而不是 --server.port=9000 在命令行上设置配置属性。您可以通过在 application.properties 中使用占位符启用此行为,如下例所示:

yaml 复制代码
server:
  port: "${port:8080}"

如果从 spring-boot-starter-parent POM 继承,maven-resources-plugins 的默认过滤标记已从 ${*} 改为 @(即 @maven.token@ 而非 ${maven.token}),以防止与 Spring 风格占位符冲突。如果直接启用了 application.properties 的 Maven 过滤功能,则可能还需要更改默认过滤标记,以使用其他分隔符
在这种特定情况下,端口绑定可在 PaaS 环境(如 Heroku 或 Cloud Foundry)中使用。在这两个平台中,PORT 环境变量会自动设置,Spring 可以绑定到Environment属性的大写同义词。

外部属性使用 YAML

YAML 是 JSON 的超集,因此是以分层格式存储外部属性的便捷语法,如下例所示:

yaml 复制代码
spring:
  application:
    name: "cruncher"
  datasource:
    driver-class-name: "com.mysql.jdbc.Driver"
    url: "jdbc:mysql://localhost/test"
server:
  port: 9000

创建一个名为 application.yaml 的文件,并将其放在类路径的根目录下。然后将 snakeyaml 添加到依赖项中(Maven 坐标 org.yaml:snakeyaml,如果使用 spring-boot-starter,则已包含)。YAML 文件会被解析为 Java Map<String,Object>(类似于 JSON 对象),Spring Boot 会对 Map 进行扁平化处理,使其深入一级并具有以句号分隔的键,就像很多人习惯使用 Java 中的属性文件一样。

前面的 YAML 示例与下面的 application.properties 文件相对应:

properties 复制代码
spring.application.name=cruncher
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/test
server.port=9000

有关 YAML 的更多信息,请参见 "Spring Boot 功能" 部分中的 "features.html"。

设置活动的 Spring 配置文件

Spring Environment 有一个相关的 API,但你通常需要设置一个系统属性(spring.profiles.active)或操作系统环境变量(SPRING_PROFILES_ACTIVE)。此外,你还可以使用 -D 参数(记得放在主类或 jar 压缩包之前)启动应用程序,如下所示:

shell 复制代码
$ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar

在 Spring Boot 中,您还可以在 application.properties 中设置活动配置文件,如下例所示:

yaml 复制代码
spring:
  profiles:
    active: "production"

以这种方式设置的值会被 System 属性或环境变量设置取代,但不会被 SpringApplicationBuilder.profiles() 方法取代。因此,可以使用后一种 Java API 来增强配置文件,而无需更改默认值。

有关详细信息,请参阅 "Spring Boot 功能" 部分中的 "features.html"。

设置默认配置文件名称

默认配置文件是在没有激活任何配置文件的情况下启用的配置文件。默认情况下,默认配置文件的名称是 default,但可以使用系统属性 (spring.profiles.default) 或操作系统环境变量 (SPRING_PROFILES_DEFAULT) 进行更改。

在 Spring Boot 中,还可以在 application.properties 中设置默认配置文件名称,如下例所示:

yaml 复制代码
spring:
  profiles:
    default: "dev"

有关详细信息,请参阅 "Spring Boot 功能" 部分中的 "features.html"。

根据环境更改配置

Spring Boot 支持多文档 YAML 和 Properties 文件(详见 features.html),可根据活动配置文件有条件地激活这些文件。

如果文档包含 spring.config.activate.on-profile 关键字,那么配置文件值(以逗号分隔的配置文件列表或配置文件表达式)将被送入 Spring Environment.acceptsProfiles() 方法。如果配置文件表达式匹配,则该文档将包含在最终合并中(否则不包含),如下例所示:

yaml 复制代码
server:
  port: 9000
---
spring:
  config:
    activate:
      on-profile: "development"
server:
  port: 9001
---
spring:
  config:
    activate:
      on-profile: "production"
server:
  port: 0

在上例中,默认端口为 9000。但是,如果名为 "development" 的 Spring 配置文件处于活动状态,则端口为 9001。如果 "production" 处于活动状态,则端口为 0。

文件合并的顺序是文件出现的先后顺序。后面的值优先于前面的值。

发现外部属性的内置选项

Spring Boot 会在运行时将 application.properties(或 YAML 文件和其他地方)中的外部属性绑定到应用程序中。单个位置不可能(技术上也不可能)列出所有支持的属性,因为这些属性可能来自类路径上的其他 jar 文件。

具有 Actuator 功能的运行中应用程序有一个 configprops 端点,可显示通过 @ConfigurationProperties 可用的所有绑定属性。

附录中包含一个 application.properties 示例,其中列出了 Spring Boot 支持的最常见属性。这份明确的列表来自于对 @ConfigurationProperties@Value 注解源代码的搜索,以及对 Binder 的偶尔使用。有关加载属性的确切顺序,请参阅 "features.html"。

嵌入式 Web 服务器

每个 Spring Boot Web 应用程序都包含一个嵌入式 Web 服务器。这一特性会导致许多操作问题,包括如何更改嵌入式服务器和如何配置嵌入式服务器。本节将回答这些问题。

使用其他网络服务器

许多 Spring Boot 启动程序都包含默认的嵌入式容器。

  • 对于 servlet 栈应用程序,spring-boot-starter-web 通过包括 spring-boot-starter-tomcat 包含 Tomcat,但你也可以使用 spring-boot-starter-jettyspring-boot-starter-undertow 代替。
  • 对于反应堆栈应用程序,spring-boot-starter-webflux 通过加入 spring-boot-starter-reactor-netty 包含了 Reactor Netty,但你也可以使用 spring-boot-starter-tomcatspring-boot-starter-jettyspring-boot-starter-undertow 代替。

当切换到不同的 HTTP 服务器时,您需要将默认依赖项替换为您需要的依赖项。为了帮助完成这一过程,Spring Boot 为每个受支持的 HTTP 服务器提供了单独的启动器。

下面的 Maven 示例展示了如何为 Spring MVC 排除 Tomcat 并包含 Jetty:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <!-- Exclude the Tomcat dependency -->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!-- Use Jetty instead -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

下面的 Gradle 示例配置了必要的依赖关系和模块替换,以便在 Spring WebFlux 中使用 Undertow 代替 Reactor Netty:

groovy 复制代码
dependencies {
    implementation "org.springframework.boot:spring-boot-starter-undertow"
    implementation "org.springframework.boot:spring-boot-starter-webflux"
    modules {
        module("org.springframework.boot:spring-boot-starter-reactor-netty") {
            replacedBy("org.springframework.boot:spring-boot-starter-undertow", "Use Undertow instead of Reactor Netty")
        }
    }
}

使用 WebClient 类时需要使用 spring-boot-starter-reactor-netty,因此即使需要包含不同的 HTTP 服务器,也可能需要保持对 Netty 的依赖。

禁用 Web 服务器

如果您的类路径包含启动 Web 服务器所需的位,Spring Boot 会自动启动它。要禁用此行为,请在 application.properties 中配置 WebApplicationType,如下例所示:

yaml 复制代码
spring:
  main:
    web-application-type: "none"

修改 HTTP 端口

在独立应用程序中,主 HTTP 端口默认为 8080,但可以使用 server.port 进行设置(例如,在 application.properties 中或作为系统属性)。由于放宽了环境值的绑定,还可以使用 SERVER_PORT(例如,作为操作系统环境变量)。

如果要完全关闭 HTTP 端点,但仍要创建 WebApplicationContext,可使用 server.port=-1(这样做有时对测试很有用)。

有关详细信息,请参阅 "Spring Boot 功能" 部分中的 "web.html" 或 ServerProperties 源代码。

使用随机的未分配 HTTP 端口

要扫描空闲端口(使用操作系统本地端口以防止冲突),请使用 server.port=0

在运行时发现 HTTP 端口

您可以通过日志输出或 WebServerApplicationContext 访问服务器运行的端口。获取端口并确保其已被初始化的最佳方法是添加一个 ApplicationListener<WebServerInitializedEvent> 类型的 @Bean,并在事件发布时将容器从事件中提取出来。

使用 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) 的测试也可以通过 @LocalServerPort 注解将实际端口注入一个字段,如下例所示:

java 复制代码
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyWebIntegrationTests {

    @LocalServerPort
    int port;

    // ...

}

@LocalServerPort@Value("${local.server.port}")的元注解。不要尝试在常规应用程序中注入端口。正如我们刚才看到的,只有在容器初始化后才会设置该值。与测试相反,应用程序代码回调会提前处理(在值实际可用之前)。

启用 HTTP 响应压缩

Jetty、Tomcat、Reactor Netty 和 Undertow 支持 HTTP 响应压缩。可在 application.properties 中启用,如下所示:

yaml 复制代码
server:
  compression:
    enabled: true

默认情况下,响应长度必须至少达到 2048 字节才能执行压缩。您可以通过设置 server.compression.min-response-size 属性来配置此行为。

默认情况下,只有当响应的内容类型为以下类型之一时,才会对其进行压缩:

  • text/html
  • text/xml
  • text/plain
  • text/css
  • text/javascript
  • application/javascript
  • application/json
  • application/xml

您可以通过设置 server.compression.mime-types 属性来配置此行为。

配置 SSL

SSL 可通过设置各种 server.ssl.* 属性进行声明式配置,通常在 application.propertiesapplication.yaml 中设置。下面的示例展示了使用 Java KeyStore 文件设置 SSL 属性:

yaml 复制代码
server:
  port: 8443
  ssl:
    key-store: "classpath:keystore.jks"
    key-store-password: "secret"
    key-password: "another-secret"

使用上例这样的配置意味着应用程序不再支持 8080 端口的纯 HTTP 连接器。Spring Boot 不支持通过 application.properties 同时配置 HTTP 连接器和 HTTPS 连接器。如果你想同时拥有这两个连接器,就需要以编程方式配置其中一个。我们建议使用 application.properties 来配置 HTTPS,因为 HTTP 连接器更容易进行编程配置。

使用 PEM 编码文件

您可以使用 PEM 编码文件代替 Java KeyStore 文件。应尽可能使用 PKCS#8 密钥文件。PEM 编码的 PKCS#8 密钥文件以 -----BEGIN PRIVATE KEY----------BEGIN ENCRYPTED PRIVATE KEY----- 头文件开始。

如果您有其他格式的文件,例如 PKCS#1 (-----BEGIN RSA PRIVATE KEY-----) 或 SEC 1 (-----BEGIN EC PRIVATE KEY-----),您可以使用 OpenSSL 将其转换为 PKCS#8 格式:

shell 复制代码
openssl pkcs8 -topk8 -nocrypt -in <input file> -out <output file>
yaml 复制代码
server:
  port: 8443
  ssl:
    certificate: "classpath:my-cert.crt"
    certificate-private-key: "classpath:my-cert.key"
    trust-certificate: "classpath:ca-cert.crt"

另外,也可以在 SSL bundle 中配置 SSL 信任材料,并应用于网络服务器,如本示例所示:

yaml 复制代码
server:
  port: 8443
  ssl:
    bundle: "example"

有关所有支持属性的详细信息,请参阅 Ssl

配置 HTTP/2

您可以使用 server.http2.enabled 配置属性在 Spring Boot 应用程序中启用 HTTP/2 支持。h2(HTTP/2 over TLS)和 h2c(HTTP/2 over TCP)均受支持。要使用 h2,还必须启用 SSL。未启用 SSL 时,将使用 h2c。例如,当应用程序在执行 TLS 终止的代理服务器后运行时,可能需要使用 h2c。

使用 Tomcat 实现 HTTP/2

Spring Boot 默认搭载 Tomcat 10.1.x,开箱即支持 h2ch2。另外,如果主机操作系统安装了 libtcnative 库及其依赖项,也可以使用 libtcnative 来支持 h2

如果 JVM 库路径中还没有库,则必须提供库目录。可以使用 JVM 参数(如 -Djava.library.path=/usr/local/opt/tomcat-native/lib)这样做。更多信息请参阅 Tomcat 官方文档

使用 Jetty 实现 HTTP/2

要支持 HTTP/2,Jetty 需要额外的 org.eclipse.jetty.http2:jetty-http2-server 依赖项。要使用 h2c,则无需其他依赖。要使用 h2,您还需要根据部署情况从以下依赖项中选择一个:

  • org.eclipse.jetty:jetty-alpn-java-server 以使用 JDK 内置支持
  • org.eclipse.jetty:jetty-alpn-conscrypt-serverConscrypt 库

使用 Reactor Netty 实现 HTTP/2

spring-boot-webflux-starter 默认使用 Reactor Netty 作为服务器。Reactor Netty 支持开箱即用的 h2ch2。为优化运行时性能,该服务器还支持使用本地库的 h2。要实现这一点,您的应用程序需要额外的依赖关系。

Spring Boot 会管理 io.netty:netty-tcnative-boringssl-static "uber jar" 的版本,其中包含适用于所有平台的本地库。开发人员可以选择使用分类器只导入所需的依赖项(参见 Netty 官方文档)。

使用 Undertow 实现 HTTP/2

Undertow 开箱即支持 h2ch2

配置 Web 服务器

一般来说,你应该首先考虑使用许多可用配置密钥之一,并通过在 application.propertiesapplication.yaml 文件中添加新条目来定制你的网络服务器。请参阅 "发现外部属性的内置选项")。server.* 命名空间在此非常有用,它包括 server.tomcat.*server.jetty.* 等命名空间,用于实现特定于服务器的功能。请参阅应用程序属性列表。

前面的章节已经介绍了许多常见用例,如压缩、SSL 或 HTTP/2。但是,如果您的用例不存在配置密钥,那么您就应该看看 WebServerFactoryCustomizer。你可以声明这样一个组件,并访问与你的选择相关的服务器工厂:你应该为所选的服务器(Tomcat、Jetty、Reactor Netty、Undertow)和所选的网络堆栈(Servlet 或 Reactive)选择变体。

下面的示例是使用 spring-boot-starter-web(servlet 栈)的 Tomcat:

java 复制代码
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;

@Component
public class MyTomcatWebServerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        // customize the factory here
    }

}

Spring Boot 在内部使用该基础架构来自动配置服务器。自动配置的 WebServerFactoryCustomizer Bean 的顺序为 0,将在任何用户定义的自定义器之前处理,除非它有明确的顺序说明。

一旦使用自定义器访问了 WebServerFactory,就可以使用它来配置特定部分,如连接器、服务器资源或服务器本身--所有这些都使用服务器特定的 API。

此外,Spring Boot 还提供:

Server Servlet stack Reactive stack
Tomcat TomcatServletWebServerFactory TomcatReactiveWebServerFactory
Jetty JettyServletWebServerFactory JettyReactiveWebServerFactory
Undertow UndertowServletWebServerFactory UndertowReactiveWebServerFactory
Reactor N/A NettyReactiveWebServerFactory

最后,您还可以声明自己的 WebServerFactory Bean,它将覆盖 Spring Boot 提供的 Bean。这样做时,自动配置的自定义器仍会应用于自定义工厂,因此请谨慎使用该选项。

向应用程序添加 Servlet、Filter或Listener

在使用 spring-boot-starter-web 的 Servlet 栈应用程序中,有两种方法可以在应用程序中添加 ServletFilterServletContextListener 和 Servlet API 支持的其他监听器:

  • 使用 Spring Bean 添加 Servlet、Filter和Listener
  • 使用类路径扫描添加 Servlet、Filter和Listener

使用 Spring Bean 添加 Servlet、Filter或Listener

要使用 Spring Bean 添加 ServletFilterservlet *Listener,必须为其提供 @Bean 定义。当你想注入配置或依赖关系时,这样做非常有用。不过,您必须非常小心,以免它们导致过多其他 Bean 的急迫初始化,因为它们必须在应用程序生命周期的早期安装到容器中。(例如,让它们依赖于数据源或 JPA 配置就不是一个好主意)。您可以绕过这些限制,在首次使用时而不是在初始化时懒散地初始化 Bean。

就 Filter 和 Servlet 而言,您还可以通过添加FilterRegistrationBeanServletRegistrationBean来添加映射和初始化参数,以代替或补充底层组件。

如果在过滤器注册时没有指定 DispatcherType,则使用 REQUEST。这与 servlet 规范的默认派发器类型一致。

与其他 Spring Bean 一样,您也可以定义 servlet filter Bean 的顺序;请务必查看 "web.html" 部分。

禁用 Servlet 或 Filter 的注册

如前所述,任何 Servlet 或 Filter Bean 都会自动向 servlet 容器注册。要禁用特定 Filter 或 Servlet Bean 的注册,请为其创建一个注册 Bean 并将其标记为禁用,如下例所示:

java 复制代码
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyFilterConfiguration {

    @Bean
    public FilterRegistrationBean<MyFilter> registration(MyFilter filter) {
        FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(filter);
        registration.setEnabled(false);
        return registration;
    }

}

使用类路径扫描添加 Servlet、Filter和Listener

通过用 @ServletComponentScan@Configuration 类进行注解,并指定包含要注册的组件的包,@WebServlet@WebFilter@WebListener 注解类可自动与嵌入式 servlet 容器注册。默认情况下,@ServletComponentScan 会从注解类的包中扫描。

配置访问日志

访问日志可通过 Tomcat、Undertow 和 Jetty 各自的命名空间进行配置。

例如,以下设置使用自定义模式记录 Tomcat 的访问日志。

yaml 复制代码
server:
  tomcat:
    basedir: "my-tomcat"
    accesslog:
      enabled: true
      pattern: "%t %a %r %s (%D microseconds)"

日志的默认位置是相对于 Tomcat 基本目录的日志目录。默认情况下,日志目录是一个临时目录,因此您可能需要固定 Tomcat 的基本目录或使用日志的绝对路径。在上例中,日志位于 my-tomcat/logs 中,相对于应用程序的工作目录。

Undertow 的访问日志可以类似方式配置,如下例所示:

yaml 复制代码
server:
  undertow:
    accesslog:
      enabled: true
      pattern: "%t %a %r %s (%D milliseconds)"
    options:
      server:
        record-request-start-time: true

请注意,除了启用访问日志和配置其模式外,还启用了记录请求开始时间。在访问日志模式中包含响应时间 (%D) 时需要这样做。日志存储在相对于应用程序工作目录的日志目录中。您可以通过设置 server.undertow.accesslog.dir 属性自定义该位置。

最后,Jetty 的访问日志也可以按以下方式配置:

yaml 复制代码
server:
  jetty:
    accesslog:
      enabled: true
      filename: "/var/log/jetty-access.log"

默认情况下,日志会重定向到 System.err。有关详细信息,请参阅 Jetty 文档。

在前端代理服务器后运行

如果您的应用程序在代理、负载平衡器或云中运行,请求信息(如主机、端口、方案...)可能会发生变化。您的应用程序可能在 10.10.10.10:8080 上运行,但 HTTP 客户端只能看到 example.org
RFC7239 "转发头"定义了转发 HTTP 头;代理可以使用该头提供原始请求的相关信息。您可以配置应用程序读取这些标头,并在创建链接时自动使用这些信息,然后通过 HTTP 302 响应、JSON 文档或 HTML 页面发送给客户端。还有一些非标准头信息,如 X-Forwarded-HostX-Forwarded-PortX-Forwarded-ProtoX-Forwarded-SslX-Forwarded-Prefix

如果代理添加了常用的 X-Forwarded-ForX-Forwarded-Proto 标头,将 server.forward-headers-strategy 设置为 NATIVE 就足以支持这些标头。有了这个选项,Web 服务器本身就能原生支持该功能;你可以查看它们的具体文档来了解具体行为。

如果这还不够,Spring Framework 还为 servlet 栈提供了 ForwardedHeaderFilter,为反应栈提供了 ForwardedHeaderTransformer。只要将 server.forward-headers-strategy 设置为 FRAMEWORK,就能在应用程序中使用它们。

如果使用 Tomcat 并在代理处终止 SSL,则 server.tomcat.redirect-context-root 应设置为 false。这样,在执行任何重定向之前,X-Forwarded-Proto 头信息都会得到尊重。
如果您的应用程序在 Cloud Foundry、Heroku 或 Kubernetes 中运行,server.forward-headers-strategy 属性默认为 NATIVE。在所有其他情况下,该属性默认为 "NONE"。

自定义 Tomcat 的代理配置

如果使用 Tomcat,还可以额外配置用于携带 "forwarded" 信息的标头名称,如下例所示:

yaml 复制代码
server:
  tomcat:
    remoteip:
      remote-ip-header: "x-your-remote-ip-header"
      protocol-header: "x-your-protocol-header"

Tomcat 还配置了一个正则表达式,用于匹配需要信任的内部代理。有关其默认值,请参阅附录中的 server.tomcat.remoteip.internal-proxies 条目。您可以在 application.properties 中添加一个条目,自定义阀门的配置,如下例所示:

yaml 复制代码
server:
  tomcat:
    remoteip:
      internal-proxies: "192\\.168\\.\\d{1,3}\\.\\d{1,3}"

通过将 internal-proxies 设置为空,可以信任所有代理(但在生产中不要这样做)。

您可以完全控制 Tomcat RemoteIpValve 的配置,方法是关闭自动配置(为此请设置 server.forward-headers-strategy=NONE),并使用 WebServerFactoryCustomizer Bean 添加一个新的阀门实例。

通过 Tomcat 启用多个连接器

您可以在 TomcatServletWebServerFactory 中添加 org.apache.catalina.connector.Connector,它可以允许多个连接器,包括 HTTP 和 HTTPS 连接器,如下例所示:

java 复制代码
import org.apache.catalina.connector.Connector;

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyTomcatConfiguration {

    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> connectorCustomizer() {
        return (tomcat) -> tomcat.addAdditionalTomcatConnectors(createConnector());
    }

    private Connector createConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setPort(8081);
        return connector;
    }

}

启用 Tomcat 的 MBean 注册表

嵌入式 Tomcat 的 MBean 注册表默认是禁用的。这最大限度地减少了 Tomcat 的内存占用。如果您想使用 Tomcat 的 MBeans,例如让 Micrometer 使用它们来公开度量指标,就必须使用 server.tomcat.mbeanregistry.enabled 属性来实现,如下例所示:

yaml 复制代码
server:
  tomcat:
    mbeanregistry:
      enabled: true

使用 Undertow 启用多个监听器

UndertowServletWebServerFactory 添加一个 UndertowBuilderCustomizer,并向 Builder 添加一个监听器,如下例所示:

java 复制代码
import io.undertow.Undertow.Builder;

import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyUndertowConfiguration {

    @Bean
    public WebServerFactoryCustomizer<UndertowServletWebServerFactory> undertowListenerCustomizer() {
        return (factory) -> factory.addBuilderCustomizers(this::addHttpListener);
    }

    private Builder addHttpListener(Builder builder) {
        return builder.addHttpListener(8080, "0.0.0.0");
    }

}

使用 @ServerEndpoint 创建 WebSocket 端点

如果要在使用嵌入式容器的 Spring Boot 应用程序中使用 @ServerEndpoint,则必须声明一个 ServerEndpointExporter @Bean,如下例所示:

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration(proxyBeanMethods = false)
public class MyWebSocketConfiguration {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

上例中显示的 Bean 会向底层 WebSocket 容器注册任何带有 @ServerEndpoint 注释的 Bean。当部署到独立的 servlet 容器时,这一角色由 servlet 容器初始化器执行,而不需要 ServerEndpointExporter Bean。

Spring MVC

Spring Boot 有许多包含 Spring MVC 的启动器。请注意,有些启动程序包含对 Spring MVC 的依赖,而不是直接包含 Spring MVC。本节将回答有关 Spring MVC 和 Spring Boot 的常见问题。

编写 JSON REST 服务

只要 Jackson2 位于类路径上,Spring Boot 应用程序中的任何 Spring @RestController 默认都应呈现 JSON 响应,如下例所示:

java 复制代码
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @RequestMapping("/thing")
    public MyThing thing() {
        return new MyThing();
    }

}

只要 MyThing 可以被 Jackson2 序列化(对于普通 POJO 或 Groovy 对象而言为 true),那么 localhost:8080/thing 默认会提供一个 JSON 表示。请注意,在浏览器中,有时可能会看到 XML 响应,因为浏览器倾向于发送偏好 XML 的接受头。

编写 XML REST 服务

如果在类路径上有 Jackson XML 扩展(jackson-dataformat-xml),就可以使用它来呈现 XML 响应。之前用于 JSON 的示例也可以使用。要使用 Jackson XML 渲染器,请在项目中添加以下依赖关系:

xml 复制代码
<dependency>
  <groupId>com.fasterxml.jackson.dataformat</groupId>
  <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

如果 Jackson 的 XML 扩展不可用,而 JAXB 可用,则可通过将 MyThing 注释为 @XmlRootElement 来呈现 XML,如下例所示:

java 复制代码
import jakarta.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class MyThing {

    private String name;

    public String getName() {
        return this.name;
    }

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

}

您需要确保 JAXB 库是项目的一部分,例如添加

xml 复制代码
<dependency>
  <groupId>org.glassfish.jaxb</groupId>
  <artifactId>jaxb-runtime</artifactId>
</dependency>

要让服务器渲染 XML 而不是 JSON,可能需要发送 Accept: text/xml 标头(或使用浏览器)。

自定义 Jackson ObjectMapper

Spring MVC(客户端和服务器端)使用 HttpMessageConverters 来协商 HTTP 交换中的内容转换。如果类路径上有Jackson,你就已经获得了Jackson2ObjectMapperBuilder提供的默认转换器,它的实例会为你自动配置。

默认创建的 ObjectMapper(或 Jackson XML 转换器的 XmlMapper)实例具有以下自定义属性:

  • MapperFeature.DEFAULT_VIEW_INCLUSION 已禁用
  • 反序列化特性 FAIL_ON_UNKNOWN_PROPERTIES 已禁用
  • SerializationFeature.WRITE_DATES_AS_TIMESTAMPS 已禁用
  • SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS 已禁用

Spring Boot 还提供了一些功能,可以让您更轻松地自定义这一行为。

您可以使用环境配置 ObjectMapperXmlMapper 实例。Jackson 提供了一整套开/关功能,可用于配置其处理过程的各个方面。这些功能在几个枚举(Jackson 中)中进行了描述,这些枚举映射到环境中的属性:

Enum Property Values
com.fasterxml.jackson.databind.cfg.EnumFeature spring.jackson.datatype.enum.<feature_name> true, false
com.fasterxml.jackson.databind.cfg.JsonNodeFeature spring.jackson.datatype.json-node.<feature_name> true, false
com.fasterxml.jackson.databind.DeserializationFeature spring.jackson.deserialization.<feature_name> true, false
com.fasterxml.jackson.core.JsonGenerator.Feature spring.jackson.generator.<feature_name> true, false
com.fasterxml.jackson.databind.MapperFeature spring.jackson.mapper.<feature_name> true, false
com.fasterxml.jackson.core.JsonParser.Feature spring.jackson.parser.<feature_name> true, false
com.fasterxml.jackson.databind.SerializationFeature spring.jackson.serialization.<feature_name> true, false
com.fasterxml.jackson.annotation.JsonInclude.Include spring.jackson.default-property-inclusion always, non_null, non_absent, non_default, non_empty

例如,要启用漂亮打印,请设置 spring.jackson.serialization.indent_output=true。请注意,由于使用了宽松绑定indent_output 的大小写不必与相应枚举常量 INDENT_OUTPUT 的大小写相匹配。

这种基于环境的配置将应用于自动配置的 Jackson2ObjectMapperBuilder Bean,并应用于使用该构建器创建的任何映射器,包括自动配置的 ObjectMapper Bean。

上下文的 Jackson2ObjectMapperBuilder 可由一个或多个 Jackson2ObjectMapperBuilderCustomizer Bean 进行自定义。这些定制器 Bean 可以排序(Boot 自带的定制器排序为 0),以便在 Boot 定制之前和之后应用额外的定制。

任何 com.fasterxml.jackson.databind.Module 类型的 Bean 都会自动注册到自动配置的 Jackson2ObjectMapperBuilder 中,并应用到它创建的任何 ObjectMapper 实例。这为您在应用程序中添加新功能时贡献自定义模块提供了一个全局机制。

如果您想完全替换默认 ObjectMapper,可以定义一个该类型的 @Bean 并将其标记为 @Primary,或者,如果您更喜欢基于构建器的方法,可以定义一个 Jackson2ObjectMapperBuilder @Bean。请注意,无论哪种情况,这样做都会禁用对象映射器的所有自动配置。

如果您提供任何 MappingJackson2HttpMessageConverter 类型的 @Beans,它们将取代 MVC 配置中的默认值。此外,我们还提供了一个 HttpMessageConverters 类型的便利 Bean(如果使用默认 MVC 配置,该 Bean 始终可用)。它有一些有用的方法来访问默认和用户增强的消息转换器。

有关详细信息,请参阅 "自定义 @ResponseBody 渲染" 部分和 WebMvcAutoConfiguration 源代码。

自定义 @ResponseBody 渲染

Spring 使用 HttpMessageConverters 来呈现 @ResponseBody(或来自 @RestController 的响应)。您可以通过在 Spring Boot 上下文中添加相应类型的 Bean 来提供额外的转换器。如果您添加的 Bean 属于默认包含的类型(如用于 JSON 转换的 MappingJackson2HttpMessageConverter),它将取代默认值。我们提供了一个 HttpMessageConverters 类型的便利 Bean,如果使用默认的 MVC 配置,它总是可用的。它有一些有用的方法来访问默认和用户增强的消息转换器(例如,如果要将它们手动注入到自定义 RestTemplate 中,它就很有用)。

与普通 MVC 的用法一样,您提供的任何 WebMvcConfigurer Bean 也可以通过覆盖 configureMessageConverters 方法来提供转换器。不过,与普通 MVC 不同的是,您只能提供您需要的额外转换器(因为 Spring Boot 使用相同的机制来贡献其默认值)。最后,如果您通过提供自己的 @EnableWebMvc 配置来选择不使用 Spring Boot 默认的 MVC 配置,您就可以完全控制并使用 WebMvcConfigurationSupport 中的 getMessageConverters 手动完成所有操作。

详情请查看 WebMvcAutoConfiguration 源代码。

处理多文件上传

Spring Boot 采用 servlet 5 jakarta.servlet.http.Part API 来支持上传文件。默认情况下,Spring Boot 为 Spring MVC 配置的每个文件最大大小为 1MB,单个请求中的文件数据最大为 10MB。您可以使用 MultipartProperties 类中公开的属性来覆盖这些值、中间数据的存储位置(例如,存储到 /tmp 目录)以及数据刷新到磁盘的阈值。例如,如果要指定文件不受限制,可将 spring.servlet.multipart.max-file-size 属性设置为-1

当你想在 Spring MVC 控制器处理程序方法中接收多文件编码文件数据作为 MultipartFile 类型的 @RequestParam 注解参数时,多文件支持会很有帮助。

有关详细信息,请参阅 MultipartAutoConfiguration 源。

建议使用容器对多文件上传的内置支持,而不是引入额外的依赖,如 Apache Commons File Upload。

关闭 Spring MVC DispatcherServlet

默认情况下,所有内容都从应用程序的根目录 (/) 提供。如果您希望映射到不同的路径,可以按如下方式配置:

yaml 复制代码
spring:
  mvc:
    servlet:
      path: "/mypath"

如果您有额外的 servlet,可以为每个 servlet 声明一个 ServletServletRegistrationBean 类型的 @Bean,Spring Boot 会以透明的方式向容器注册它们。由于 Servlet 是以这种方式注册的,因此可以将它们映射到 DispatcherServlet 的子上下文中,而无需调用它。

自行配置 DispatcherServlet 并不常见,但如果确实需要,则必须提供 DispatcherServletPath 类型的 @Bean 以提供自定义 DispatcherServlet 的路径。

关闭默认 MVC 配置

要完全控制 MVC 配置,最简单的方法就是使用 @EnableWebMvc 注解提供自己的 @Configuration。这样一来,所有的 MVC 配置就都掌握在你的手中了。

自定义 ViewResolvers

ViewResolver 是 Spring MVC 的核心组件,它将 @Controller 中的视图名称转换为实际的视图实现。请注意,ViewResolver 主要用于 UI 应用程序,而不是 REST 类型的服务(View 并不用于渲染 @ResponseBody)。ViewResolver 有许多实现可供选择,Spring 本身并不主张使用哪种实现。另一方面,Spring Boot 会根据它在类路径和应用上下文中的发现,为你安装一个或两个。DispatcherServlet 会使用它在应用上下文中找到的所有解析器,依次尝试每个解析器,直到得到结果。如果要添加自己的解析器,必须注意添加的顺序和位置。
WebMvcAutoConfiguration 会在上下文中添加以下 ViewResolvers

  • 名为 "defaultViewResolver" 的 InternalResourceViewResolver。它用于定位可通过使用 DefaultServlet 呈现的物理资源(包括静态资源和 JSP 页面,如果使用的话)。它会为视图名称添加前缀和后缀,然后在 servlet 上下文中查找具有该路径的物理资源(默认值均为空,但可通过 spring.mvc.view.prefixspring.mvc.view.suffix 进行外部配置)。您可以通过提供相同类型的 Bean 来覆盖它。
  • 一个名为 "beanNameViewResolver" 的 BeanNameViewResolver。它是视图解析器链中一个有用的成员,可拾取与正在解析的视图同名的任何 Bean。无需覆盖或替换它。
  • 只有当实际存在 View 类型的 Bean 时,才会添加名为 "viewResolver" 的 ContentNegotiatingViewResolver。这是一个复合解析器,委托给所有其他解析器,并试图找到与客户端发送的 "Accept" HTTP 头信息相匹配的解析器。有一篇关于 ContentNegotiatingViewResolver 的博客很有用,你可以参考一下以了解更多信息,也可以查看源代码以了解细节。你可以通过定义一个名为 "viewResolver" 的 Bean 来关闭自动配置的 ContentNegotiatingViewResolver
  • 如果使用 Thymeleaf,还有一个名为 "thymeleafViewResolver" 的 ThymeleafViewResolver。它通过在视图名称周围加上前缀和后缀来查找资源。前缀是 spring.thymeleaf.prefix,后缀是 spring.thymeleaf.suffix。前缀和后缀的默认值分别为 "classpath:/templates/"和".html"。你可以通过提供一个同名的 Bean 来覆盖 ThymeleafViewResolver
  • 如果您使用 FreeMarker,您还将拥有一个名为 "freeMarkerViewResolver" 的 FreeMarkerViewResolver。它通过在视图名称周围加上前缀和后缀,在加载器路径(外部化为 spring.freemarker.templateLoaderPath,默认值为 "classpath:/templates/")中查找资源。前缀外部化为 spring.freemarker.prefix,后缀外部化为 spring.freemarker.suffix。前缀和后缀的默认值分别为空和".ftlh"。您可以通过提供同名的 Bean 来覆盖 FreeMarkerViewResolver
  • 如果你使用 Groovy 模板(实际上,如果你的类路径上有 groovy-templates),你还会有一个名为 "groovyMarkupViewResolver" 的 GroovyMarkupViewResolver。它通过在视图名称周围加上前缀和后缀(外部化为 spring.groovy.template.prefixspring.groovy.template.suffix)来查找加载器路径中的资源。前缀和后缀的默认值分别为 "classpath:/templates/"和".tpl"。您可以通过提供同名的 Bean 来覆盖 GroovyMarkupViewResolver
  • 如果您使用的是 Mustache,您还会有一个名为 "mustacheViewResolver" 的 MustacheViewResolver。它通过在视图名称周围添加前缀和后缀来查找资源。前缀是 spring.mustache.prefix,后缀是 spring.mustache.suffix。前缀和后缀的默认值分别为 "classpath:/templates/"和".mustache"。您可以通过提供同名的 Bean 来覆盖 MustacheViewResolver

更多详情,请参阅以下章节:

相关推荐
向前看-3 小时前
验证码机制
前端·后端
xlsw_3 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹4 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭4 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫5 小时前
泛型(2)
java
超爱吃士力架5 小时前
邀请逻辑
java·linux·后端
南宫生5 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石5 小时前
12/21java基础
java
李小白665 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp5 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea