Spring MVC(非Spring Boot)项目:SpringDoc集成后String类型JSON响应格式异常的解决问询
我来帮你解决这个棘手的问题——你现在面临的核心矛盾是:为了让SpringDoc返回正确的OpenAPI JSON,不得不添加StringHttpMessageConverter,但这又破坏了业务接口返回String类型时的JSON格式(本该带双引号,现在变成纯文本)。下面给你几个可行的解决方案,按推荐程度排序:
这个方案最精准,既能保证SpringDoc的输出正常,又不影响业务接口。核心思路是让StringHttpMessageConverter只对SpringDoc的接口生效,其他请求的String类型响应交给Jackson转换器处理(Jackson会自动把String序列化为带双引号的合法JSON字符串)。
步骤如下:
- 创建一个自定义的
StringHttpMessageConverter子类,重写canWrite方法,通过请求路径判断是否为SpringDoc的接口:
import org.springframework.http.HttpServletRequest; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; public class SpringDocStringHttpMessageConverter extends StringHttpMessageConverter { // 匹配SpringDoc的API文档路径,根据你的实际路径调整 private static final String SPRINGDOC_API_PATH_PREFIX = "/v3/api-docs"; @Override public boolean canWrite(Class<?> clazz, org.springframework.http.MediaType mediaType) { // 只有当请求是SpringDoc的接口,且返回类型是String时,才使用这个转换器 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes != null) { HttpServletRequest request = attributes.getRequest(); if (request.getRequestURI().startsWith(SPRINGDOC_API_PATH_PREFIX) && String.class.isAssignableFrom(clazz)) { return super.canWrite(clazz, mediaType); } } // 其他情况,交给后续的转换器处理 return false; } }
- 在你的
WebConfig里替换原来的StringHttpMessageConverter为这个自定义版本:
@Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { // 用自定义的String转换器替代默认的,仅处理SpringDoc请求 converters.add(new SpringDocStringHttpMessageConverter()); converters.add(jsonConverter()); // 别忘了添加XML转换器 converters.add(marshallingConverter()); }
这样一来:
- 访问
/v3/api-docs时,自定义转换器会直接输出SpringDoc返回的JSON字符串,得到正确的OpenAPI JSON结构; - 业务接口返回String时,因为自定义转换器的
canWrite返回false,会交给Jackson转换器处理,Jackson会自动把String包裹成双引号,输出合法的JSON格式(比如返回"response-string"而不是response-string)。
如果你使用的SpringDoc版本比较旧,可能存在返回String类型JSON的问题。新版本的SpringDoc(比如springdoc-openapi-webmvc-core的v1.6+)中,OpenApiResource的getOpenApi方法默认返回OpenAPI对象而非String,此时Jackson转换器可以直接将这个对象序列化为正确的JSON,完全不需要添加StringHttpMessageConverter。
升级后,你可以移除configureMessageConverters中的StringHttpMessageConverter,这样:
- SpringDoc的OpenAPI对象会被Jackson直接序列化为合法的JSON;
- 业务接口返回的String会被Jackson自动转成带双引号的JSON字符串,完美解决两个问题。
如果上面的方案暂时无法实施,你可以临时为业务接口的String返回做包装:比如用ResponseEntity包裹,或者将String封装成一个简单的DTO对象。
比如:
@GetMapping("/your-string-api") public ResponseEntity<String> getStringResponse() { String content = "response-string"; // 手动将String转成JSON格式的字符串,或者让Jackson处理 return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body("\"" + content + "\""); }
不过这个方案需要修改所有相关接口,比较繁琐,只建议作为临时应急使用。
内容的提问来源于stack exchange,提问作者Pieter

