1.简介:

Spring在处理请求时,由合适的消息转换器将请求报文绑定为方法中的形参对象,在这里,同一个对象就有可能出现多种不同的消息形式,比如json和xml。同样,当响应请求时,方法的返回值也同样可能被返回为不同的消息形式,比如json和xml。

在Spring中,针对不同的消息形式,我们有不同的HttpMessageConverter实现类来处理各种消息形式。但是,只要这些消息所蕴含的“有效信息”是一致的,那么各种不同的消息转换器,都会生成同样的转换结果。至于各种消息间解析细节的不同,就被屏蔽在不同的HttpMessageConverter实现类中了。

2.应用:

方法一:

SpringBoot中很多配置都使用默认的,但是如果你自己手动配置了,那么容器就是使用你自己的配置

自定义消息转化器,只需要在@Configuration的类中添加消息转化器的@bean加入到Spring容器,就会被Spring Boot自动加入到容器中。

@Configuration
public class FastJsonHttpMessageConverterConfig {@Beanpublic HttpMessageConverters fastJsonHttpMessageConverters(){//1.需要定义一个convert转换消息的对象;FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();//2:添加fastJson的配置信息;FastJsonConfig fastJsonConfig = new FastJsonConfig();fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);//3处理中文乱码问题List<MediaType> fastMediaTypes = new ArrayList<>();fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);//4.在convert中添加配置信息.
        fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);HttpMessageConverter<?> converter = fastJsonHttpMessageConverter;return new HttpMessageConverters(converter);}
}

方法二:

在继承WebMvcConfigurerAdapter的类中重写(覆盖)configureMessageConverters方法

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import java.util.List;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;/*** Created by qhong on 2018/6/1 10:59**/
@ControllerAdvice
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();builder.serializationInclusion(JsonInclude.Include.NON_NULL);ObjectMapper objectMapper = builder.build();SimpleModule simpleModule = new SimpleModule();simpleModule.addSerializer(Long.class, ToStringSerializer.instance);objectMapper.registerModule(simpleModule);objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);// 忽略 transient 修饰的属性converters.add(new MappingJackson2HttpMessageConverter(objectMapper));//字符串转换器//StringHttpMessageConverter converter  = new StringHttpMessageConverter(Charset.forName("UTF-8"));//converters.add(converter);//FastJson转换器
//        //1.需要定义一个convert转换消息的对象;
//        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
//        //2.添加fastJson的配置信息,比如:是否要格式化返回的json数据;
//        FastJsonConfig fastJsonConfig = new FastJsonConfig();
//        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
//        //3处理中文乱码问题
//        List<MediaType> fastMediaTypes = new ArrayList<>();
//        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
//        //4.在convert中添加配置信息.
//        fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
//        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
//        //5.将convert添加到converters当中.
//        converters.add(fastJsonHttpMessageConverter);
super.configureMessageConverters(converters);}@Overridepublic void extendMessageConverters(List<HttpMessageConverter<?>> converters) {System.out.println("Converters:Begin");System.out.println("num:"+converters.size());for (HttpMessageConverter<?> messageConverter : converters) {System.out.println(messageConverter);}System.out.println("Converters:End");}
}

方法三:

使用extendMessageConverters方法,其实在上一个code中已经贴出来,只是用来查看总共有那些消息转换器的,通过上面的,可以查看的自己手动添加的消息转换器。

    @Overridepublic void extendMessageConverters(List<HttpMessageConverter<?>> converters) {converters.clear();converters.add(new FastJsonHttpMessageConverter());}

3.原理

我们知道,Http请求和响应报文本质上都是一串字符串,当请求报文来到java世界,它会被封装成为一个ServletInputStream的输入流,供我们读取报文。响应报文则是通过一个ServletOutputStream的输出流,来输出响应报文。

我们从流中,只能读取到原始的字符串报文,同样,我们往输出流中,也只能写原始的字符。而在java世界中,处理业务逻辑,都是以一个个有业务意义的对象为处理维度的,那么在报文到达SpringMVC和从SpringMVC出去,都存在一个字符串到java对象的阻抗问题。这一过程,不可能由开发者手工转换。我们知道,在Struts2中,采用了OGNL来应对这个问题,而在SpringMVC中,它是HttpMessageConverter机制。

package org.springframework.http.converter;import java.io.IOException;
import java.util.List;import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;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;}

HttpMessageConverter接口的定义出现了成对的canRead(),read()和canWrite(),write()方法,MediaType是对请求的Media Type属性的封装。举个例子,当我们声明了下面这个处理方法。

@RequestMapping(value="/query", method=RequestMethod.POST)
public @ResponseBody User queryUser(@RequestBody String tel) {return query(tel);
}

