FastJsonHttpMessageConverter的坑

果FastJsonHttpMessageConverter不配置supportMediaType,那么默认是MediaType.ALL。
FastJsonHttpMessageConverter应配置MediaType.APPLICATION_JSON_UTF8
List supportMediaTypeList = new ArrayList<>();
supportMediaTypeList.add(MediaType.APPLICATION_JSON_UTF8);
converter.setSupportedMediaTypes(supportMediaTypeList);

我有一个业务场景,需要缓存商品详情页,手动渲染Thymeleaft模板,在Controller中返回html片段。
配置如下:

   @RequestMapping(value = "/to_list", produces = "text/html;charset=UTF-8")
    @ResponseBody
    public String list(MiaoshaUser miaoshaUser){
        ...
        return html;
    }

虽然在Controller中可以通过手动打开输出流,设置ContentType,把Thymeleaf模板输出到Response的body,可以解决问题。
但是本着阿Q精神,我Debug消息转换器的流程,发现问题出在FastJsonHttpMessageConverter没有配置MediaType.APPLICATION_JSON_UTF8,
导致其默认的MediaType.ALL影响Thymeleaf模板最后的输出。

1.RequestResponseBodyProcessor实现了HandlerMethodReturnValueHandler、HandlerMethodAgumentResolver接口,
实现了boolean supportsParamter()、void resolveArgument()、boolean supportsReturnType()、void handleReturnValue()
所以具备了处理参数、处理返回值的能力。

2.handleReturnValue()获取inputMessage,outMessage对象,
调用writeWithMessageConverters()方法,让消息转换器对消息进行下一步处理.

3.在AbstarctMessageConverterProcess的writeWithMessageConverters()中,
根据HandlerMethod中的ReturnValueMethodParameter对象获取valueType(返回值类型),同时也能得到
outputValue(返回值)、decalredType(返回值实际类型)

4.根据request对象中获取请求中Accept的属性值,得到requestedMediaTypes,
根据HandlerMapping中的produces属性获得producibleMediaTypes。如果没有设置produces属性,
默认遍历系统中所有的HttpMessageConverter,找到合适的supportMediaTypes。
通过两次for循环,比较requestedMediaTypes和producibleMediaTypes
得到compatiableMediaTypes。如果compatiableMediaTypes为空,会抛出HttpMediaTypeNotAcceptableException异常
白话意思就是producibleMediaTypes没有一个MediaType与requestedMediaTypes匹配,肯定无法执行下一步了。

5.排序、for循环compatiableMediaTypes,得到selectedMediaType(最终的MediaType)

6.for循环已配置所有的HttpMessageConverter,调用canWrite()方法,根据valueType(返回值类型)
和selectedMediaType来判断消息是否可以转换。

如果没有配置MediaType.APPLICATION_JSON_UTF8,默认值是MediaType.ALL,FastJsonHttpMessageConverter
会去处理消息格式为"text/html;charset=UTF-8",

调用方法如下:
=》write(Object o, Type type, MediaType contentType, HttpOutputMessage outputMessage) :AbstractHttpMessageConverter
=》writeInternal(t, outputMessage) :FastJsonHttpMessageConverter
=》JSON.writeJSONString(...), serializer.write(object)
卧槽,把html序列化了,GG,界面出现大量的\n\t

如果配置了MediaType.APPLICATION_JSON_UTF8,FastJsonHttpMessageConverter
只能处理"application/json;charset=UTF-8"的消息,"text/html;charset=UTF-8"格式的消息被StringHttpMessageConverter得到了处理,
调用方法如下:
=》write(t,contentType, outputMessage) :AbstractHttpMessageConverter
=> writeInternal(t, outputMessage) :StringHttpMessageConverter
=>StreamUtils.copy(str, charset, outputMessage.getBody()) :StringHttpMessageConverter
输出html片段

最后HttpMessageConverter加载顺序,可以在WebMvcConfigurationSupport看到端倪。
我们其实是重写configureMessageConverters()方法去配置FastJsonHttpMessageConverter,
所以它是第一个。

  protected final List<HttpMessageConverter<?>> getMessageConverters() {
    if (this.messageConverters == null) {
        this.messageConverters = new ArrayList<HttpMessageConverter<?>>();
        configureMessageConverters(this.messageConverters);
        if (this.messageConverters.isEmpty()) {
            addDefaultHttpMessageConverters(this.messageConverters);
        }
        extendMessageConverters(this.messageConverters);
    }
    return this.messageConverters;
}

    protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
    StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
    stringConverter.setWriteAcceptCharset(false);

    messageConverters.add(new ByteArrayHttpMessageConverter());
    messageConverters.add(stringConverter);
    messageConverters.add(new ResourceHttpMessageConverter());
    messageConverters.add(new SourceHttpMessageConverter<Source>());
    messageConverters.add(new AllEncompassingFormHttpMessageConverter());

    if (romePresent) {
        messageConverters.add(new AtomFeedHttpMessageConverter());
        messageConverters.add(new RssChannelHttpMessageConverter());
    }

    if (jackson2XmlPresent) {
        messageConverters.add(new MappingJackson2XmlHttpMessageConverter(
                Jackson2ObjectMapperBuilder.xml().applicationContext(this.applicationContext).build()));
    }
    else if (jaxb2Present) {
        messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
    }

    if (jackson2Present) {
        messageConverters.add(new MappingJackson2HttpMessageConverter(
                Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build()));
    }
    else if (gsonPresent) {
        messageConverters.add(new GsonHttpMessageConverter());
    }
}

根据上面的源码可知先配置FastJsonHttpMessageConverter,其他的走默认。顺序很重要

@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    FastJsonHttpMessageConverter fastConvertor = new FastJsonHttpMessageConverter();
    FastJsonConfig fastJsonConfig = new FastJsonConfig();
    fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue,
            SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.WriteNullListAsEmpty);
    fastConvertor.setFastJsonConfig(fastJsonConfig);
    List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();
    supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
    supportedMediaTypes.add(MediaType.APPLICATION_JSON);
    fastConvertor.setSupportedMediaTypes(supportedMediaTypes);
    converters.add(fastConvertor);
    super.addDefaultHttpMessageConverters(converters);
}
  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Fastjson是一个用于处理JSON数据的Java库,Fastjson2则是Fastjson的第二个版本。 Fastjson2提供了一个FastJsonHttpMessageConverter类,用于在Spring MVC中将Java对象转换为JSON数据。它可以将请求的JSON数据转换为Java对象,并将Java对象转换为响应的JSON数据。这个转换器可以方便地集成到Spring应用程序中。 要在Spring MVC中使用FastJsonHttpMessageConverter,你需要在配置文件中进行相应的配置。首先,你需要添加Fastjson的依赖项到你的项目中。然后,在Spring的配置文件中,通过添加以下代码来配置FastJsonHttpMessageConverter: ```java @Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); converters.add(fastConverter); } @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { for (HttpMessageConverter<?> converter : converters) { if (converter instanceof MappingJackson2HttpMessageConverter) { MappingJackson2HttpMessageConverter jsonConverter = (MappingJackson2HttpMessageConverter) converter; jsonConverter.setObjectMapper(new ObjectMapper()); } } } } ``` 以上配置将FastJsonHttpMessageConverter添加到Spring MVC中,并将其作为默认的JSON转换器。你还可以根据需要进一步配置Fastjson的相关选项,比如日期格式化、类型处理等。 希望这能解答你关于Fastjson2和FastJsonHttpMessageConverter的问题!如有更多疑问,请随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值