0x07 Spring Boot 2.x 之开发Web 应用程序

1. 开发Web 应用程序

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

1.1 Spring Web MVC框架

Spring MVC允许我们创建特殊@Controller@RestController bean来处理传入的HTTP请求。控制器中的方法通过使用@RequestMapping注解映射到HTTP 。

以下代码显示了@RestController为JSON数据提供服务的典型代码:

@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 核心的一部分,更多详细信息参考文档
另外也可以找到一些指南在官方指南库

1.1.1 Spring MVC 自动配置

和大多数应用程序一样,Spring Boot 也自动配置了Spring MVC。
自动配置包含Spring 的以下功能:

  • ContentNegotiatingViewResolverBeanNameViewResolver Bean
  • 支持提供静态资源,包括对WebJars的支持
  • 自动注册Converter, GenericConverter 和 Formatter Bean
  • 支持HttpMessageConverters
  • 自动注册MessageCodesResolver
  • 静态index.html 支持
  • 自定义Favicon 支持
  • 自动使用ConfigurableWebBindingInitializer Bean

如果我们想保留Spring Boot MVC功能并且想要添加其他MVC配置(拦截器,格式化程序,视图控制器和其他功能,那么需要添加自己的@Configuration类并继承WebMvcConfigurer接口,但不需要 @EnableWebMvc
如果我们想要自定义实例化RequestMappingHandlerMapping, RequestMappingHandlerAdapter或者ExceptionHandlerExceptionResolver,我们需要声明WebMvcRegistrationsAdapter

如果我们想完全控制Spring MVC,可以添加自己的@Configuration 注解,然后再添加@EnableWebMvc 注解

1.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都将添加到转换器列表中。我们也可以使用相同的方式覆盖默认转换器。

1.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 也提供 JsonObjectSerializerJsonObjectDeserializer基础类,序列化对象时提供标准版本的Jackson有用的替代。见 JsonObjectSerializerJsonObjectDeserializer在Javadoc了解详情。

1.1.4 MessageCodesResolver

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

1.1.5 静态内容

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

在独立的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提供的高级资源处理功能,允许使用缓存cache-busting 静态资源或为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=/**

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

使用(例如)JavaScript模块加载器动态加载资源时,不能重命名文件。这就是为什么其他策略也得到支持并可以合并的原因。“固定”策略在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

使用此配置,JavaScript模块位于"/js/lib/“使用固定版本控制策略(”/v12/js/lib/mymodule.js"),而其他资源仍使用内容(<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>)。

有关ResourceProperties 更多支持选项,请参阅
此功能已在专门的博客文章和Spring Framework的 参考文档中进行了详细描述

1.1.6 欢迎页

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

1.1.7 自定义Favicon.ico

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

1.1.8 路径匹配与内容协商

Spring MVC 能匹配接受到的HTTP 请求然后去处理通过查找请求路径和匹配程序中定义的Controller 方法上的@GetMappping 注解

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

有其他方法可以处理http clients, 不使用后缀匹配,而是使用参数来确保诸如"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

1.1.9 ConfigurableWebBindingInitializer

Spring MVC 使用一个WebBindingInitializer 来针对特定的请求初始化一个WebDataBinder。如果你创建了你自己的ConfigurableWebBindingInitializer @Bean ,Spring Boot 将会自动配置Spring MVC 去使用它。

1.1.10 模板引擎

和大多数的REST WEB Service一样,我们也可以使用Spring MVC 来提供动态的HTML 内容输出。 Spring MVC 支持许多模板引擎技术,包含Thymeleaf ,FreeMarker, 和JSPs, 因此,许多的模板引擎包含他们自己的Spring MVC 集成方式。

Spring Boot 包含自动配置如下的模板引擎:

  • FreeMarker
  • Groovy
  • Thymeleaf
  • Mustache

如果可能的话,JSPs 最好避免使用。因为当我们使用内嵌的servlet 容器时候,很显然会有一些限制。

当我们使用这些模板中任意一个默认配置的时候,我们会自动在src/main/resources/templates 路径下面寻找我们的模板文件。

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

1.1.11 错误处理

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

在BasicErrorController可以用作自定义基类ErrorController。如果要为新内容类型添加处理程序(默认情况下是text/html专门处理并为其他所有内容提供后备),这将特别有用。为此,请扩展BasicErrorController,添加@RequestMapping具有produces属性的公共方法,并创建新类型的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);
	}
}

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

自定义错误页面

如果想根据给出的错误状态码自定义一个HTML 错误页面,我们可以在src/main/resources/ 目录下添加一个“/Error”文件夹,错误的页面可以是静态页面或者使用模板文件。文件名应该是确切的状态代码。
例如:
匹配404 页面到一个静态的HTML页面,文件结构如下:

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

要匹配所有的500错误使用FreeMarker 模板的话就是这样

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接收任何未处理的异常。

没有使用Spring MVC前提下匹配错误的页面

对于没有使用Spring MVC 的应用程序,也可以使用ErrorPageRegistrar 接口来直接注册错误页面。此抽象直接与基础的内嵌的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"));
	}

}

如果用过滤器处理的路径注册一个错误页(这在一些非Spring Web框架中很常见,比如Jersey和wicket),那么过滤器必须显式注册为错误调度程序,如下例所示。

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

注意,默认的FilterRegistrationBean 不包含错误转发的类型。

警告:当部署到servlet容器时,Spring Boot使用其错误页筛选器将具有错误状态的请求转发到相应的错误页。只有在默认情况下尚未提交响应时,才能将请求转发到正确的错误页,WebSphere Application Server 8.0及更高版本在成功完成servlet服务方法后提交响应。您应该通过设置禁用此行为

com.ibm.ws.webcontainer.invokeFlushAfterService     false

1.1.12 Spring HATEOAS

如果我们开发了一个一个使用超媒体的RESTful API,那么SpringBoot为Spring HATEOAS提供了自动配置,它可以很好地与大多数应用程序配合使用。这个自动配置替换需要@EnableHypermediaSupport 注解和注册了一些bean以简化构建基于超媒体的应用程序,包括LinkDiscoverers(客户端支持)以及ObjectMapper 配置为正确地将响应编组为所需的表示。 ObjectMapper是通过设置各种spring.jackson.*属性或者如果存在的话,通过设置Jackson2ObjectMapperBuilder bean来定制的。

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

1.1.13 CORS(跨源资源共享) 支持

Cross-origin resource sharing (跨源资源共享,简称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/**");
			}
		};
	}
}

1.2 Spring WebFlux Framework

Spring WebFlux 是一个全新的 Spring Framework 5.0 reactive web 框架
和Spring MVC 不一样的是,它不需要Servlet API, 它是一个异步无阻塞的通过Reactor 项目 中Reactive Streams 的实现

SpringWebFlux有两种风格:基于函数和注解。基于注解的模型非常接近SpringMVC模型,如下例所示

@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 5.x框架的一部分

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

要开始使用,添加spring-boot-starter-webflux 依赖项到我们的应用程序中。

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

1.2.1 Spring WebFlux 自动配置

SpringBoot为SpringWebFlux提供了自动配置,适用于大多数应用程序。

自动配置添加了如下功能:

  • 为httpmessagereader和httpmessageliniter实例配置编解码器
  • 提供静态资源的支持,包括对Webjar的支持

如果您想要保留SpringBootWebFlux特性,并且想要添加额外的WebFlux 配置,我们可以添加自己的带有@Configuration注解的配置类,但是不要添加@EnableWebFlux注解

如果你想完全控制SpringWebFlux,需要添加@Configuration 和@EnableWebFlux 注解。

1.2.2 HttpMessageReaders and HttpMessageWriters Http编解码器

Spring WebFlux 使用HttpMessageReader 和HttpMessageWriter 接口来转换HTTP请求和响应。通过查看classpath中可用的库,它们配置了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 -> {
			// ...
		}
	}
}

1.2.3 静态内容

默认情况下,Spring Boot 在classpath 下这几个位置提供了静态内容

  • /static
  • /public
  • /resources
  • /META-INF/resources

Spring WebFlux 使用了ResourceWebHandler 类因此我们可以自己的WebFluxConfigurer 或者重写addResourceHandlers 方法

默认情况下,通过设置spring.webflux.static-path-pattern属性,使用 /** 拦截所有的请求

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目录。

1.2.4 模板引擎

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

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

FreeMarker
Thymeleaf
Mustache

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

1.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并覆盖特定方法。

自定义错误页面

如果要显示给定状态代码的自定义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>

1.2.6 Web Filters

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

1.3 JAX-RS 和 Jersey

Jersey RESTful 框架是开源的RESTful框架, 实现了JAX-RS (JSR 311 & JSR 339) 规范

如果您更喜欢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";
	}
}

由于Endpoint是Spring @Component,它的生命周期由Spring管理,您可以使用@Autowired注解注入依赖项并使用@Value注解注入外部配置。默认情况下,Jersey servlet已注册并映射到/ *。您可以通过将@ApplicationPath添加到ResourceConfig来更改映射。

默认情况下,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参数。

1.4 内嵌Servlet 容器支持

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

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

1.4.1 Servlets, Filters, and listeners

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

注册 Servlets, Filters, 和 Listeners 为 Spring Beans

任何的Servlet,Filter, 或者servlet *Listener 实例 是一个Spring Bean 都需要注册到内嵌的容器中。

如果要在配置期间引用application.properties中的值,这可能特别方便。

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

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

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

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

将Filter Bean无序放置通常是安全的。

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

1.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的适配器。

扫描 Servlets, Filters, and listeners

当使用内嵌的容器的时候,可以通过使用@ServletComponentScan
扫描带有@WebServlet, @WebFilter, 和 @WebListener 注解的类来实现自动注册。

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

1.4.3 ServletWebServerApplicationContext

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

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

1.4.4 自定义内嵌的Servlet 容器

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

常用服务器设置包括:

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

如果需要以编程方式配置嵌入式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);
	}

}

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

直接自定义ConfigurableServletWebServerFactory

如果前面的自定义技术太有限,您可以自己注册TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactory 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。 如果您需要做一些更具异国情调的事情,还会提供一些受保护的方法“hook”。

1.4.5 JSP 限制

运行使用嵌入式servlet容器的Spring Boot应用程序(并打包为可执行存档)时,JSP支持存在一些限制。
使用Jetty和Tomcat,如果使用war包装,它应该可以工作。 使用java -jar启动时,可执行的war将起作用,并且还可以部署到任何标准容器。 使用可执行jar时不支持JSP。
Undertow不支持JSP。
创建自定义error.jsp页面不会覆盖错误处理的默认视图。 应该使用自定义错误页面。

JSP sample

1.5. 内嵌的Reactive Server 支持

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

1.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的资源配置 - 这将应用于客户端和服务器。

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

本篇完~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值