You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring自定义CSV消息转换器后Swagger示例仍显示JSON问题求助

问题:Spring自定义HttpMessageConverter后Swagger CSV示例仍显示JSON格式

我已在Spring中实现了AbstractGenericHttpMessageConverter的自定义转换器类:

public class SongConverter extends AbstractGenericHttpMessageConverter<Song> {

    public SongConverter() {
        super(new MediaType("text", "csv"));
    }

    @Override
    protected void writeInternal(@NonNull Song song, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        try (var writer = new OutputStreamWriter(outputMessage.getBody())) {
            new StatefulBeanToCsvBuilder<>(writer).withSeparator(',').build().write(song);
        } catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException ex) {
            log.error("Error while writing song to csv", ex);
        }
    }

    @Override
    public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
        return super.canWrite(clazz, mediaType) && clazz == Song.class;
    }
}

同时配置了WebMvcConfigurer:

@Bean
public WebMvcConfigurer configurer() {
    return new WebMvcConfigurer() {
        @Override
        public void configureContentNegotiation(@NonNull ContentNegotiationConfigurer configurer) {
            configurer.parameterName("mediaType").ignoreAcceptHeader(false)
                .defaultContentType(MediaType.APPLICATION_JSON)
                .mediaType("xml", MediaType.APPLICATION_XML)
                .mediaType("csv", new MediaType("text", "csv"))
                .mediaType("json", MediaType.APPLICATION_JSON);
        }

        @Override
        public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
            converters.add(new SongConverter());
            //converters.add(new SongsConverter());
        }
    };
}

现在Swagger生成的文档里虽然显示了CSV选项,但对应的示例仍然是JSON格式(添加XML时示例显示正常)。我知道有临时覆盖API默认值的解决方案,但不够稳妥,想问是否遗漏了某些配置?


解决方案

Swagger(OpenAPI)不会自动识别自定义HttpMessageConverter对应的媒体类型示例,必须手动配置该类型的示例生成逻辑,以下是几种可靠的配置方式:

1. 接口级指定CSV示例

在Controller的接口方法上,通过@ApiResponse注解明确指定text/csv类型的响应示例:

@GetMapping(value = "/song", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE, "text/csv"})
@ApiResponse(responseCode = "200", description = "成功返回Song数据", 
             content = {
                 @Content(mediaType = "text/csv", 
                          schema = @Schema(type = "string"),
                          examples = @ExampleObject(value = "id,name,duration\n1,Hello,180"))
             })
public Song getSong() {
    // 业务逻辑实现
}

2. 全局配置CSV示例模板

通过自定义OpenAPI配置和OperationCustomizer,为所有支持text/csv的接口统一添加示例:

@Bean
public OpenAPI customOpenAPI() {
    return new OpenAPI()
            .components(new Components()
                    .addExamples("csvSongExample", new Example()
                            .summary("CSV格式Song示例")
                            .value("id,name,duration\n1,Hello,180")))
            .info(new Info().title("API文档").version("v1"));
}

@Bean
public OperationCustomizer csvExampleCustomizer() {
    return (operation, handlerMethod) -> {
        operation.getResponses().values().forEach(response -> {
            response.getContent().forEach((mediaType, mediaTypeObj) -> {
                if ("text/csv".equals(mediaType)) {
                    mediaTypeObj.setExample(new ExampleObject().ref("#/components/examples/csvSongExample"));
                }
            });
        });
        return operation;
    };
}

3. 调整Converter优先级(可选)

确保SongConverter在转换器列表中的优先级足够高,避免被其他通用转换器覆盖。可以修改extendMessageConverters的添加顺序,把自定义转换器放到列表头部:

@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    // 放到列表首位,优先使用自定义转换器
    converters.add(0, new SongConverter());
}

注:Song类字段与CSV的映射正确性只影响实际接口返回,和Swagger示例显示无关。


内容的提问来源于stack exchange,提问作者KChas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 13:30:47