FastJsonHttpMessageConverter转义字符串问题处理

FastJsonHttpMessageConverter转义字符串问题处理

最近进行几个api项目进行合并,发现rest接口原有的Date类型被转成时间戳,与期望的long类型不一致,于是引入FastJsonHttpMessageConverter进行统一转换,复制粘贴一气呵成:

	@Bean
	public HttpMessageConverters fastJsonHttpMessageConverters() {
		//1、定义一个convert转换消息的对象
		FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
		//2、添加fastjson的配置信息
		FastJsonConfig fastJsonConfig = new FastJsonConfig();
		fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue);
		//3、在convert中添加配置信息
		fastConverter.setFastJsonConfig(fastJsonConfig);
		//4、将convert添加到converters中
		HttpMessageConverter<?> converter = fastConverter;
		return new HttpMessageConverters(converter);
	}

然后自测中发现有些接口返回值被进行了二次转换,如:

"{\"a\":\"a\"}"

看代码发现,有个项目RestController的所有返回值都被手动转换了:

return JSON.toJSONString(resultMap);

上面的配置方式,由于FastJsonHttpMessageConverter 的优先级高于StringHttpMessageConverter,导致所有返回都被进行转换,而且没有排除String类型的配置,于是debug一下springboot源码,发现默认转换器的添加逻辑:

	/**
	 * Adds a set of default HttpMessageConverter instances to the given list.
	 * Subclasses can call this method from {@link #configureMessageConverters}.
	 * @param messageConverters the list to add the default message converters to
	 */
	protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
		StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
		stringHttpMessageConverter.setWriteAcceptCharset(false);  // see SPR-7316

		messageConverters.add(new ByteArrayHttpMessageConverter());
		messageConverters.add(stringHttpMessageConverter);
		messageConverters.add(new ResourceHttpMessageConverter());
		messageConverters.add(new ResourceRegionHttpMessageConverter());
		messageConverters.add(new SourceHttpMessageConverter<>());
		messageConverters.add(new AllEncompassingFormHttpMessageConverter());

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

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

		if (jackson2Present) {
			Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
			if (this.applicationContext != null) {
				builder.applicationContext(this.applicationContext);
			}
			messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
		}
		else if (gsonPresent) {
			messageConverters.add(new GsonHttpMessageConverter());
		}
		else if (jsonbPresent) {
			messageConverters.add(new JsonbHttpMessageConverter());
		}

		if (jackson2SmilePresent) {
			Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile();
			if (this.applicationContext != null) {
				builder.applicationContext(this.applicationContext);
			}
			messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));
		}
		if (jackson2CborPresent) {
			Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.cbor();
			if (this.applicationContext != null) {
				builder.applicationContext(this.applicationContext);
			}
			messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
		}
	}

然后决定换一种方式添加FastJsonHttpMessageConverter,只需其优先级高于默认的jacksonConverter,并且低于StringHttpMessageConverter即可:


@Configuration
public class Mvc2JsonConfig implements WebMvcConfigurer {

    /**
     * FastJsonHttpMessageConverter 在 HttpMessageConverter 列表中的位置
     * 若 FastJsonHttpMessageConverter 在 StringHttpMessageConverter 前被调用,会导致对string进行二次转换
     * 由于 StringHttpMessageConverter 在第1和2的位置上,要排在其后,并且排在jacksonConverter之前,故位置为3
     */
    private static final int FAST_JSON_CONVERTER_INDEX = 3;

    FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();

        List<MediaType> supportMediaTypeList = new ArrayList<>();
        supportMediaTypeList.add(MediaType.TEXT_HTML);
        supportMediaTypeList.add(MediaType.APPLICATION_JSON);
        supportMediaTypeList.add(MediaType.APPLICATION_JSON_UTF8);
        supportMediaTypeList.add(MediaType.valueOf("application/*+json"));

        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue);
        converter.setFastJsonConfig(fastJsonConfig);
        converter.setSupportedMediaTypes(supportMediaTypeList);

        return converter;
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
        messageConverters.add(FAST_JSON_CONVERTER_INDEX, fastJsonHttpMessageConverter());
    }
}