我的項目中默認是這樣使用FastJsonHttpMessageConverter的:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
// 防止循環引用
SerializerFeature.DisableCircularReferenceDetect,
// 空集合返回[],不返回null
SerializerFeature.WriteNullListAsEmpty,
// 空字符串返回"",不返回null
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteMapNullValue
);
fastJsonConfig.getSerializeConfig().put(String.class,MyStringSerializer.instance);
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
//處理中文亂碼問題
List<MediaType> fastMediaTypes = new ArrayList<>();
fastMediaTypes.add(MediaType.APPLICATION_JSON);
fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
converters.add(0, fastJsonHttpMessageConverter);//放到前面
}
之前本來相安無視,后面因為springboot升級到2.6.x,原有的springfox因為很久沒有更新出現兼容問題(雖然可以解決),再加上想嘗試使用新的openapi3,因此換用了最近有在更新的springdoc-openapi。結果兩者配合使用時,swagger界面無法加載,而v3/api-docs中的json都多出了\:
"{\"openapi\":\"3.0.1\",\"info\":{\"title\":\"OpenAPI definition\",\"version\":\"v0\"},\"servers\":[{\"url\":\"http://localhost:8099\",\"description\":\"Generated server url\"}],\"paths\":{},\"components\":{}}"
這直接導致swagger無法正確的識別,從而界面加載失敗。而原來使用springfox時,並沒有出現這個問題。
經過打斷點分析,發現原來使用springfox時,傳到com.alibaba.fastjson.serializer.SerializeConfig#getObjectWriter(java.lang.Class<?>, boolean)
這里時,class是springfox.documentation.spring.web.json.Json
,fastjson對此作了特殊處理,因此可以保持原樣。而改換springdoc時,此處傳入的class卻是String! 而fastjson默認會對String進行處理,加上轉義符號,因此導致最終的結果出現異常。
解決辦法:
1、換成Jackson的converter(springboot默認就是Jackson)。
2、FastJsonHttpMessageConverter:自定義一個StringSerializer,覆蓋掉fastjson的默認的StringSerializer
public class MyStringSerializer implements ObjectSerializer {
public static final MyStringSerializer instance = new MyStringSerializer();
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
SerializeWriter out = serializer.getWriter();
out.write(object.toString());
}
}
然后在FastJsonHttpMessageConverter的配置文件中,如下使用
fastJsonConfig.getSerializeConfig().put(String.class,MyStringSerializer.instance);
即可覆蓋掉fastjson默認的StringSerializer。(也可以通過這么操作,對其它類進行自定義處理)。
因為理解不是很透徹,不清楚fastjson為什么默認要對String進行字符轉義處理,也不太清楚這樣修改是否會導致其他后果,如果不妥希望能指出。
(本bug已經提交到fastjson在github上的issues中,期望能得到解答,不過這個好像只能靠分析String里的內容來solve了...)
這個bug只有FastJsonHttpMessageConverter添加到converters最前面或在默認的Jackson之前時會引起這個問題,關於converters的順序等更深入的探討,可以參考這篇文章: