29.开发web应用
大部分web应用使用 spring-boot-starter-web
就够了。也可以使用 spring-boot-starter-webflux
构建响应式的web应用。
1. Spring MVC 自动配置⚓
在Spring默认功能上添加了以下特性:
- Inclusion of(引入)
ContentNegotiatingViewResolver
andBeanNameViewResolver
beans. - Support for serving static resources, including support for WebJars (covered later in this document)).
- Automatic registration of
Converter
,GenericConverter
, andFormatter
beans. - Support for
HttpMessageConverters
(covered later in this document). - Automatic registration of
MessageCodesResolver
(covered later in this document). - Static
index.html
support. - Custom
Favicon
support (covered later in this document). - Automatic use of a
ConfigurableWebBindingInitializer
bean (covered later in this document).
如果想添加额外的 MVC configuration (interceptors, formatters, view controllers, and other features),可以添加 WebMvcConfigurer
类型的@Configuration
的类并不要有 @EnableWebMvc
。如果想要添加自定义的RequestMappingHandlerMapping
, RequestMappingHandlerAdapter
, or ExceptionHandlerExceptionResolver
,可以声明一个WebMvcRegistrationsAdapter
类型的。
如果想要完全的控制Spring MVC,在@Configuration 类上添加@EnableWebMvc
注解。
2. HttpMessageConverters⚓
Spring MVC使用该接口转换HTTP requests和responses。
默认情况下字符串使用UTF-8
编码。
使用Spring Boot的HttpMessageConverters
类添加或定制转换器:
import org.springframework.boot.autoconfigure.http.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);
}
}
在上下文中存在的任何转换器都会被加入到转换器列表中。也可通过此方式覆盖默认的转换器。
3. 自定义JSON 序列化和反序列化⚓
适用于Jackson
。直接在 JsonSerializer
or 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> {
// ...
}
}
4. MessageCodesResolver⚓
TODO
Spring MVC有一组生成错误码的策略,用于从绑定错误中呈现错误消息:MessageCodesResolver。
设置spring.mvc.message-codes-resolver.format
属性PREFIX_ERROR_CODE
or POSTFIX_ERROR_CODE
,Spring Boot会给你创建一个。
5. 错误处理⚓
Spring Boot默认提供一个/error
映射处理所有的错误。对于浏览器,是一个html格式的whitelabel
错误视图。替换默认行为有两种方式:
- 实现
ErrorController
并注册成bean完全地改变该行为 - 添加
ErrorAttributes
类型的bean替换掉内容
还可以使用@ControllerAdvice
注解定义一个类来为一个controller
和/或者异常类型自定义返回的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);
}
}
如果该controller抛出了异常,会使用CustomErrorType
POJO的JSON表示而不是ErrorAttributes
表示。
6. Spring HATEOAS⚓
如果正在开发基于超媒体的RESTful API,你可能需要Spring HATEOAS,而Spring Boot会为其提供自动配置。
自动配置取代了@EnableHypermediaSupport
,只需注册一定数量的beans就能轻松构建基于超媒体的应用,这些beans包括LinkDiscoverers
(客户端支持),ObjectMapper
(用于将响应编排为想要的形式)。ObjectMapper
可以根据spring.jackson.*
属性或Jackson2ObjectMapperBuilder
bean进行自定义。
通过注解@EnableHypermediaSupport
,你可以控制Spring HATEOAS的配置,但这会禁用上述ObjectMapper
的自定义功能。
1. Spring WebFlux 框架⚓
在Spring5.0引入的新的响应式的web框架。
不像Spring MVC,它不要求Servlet API,完全异步、非阻塞,并通过 the Reactor project 实现了 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) {
// ...
}
}
函数式风格:
@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) {
// ...
}
}
添加 spring-boot-starter-webflux
,去除 spring-boot-starter-web
。