在我们开发自己的应用时,有时候,我们可能需要自定义一些自己的数据格式来传输,这时,自定义的数据传输和类的实例之间进行转化就需要统一起来了, Spring MVC 中的 HttpMessageConverter 就派上用场了。

HttpMessageConverter 的声明:

public interface HttpMessageConverter<T> {    /**     * Indicates whether the given class can be read by this converter.     * @param clazz the class to test for readability     * @param mediaType the media type to read (can be {@code null} if not specified);     * typically the value of a {@code Content-Type} header.     * @return {@code true} if readable; {@code false} otherwise     */    boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);    /**     * Indicates whether the given class can be written by this converter.     * @param clazz the class to test for writability     * @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 writable; {@code false} otherwise     */    boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);    /**     * Return the list of {@link MediaType} objects supported by this converter.     * @return the list of supported media types     */    List<MediaType> getSupportedMediaTypes();    /**     * Read an object of the given type from the given input message, and returns it.     * @param clazz the type of object to return. This type must have previously been passed to the     * {@link #canRead canRead} method of this interface, which must have returned {@code true}.     * @param inputMessage the HTTP input message to read from     * @return the converted object     * @throws IOException in case of I/O errors     * @throws HttpMessageNotReadableException in case of conversion errors     */    T read(Class<? extends T> clazz, HttpInputMessage inputMessage)            throws IOException, HttpMessageNotReadableException;    /**     * Write an given object to the given output message.     * @param t the object to write to the output message. The type of this object must have previously been     * passed to the {@link #canWrite canWrite} method of this interface, which must have returned {@code true}.     * @param contentType the content type to use when writing. May be {@code null} to indicate that the     * default content type of the converter must be used. If not {@code null}, this media type must have     * previously been passed to the {@link #canWrite canWrite} method of this interface, which must have     * returned {@code true}.     * @param outputMessage the message to write to     * @throws IOException in case of I/O errors     * @throws HttpMessageNotWritableException in case of conversion errors     */    void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)            throws IOException, HttpMessageNotWritableException;}

里面有四个方法:

  1. canRead: 查看对应的类型和 content-type 头部类型是否支持被读取.
  2. canWrite: 查看对应的类型和 content-type 头部类型是否支持输出.
  3. getSupportedMediaTypes: 获取支持的类型
  4. read: 从 http 请求中,读取数据,并转化为指定类型。
  5. write: 将指定类型的实例写入到response中。

内置的常用HttpMessageConverter 类型:

  1. ByteArrayHttpMessageConverter – 转换 byte array 类型数据
  2. StringHttpMessageConverter – 根据编码格式,转化Strings
  3. ResourceHttpMessageConverter – converts org.springframework.core.io.Resource for any type of octet stream
  4. SourceHttpMessageConverter – 转换 javax.xml.transform.Source 类型的数据。
  5. FormHttpMessageConverter – 转换 application/x-www-form-urlencodedmultipart/form-data 类型的消息.
  6. Jaxb2RootElementHttpMessageConverter – 将对象和xml转换。
  7. MappingJackson2HttpMessageConverter – 使用 jackson2 转换 json 数据和 对象实例

自定义 HttpMessageConverter 并使用

  1. 首先,自定义 HttpMessageConverter:

需要转化的对象为:

public class TestRequestInfo {    private String key;    private int value;    private MultipartFile file;    public int getValue() {        return value;    }    public void setValue(int value) {        this.value = value;    }    public String getKey() {        return key;    }    public void setKey(String key) {        this.key = key;    }    public MultipartFile getFile() {        return file;    }    @Override    public String toString() {        return "TestRequestInfo{" +                "key='" + key + '\'' +                ", value=" + value +                '}';    }}

Converter

public class TestMessageConverter extends AbstractHttpMessageConverter<TestRequestInfo> {    public TestMessageConverter(){        super(new MediaType("application", "test-converter", Charset.forName("UTF-8")));    }    @Override    protected boolean supports(Class<?> clazz) {        return true;    }    @Override    protected TestRequestInfo readInternal(Class<? extends TestRequestInfo> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {        String temp = StreamUtils.copyToString(inputMessage.getBody(), Charset.forName("UTF-8"));        TestRequestInfo test = new TestRequestInfo();        test.setKey(temp);        return test;    }    @Override    protected void writeInternal(TestRequestInfo testRequestInfo, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {        outputMessage.getBody().write(testRequestInfo.toString().getBytes());    }}
  1. 注册 HttpMessageConverter:
@EnableWebMvc@Configuration@ComponentScanpublic class MVCConfig implements WebMvcConfigurer {    @Override    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {        converters.add(new TestMessageConverter());    }}
  1. 定义 Controller:
@RestControllerpublic class TestController {    @RequestMapping(        value="/reports",        method = {RequestMethod.GET, RequestMethod.POST}    )    public @ResponseBody    TestRequestInfo getReports(@RequestBody TestRequestInfo requestInfo){        System.out.println(requestInfo);        return requestInfo;    }}

请求结果为:
{"key":"sdfasfasdf","value":0,"file":null}.