4.7 开发Web应用程序

优质
小牛编辑
140浏览
2023-12-01

Spring Boot非常适合Web应用程序开发。 您可以使用嵌入式Tomcat,Jetty,Undertow或Netty创建自包含的HTTP服务器。 大多数Web应用程序使用spring-boot-starter-web模块快速启动和运行。 您还可以使用spring-boot-starter-webflux模块选择构建响应式Web应用程序。

如果您还没有开发Spring Boot Web应用程序,可以按照“Hello World!”进行操作。 “入门”部分中的示例。

4.7.1 “Spring Web MVC框架”

Spring Web MVC框架(通常简称为“Spring MVC”)是一个丰富的“模型视图控制器”Web框架。 Spring MVC允许您创建特殊的@Controller或@RestController bean来处理传入的HTTP请求。 控制器中的方法通过使用@RequestMapping注释映射到HTTP。

以下代码显示了一个提供JSON数据的典型@RestController:

@RestController
@RequestMapping(value="/users")
public class MyRestController {

	@RequestMapping(value="/{user}", method=RequestMethod.GET)
	public User getUser(@PathVariable Long user) {
		// ...
	}

	@RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
	List<Customer> getUserCustomers(@PathVariable Long user) {
		// ...
	}

	@RequestMapping(value="/{user}", method=RequestMethod.DELETE)
	public User deleteUser(@PathVariable Long user) {
		// ...
	}

}

Spring MVC是核心Spring Framework的一部分,详细信息可在参考文档中找到。 Spring.io/guides还提供了几个涵盖Spring MVC的指南。

4.7.1.1 Spring MVC自动配置

Spring Boot为Spring MVC提供自动配置,适用于大多数应用程序。

自动配置在Spring的默认值之上添加了以下功能:

  • 包含ContentNegotiatingViewResolver和BeanNameViewResolver bean。
  • 支持提供静态资源,包括对WebJars的支持(本文档稍后介绍))。
  • 自动注册Converter,GenericConverter和Formatter bean。
  • 支持HttpMessageConverters(本文档稍后介绍)。
  • 自动注册MessageCodesResolver(本文档后面会介绍)。
  • 静态index.html支持。
  • 自定义Favicon支持(本文档稍后介绍)。
  • 自动使用ConfigurableWebBindingInitializer bean(本文稍后介绍)。

如果要保留Spring Boot MVC功能并且想要添加其他MVC配置(拦截器,格式化器,视图控制器和其他功能),可以添加自己的类型为WebMvcConfigurer的@Configuration类但不使用@EnableWebMvc。 如果要提供RequestMappingHandlerMapping,RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver的自定义实例,可以声明WebMvcRegistrationsAdapter实例以提供此类组件。

如果您想完全控制Spring MVC,可以使用@EnableWebMvc添加自己的@Configuration注释。

4.7.1.2 HttpMessageConverters

Spring MVC使用HttpMessageConverter接口来转换HTTP请求和响应。 明智的默认设置包含在开箱即用中。 例如,对象可以自动转换为JSON(通过使用Jackson库)或XML(如果可用,则使用Jackson XML扩展,或者如果Jackson XML扩展不可用,则使用JAXB)。 默认情况下,字符串以UTF-8编码。

如果需要添加或自定义转换器,可以使用Spring Boot的HttpMessageConverters类,如下面的清单所示:

import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;

@Configuration
public class MyConfiguration {

	@Bean
	public HttpMessageConverters customConverters() {
		HttpMessageConverter<?> additional = ...
		HttpMessageConverter<?> another = ...
		return new HttpMessageConverters(additional, another);
	}

}

上下文中存在的任何HttpMessageConverter bean都将添加到转换器列表中。 您也可以以相同的方式覆盖默认转换器。

4.7.1.3 自定义JSON序列化程序和反序列化程序

如果您使用Jackson序列化和反序列化JSON数据,您可能需要编写自己的JsonSerializer和JsonDeserializer类。 自定义序列化程序通常通过模块向Jackson注册,但Spring Boot提供了另一种@JsonComponent注释,可以更容易地直接注册Spring Beans。

您可以直接在JsonSerializer或JsonDeserializer实现上使用@JsonComponent注释。 您还可以在包含序列化程序/反序列化程序作为内部类的类上使用它,如以下示例所示:

import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;

@JsonComponent
public class Example {

	public static class Serializer extends JsonSerializer<SomeObject> {
		// ...
	}

