【SpringMVC(十四)】HttpMessageConverter

32 篇文章 15 订阅
30 篇文章 5 订阅

接口定义:

public interface HttpMessageConverter<T> {

	boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

	boolean canWrite(Class<?> clazz, @Nullable 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;
}

该接口的主要职责是将某一java类实例转换为http的请求或者响应,这里主要看响应。其中两个canXxx方法定义了该converter是否可以处理当前响应。read以及write方法定义了具体的读写方法。

该类型的实例是如何被SpringMVC框架处理的?

AbstractMessageConverterMethodProcessor的抽象类实现了returnValueHandler以及arguementResolver接口,会在Adapter调用controller的前后被调用。这个类内部会持有一个HttpMessageConverter类型的List,逐个调用converter。所以这个类可以理解为一个桥梁,连接了RequestMappingAdapter以及HttpMessageConverter。

该抽象类有两个常见的实现类,一个是HttpEntityMethodProcessor,用于处理RequestEntity类型的返回值;另一个是RequestResponseBodyMethodProcessor,用于处理json类型的返回值。

以HttpEntityMethodProcessor处理二进制内容为例:

二进制数据会被ByteArrayHttpMessageConverter类型的converter处理。

该类继承自抽象类AbstractHttpMessageConverter。在AbstractHttpMessageConverter类中定义了一些公共的骨架方法。比如canXxx方法:

	@Override
	public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
		return supports(clazz) && canWrite(mediaType);
	}

	/**
	 * Returns {@code true} if the given media type includes any of the
	 * {@linkplain #setSupportedMediaTypes(List) supported media types}.
	 * @param mediaType the media type to write, can be {@code null} if not specified.
	 * Typically the value of an {@code Accept} header.
	 * @return {@code true} if the supported media types are compatible with the media type,
	 * or if the media type is {@code null}
	 */
	protected boolean canWrite(@Nullable MediaType mediaType) {
		if (mediaType == null || MediaType.ALL.equalsTypeAndSubtype(mediaType)) {
			return true;
		}
		for (MediaType supportedMediaType : getSupportedMediaTypes()) {
			if (supportedMediaType.isCompatibleWith(mediaType)) {
				return true;
			}
		}
		return false;
	}

其中canWrite方法会根据MediaType判断是否执行。对于ByteArrayHttpMessageConverter来说,其所支持的MediaType为:

public ByteArrayHttpMessageConverter() {
	super(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL);
}

也就是二进制类数据。

另一个抽象方法write方法:

@Override
public final void write(final T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
		throws IOException, HttpMessageNotWritableException {

	final HttpHeaders headers = outputMessage.getHeaders();
	addDefaultHeaders(headers, t, contentType);

	if (outputMessage instanceof StreamingHttpOutputMessage) {
		StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage;
		streamingOutputMessage.setBody(outputStream -> writeInternal(t, new HttpOutputMessage() {
			@Override
			public OutputStream getBody() {
				return outputStream;
			}
			@Override
			public HttpHeaders getHeaders() {
				return headers;
			}
		}));
	}
	else {
		writeInternal(t, outputMessage);
		outputMessage.getBody().flush();
	}
}

会调用writeInternal抽象方法,将数据写入httpResponse的body里。

仍然以ByteArrayHttpMessageConverter为例:

@Override
protected void writeInternal(byte[] bytes, HttpOutputMessage outputMessage) throws IOException {
	StreamUtils.copy(bytes, outputMessage.getBody());
}

其writeInternal方法就是将二进制数组写入到body中。

类图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值