尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
SpringBoot3整合FastJSON2配置消息转换器避坑指南
SpringBoot3整合FastJSON2的消息转换器配置说白了就是一件事怎么让Spring MVC在处理HTTP请求和响应时用FastJSON2替换掉默认的Jackson来输出JSON。这套配置折腾过的人应该都有感触版本一变就是一堆新坑SpringBoot3里WebMvcConfigurer的默认行为和2.x有区别FastJSON2的类加载机制也和原来的FastJSON 1.x完全不同网上不少老教程直接抄过来是跑不起来的。这篇文章把我实际梳理过的配置思路、几个容易踩的隐性坑以及完整的configureMessageConverters写法都拆开讲清楚。适合正在做SpringBoot3技术升级、或者想把项目里的JSON序列化方案切到FastJSON2的开发者参考。1. 为什么SpringBoot3里要手动配置FastJSON2很多人第一个疑问是SpringBoot3明明自己有Jackson引入FastJSON2之后难道不能自动生效吗答案是不能而且这里牵扯到SpringBoot3的自动配置机制变化。用一句话概括SpringBoot3的HttpMessageConvertersAutoConfiguration会优先选择类路径下存在的转换器但MappingJackson2HttpMessageConverter是内置默认项只要Jackson在依赖里它就会默认注册进去。FastJSON2提供了自己的FastJsonHttpMessageConverter但SpringBoot不会自动感知它必须通过WebMvcConfigurer的configureMessageConverters方法明确把自己的转换器塞进转换器列表里。我们项目当时从SpringBoot2.x升到3.x原来在2.x时代的配置方式在3.2版本上突然失效排查了半天最后定位到两个核心差异SpringBoot3基于Jakarta EE 9Servlet API包名从javax.*变成jakarta.*FastJSON2的适配要注意版本。SpringBoot3中WebMvcConfigurationSupport和WebMvcConfigurer的协作方式有调整部分自动配置类的生效条件变了。所以在SpringBoot3下我们不光要写配置类还得理解转换器在整个请求链路中的位置否则会出现“配置了但没生效”“生效了但顺序不对”“顺序对了但请求走了其他转换器”等各种诡异情况。2. configureMessageConverters和extendMessageConverters怎么选先把这个基础问题理清楚因为它会直接影响后面代码怎么写。WebMvcConfigurer接口里有两个跟消息转换器相关的方法configureMessageConverters(ListHttpMessageConverter? converters)这个方法是先清空默认转换器列表再添加你注册的转换器。也就是说如果只重写这一个方法并且只加了FastJSON2的转换器那Spring MVC默认的Jackson转换器、字符串转换器、字节数组转换器等全部失效。extendMessageConverters(ListHttpMessageConverter? converters)这个方法不会清空默认转换器列表而是在默认列表基础之上追加或者调整保留SpringBoot原有的能力。两者的名字只差一个词行为差异却是天壤之别。所以在做FastJSON2整合时方案有两种思路方案A全替换。项目对JSON序列化有统一规范比如全部统一由FastJSON2处理不信任Jackson的某些行为才用configureMessageConverters。这种方案的代价是你需要手动补上其他必要的转换器比如StringHttpMessageConverter否则controller直接返回String时可能被处理成JSON字符串而不是纯文本引发一堆接口兼容问题。方案B追加优先级。在extendMessageConverters里把FastJsonHttpMessageConverter放到列表最前面并设置其支持的MediaType包含application/json。因为Spring MVC遍历转换器时按列表顺序匹配如果FastJSON2排在前面就能优先拦截JSON请求。很多人问到底用哪个我给的建议是如果你不能保证项目里所有接口的返回类型都兼容FastJSON2的反序列化规则优先用方案B。configureMessageConverters一把梭全替换只适合从零搭建的新项目、且你完全掌控所有接口场景的情况。我自己的项目实际采用的是configureMessageConverters因为团队对统一JSON输出格式有刚需。但我在方法里手动保留了必要的默认转换器后续文章会完整给出代码。3. SpringBoot3完整配置代码拆解直接上最终能跑的配置类再逐个解释关键点。package com.example.demo.config; import com.alibaba.fastjson2.JSONReader; import com.alibaba.fastjson2.JSONWriter; import com.alibaba.fastjson2.support.config.FastJsonConfig; import com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; Configuration public class FastJsonConfigurer implements WebMvcConfigurer { Override public void configureMessageConverters(ListHttpMessageConverter? converters) { // 1. 保留默认的字符串与字节数组转换器避免Controller直接返回String时出问题 converters.add(new ByteArrayHttpMessageConverter()); StringHttpMessageConverter stringConverter new StringHttpMessageConverter(StandardCharsets.UTF_8); converters.add(stringConverter); // 2. 构建FastJSON2转换器 FastJsonHttpMessageConverter fastJsonConverter new FastJsonHttpMessageConverter(); FastJsonConfig config new FastJsonConfig(); // 3. 配置序列化特性 config.setWriterFeatures( JSONWriter.Feature.WriteMapNullValue, JSONWriter.Feature.WriteNullListAsEmpty, JSONWriter.Feature.WriteNullStringAsEmpty ); // 4. 配置反序列化特性 config.setReaderFeatures( JSONReader.Feature.FieldBased, JSONReader.Feature.SupportArrayToBean ); // 5. 设置日期格式 config.setDateFormat(yyyy-MM-dd HH:mm:ss); fastJsonConverter.setFastJsonConfig(config); // 6. 设置支持的MediaType ListMediaType supportedMediaTypes new ArrayList(); supportedMediaTypes.add(MediaType.APPLICATION_JSON); supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); fastJsonConverter.setSupportedMediaTypes(supportedMediaTypes); // 7. 将FastJSON2转换器置于列表首位 converters.add(0, fastJsonConverter); } }这段代码有几个容易忽略的点逐个说明。第一个点是converters.add(0, fastJsonConverter)。之所以要放在第0位是因为Spring MVC在接收请求时会遍历converters列表根据请求的Content-Type和转换器的supportedMediaTypes做匹配命中的第一个转换器负责反序列化。如果FastJSON2没排到Jackson前面即使我们在类路径里引入了FastJSON2请求体照样会被Jackson先拿走。列表顺序就是优先级这句话很重要。第二个点是手动添加StringHttpMessageConverter的必要性。用configureMessageConverters时默认转换器全部被清空没有字符串转换器的话Controller里ResponseBody String会直接走FastJSON2把普通String序列化成带引号的JSON字符串格式比如返回hello而不是hello前端收到的内容多出一对双引号接口兼容性立刻崩。这种问题在联调阶段才会暴露排查起来还非常隐蔽。第三个点是config.setWriterFeatures和setReaderFeatures的区别。FastJSON2里把原来1.x的SerializerFeature和ParserFeature都换成了JSONWriter.Feature和JSONReader.Feature这两个枚举API结构完全变了。老教程里写SerializerFeature.WriteMapNullValue在FastJSON2中编译直接报错这也就是网上很多旧代码跑不起来的核心原因。第四个点是MediaType.APPLICATION_JSON_UTF8在Spring6中标记为废弃。SpringBoot3里这个常量还存在但已经不推荐使用因为application/json;charsetUTF-8在RFC 8259中默认就是UTF-8编码不需要再显式声明。不过FastJSON2转换器内部做媒体类型匹配时对带不带charset的请求头处理情况不一样所以我在代码里同时加入了两种实测对兼容性是有帮助的。4. FastJsonConfig序列化特性细节详解FastJsonConfig是FastJSON2转换器的配置核心很多序列化行为都靠它上面的特性开关控制。我们逐个看几个最常用的特性组合。JSONWriter.Feature.WriteMapNullValue默认情况下FastJSON2序列化对象的null字段时直接跳过不输出。这会导致一个问题接口文档里写明返回10个字段实际报文里可能只有8个前端取数据时拿到undefined对前后端联调非常不友好。开启这个特性后null字段也保留在JSON里输出成field: null字段数量保持稳定。这里有个连锁反应开启WriteMapNullValue后null字段虽然保留了但类型不同表现不一样。String类型的null字段输出为nullList类型的null字段输出为null如果前端期望的是空数组[]对接时仍然会出问题。所以通常建议配合下面两个特性一起使用。JSONWriter.Feature.WriteNullListAsEmpty和JSONWriter.Feature.WriteNullStringAsEmpty这两个特性分别把null的List字段输出为[]null的String字段输出为。结合WriteMapNullValue一起用效果比较理想字段都在、null值转成空值、前端拿到手就能直接用不需要额外判空。实际项目中我还遇到过一种情况某些字段是BigDecimalnull时前端希望输出0。这时可以再加JSONWriter.Feature.WriteNullNumberAsZero特性。团队内部如果没有统一的序列化规范这些特性最好拉齐后固定下来否则不同接口输出的null策略五花八门联调阶段会非常痛苦。JSONReader.Feature.FieldBased这个特性的含义是反序列化时基于字段而非getter/setter方法。默认情况下FastJSON2反序列化时优先选择setter方法但如果某些Bean只暴露了getter、没有setter或者字段名和方法名对不上默认策略可能反序列化失败。开启FieldBased后直接通过反射操作字段能兼容更多的POJO场景。不过注意FieldBased是一把双刃剑。它对私有字段也能直接赋值有些安全扫描工具会对此误报。如果项目对反射使用有严格限制建议先评估再开启。日期格式配置config.setDateFormat(yyyy-MM-dd HH:mm:ss)会影响两类场景一是序列化时Date类型字段的输出格式二是反序列化时字符串转Date的解析。项目里如果用了Java 8的LocalDateTime这个dateFormat不生效因为LocalDateTime的序列化走的是com.alibaba.fastjson2.util.DateUtils的格式化逻辑。需要额外配置JSONWriter.Feature.WriteClassName才能输出类型信息但这又会带出安全风险所以我的经验是java.util.Date和java.time.LocalDateTime分开处理前者用setDateFormat后者在字段上定义JSONField(format yyyy-MM-dd HH:mm:ss)注解这样最可控。5. 复杂场景处理Long精度丢失很多项目在这一步会踩一个大坑Vue前端的JavaScript Number类型精度不够后端返回一个超过JavaScript安全整数范围Number.MAX_SAFE_INTEGER即9007199254740991的Long类型ID时前端拿到的值最后几位会变成0。比如数据库自增ID是1888888888888888888传到前端变成了1888888888888888800点击详情时ID不对请求直接报错。FastJSON2解决这个问题的思路有两种方案一全局配置将Long序列化为String。通过指定序列化Converter或者用JSONField(serializeUsing ToStringSerializer.class)。全局配置比较繁琐SpringBoot3环境下最快的办法是在FastJsonConfig的writerFeatures里开启JSONWriter.Feature.WriteLongAsString但这个特性并不是FastJSON2标准枚举里默认支持的需要看具体版本。实测下来2.0.x版本里确实存在这类排序位置的特性配置在部分版本中会报警告。更稳妥的做法是给ID字段单独加注解。方案二在实体字段上加JSONField(serializeUsing ToStringSerializer.class)注解。JSONField(serializeUsing ToStringSerializer.class) private Long id;这是最直接、影响范围最小的办法不会动全局配置也不会影响其他Long字段。但缺点是每个实体类都要加一遍字段多了繁琐。如果项目Long字段特别多且全部都需要序列化为String那就得全局统一配置。FastJSON2提供了一个ObjectWriterCreator的机制可以按Type定制序列化器。我提供一个参考实现思路自定义一个ObjectWriter判断字段类型为Long时使用ToStringWriter然后注册到ObjectWriterCreator。这个做法的代码量不小但能做到完全无侵入全局生效。从我的经验看宁可多写几十行配置也要把精度问题在序列化层解决掉别拖到前端去处理。前端处理精度丢失已经有方案但无论怎么做都多一道勾稽还容易漏。6. 枚举字段的序列化和反序列化SpringBoot3 FastJSON2整合时枚举也是高频踩坑点。默认情况下FastJSON2序列化枚举时输出枚举名比如OrderStatus.PENDING输出为PENDING。但前端很多团队习惯用数字编码比如status 1表示待处理status 2表示已完成。如果服务端不做处理直接输出PENDING前端对接就对不上。同时反序列化也一样前端传1后端字段是枚举类型OrderStatus默认解析是失败的因为FastJSON2不知道1对应哪个枚举项。我的做法是定义枚举的时候做两层保障第一层给枚举字段加JSONField的deserializeUsing和serializeUsing但这种方法需要给每个枚举字段都配置比较繁琐。第二层在FastJSON2的FastJsonConfig里注册自定义的枚举反序列化器。实际上FastJSON2对枚举的认知比较特殊——它默认通过枚举的name进行匹配但同时也支持使用JSONField标注在枚举常量上映射到自定义的value值。一个常见的操作示范public enum OrderStatus { PENDING(1, 待处理), FINISHED(2, 已完成); JSONField(value 1) private final int code; private final String desc; OrderStatus(int code, String desc) { this.code code; this.desc desc; } }但仅这样写在FastJSON2中还不够稳定因为JSONField在枚举常量上的支持力度在不同版本里有回退。最稳妥的方案是通过ObjectReaderCreator注册一个针对枚举的通用读取器Configuration public class FastJsonEnumConfig { Bean public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() { FastJsonHttpMessageConverter converter new FastJsonHttpMessageConverter(); FastJsonConfig config new FastJsonConfig(); // 注册枚举反序列化器 config.setReaderFeatures(JSONReader.Feature.SupportSmartMatch); converter.setFastJsonConfig(config); return converter; } }SupportSmartMatch特性有什么用它让反序列化时能自动匹配枚举的code、value、ordinal等字段值不再单纯依赖枚举name。如果枚举里定义了code字段并赋了值前端传1就能映射到对应枚举项。这个特性非常实用但小心别把布尔字段的isXXX也做模糊匹配偶尔会出现想不到的匹配结果。实测下来最省心的组合是枚举类里定义好code字段开启JSONReader.Feature.SupportSmartMatch然后枚举值本身和code一一对应。如果希望序列化时也直接输出code而不是枚举名可以给枚举写一个带JSONField的getter方法或者在枚举常量上提供getCode()并配置FastJSON2的JSONWriter.Feature让它优先使用字段getter。7. 和SpringBoot3自动配置的冲突处理SpringBoot3里配置FastJSON2时最常见的冲突是HttpMessageConvertersbean和configureMessageConverters同时存在导致FastJSON2转换器被覆盖。详细说明这个场景你定义了一个Bean返回HttpMessageConverters手动在里面加入了FastJsonHttpMessageConverter。同时又在WebMvcConfigurer里通过configureMessageConverters配置了转换器列表。这两个配置同时生效时Spring MVC怎么决定用哪个实际上是WebMvcConfigurationSupport先收集WebMvcConfigurer中的转换器再把所有HttpMessageConvertersbean合并到列表里。如果bean中还包含默认的Jackson转换器那么Jackson会被加到列表末尾和前面的FastJSON2形成竞争关系。而configureMessageConverters却把默认转换器全部清空了再添加自己的两条配置路径叠加行为就变得不可预测。我个人建议是二选一不要混用。如果项目里已经有HttpMessageConverters自定义bean那就别再去实现configureMessageConverters如果走了WebMvcConfigurer配置就把bean方式去掉。最怕的就是朋友圈抄来的配置杂糅这里有configureMessageConverters那边又有个Bean注入最后没人说得清为什么A接口走Jackson、B接口走FastJSON2。另外需要注意SpringBoot3的WebMvcAutoConfiguration条件装配设计。它通过ConditionalOnMissingBean({HttpMessageConverters.class})判断——如果容器里已经有HttpMessageConverters类型的bean自动配置就直接放弃你自己定义的bean完全接管转换器列表。这个设计本意是方便扩展但很多人没意识到一旦自己声明了HttpMessageConvertersSpringBoot自带的Jackson转换器和其他默认行为全部失效相当于不知不觉走了configureMessageConverters的极端路线。这时如果自定义bean里没考虑周全线上接口就会出现各种不可预期的错误。8. 三种实际场景下的最佳配置模板前面讲了不少原理和细节这里给出几个按场景划分的配置模板可以直接拿来改。场景一全新SpringBoot3项目统一使用FastJSON2。适合内部服务、前后端完全可控、JSON结构统一。直接走configureMessageConverters保留字符串和字节数组转换器FastJSON2排首位。Override public void configureMessageConverters(ListHttpMessageConverter? converters) { converters.add(new ByteArrayHttpMessageConverter()); converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8)); FastJsonHttpMessageConverter fastJsonConverter new FastJsonHttpMessageConverter(); FastJsonConfig config new FastJsonConfig(); config.setDateFormat(yyyy-MM-dd HH:mm:ss); config.setWriterFeatures( JSONWriter.Feature.WriteMapNullValue, JSONWriter.Feature.WriteNullStringAsEmpty, JSONWriter.Feature.WriteNullListAsEmpty, JSONWriter.Feature.WriteNullNumberAsZero ); fastJsonConverter.setFastJsonConfig(config); ListMediaType mediaTypes new ArrayList(); mediaTypes.add(MediaType.APPLICATION_JSON); fastJsonConverter.setSupportedMediaTypes(mediaTypes); converters.add(0, fastJsonConverter); }场景二老项目升级SpringBoot3希望最小化影响。适合已有大量接口、不能冒进替换的场景。用extendMessageConverters在原有转换器列表前追加FastJSON2同时所有序列化特性先不开只设置日期格式逐步观察。Override public void extendMessageConverters(ListHttpMessageConverter? converters) { FastJsonHttpMessageConverter fastJsonConverter new FastJsonHttpMessageConverter(); FastJsonConfig config new FastJsonConfig(); config.setDateFormat(yyyy-MM-dd HH:mm:ss); fastJsonConverter.setFastJsonConfig(config); ListMediaType mediaTypes new ArrayList(); mediaTypes.add(MediaType.APPLICATION_JSON); fastJsonConverter.setSupportedMediaTypes(mediaTypes); converters.add(0, fastJsonConverter); }场景三既要FastJSON2又要保留Jackson处理部分特殊类型。比如项目某些接口依赖Jackson处理Xml或特殊类型不能一刀切。这种情况建议在extendMessageConverters里把FastJSON2添加在第二位Jackson还在第一位让FastJSON2只处理那些标注了特定MediaType的请求或者通过自定义HttpMessageConverter的supports方法控制范围。不过实现复杂度会上升不是特别刚需的话不推荐。9. 常见问题与排查技巧实录把实际项目中遇到过的问题整理成速查表方便直接对照。现象可能原因排查方向配置了FastJSON2但请求体还是被Jackson解析转换器顺序不对Jackson排在前面检查converters列表中FastJSON2的位置返回String多了一对双引号缺少StringHttpMessageConverter检查configureMessageConverters是否加了字符串转换器Long类型ID前端精度丢失没有将Long序列化为String加JSONField(serializeUsing ToStringSerializer.class)null字段直接消失未开启WriteMapNullValueFastJsonConfig里检查writerFeaturesDate字段序列化成时间戳未设置setDateFormat检查FastJsonConfig的日期格式配置LocalDateTime格式不生效setDateFormat对LocalDateTime无效改为字段注解JSONField(format yyyy-MM-dd HH:mm:ss)启动报错找不到SerializerFeatureFastJSON2不再使用1.x的API改为JSONWriter.Feature枚举反序列化报错没有开启SupportSmartMatch或枚举没有code字段检查枚举设计及readerFeatures转换器配置了但完全不生效WebMvcConfigurer没有被SpringBoot扫描到检查配置类是否加了Configuration既有HttpMessageConvertersBean又有configureMessageConverters两条配置路径冲突只保留一种配置方式排查这类问题有一个通用的切入思路在configureMessageConverters或extendMessageConverters方法里打断点看运行时传入的converters列表中到底有哪些转换器、顺序是什么。一定要实际看一遍列表内容比自己对着配置猜要快得多。我之前排查一个诡异问题代码里明明写了converters.add(0, fastJsonConverter)但运行时列表里FastJSON2排在了第3位最后发现是某个过滤器在Servlet层做了请求体包装导致实际匹配转换器的逻辑变了。这种问题不打断点是根本定位不到的。另外一个高频问题是FastJsonHttpMessageConverter的包名写错。FastJSON2在fastjson2-extension模块中的类路径是com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter注意中间是support.spring.http.converter不是老版本里的support.spring.FastJsonHttpMessageConverter更不是FastJSON 1.x的com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter。这个类路径只要写错一个单词编译期不报错运行期直接ClassNotFoundException而且出错点还在Spring MVC内部不太直观。pom依赖方面SpringBoot3整合FastJSON2需要引入的是dependency groupIdcom.alibaba.fastjson2/groupId artifactIdfastjson2/artifactId version2.0.55/version /dependency dependency groupIdcom.alibaba.fastjson2/groupId artifactIdfastjson2-extension-spring6/artifactId version2.0.55/version /dependency注意fastjson2-extension-spring6这个artifactId它是专门为Spring 6 / SpringBoot3准备的扩展包里面的类针对Jakarta API编译。如果还用旧的fastjson2-extension-spring5包在SpringBoot3下会因为javax和jakarta包名差异直接报NoClassDefFoundError。这里很容易踩坑因为它不是编译期报错而是运行到消息转换器初始化时才暴露。10. 性能对比FastJSON2到底快在哪很多人关心FastJSON2替换Jackson后性能有没有提升。实话说在SpringBoot3默认装配下Jackson本身也针对JSON序列化做了很多优化两者差距在高并发场景下并没有网传的那么夸张。但FastJSON2在某些基准测试中确实有优势主要体现在几个方面对象序列化时采用了类似字段直接写入的机制减少了中间StringBuilder的拼接开销。反序列化时支持JSONReader.Feature.FieldBased直接操作字段减少了setter调用的反射损耗。UTF-8编码处理上做了SIMD优化长字符串场景下吞吐量更高。不过性能不是换FastJSON2唯一理由。很多团队切换FastJSON2其实是为了统一团队内部的JSON处理API——原先项目里既有JacksonSpring MVC默认又有人在工具类里直接用FastJSON两套API并存序列化结果不统一。整合FastJSON2后HTTP层和业务层的JSON处理都走同一套API减少了心智负担。另外不要忽略FastJSON2的一些特有功能比如对JSONPath的支持更丰富在处理嵌套结构时写起来比Jackson的JsonNode路径访问舒服很多。这些都是推动切换的隐性价值。我们自己在压测环境里做过简单对比单看JSON序列化纯处理速度FastJSON2确实略快但在SpringBoot完整请求链路里性能瓶颈通常不在JSON序列化上。所以如果你的项目换FastJSON2预期不要放在性能提升上放在API统一和管理便利性上更合理。11. 最后的实操心得把这次整合过程中印象最深的几点经验记录下来。第一配置类一定要保证被SpringBoot扫描到。Configuration注解写在配置类上同时确保这个类所在的包在SpringBootApplication扫包范围内。我见过有人把FastJsonConfigurer放在独立module的某个包里主启动类根本扫不到结果配置全程不生效排查了一整天。第二自定义FastJsonConfig里的特性不要一次全开。先跑通最简配置再把WriteMapNullValue、WriteNullListAsEmpty这些特性逐个加进去每加一个就过一遍已有接口的回归测试。特性全开时可能把历史接口的返回结构改得面目全非比如原来不输出的null字段全出来了前端直接报错。第三注意控制反转Inversion of Control的使用边界。有人习惯在FastJsonConfig里注册很多自定义读卡器、写入器认为统一处理方便。但如果自定义逻辑过于复杂会让后面维护的人看到序列化结果时一头雾水。团队成员能直接看懂的配置才是好配置。第四如果项目里同时使用了SpringDoc或者Swagger做接口文档注意FastJSON2的序列化结果对OpenAPI自动生成是有影响的。特别是字段为null时还输出到文档示例里会导致文档里的响应示例和实际接口输出有偏差。这个问题在对接前端时经常被忽略。第五如果已经决定用FastJSON2那就干脆点统一把Controller层的ResponseBody返回全部交给FastJSON2处理不要在业务代码里零零散散地手动调用JSON.toJSONString()再包一层String返回。后者会让消息转换器形同虚设还会因为多序列化一次造成性能损耗和转义问题。最后再分享一个小技巧调试FastJSON2配置时可以临时在configureMessageConverters里加一行日志把当前转换器列表的类名和顺序打出来。这个操作不复杂但能看到非常明确的信息比反复猜测有用得多。等你把配置调整稳定后再把这行日志删掉就行。
RELATED

相关推荐

Spring Boot 3整合MyBatis-Plus报错排查与解决

Spring Boot 3整合MyBatis-Plus报错排查与解决

1. 报错现场还原:一场由"命名空间"引发的启动惨案先描述一下我这边遇到的实际场景。某天在搭建一个新项目,技术栈选的Spring Boot 3.1.x,持久层框架自然就用了MyBatis-Plus——毕竟在国内这套组合太常见了,社区活跃、文…

📅 2026/10/12 14:24:09
机器学习量化投资实战:从数据到回测的完整策略搭建指南

机器学习量化投资实战:从数据到回测的完整策略搭建指南

简介:一套帮助初学者快速入门的机器学习量化投资演示源码,以A股市场为例,面向已有一定Python基础、但对炒股和量化投资了解不深的读者。量化投资的核心是通过历史数据分析发现并利用市场规律,在风险可控前提下追求超额收益&#x…

📅 2026/10/12 14:24:09
人脸关键点检测必备:PFLD轻量模型源码+权重+ONNX部署全攻略

人脸关键点检测必备:PFLD轻量模型源码+权重+ONNX部署全攻略

简介:基于PFLD算法的人脸关键点检测完整工程,提供Python源码、预训练模型与ONNX导出文件,适合算法学习者和有检测落地需求的研究者。压缩包共74个文件,大小约89.88MB,涵盖py源码、pth模型、onnx模型、jpg样例、txt说明…

📅 2026/10/12 14:24:09
MORE NEWS

更多资讯

📰

Hermes Agent实战:轻量级Agent框架的配置化任务编排与工具调用

如果你正准备上手一个Agent框架,想把任务编排、工具调用、Prompt管理这些事情一次理顺,那Hermes Agent确实值得花点时间了解。这篇内容会从“它到底解决什么问题”讲起,然后带你完成安装、配置,并跑通一个可扩展的Agent实例。全程…

📰

SQL Server 2008R2在Win11安装失败:兼容补丁与排查指南

简介:SQL Server 2005 与 2008 R2 在 Windows 11 下安装时经常出现兼容性拦截、服务无法启动或 ATL 合成失败等报错,这份兼容补丁包正是针对这类问题整理的解决方案,适合需要在 Win11 上部署旧版数据库、开展遗留系统维护或实验学习的开发与运…

📰

openclaw 用例翻译笔记:Event Guest Confirmation 的 Twilio 与 OpenAI 配置拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

FastReport批量打印实战:从循环直打到队列调度的稳定方案

1. 批量打印这件事,为什么值得单独拎出来说做过企业信息化的人都有一个共识:报表模块往往是项目里最不起眼、但上线后挨骂最多的部分。单张打印谁都会做,拖一个控件、绑一个数据源、点一下预览,完事。可一旦业务方甩过来一句“这批…

📰

C++实战:从CSV解析到疫情数据统计管线

1. 从一份CSV到一套分析管线:这个项目的真实定位很多人看到“用C分析疫情数据”这个标题,第一反应是:为什么不用Python?pandas几行代码就能搞定的事,何必用C折腾?这个问题我当初也问过自己。后来真正动手做…

📰

大模型 Tool Use 手写实战:三套实现方案全拆解

面试现场碰到这种题,估计不少人跟我第一反应一样:Tool Use 不就是 Function Calling 吗,直接调接口就行。可真到了“不借助任何框架,不调 SDK,白板角落写一个运行时”的时候,才会发现里面全是细节。 手写一…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