HttpMessageConverter
,报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为响应报
文。HttpMessageConverter
提供了两个注解和两个类型:@RequestBody,@ResponseBody
,RequestEntity,ResponseEntity
【1】两个注解和两个类型
① HttpEntity
HttpEntity
封装了headers和body,用于暴露(获取)请求头(响应头)和请求体(响应体)。下面的列表显示了一个示例:
@PostMapping("/accounts")
public void handle(HttpEntity<Account> entity) {
// ...
}
HttpEntity主要属性和构造方法
public class HttpEntity<T> {
//The empty {@code HttpEntity}, with no body or headers.
public static final HttpEntity<?> EMPTY = new HttpEntity<>();
//请求头 响应头
private final HttpHeaders headers;
//请求体 响应体
@Nullable
private final T body;
//创建一个空的HttpEntity
protected HttpEntity() {
this(null, null);
}
//使用body创建HttpEntity,此时headers为null
public HttpEntity(T body) {
this(body, null);
}
//使用headers创建HttpEntity,此时body为null
public HttpEntity(MultiValueMap<String, String> headers) {
this(null, headers);
}
//使用body和headers创建HttpEntity
public HttpEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers) {
this.body = body;
this.headers = HttpHeaders.readOnlyHttpHeaders(headers != null ? headers : new HttpHeaders());
}
//...
}
其类继承树图示如下
与template整合使用
//POST
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
HttpEntity<String> entity = new HttpEntity<String>(helloWorld, headers);
URI location = template.postForLocation("https://example.com", entity);
//GET
HttpEntity<String> entity = template.getForEntity("https://example.com", String.class);
String body = entity.getBody();
MediaType contentType = entity.getHeaders().getContentType();
作为SpringMVC中方法的返回值
@RequestMapping("/handle")
public HttpEntity<String> handle() {
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeader", "MyValue");
return new HttpEntity<String>("Hello World", responseHeaders);
}
② @RequestBody
你可以使用@RequestBody
注解获取请求体并通过HttpMessageConverter
将其反序列化到Object对象。
您可以使用@RequestBody
注解,通过HttpMessageConverter
将请求body读取并反序列化为对象。以下示例使用@RequestBody参数:
@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
// ...
}
您可以使用MVC Config的 Message Converters选项来配置或自定义消息转换。
您可以将@RequestBody
与javax.validation.Valid
结合使用,或者使用Spring
的@Validated
注解,这两种注解都会应用Standard Bean Validation验证。默认情况下,验证错误会导致MethodArgumentNotValidException
,该异常会转换为400(BAD_REQUEST
)响应。或者,您可以通过Errors
或BindingResult
参数在控制器内本地处理验证错误,如下例所示:
@PostMapping("/accounts")
public void handle(@Valid @RequestBody Account account, BindingResult result) {
// ...
}
③ @ResponseBody
可以在方法上使用@ResponseBody
注解,通过HttpMessageConverter
将返回序列化到响应体。下面的列表显示了一个示例:
@GetMapping("/accounts/{id}")
@ResponseBody
public Account handle() {
// ...
}
在类级别上也支持@ResponseBody
,在这种情况下,它由所有控制器方法继承。这就是@RestController
的效果,它只不过是一个用@Controller
和@ResponseBody
标记的元注解。
你可以将@ResponseBody
与reactive
类型一起使用,更多参考 Asynchronous Requests和 Reactive Types。
你可以使用MVC Config的Message Converters选项配置或者自定义信息转换。
您可以将@ResponseBody方法与JSON序列化视图相结合。
④ ResponseEntity
ResponseEntity
类似于@ResponseBody
,但有Status
和header
。例如:
@GetMapping("/something")
public ResponseEntity<String> handle() {
String body = ... ;
String etag = ... ;
return ResponseEntity.ok().eTag(etag).build(body);
}
Spring MVC支持使用单值反应类型异步生成响应,和/或为主体生成单值和多值反应类型。这允许以下类型的异步响应:
ResponseEntity<Mono<T>>
或ResponseEntity<Flux<T>>
可在稍后异步提供主体时立即了解响应状态和头。如果主体由0..1
个值组成,则使用Mono
;如果主体可以生成多个值,则使用Flux
。Mono<ResponseEntity<T>>
提供了这三种功能 —response status, headers, and body
。这允许response status and headers
根据异步请求处理的结果而变化。
通过使用可通过静态方法created访问的生成器来获取ResponseEntity:
@RequestMapping("/handle")
public ResponseEntity<String> handle() {
URI location = ...;
return ResponseEntity.created(location).header("MyResponseHeader", "MyValue").body("Hello World");
}
SpringMVC中作为方法的返回值(直接返回response,不跳页面):
@PostMapping("test")
public ResponseEntity test(@RequestParam List name) throws URISyntaxException {
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setLocation(new URI("/test/location"));
responseHeaders.set("MyResponseHeader", "MyValue");
ResponseEntity<String> responseEntity = new ResponseEntity<>("hello", responseHeaders, HttpStatus.CREATED);
return responseEntity;
}
⑤ RequestEntity
RequestEntity
类似于@RequestBody
,但是多了HTTP method
和target URL
。
如下所示,与RestTemplate结合使用
MyRequest body = ...
RequestEntity<MyRequest> request = RequestEntity
.post("https://example.com/{foo}", "bar")
.accept(MediaType.APPLICATION_JSON)
.body(body);
ResponseEntity<MyResponse> response = template.exchange(request, MyResponse.class)
在SpringMVC的Controller中使用:
@RequestMapping("/handle")
public void handle(RequestEntity<String> request) {
HttpMethod method = request.getMethod();
URI url = request.getUrl();
String body = request.getBody();
}
【2】HttpMessageConverter<T>
其是Spring3.0新添加的一个接口,负责将请求信息转换为一个对象(类型为T),将对象(类型为T)输出为响应信息。
其是一个策略接口哦。
① 接口源码
public interface HttpMessageConverter<T> {
// 指示此转换器是否可以读取给定类。mediaType通常是Content-Type header
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
// 指示给定类是否可以由此转换器写入。mediaType是 Accept header
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
//返回此转换器支持的MediaType
List<MediaType> getSupportedMediaTypes();
// 从给定的输入消息中读取给定类型的对象,并返回该对象。
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
// 将给定对象写入给定的输出消息
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
② 运行流程
使用HttpMessageConverter<T>
将请求信息转化并绑定到处理方法的入参中,或将响应结果转换为对应类型的响应信息,Spring提供了两种途径:
-
① 使用
@RequestBody
/@ResponseBody
对处理方法进行标注; -
② 使用
RequestEntity<T>
/ResponseEntity<T>
作为处理方法的入参或返回值;
当控制器处理方法使用到了① 或②
时,Spring首先根据请求头Content-Type
属性或响应头的Accept
属性选择匹配的HttpMessageConverter
,进而根据参数类型和泛型类型的过滤得到匹配的HttpMessageConverter
。若找不到可用的HttpMessageConverter
,将报错。
③ 接口实现类继承树
④ 常用实现类功能说明
① StringHttpMessageConverter
:支持的MediaType:text/plain,*/*
,将请求信息转换为字符串;
② ByteArrayHttpMessageConverter
:支持的MediaType:application/octet-stream,*/*
读写二进制数据;
③ SourceHttpMessageConverter
:支持的MediaType:application/xml,text/xml,application/*+xml,
读写javax.xml.transform.Source
类型的数据;
④ FormHttpMessageConverter
:支持的MediaType:application/x-www-form-urlencoded,multipart/form-data
将表单数据读取到MultiValueMap
中;
⑤ ResourceHttpMessageConverter
:支持的MediaType:*/*,
读写org.springframework.core.io.Resource
对象;
⑥ BufferedImageHttpMessageConverter
:读写BufferedImage
对象;
⑦ MappingJackson2HttpMessageConverter
:支持的MediaType:application/json,application/*+json,
利用jackson开源包的objectMapper读写JSON数据。
⑧ Jaxb2RootElementHttpMessageConverte
:支持的MediaType:application/xml,text/xml,application/*+xml
【3】HttpInputMessage 接口
表示HTTP输入消息,由headers
和可读的body
组成。通常由服务器端的HTTP请求处理器或客户端的HTTP响应处理器实现
① 接口源码
public interface HttpInputMessage extends HttpMessage {
//把请求体转换为input stream
InputStream getBody() throws IOException;
}
② 接口的继承树示意图
【4】HttpOutputMessage 接口
表示HTTP输出消息,由headers和body组成。通常由客户端的HTTP请求处理器或者服务端端的HTTP 响应处理器实现。
① 接口源码
public interface HttpOutputMessage extends HttpMessage {
// 把消息体转换为output stream返回
OutputStream getBody() throws IOException;
}