SpringMVC中HttpMessageConverter使用实践详解

HttpMessageConverter,报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为响应报
文。HttpMessageConverter提供了两个注解和两个类型:@RequestBody,@ResponseBodyRequestEntity,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选项来配置或自定义消息转换。

您可以将@RequestBodyjavax.validation.Valid结合使用,或者使用Spring@Validated注解,这两种注解都会应用Standard Bean Validation验证。默认情况下,验证错误会导致MethodArgumentNotValidException,该异常会转换为400(BAD_REQUEST)响应。或者,您可以通过ErrorsBindingResult 参数在控制器内本地处理验证错误,如下例所示:

@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标记的元注解。

你可以将@ResponseBodyreactive 类型一起使用,更多参考 Asynchronous Requests和 Reactive Types。
你可以使用MVC Config的Message Converters选项配置或者自定义信息转换。

您可以将@ResponseBody方法与JSON序列化视图相结合。

④ ResponseEntity

ResponseEntity类似于@ResponseBody,但有Statusheader。例如:

@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 methodtarget 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;
}

② 接口继承树示意图

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值