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

Spring Boot使用OpenCSV实现POST接口导出CSV文件的问题

解决Spring Boot POST接口导出CSV文件的问题

1. 核心问题分析

  • POST接口报错是因为Spring默认没有text/csv类型的消息转换器,无法直接将ArrayList转换为CSV格式响应
  • GET导出为空大概率是数据生成逻辑未正确返回数据,或是响应头、输出流处理不当导致内容未写入

2. 完整实现方案

方案一:直接操作响应输出流(推荐,无需额外配置)

绕开Spring的消息转换器,直接用OpenCSV将数据写入响应输出流,逻辑更直接可控。

步骤1:编写POST接口与CSV生成逻辑

import com.opencsv.CSVWriter;
import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import com.opencsv.exceptions.CsvException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@RestController
public class CsvExportController {

    @PostMapping("/export-csv")
    public void exportCsv(@RequestBody ExportParams params, HttpServletResponse response) throws IOException, CsvException {
        // 1. 根据前端参数生成业务数据
        List<MyObject> dataList = buildDataWithParams(params);

        // 2. 设置响应头,触发浏览器下载
        response.setContentType(MediaType.TEXT_PLAIN_VALUE);
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"exported-data.csv\"");

        // 3. 使用OpenCSV将数据写入响应流
        StatefulBeanToCsv<MyObject> beanToCsv = new StatefulBeanToCsvBuilder<MyObject>(response.getWriter())
                .withSeparator(CSVWriter.DEFAULT_SEPARATOR)
                .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
                .build();
        beanToCsv.write(dataList);
    }

    // 替换为你的实际业务数据生成逻辑
    private List<MyObject> buildDataWithParams(ExportParams params) {
        return List.of(new MyObject("张三", 25), new MyObject("李四", 30));
    }
}

步骤2:实体类CSV列配置(可选)

给MyObject添加OpenCSV注解,自定义CSV列名与顺序:

import com.opencsv.bean.CsvBindByName;

public class MyObject {
    @CsvBindByName(column = "姓名")
    private String name;

    @CsvBindByName(column = "年龄")
    private Integer age;

    // 构造方法、getter、setter省略
}

方案二:自定义CSV消息转换器(适合多接口统一处理)

如果多个接口需要返回CSV,可自定义Spring消息转换器,让接口直接返回List<MyObject>。

步骤1:实现HttpMessageConverter

import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import com.opencsv.exceptions.CsvException;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;

import java.io.IOException;
import java.util.List;

public class CsvMessageConverter extends AbstractHttpMessageConverter<List<?>> {

    public CsvMessageConverter() {
        super(MediaType.TEXT_CSV);
    }

    @Override
    protected boolean supports(Class<?> clazz) {
        return List.class.isAssignableFrom(clazz);
    }

    @Override
    protected List<?> readInternal(Class<? extends List<?>> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        // 无需处理请求,直接返回null
        return null;
    }

    @Override
    protected void writeInternal(List<?> list, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        try {
            StatefulBeanToCsv<?> beanToCsv = new StatefulBeanToCsvBuilder<>(outputMessage.getBody())
                    .withSeparator(',')
                    .build();
            beanToCsv.write(list);
        } catch (CsvException e) {
            throw new HttpMessageNotWritableException("CSV数据写入失败", e);
        }
    }
}

步骤2:注册消息转换器

import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new CsvMessageConverter());
    }
}

步骤3:编写POST接口

import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class CsvExportController {

    @PostMapping(value = "/export-csv", produces = MediaType.TEXT_CSV_VALUE)
    public ResponseEntity<List<MyObject>> exportCsv(@RequestBody ExportParams params) {
        List<MyObject> dataList = buildDataWithParams(params);
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"exported-data.csv\"");
        return ResponseEntity.ok()
                .headers(headers)
                .body(dataList);
    }

    private List<MyObject> buildDataWithParams(ExportParams params) {
        // 实际业务逻辑
        return List.of(new MyObject("张三", 25), new MyObject("李四", 30));
    }
}

3. 常见问题排查

  • 导出文件为空:检查数据生成方法是否返回有效数据,确认dataList不为空
  • 依赖兼容问题:确保opencsv版本(推荐5.x及以上)与Spring Boot版本适配
  • 前端请求处理:POST请求需设置Content-Type: application/json,接收响应时需处理blob类型,通过创建下载链接触发浏览器下载

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 06:48:45