SpringBoot自定义HttpMessageConverter操作

 更新时间:2021年08月18日 10:24:14   作者:躺在家里不干活  
这篇文章主要介绍了SpringBoot自定义HttpMessageConverter的操作,具有很好的参考价值,如有错误或未考虑完全的地方,望不吝赐教

简介

我们使用**@RequestBody可以将请求体中的JSON字符串绑定到相应的bean,使用@ResponseBody**可以使返回结果不会被解析为跳转路径,而是直接写入 HTTP response body 中,而整个数据绑定的过程其实是HttpMessageConverter在起作用。

MediaType

MediaType,即是Internet Media Type,互联网媒体类型;也叫做MIME类型,在Http协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息。

@RequestBody的简单实用

@requestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容,比如说:application/json或者是application/xml等。一般情况下来说常用其来处理application/json类型。

1、解析json

Content-Type: application/json

请求数据格式

{
 "question": "aaa",
 "fromUser": "bbb"
}

2、解析xml

Content-Type: application/xml

请求数据格式

<?xml version='1.0' encoding="utf-8"?> 
<Request>
 <question>aaa</question>
 <fromUser>bbb</fromUser>
</Request>

上面两种方式都是可以把数据映射到Bean中的。

3、原理

Spring会根据MediaType查找合适的HttpMessageConverter的实现类进行序列化的操作

public interface HttpMessageConverter<T> {
 boolean canRead(Class<?> clazz, MediaType mediaType);
 boolean canWrite(Class<?> clazz, MediaType mediaType);
 List<MediaType> getSupportedMediaTypes();
 T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
   throws IOException, HttpMessageNotReadableException;
 void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
   throws IOException, HttpMessageNotWritableException;
}
方法 作用
getSupportedMediaTypes 获取支持的MediaType
read 读取request的body
write 把数据写到response的body中

@ResponseBody

ResponseBody中的使用和RequestBody类似

自定义HttpMessageConverter

1、目的

SpringBoot提供一系列的HttpMessageConverter,满足了我们的绝大部分需求,如果有特性需求,我们可以编写自定义的转换器

2、步骤

编写Converter类,需要实现HttpMessageConverter,或者继承已经存在的实现类,并重写上文中的关键方法

编写WebConfig(extends WebMvcConfigurerAdapter)

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    /**
     * 自定义message_convert
     */
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
       // 把converter添加到converters的最后(SpringBoot会使用第一个匹配到的Converter)
       converters.add(new XxxConverter());
       // 把converter添加到converters的最前面
       // converters.add(0, new XxxConverter());
    }
}

到此为止,我们自定义的Converter已经生效了

3、自定义MediaType

虽然我们已经编写Converter,但是我们一般会为自定义的Converter指定可以处理的媒体类型,可以指定自定义的媒体类型

在自定义的Converter中新增自定义的MediaType,并且根据需要修改canRead,canWrite;

public class XxxConverter implements HttpMessageConverter<Serializable> {
    public static final String CUSTOM_MEDIA = "application/custom-media";
    @Override
    public boolean canRead(Class<?> clazz, MediaType mediaType) {
        return true;
    }
    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return true;
    }
    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return Lists.newArrayList(MediaType.parseMediaType(CUSTOM_MEDIA));
    }
    @Override
    public Serializable read(Class<? extends Serializable> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }
    @Override
    public void write(Serializable serializable, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
    }
}

这里一定要修改getSupportedMediaTypes方法,SpringBoot是根据这个方法的返回,以及Controller—@RequestMapping中指定的MediaType,判断是否可用于当前请求/返回。

在Controller的@RequestMapping中指定consumes或者produces

@RestController
@RequestMapping(produces = CUSTOM_MEDIA, consumes = CUSTOM_MEDIA)
@Validated
public class HomeController {
    @GetMapping(HOME)
    JsonResult info(@RequestHeader("userId") Long userId) {
        return JsonResult.ok();
    }
}

consumes是指定请求的MediaType,需要调用方设置成我们提供的application/custom-media

produces是指定返回的MediaType,如果我们设置成application/custom-media,那么方法返回的数据就会通过自定义的XxxConverter进行转换。

问题

注意:如果我们修改了produces的MediaType,那么HTTP返回中的MediaType也会是我们自定义的类型,除非和调用方约定好,否则调用方是没有办法解析的。

解决办法:

public class XxxConverter implements HttpMessageConverter<Serializable> {
 ......
    @Override
    public void write(Serializable serializable, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        // 最后把Content-Type改成APPLICATION_JSON_UTF8_VALUE,要不然请求方会无法解析
        ((ServletServerHttpResponse) outputMessage)
        .getServletResponse().setHeader("Content-Type",APPLICATION_JSON_UTF8_VALUE);
    }
}

总结

一般情况下,SpringBoot提供的默认转换器已经足够我们使用,但是在一些接口的参数需要加解密,调整返回体的结构等情况下会用到。以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java yield()线程让步实现过程解析

    Java yield()线程让步实现过程解析

    这篇文章主要介绍了Java yield()线程让步实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • 从基础学java--数组

    从基础学java--数组

    数组是相同类型数据的有序集合数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们数组的声明创建
    2021-09-09
  • Spring Lifecycle 和 SmartLifecycle区别面试精讲

    Spring Lifecycle 和 SmartLifecycle区别面试精讲

    这篇文章主要为大家介绍了Spring Lifecycle和SmartLifecycle的区别面试精讲,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Spring Web MVC基础理论概念

    Spring Web MVC基础理论概念

    Spring Web MVC是基于Servlet API构建的原始Web框架,从⼀开始就包在Spring框架中,Spring Web MVC是一个Web框,本文给大家介绍Spring Web MVC基础理论,感兴趣的朋友一起看看吧
    2024-08-08
  • java数据结构与算法之希尔排序详解

    java数据结构与算法之希尔排序详解

    这篇文章主要介绍了java数据结构与算法之希尔排序,结合实例形式分析了希尔排序的概念、原理、实现方法与相关注意事项,需要的朋友可以参考下
    2017-05-05
  • 如何获取springboot打成jar后的classpath

    如何获取springboot打成jar后的classpath

    这篇文章主要介绍了如何获取springboot打成jar后的classpath问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • sentinel整合ribbon与fallback流程分步讲解

    sentinel整合ribbon与fallback流程分步讲解

    这篇文章主要介绍了sentinel整合ribbon与fallback分步流程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • 浅谈java中文本框和文本区

    浅谈java中文本框和文本区

    本文给大家介绍的是java中的文本框和文本区的概念和使用方法,以及简单的示例,十分实用,有需要的小伙伴可以参考下。
    2015-06-06
  • 如何解决Java程序包不存在问题

    如何解决Java程序包不存在问题

    在使用IDEA 2022版本和Maven项目中,可能遇到Java程序包不存在的问题,这是由于IDEA的小bug引起的,文章提供了两种解决方法:第一种是在IDEA的Settings中配置,并在pom.xml中添加特定代码刷新Maven;第二种是通过IDEA的设置菜单修改Maven导入配置
    2024-10-10
  • java位运算加密示例

    java位运算加密示例

    通过位运算中的"^"异或运算符把字符串与一个指定的值进行异或运算,从而改变字符串每个字符的值,这样就可以得到一个加密后的字符串
    2014-02-02

最新评论