	public static class Deserializer extends JsonDeserializer<SomeObject> {
		// ...
	}

}

ApplicationContext中的所有@JsonComponent bean都会自动注册到Jackson。 因为@JsonComponent是使用@Component进行元注释的,所以常规的组件扫描规则适用。

Spring Boot还提供了JsonObjectSerializer和JsonObjectDeserializer基类,它们在序列化对象时提供了标准Jackson版本的有用替代方法。 有关详细信息,请参阅Javadoc中的JsonObjectSerializer和JsonObjectDeserializer。

4.7.1.4 MessageCodesResolver

Spring MVC有一个生成错误代码的策略,用于从绑定错误中呈现错误消息:MessageCodesResolver。 如果设置spring.mvc.message-codes-resolver.format属性PREFIX_ERROR_CODE或POSTFIX_ERROR_CODE,Spring Boot会为您创建一个(请参阅DefaultMessageCodesResolver.Format中的枚举)。

4.7.1.5 静态内容

默认情况下,Spring Boot从类路径中的/static(或/public或/resources或/META-INF /resources)目录或ServletContext的根目录中提供静态内容。 它使用Spring MVC中的ResourceHttpRequestHandler,以便您可以通过添加自己的WebMvcConfigurer并覆盖addResourceHandlers方法来修改该行为。

在独立的Web应用程序中,容器中的默认servlet也被启用,并充当后盾,如果Spring决定不处理它,则从ServletContext根目录中提供内容。大多数情况下,这种情况不会发生(除非修改默认的MVC配置),因为Spring总是可以通过DispatcherServlet处理请求。

默认情况下,资源映射到/,但您可以使用spring.mvc.static-path-pattern属性对其进行调整。 例如,可以按如下方式将所有资源重新定位到/resources/

