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; }
② 接口继承树示意图