解析自定义MediaType的HttpMessageConverter

HandlerMethodReturnValueHandlerHandlerMethodArgumentResolver面向的是控制器返回值和方法入参类型,即当请求一个控制器方法时,SpringMVC根据请求的控制器的方法入参类型决定使用哪个HandlerMethodArgumentResolver,例如下面的代码

@PostMapping(value = "/properties",
            consumes = "text/properties;charset=utf-8")
    public Properties properties(@RequestBody Properties properties){
        return properties;
    }

由于入参参数存在@RequestBody注解,因此参数处理器使用的是RequestResponseBodyMethodProcessor,而Rest应用存在@ResponseBody注解,因此返回值的处理器也是RequestResponseBodyMethodProcessor
不同的处理器在处理参数和返回值时方法不同,但大多的套路都是:

  1. 使用MessageConverters对进来的参数进行解析拿到值
  2. 解析参数对应的参数名称
  3. 使用WebDataBinder进行参数名称与参数值的绑定

MessageConverters的作用是对传进来的参数进行解析,不同的转换器支持不同的媒体类型,在解析时会遍历已注册的转换器进行尝试解析

下面在基于RequestResponseBodyMethodProcessor的情况下自定义新的HttpMessageConverter用于解析我们自定义的媒体类型text/Properties

由于是Rest风格,使用的是RequestResponseBodyMethodProcessor,我们模仿jackson的convert进行仿写

public class PropertiesConvert extends AbstractGenericHttpMessageConverter<Properties> {

    /**
     * 支持的处理类型
     */
    public PropertiesConvert() {
        super(new MediaType("text","properties"));
    }

    /**
     * 返回值处理
     */
    @Override
    protected void writeInternal(Properties properties, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        HttpHeaders httpHeaders = outputMessage.getHeaders();
        Charset charset = httpHeaders.getContentType().getCharset();
        charset = charset == null ? Charset.forName("utf-8") : charset;

        OutputStream outputStream = outputMessage.getBody();
        Writer writer = new OutputStreamWriter(outputStream,charset);
        properties.store(writer,"my convert");
    }

    /**
     * 入参转换
     */
    @Override
    protected Properties readInternal(Class<? extends Properties> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        HttpHeaders httpHeaders = inputMessage.getHeaders();
        Charset charset = httpHeaders.getContentType().getCharset();
        charset = charset == null ? Charset.forName("utf-8") : charset;

        InputStream inputStream = inputMessage.getBody();
        InputStreamReader reader = new InputStreamReader(inputStream,charset);
        Properties properties = new Properties();
        properties.load(reader);

        return properties;
    }

    @Override
    public Properties read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return readInternal(null,inputMessage);
    }
}

@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //由于json可以处理properties,如果不指定位置添加是添加到末尾,在选择convert处理时会优先选择json的而不是我们自定义的
        converters.add(0,new PropertiesConvert());
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们没有指定返回媒体类型,因此是所有的都可以。但由于我们自定义的添加到了第一个位置,所以会用完没自定义的这个convert进行转换返回

发布了98 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Mutou_ren/article/details/104081053