在SpringMVC进入queryUser方法前,会根据@RequestBody注解选择适当的HttpMessageConverter实现类来将请求参数解析到string变量中,具体来说是使用了StringHttpMessageConverter类,它的canRead()方法返回true,然后它的read()方法会从请求中读出请求参数,绑定到readString()方法的string变量中。

当SpringMVC执行readString方法后,由于返回值标识了@ResponseBody,SpringMVC将使用MappingJackson2HttpMessageConverter(或者自定义的FastJsonHttpMessageConverter)的write()方法,将结果转换成json字符串写入响应报文,当然,此时canWrite()方法返回true。

我们可以用下面的图,简单描述一下这个过程。

上面只是利用一些第三方的消息转换器

自定义消息转换器:

捡到网上一个注释比较全的。

public class MyMessageConverter extends AbstractHttpMessageConverter<DemoObj> {public MyMessageConverter() {//x-zyf 是自定义的媒体类型super(new MediaType("application", "x-zyf", Charset.forName("Utf-8")));}@Overrideprotected boolean supports(Class<?> aClass) {//表示只支持DemoObj这个类//return DemoObj.class.isAssignableFrom(aClass);//返回false则不会支持任何类,要想使用,就需要返回truereturn true;}/*** 重写readInternal方法* 处理请求中的数据** @param aClass* @param httpInputMessage* @return* @throws IOException* @throws HttpMessageNotReadableException*/@Overrideprotected DemoObj readInternal(Class<? extends DemoObj> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {//获得请求中的数据,得到字符串形式String temp = StreamUtils.copyToString(httpInputMessage.getBody(), Charset.forName("UTF-8"));//前端请求的格式是我们自己约定的String[] tempArr = temp.split("-");return new DemoObj(new Long(tempArr[0]), tempArr[1]);}/*** 重写writeInternal方法* 处理任何输出数据到response** @param obj  要输出到response的对象* @param httpOutputMessage* @throws IOException* @throws HttpMessageNotWritableException*/@Overrideprotected void writeInternal(DemoObj obj, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {String out = "hello:" + obj.getId() + "-" + obj.getName();httpOutputMessage.getBody().write(out.getBytes());}
}

这里特别要注意的就是support,特么的,我以为返回false就是不进行消息转换呢,原来不是。

readInternal:

public class MappingJackson2HttpMessageConverter extends AbstractHttpMessageConverter<Object> {public static final ObjectMapper mapper = new ObjectMapper();public static final Logger LOG = LoggerFactory.getLogger(MappingJackson2HttpMessageConverter.class);private boolean encryptFlag = false;public void setEncryptFlag(boolean encryptFlag) {this.encryptFlag = encryptFlag;}public MappingJackson2HttpMessageConverter() {super(new MediaType("application", "json", Charset.forName("UTF-8")));}protected boolean supports(Class<?> clazz) {return true;}protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {return mapper.readValue(inputMessage.getBody(), clazz);}protected void writeInternal(Object d, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {byte[] jsonBytes;if(d.getClass()!=HuishiUserLoginResponse.class) {BasicRes r = new BasicRes();if (d != null && d != SysConstant.NULL_RESPONSE) {LOG.info("====>>>>> 响应数据:response={}", d.toString());if (encryptFlag) {try {long repStart = System.currentTimeMillis();String json = ToJson(d);String data = CoderUtil.encryptAES(json);r.setData(data);long repEnd = System.currentTimeMillis();long repTime = repEnd - repStart;logger.info("加密耗时==>" + repTime + " ms");} catch (Exception e) {e.printStackTrace();}} else {r.setData(d);}}jsonBytes = ToJsonAsBytes(r);}else{jsonBytes = ToJsonAsBytes(d);}OutputStream out = outputMessage.getBody();out.write(jsonBytes, 0, jsonBytes.length);out.close();}public static byte[] ToJsonAsBytes(Object value) {try {return mapper.writeValueAsBytes(value);} catch (Exception var2) {LOG.error("ToJsonAsBytes error,Object:{}", value, var2);return null;}}public static String ToJson(Object value) {try {return mapper.writeValueAsString(value);} catch (Exception var2) {LOG.error("ToJosn error,Object:{}", value, var2);return "";}}
}

https://www.jianshu.com/p/ffe56d9553fd

https://www.cnblogs.com/hellxz/p/8735602.html

https://blog.csdn.net/mickjoust/article/details/51671060

https://www.cnblogs.com/page12/p/8166935.html

https://my.oschina.net/lichhao/blog/172562

https://blog.csdn.net/L_Sail/article/details/70209845

https://blog.csdn.net/linFeng_csdn/article/details/72835451

SpringBoot 消息转换器 HttpMessageConverter相关推荐