spring.mvc.static-path-pattern=/resources/**

您还可以使用spring.resources.static-locations属性(使用目录位置列表替换默认值)来自定义静态资源位置。 根Servlet上下文路径“/”也会自动添加为位置。

除了前面提到的“标准”静态资源位置之外,还为Webjars内容制作了一个特例。 在/webjars/**中具有路径的任何资源都是从jar文件提供的,如果它们以Webjars格式打包的话。

如果您的应用程序打包为jar,请不要使用src/main/webapp目录。 虽然这个目录是一个通用标准,但它只适用于打包war,如果你生成一个jar,它会被大多数构建工具默默忽略。

Spring Boot还支持Spring MVC提供的高级资源处理功能,允许使用非缓存静态资源或使用与Webjars无关的URL。

要为Webjars使用版本无关的URL,请添加webjars-locator-core依赖项。 然后声明你的Webjar。 以jQuery为例,添加“/webjars/jquery/jquery.min.js”会产生“/webjars/jquery/x.y.z/jquery.min.js”。 其中x.y.z是Webjar版本。

如果使用JBoss,则需要声明webjars-locator-jboss-vfs依赖项而不是webjars-locator-core。 否则,所有Webjars都将解析为404。

要使用缓存清除,以下配置为所有静态资源配置缓存清除解决方案,有效地在URL中添加内容哈希,例如。

spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

由于为Thymeleaf和FreeMarker自动配置了ResourceUrlEncodingFilter,因此在运行时可以在模板中重写资源链接。 您应该在使用JSP时手动声明此过滤器。 目前不支持其他模板引擎,但可以使用自定义模板宏/帮助程序以及ResourceUrlProvider的使用。

使用(例如)JavaScript模块加载器动态加载资源时,不能重命名文件。 这就是为什么其他策略也得到支持并可以合并的原因。 “fixed”策略在URL中添加静态版本字符串而不更改文件名,如以下示例所示:

spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/js/lib/
spring.resources.chain.strategy.fixed.version=v12

使用此配置,位于“/js/lib/”下的JavaScript模块使用固定版本控制策略(“/v12/js/lib/mymodule.js”),而其他资源仍使用content()。

有关更多支持的选项,请参阅ResourceProperties。

此功能已在专门的博客文章和Spring Framework的参考文档中进行了详细描述。

4.7.1.6 欢迎页面

Spring Boot支持静态和模板化欢迎页面。 它首先在配置的静态内容位置中查找index.html文件。 如果找不到,则查找索引模板。 如果找到任何一个,它将自动用作应用程序的欢迎页面。

4.7.1.7 自定义Favicon

Spring Boot在配置的静态内容位置和类路径的根(按此顺序)中查找favicon.ico。 如果存在这样的文件,它将自动用作应用程序的favicon。

4.7.1.8 路径匹配和内容协商

Spring MVC可以通过查看请求路径并将其与应用程序中定义的映射(例如Controller方法上的注释@GetMapping)相匹配,将传入的HTTP请求映射到处理程序。

Spring Boot默认选择禁用后缀模式匹配,这意味着像“GET /projects/spring-boot.json”这样的请求将不会与@GetMapping("/projects/ spring-boot")映射匹配。 这被认为是Spring MVC应用程序的最佳实践。 对于没有发送正确“接受”请求标头的HTTP客户端,此功能在过去主要有用; 我们需要确保将正确的内容类型发送给客户端。 如今,内容协商更加可靠。

还有其他方法可以处理不一致发送正确“接受”请求标头的HTTP客户端。 我们可以使用查询参数来确保像“GET /projects/spring-boot?format=json”这样的请求将映射到@GetMapping("/projects/spring-boot"),而不是使用后缀匹配:

spring.mvc.contentnegotiation.favor-parameter=true

# We can change the parameter name, which is "format" by default:
# spring.mvc.contentnegotiation.parameter-name=myparam

# We can also register additional file extensions/media types with:
spring.mvc.contentnegotiation.media-types.markdown=text/markdown

如果您了解警告并仍希望您的应用程序使用后缀模式匹配,则需要以下配置:

spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-suffix-pattern=true

或者,不是打开所有后缀模式,而是仅支持已注册的后缀模式更安全:

spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-registered-suffix-pattern=true

# You can also register additional file extensions/media types with:
# spring.mvc.contentnegotiation.media-types.adoc=text/asciidoc

4.7.1.9 ConfigurableWebBindingInitializer

Spring MVC使用WebBindingInitializer为特定请求初始化WebDataBinder。 如果您创建自己的ConfigurableWebBindingInitializer @Bean,Spring Boot会自动配置Spring MVC以使用它。

4.7.1.10 模板引擎

除REST Web服务外,您还可以使用Spring MVC来提供动态HTML内容。 Spring MVC支持各种模板技术,包括Thymeleaf,FreeMarker和JSP。 此外,许多其他模板引擎包括他们自己的Spring MVC集成。

Spring Boot包括对以下模板引擎的自动配置支持:

  • FreeMarker
  • Groovy
  • Thymeleaf
  • Mustache

如果可能,应该避免使用JSP。 将它们与嵌入式servlet容器一起使用时有几个已知的限制。

当您使用其中一个模板引擎和默认配置时,您的模板将自动从src/main/resources/templates中获取。

根据您运行应用程序的方式,IntelliJ IDEA以不同方式对类路径进行排序。 从主方法在IDE中运行应用程序会导致与使用Maven或Gradle或其打包的jar运行应用程序时的顺序不同。 这可能导致Spring Boot无法在类路径中找到模板。 如果遇到此问题,可以在IDE中重新排序类路径,以便首先放置模块的类和资源。 或者,您可以配置模板前缀以搜索类路径上的每个模板目录,如下所示:classpath*:/templates/。

4.7.1.11 错误处理

默认情况下,Spring Boot提供/error映射,以合理的方式处理所有错误,并在servlet容器中注册为“全局”错误页面。 对于计算机客户端,它会生成一个JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。 对于浏览器客户端,有一个“whitelabel”错误视图,以HTML格式呈现相同的数据(要自定义它,添加解析为错误的View)。 要完全替换默认行为,可以实现ErrorController并注册该类型的bean定义,或者添加ErrorAttributes类型的bean以使用现有机制但替换内容。

BasicErrorController可以用作自定义ErrorController的基类。 如果要为新内容类型添加处理程序,则此功能特别有用(默认情况下是专门处理text / html并为其他所有内容提供后备)。 为此,请扩展BasicErrorController,使用具有produce属性的@RequestMapping添加公共方法,并创建新类型的bean。

您还可以定义一个使用@ControllerAdvice注释的类,以自定义JSON文档以返回特定控制器和/或异常类型,如以下示例所示:

@ControllerAdvice(basePackageClasses = AcmeController.class)
public class AcmeControllerAdvice extends ResponseEntityExceptionHandler {

	@ExceptionHandler(YourException.class)
	@ResponseBody
	ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
		HttpStatus status = getStatus(request);
		return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status);
	}

	private HttpStatus getStatus(HttpServletRequest request) {
		Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
		if (statusCode == null) {
			return HttpStatus.INTERNAL_SERVER_ERROR;
		}
		return HttpStatus.valueOf(statusCode);
	}

}

在前面的示例中,如果在与AcmeController相同的包中定义的控制器抛出YourException,则使用CustomErrorType POJO的JSON表示而不是ErrorAttributes表示。

1)自定义错误页面

如果要显示给定状态代码的自定义HTML错误页面,可以将文件添加到/error文件夹。 错误页面可以是静态HTML(即,添加到任何静态资源文件夹下),也可以使用模板构建。 文件名应该是确切的状态代码或系列掩码。

例如,要将404映射到静态HTML文件,您的文件夹结构将如下所示:

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- public/
             +- error/
             |   +- 404.html
             +- <other public assets>

要使用FreeMarker模板映射所有5xx错误,您的文件夹结构如下:

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- templates/
             +- error/
             |   +- 5xx.ftl
             +- <other templates>

对于更复杂的映射,您还可以添加实现ErrorViewResolver接口的bean,如以下示例所示:

public class MyErrorViewResolver implements ErrorViewResolver {

	@Override
	public ModelAndView resolveErrorView(HttpServletRequest request,
			HttpStatus status, Map<String, Object> model) {
		// Use the request or status to optionally return a ModelAndView
		return ...
	}

}

您还可以使用常规的Spring MVC功能,例如@ExceptionHandler方法和@ControllerAdvice。 然后,ErrorController将获取任何未处理的异常。

2)映射Spring MVC之外的错误页面

对于不使用Spring MVC的应用程序,可以使用ErrorPageRegistrar接口直接注册ErrorPages。 这种抽象直接与底层嵌入式servlet容器一起工作,即使你没有Spring MVC DispatcherServlet也可以工作。

@Bean
public ErrorPageRegistrar errorPageRegistrar(){
	return new MyErrorPageRegistrar();
}

// ...

private static class MyErrorPageRegistrar implements ErrorPageRegistrar {

	@Override
	public void registerErrorPages(ErrorPageRegistry registry) {
		registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
	}

}

如果您注册一个ErrorPage,其路径最终由Filter处理(这与一些非Spring Web框架(如Jersey和Wicket)一样),则Filter必须显式注册为ERROR调度程序,如 以下示例:

@Bean
public FilterRegistrationBean myFilter() {
	FilterRegistrationBean registration = new FilterRegistrationBean();
	registration.setFilter(new MyFilter());
	...
	registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
	return registration;
}

请注意,默认的FilterRegistrationBean不包含ERROR调度程序类型。

小心:当部署到servlet容器时,Spring Boot使用其错误页面过滤器将具有错误状态的请求转发到相应的错误页面。 如果尚未提交响应,则只能将请求转发到正确的错误页面。 缺省情况下,WebSphere Application Server 8.0及更高版本在成功完成servlet的服务方法后提交响应。 您应该通过将com.ibm.ws.webcontainer.invokeFlushAfterService设置为false来禁用此行为。

4.7.1.12 Spring HATEOAS

如果您开发使用超媒体的RESTful API,Spring Boot为Spring HATEOAS提供自动配置,适用于大多数应用程序。 自动配置取代了使用@EnableHypermediaSupport的需要,并注册了许多bean以简化构建基于超媒体的应用程序,包括LinkDiscoverers(用于客户端支持)和配置为正确地将响应编组到所需表示中的ObjectMapper。 ObjectMapper是通过设置各种spring.jackson.*属性或者如果存在的话,通过设置Jackson2ObjectMapperBuilder bean来定制的。

您可以使用@EnableHypermediaSupport控制Spring HATEOAS的配置。 请注意,这样做会禁用前面描述的ObjectMapper自定义。

4.7.1.13 支持CORS

跨源资源共享(CORS)是大多数浏览器实现的W3C规范,允许您以灵活的方式指定授权何种跨域请求,而不是使用一些安全性较低且功能较弱的方法,如IFRAME或JSONP。

从版本4.2开始,Spring MVC支持CORS。 在Spring Boot应用程序中使用带有@CrossOrigin注释的控制器方法CORS配置不需要任何特定配置。 可以通过使用自定义的addCorsMappings(CorsRegistry)方法注册WebMvcConfigurer bean来定义全局CORS配置,如以下示例所示:

@Configuration
public class MyConfiguration {

	@Bean
	public WebMvcConfigurer corsConfigurer() {
		return new WebMvcConfigurer() {
			@Override
			public void addCorsMappings(CorsRegistry registry) {
				registry.addMapping("/api/**");
			}
		};
	}
}

4.7.2 “Spring WebFlux框架”

Spring WebFlux是Spring Framework 5.0中引入的新的响应式Web框架。 与Spring MVC不同,它不需要Servlet API,完全异步且无阻塞,并通过Reactor项目实现Reactive Streams规范。

Spring WebFlux有两种版本:基于方法和注释。 基于注释的注释非常接近Spring MVC模型,如以下示例所示:

@RestController
@RequestMapping("/users")
public class MyRestController {

	@GetMapping("/{user}")
	public Mono<User> getUser(@PathVariable Long user) {
		// ...
	}

	@GetMapping("/{user}/customers")
	public Flux<Customer> getUserCustomers(@PathVariable Long user) {
		// ...
	}

	@DeleteMapping("/{user}")
	public Mono<User> deleteUser(@PathVariable Long user) {
		// ...
	}

}

“WebFlux.fn”是函数变体,它将路由配置与请求的实际处理分开,如以下示例所示:

@Configuration
public class RoutingConfiguration {

	@Bean
	public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
		return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
				.andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
				.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
	}

}

@Component
public class UserHandler {

	public Mono<ServerResponse> getUser(ServerRequest request) {
		// ...
	}

	public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
		// ...
	}

	public Mono<ServerResponse> deleteUser(ServerRequest request) {
		// ...
	}
}

WebFlux是Spring Framework的一部分,详细信息可在其参考文档中找到。

您可以根据需要定义尽可能多的RouterFunction bean来模块化路由器的定义。 如果需要应用优先级,可以排序Bean。

首先,将spring-boot-starter-webflux模块添加到您的应用程序中。

在应用程序中添加spring-boot-starter-web和spring-boot-starter-webflux模块会导致Spring Boot自动配置Spring MVC,而不是WebFlux。 选择此行为是因为许多Spring开发人员将spring-boot-starter-webflux添加到他们的Spring MVC应用程序中以使用反应式WebClient。 您仍然可以通过将所选应用程序类型设置为SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)来强制执行您的选择。

4.7.2.1 Spring WebFlux自动配置

Spring Boot为Spring WebFlux提供自动配置,适用于大多数应用程序。

自动配置在Spring的默认值之上添加了以下功能:

  • 为HttpMessageReader和HttpMessageWriter实例配置编解码器(本文档稍后将介绍)。
  • 支持提供静态资源,包括对WebJars的支持(在本文档后面介绍)。

如果你想保留Spring Boot WebFlux功能,并且想要添加额外的WebFlux配置,你可以添加自己的@Configuration类,类型为WebFluxConfigurer,但没有@EnableWebFlux。

如果您想完全控制Spring WebFlux,可以添加自己的@Configuration注释@EnableWebFlux。

4.7.2.2 带有HttpMessageReaders和HttpMessageWriters的HTTP编解码器

Spring WebFlux使用HttpMessageReader和HttpMessageWriter接口来转换HTTP请求和响应。 通过查看类路径中可用的库,它们配置了CodecConfigurer以具有合理的默认值。

Spring Boot通过使用CodecCustomizer实例进一步自定义。 例如,spring.jackson.*配置键应用于Jackson编解码器。

如果需要添加或自定义编解码器,可以创建自定义CodecCustomizer组件,如以下示例所示:

import org.springframework.boot.web.codec.CodecCustomizer;

@Configuration
public class MyConfiguration {

	@Bean
	public CodecCustomizer myCodecCustomizer() {
		return codecConfigurer -> {
			// ...
		}
	}

}

您还可以利用Spring Boot的自定义JSON序列化程序和反序列化程序。

4.7.2.3 静态内容

默认情况下,Spring Boot从类路径中名为/static(或/public或/resources或/META-INF/resources)的目录中提供静态内容。 它使用Spring WebFlux中的ResourceWebHandler,以便您可以通过添加自己的WebFluxConfigurer并覆盖addResourceHandlers方法来修改该行为。

默认情况下,资源映射到/,但您可以通过设置spring.webflux.static-path-pattern属性来调整它。 例如,可以按如下方式将所有资源重新定位到/resources/

spring.webflux.static-path-pattern=/resources/**

您还可以使用spring.resources.static-locations自定义静态资源位置。 这样做会将默认值替换为目录位置列表。 如果这样做,默认的欢迎页面检测将切换到您的自定义位置。 因此,如果启动时您的任何位置都有index.html,那么它就是应用程序的主页。

除了前面列出的“标准”静态资源位置之外,还为Webjars内容制作了一个特例。 在/webjars/**中具有路径的任何资源都是从jar文件提供的,如果它们以Webjars格式打包的话。

Spring WebFlux应用程序并不严格依赖于Servlet API,因此它们不能作为war文件部署,也不能使用src/main/webapp目录。

4.7.2.4 模板引擎

除REST Web服务外,您还可以使用Spring WebFlux来提供动态HTML内容。 Spring WebFlux支持各种模板技术,包括Thymeleaf,FreeMarker和Mustache。

Spring Boot包括对以下模板引擎的自动配置支持:

  • FreeMarker
  • Thymeleaf
  • Mustache

当您使用其中一个模板引擎和默认配置时,您的模板将自动从src/main/resources/templates中获取。

4.7.2.5 错误处理

Spring Boot提供了一个WebExceptionHandler,它以合理的方式处理所有错误。 它在处理顺序中的位置紧接在WebFlux提供的处理程序之前,这些处理程序被认为是最后一个。 对于计算机客户端,它会生成一个JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。 对于浏览器客户端,有一个“whitelabel”错误处理程序,它以HTML格式呈现相同的数据。 您还可以提供自己的HTML模板来显示错误(请参阅下一节)。

自定义此功能的第一步通常涉及使用现有机制,但替换或扩充错误内容。 为此,您可以添加ErrorAttributes类型的bean。

要更改错误处理行为,可以实现ErrorWebExceptionHandler并注册该类型的bean定义。 因为WebExceptionHandler是一个非常低级的,所以Spring Boot还提供了一个方便的AbstractErrorWebExceptionHandler来让你以WebFlux函数方式处理错误,如下例所示:

public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {

	// Define constructor here

	@Override
	protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {

		return RouterFunctions
				.route(aPredicate, aHandler)
				.andRoute(anotherPredicate, anotherHandler);
	}

}

要获得更完整的片段,您还可以直接继承DefaultErrorWebExceptionHandler并覆盖特定方法。

1)自定义错误页面

如果要显示给定状态代码的自定义HTML错误页面,可以将文件添加到/error文件夹。 错误页面可以是静态HTML(即,添加到任何静态资源文件夹下)或使用模板构建。 文件名应该是确切的状态代码或系列掩码。

例如,要将404映射到静态HTML文件,您的文件夹结构将如下所示:

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- public/
             +- error/
             |   +- 404.html
             +- <other public assets>

要使用Mustache模板映射所有5xx错误,您的文件夹结构如下:

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- templates/
             +- error/
             |   +- 5xx.mustache
             +- <other templates>

4.7.2.6 Web过滤器

Spring WebFlux提供了一个WebFilter接口,可以实现该接口来过滤HTTP请求 - 响应交换。 在应用程序上下文中找到的WebFilter bean将自动用于过滤每个交换。

如果过滤器的顺序很重要,则可以实现Ordered或使用@Order进行注释。 Spring Boot自动配置可以为您配置Web过滤器。 执行此操作时,将使用下表中显示的顺序:

Web FilterOrder
MetricsWebFilterOrdered.HIGHEST_PRECEDENCE + 1
WebFilterChainProxy (Spring Security)-100
HttpTraceWebFilterOrdered.LOWEST_PRECEDENCE - 10

4.7.3 JAX-RS 和 Jersey

如果您更喜欢REST端点的JAX-RS编程模型,则可以使用其中一个可用的实现而不是Spring MVC。 Jersey和Apache CXF开箱即用。 CXF要求您在应用程序上下文中将其Servlet或Filter注册为@Bean。 Jersey有一些原生的Spring支持,因此我们还在Spring Boot中为它提供了自动配置支持以及启动器。

要开始使用Jersey,请将spring-boot-starter-jersey作为依赖项包含在内,然后您需要一个类型为ResourceConfig的@Bean,您可以在其中注册所有端点,如以下示例所示:

@Component
public class JerseyConfig extends ResourceConfig {

	public JerseyConfig() {
		register(Endpoint.class);
	}

}

Jersey对扫描可执行档案的支持相当有限。 例如,在运行可执行war文件时,它无法扫描完全可执行jar文件或WEB-INF/classes中找到的包中的端点。 为避免此限制,不应使用packages方法,并且应使用register方法单独注册端点,如上例所示。

对于更高级的自定义,您还可以注册实现ResourceConfigCustomizer的任意数量的bean。

所有已注册的端点都应该是具有HTTP资源注释的@Components(@GET和其他),如以下示例所示:

@Component
@Path("/hello")
public class Endpoint {

	@GET
	public String message() {
		return "Hello";
	}

}

默认情况下,Jersey在名为jerseyServletRegistration的ServletRegistrationBean类型的@Bean中设置为Servlet。 默认情况下,servlet是懒惰地初始化的,但您可以通过设置spring.jersey.servlet.load-on-startup来自定义该行为。 您可以通过创建具有相同名称的bean来禁用或覆盖该bean。 您还可以通过设置spring.jersey.type = filter来使用过滤器而不是servlet(在这种情况下,要替换或覆盖的@Bean是jerseyFilterRegistration)。 过滤器有一个@Order,可以使用spring.jersey.filter.order设置。 通过使用spring.jersey.init.*指定属性映射,可以为servlet和过滤器注册提供init参数。

有一个Jersey样本,以便您可以看到如何设置。

4.7.4 嵌入式Servlet容器支持

Spring Boot包括对嵌入式Tomcat,Jetty和Undertow服务器的支持。 大多数开发人员使用适当的“Starter”来获取完全配置的实例。 默认情况下,嵌入式服务器在端口8080上侦听HTTP请求。

如果您选择在CentOS上使用Tomcat,请注意,默认情况下,临时目录用于存储已编译的JSP,文件上载等。 应用程序运行时,tmpwatch可能会删除此目录,从而导致失败。 要避免此行为,您可能希望自定义tmpwatch配置,以便不删除tomcat.*目录或配置server.tomcat.basedir,以便嵌入式Tomcat使用不同的位置。

4.7.4.1 Servlets, Filters, 和 listeners

使用嵌入式servlet容器时,可以通过使用Spring bean或扫描Servlet组件,从Servlet规范中注册servlet,过滤器和所有侦听器(如HttpSessionListener)。

1)注册Servlets, Filters, 和 Listeners 作为 Spring Beans

任何Servlet,Filter或servlet *作为Spring bean的监听器实例都是在嵌入式容器中注册的。 如果要在配置期间引用application.properties中的值,这可能特别方便。

默认情况下,如果上下文仅包含一个Servlet,则将其映射到/。 在多个servlet bean的情况下,bean名称用作路径前缀。 过滤器映射到/*。

如果基于约定的映射不够灵活,则可以使用ServletRegistrationBean,FilterRegistrationBean和ServletListenerRegistrationBean类进行完全控制。

Spring Boot附带了许多可以定义Filter bean的自动配置。 以下是过滤器及其各自顺序的一些示例(较低的顺序值表示较高的优先级):

Servlet FilterOrder
OrderedCharacterEncodingFilterOrdered.HIGHEST_PRECEDENCE
WebMvcMetricsFilterOrdered.HIGHEST_PRECEDENCE + 1
ErrorPageFilterOrdered.HIGHEST_PRECEDENCE + 1
HttpTraceFilterOrdered.LOWEST_PRECEDENCE - 10

将过滤器无序放置通常是安全的。

如果需要特定的顺序,则应避免在Ordered.HIGHEST_PRECEDENCE中配置读取请求主体的过滤器,因为它可能违反应用程序的字符编码配置。 如果Servlet过滤器包装请求,则应使用小于或等于OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER的顺序对其进行配置。

4.7.4.2 初始化Servlet Context

嵌入式servlet容器不直接执行Servlet 3.0+ javax.servlet.ServletContainerInitializer接口或Spring的org.springframework.web.WebApplicationInitializer接口。 这是一个有意的设计决策,旨在降低设计在war中运行的第三方库可能会破坏Spring Boot应用程序的风险。

如果需要在Spring Boot应用程序中执行servlet上下文初始化,则应注册实现org.springframework.boot.web.servlet.ServletContextInitializer接口的bean。 单个onStartup方法提供对ServletContext的访问,如果需要,可以轻松地用作现有WebApplicationInitializer的适配器。

1)扫描Servlets, Filters, 和 listeners

使用嵌入式容器时,可以使用@ServletComponentScan启用使用@WebServlet,@WebFilter和@WebListener注释的类的自动注册。

@ServletComponentScan对独立容器没有影响,其中使用容器的内置发现机制。

4.7.4.3 ServletWebServerApplicationContext

在内部,Spring Boot使用不同类型的ApplicationContext来支持嵌入式servlet容器。 ServletWebServerApplicationContext是一种特殊类型的WebApplicationContext,它通过搜索单个ServletWebServerFactory bean来引导自身。 通常已自动配置TomcatServletWebServerFactory,JettyServletWebServerFactory或UndertowServletWebServerFactory。

您通常不需要了解这些实现类。 大多数应用程序都是自动配置的,并且代表您创建了相应的ApplicationContext和ServletWebServerFactory。

4.7.4.4 自定义嵌入式Servlet容器

可以使用Spring Environment属性配置公共servlet容器设置。 通常,您将在application.properties文件中定义属性。

常用服务器设置包括:

  • 网络设置:侦听传入HTTP请求的端口(server.port),绑定到server.address的接口地址,等等。
  • 会话设置:会话是持久的(server.servlet.session.persistence),会话超时(server.servlet.session.timeout),会话数据的位置(server.servlet.session.store-dir)和会话cookie 配置(server.servlet.session.cookie.*)。
  • 错误管理:错误页面的位置(server.error.path)等。
  • SSL
  • HTTP压缩

Spring Boot尽可能尝试共用常见设置,但这并不总是可行。 对于这些情况,专用命名空间提供特定于服务器的自定义(请参阅server.tomcat和server.undertow)。 例如,可以使用嵌入式servlet容器的特定功能配置访问日志。

有关完整列表,请参阅ServerProperties类。

1)程序化定制

如果需要以编程方式配置嵌入式servlet容器,可以注册实现WebServerFactoryCustomizer接口的Spring bean。 WebServerFactoryCustomizer提供对ConfigurableServletWebServerFactory的访问,其中包括许多自定义setter方法。 以下示例以编程方式设置端口:

import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;

@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

	@Override
	public void customize(ConfigurableServletWebServerFactory server) {
		server.setPort(9000);
	}

}

TomcatServletWebServerFactory,JettyServletWebServerFactory和UndertowServletWebServerFactory是ConfigurableServletWebServerFactory的专用变体,它们分别为Tomcat,Jetty和Undertow提供了其他自定义setter方法。

2)直接自定义ConfigurableServletWebServerFactory

如果前面的自定义技术太有限,您可以自己注册TomcatServletWebServerFactory,JettyServletWebServerFactory或UndertowServletWebServerFactory bean。

@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
	TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
	factory.setPort(9000);
	factory.setSessionTimeout(10, TimeUnit.MINUTES);
	factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
	return factory;
}

为许多配置选项提供了Setter。 如果您需要做一些更具异国情调的事情,还会提供一些受保护的方法“挂钩”。 有关详细信息,请参阅源代码文档。

4.7.4.5 JSP限制

运行使用嵌入式servlet容器的Spring Boot应用程序(并打包为可执行存档)时,JSP支持存在一些限制。

  • 使用Jetty和Tomcat,如果使用war包装,它应该可以工作。 使用java -jar启动时,可执行的war将起作用,并且还可以部署到任何标准容器。 使用可执行jar时不支持JSP。
  • Undertow不支持JSP。
  • 创建自定义error.jsp页面不会覆盖错误处理的默认视图。 应该使用自定义错误页面。

有一个JSP示例,以便您可以看到如何设置。

4.7.5 嵌入式Reactive Server支持

Spring Boot包括对以下嵌入式响应式Web服务器的支持:Reactor Netty,Tomcat,Jetty和Undertow。 大多数开发人员使用适当的“Starter”来获取完全配置的实例。 默认情况下,嵌入式服务器在端口8080上侦听HTTP请求。

4.7.6 Reactive Server资源配置

在自动配置Reactor Netty或Jetty服务器时,Spring Boot将创建特定的bean,为服务器实例提供HTTP资源:ReactorResourceFactory或JettyResourceFactory。

默认情况下,这些资源也将与Reactor Netty和Jetty客户端共享,以获得最佳性能,具体如下:

  • 相同的技术用于服务器和客户端
  • 客户端实例是使用Spring Boot自动配置的WebClient.Builder bean构建的

开发人员可以通过提供自定义的ReactorResourceFactory或JettyResourceFactory bean来覆盖Jetty和Reactor Netty的资源配置 - 这将应用于客户端和服务器。

您可以在4.14.1 运行时WebClient部分中了解有关客户端资源配置的更多信息。