被坑过后才知道HttpMessageConverter多重要( 二 )

对 , 没错 , 这就解决了 , MappingJackson2HttpMessageConverter也是一个HttpMessageConverter转换类 , 但是他不能处理text/html的数据 , 原因是他的父类AbstractHttpMessageConverter中的supportedMediaTypes集合中没有text/html类型 , 如果有的话就能处理了 , 通过setSupportedMediaTypes可以给他指定一个新的MediaType集合 , 上面的写法会导致MappingJackson2HttpMessageConverter只能处理text/html类型的数据 。
但是 , 为了更深的研究 , 我们要直接继承HttpMessageConverter(当然更推荐的是继承AbstractHttpMessageConverter)来实现,在此之前 , 先看这几个方法具体代表什么意思 , 才能继续往下写 。
public interface HttpMessageConverter {/*** 根据mediaType判断clazz是否可读*/boolean canRead(Class clazz, @Nullable MediaType mediaType);/*** 根据mediaType判断clazz是否可写*/boolean canWrite(Class clazz, @Nullable MediaType mediaType);/*** 获取支持的mediaType*/List getSupportedMediaTypes();/*** 将HttpInputMessage流中的数据绑定到clazz中*/T read(Class clazz, HttpInputMessage inputMessage)throws IOException, HttpMessageNotReadableException;/*** 将t对象写入到HttpOutputMessage流中*/void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)throws IOException, HttpMessageNotWritableException;}复制代码对于解决这个问题 , canWrite , write方式是不需要处理的 , 只管canRead和read就行 , 在canRead方法中判断了是不是text/html类型 , 是的话就会返回true , Spring就会调用read , 用来将字节流中的数据转换成具体实体 , aClass就是我们最终想要得到的实例对象的Class , StreamUtils这个工具类是SpringBoot自带的一个 , 用来读取InputStream中的数据并返回String字符串 , SpringBoott内部很多地方都用到了这个工具类 , 所以这里来借用一下 , 现在拿到了String型的数据后 , 就需要将String转换成对应的对象 , 这里可能想到了Gson、Fastjson , 使用他们也可以完成 , 但是还需要额外的加入jar包 , SpringBoot自身已经集成了ObjectMapper , 所以在来借用一下 。
package com.hxl.vote.config;import com.fasterxml.jackson.databind.DeserializationFeature;import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.http.HttpInputMessage;import org.springframework.http.HttpOutputMessage;import org.springframework.http.MediaType;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.http.converter.HttpMessageNotReadableException;import org.springframework.http.converter.HttpMessageNotWritableException;import org.springframework.util.StreamUtils;import java.io.IOException;import java.nio.charset.Charset;import java.util.Arrays;import java.util.List;public class QQHttpMessageConverter implements HttpMessageConverter {@Overridepublic boolean canRead(Class aClass, MediaType mediaType) {if (mediaType != null) {return mediaType.isCompatibleWith(MediaType.TEXT_HTML);}return false;}@Overridepublic boolean canWrite(Class aClass, MediaType mediaType) {return false;}@Overridepublic List getSupportedMediaTypes() {return Arrays.asList(MediaType.TEXT_HTML);}@Overridepublic Object read(Class aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {String json = StreamUtils.copyToString(httpInputMessage.getBody(), Charset.forName("UTF-8"));ObjectMapper objectMapper = new ObjectMapper();objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);return objectMapper.readValue(json, aClass);}@Overridepublic void write(Object o, MediaType mediaType, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {}}复制代码最后需要要进行配置 , getMessageConverters()会返回现有的HttpMessageConverter集合 , 我们在这个基础上加入我们自定义的HttpMessageConverter即可 , 这回就不报错了 。
@Beanpublic RestTemplate restTemplate(){RestTemplate restTemplate = new RestTemplate();restTemplate.getMessageConverters().add(new QQHttpMessageConverter());returnrestTemplate;}复制代码继承AbstractHttpMessageConverterAbstractHttpMessageConverter帮我们封装了一部分事情 , 但是有些事情是他不能确定的 , 所以要交给子类实现 , 使用以下方法 , 同样可以解决text/html的问题 。
public class QQHttpMessageConverter extends AbstractHttpMessageConverter {public QQHttpMessageConverter() {super(MediaType.TEXT_HTML);}@Overrideprotected boolean supports(Class aClass) {return true;}@Overrideprotected Object readInternal(Class aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {String json = StreamUtils.copyToString(httpInputMessage.getBody(), Charset.forName("UTF-8"));ObjectMapper objectMapper = new ObjectMapper();objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);return objectMapper.readValue(json, aClass);}@Overrideprotected void writeInternal(Object o, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {}}复制代码