  1. springMVC消息转换器HttpMessageConverter

    前言 为何需要消息转换器 HttpMessageConverter是用来处理request和response里的数据的. 请求和响应都有对应的body,而这个body就是需要关注的主要数据. 请求体的 ...

  2. 【Spring学习笔记-MVC-1.3】消息转换器HttpMessageConverter

    作者:ssslinppp       参考链接: SpringMVC源码剖析(五)-消息转换器HttpMessageConverter: http://my.oschina.net/lichhao/b ...

  3. SpringBoot消息转换器:HttpMessageConverter

    文章目录 消息转化器的作用 消息转化器的主要方法 默认配置的消息转化器 注意事项 在整个数据流转过程中,前端的请求报文转化为Java对象,Java对象转化为响应报文,这里就用到了HttpMessage ...

  4. springboot自定义消息转换器HttpMessageConverter

    在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,底层这种灵活的消息转换机制就是利用HttpMessageCo ...

  5. java注解返回不同消息,SpringMVC源码剖析5:消息转换器HttpMessageConverter与@ResponseBody注解...

    转自 [SpringMVC关于json.xml自动转换的原理研究[附带源码分析]](https://www.cnblogs.com/fangj... 部分代码会放在我的的Github:https:// ...

  6. SpringMVC源码剖析(五)-消息转换器HttpMessageConverter

    概述 在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,底层这种灵活的消息转换机制,就是Spring3.x中新 ...

  7. json txt格式转换器_SpringBoot项目中如何定制HTTP消息转换器

    本文首发于个人网站:Spring Boot项目中如何定制HTTP消息转换器,如需转载,请注明来源 在构建RESTful数据服务过程中,我们定义了controller.repositories,并用一些 ...

  8. SpringMVC自定义配置消息转换器踩坑总结

    问题描述 最近在开发时候碰到一个问题,springmvc页面向后台传数据的时候,通常我是这样处理的,在前台把数据打成一个json,在后台接口中使用@requestbody定义一个对象来接收,但是这次数 ...

  9. 基于Springboot外卖系统08:员工账号状态管理功能+对象转换器+扩展Spring mvc的消息转换器

    1. 员工账号状态管理 1.1 需求分析 在员工管理列表页面,可以对某个员工账号进行启用或者禁用操作.账号禁用的员工不能登录系统,启用后的员工可以正常登录.如果某个员工账号状态为正常,则按钮显示为 & ...

最新文章

  1. java 远程共享_【原创】(扫盲)远程共享对象SharedObject的用法
  2. Go 分布式学习利器(8)-- Go的函数
  3. QR分解原理与C实现(一般实矩阵)
  4. 华为智能家居app未能连接上远程云服务_【InForSec通讯】智能家居云平台实体间交互状态安全分析 | Usenix2019...
  5. mysql 5.1升级5.6_mysql 5.1.71升级到5.6.30
  6. 安装nodejs express框架时express命令行无效
  7. jsp循环输出表格_使用 ale.js 制作一个小而美的表格编辑器(1)
  8. 20144303 《Java程序设计》第一周学习总结
  9. 韩立刚计算机网络——第四章:网络层
  10. Goldendict 1.5.0 VS2015 Qt 5.7 源代码编译
  11. DDG-1000下水
  12. 吉尼斯官方确认火狐首日下载世界记录
  13. 基于MatlabSimulin的微电网模型及光伏电池建模仿真分析
  14. Unity ADB调试和一些常用命令
  15. 【新知实验室】实时音视频(TRTC)之初体验
  16. IntelliJ IDEA默认的keymap设置是哪个?
  17. VMware安装Centos7_64位系统安装步骤
  18. [4G5G专题-12]:功能-LTE载波聚合CA对空口协议栈的影响概述
  19. 计算机硬件故障检测实验报告,计算机系统的硬件检测实验报告
  20. LPDDR4x 的 学习总结(1) - 存储体的浅识

热门文章

  1. 曝苹果 2022 新款 iPad Pro 将在 9 月或 10 月发布:配备 M2 芯片、无线充电、相机系统升级
  2. [量化-027]段永平投资哲学整理
  3. 第七天之多态原理探究
  4. hangye5:2011医疗行业网络营销发展动态
  5. Kotlin学习九:Kotlin中的“==”和“===”
  6. Python实时检测文件及文件夹变动
  7. 跟我学UDS(ISO14229) ———— 0x2C(DynamicallyDefineDataIdentifier)
  8. 神级以下必读! ~程序员学习资料(图书源码) 01
  9. 职场吐槽大会:一起聊聊职场里的奇葩人奇葩事
  10. 2020年2月12日 林大OJ习题 队列