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

如何使用Spring Boot WebFlux与OpenCSV读取CSV文件?

嘿,我来帮你搞定Spring Boot WebFlux结合OpenCSV读取CSV文件的需求!咱们一步步来完善你的代码,让它能正常解析上传的CSV:

第一步:添加OpenCSV依赖

先把OpenCSV的依赖加到项目里,这是解析CSV的基础:

  • Maven(pom.xml):
<dependency>
    <groupId>com.opencsv</groupId>
    <artifactId>opencsv</artifactId>
    <version>5.6</version> <!-- 建议用最新稳定版 -->
</dependency>
  • Gradle(build.gradle.kts):
implementation("com.opencsv:opencsv:5.6")

第二步:完善CSV读取逻辑

WebFlux是响应式框架,FilePart.content()返回的是Flux<DataBuffer>,咱们得先把这些零散的缓冲区合并成完整的输入流,再用OpenCSV解析。这里给你两种实用的实现方式:

方式一:映射到数据类(推荐,代码更简洁)

先定义一个和CSV结构匹配的Kotlin数据类,比如假设你的CSV是用户数据(包含id、name、email三列):

import com.opencsv.bean.CsvBindByName

data class User(
    @CsvBindByName(column = "id")
    val id: Long,
    @CsvBindByName(column = "name")
    val name: String,
    @CsvBindByName(column = "email")
    val email: String
)

然后完善你的Controller方法:

import com.opencsv.bean.CsvToBeanBuilder
import org.springframework.http.MediaType
import org.springframework.http.codec.multipart.FilePart
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestPart
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Flux
import org.springframework.core.io.buffer.DataBufferUtils
import java.io.InputStreamReader
import java.nio.charset.Charsets

@RestController
class CsvUploadController {

    @PostMapping(value = ["/upload-csv"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
    fun uploadCsvFile(@RequestPart("file") filePart: FilePart): Flux<User> {
        // 合并所有DataBuffer,转换成可读取的输入流
        return DataBufferUtils.join(filePart.content())
            .map { dataBuffer ->
                // 指定UTF-8编码避免乱码
                InputStreamReader(dataBuffer.asInputStream(), Charsets.UTF_8)
            }
            .flatMapMany { reader ->
                // 用OpenCSV的CsvToBean直接把CSV行映射到User对象
                val userList = CsvToBeanBuilder<User>(reader)
                    .withType(User::class.java)
                    .withIgnoreLeadingWhiteSpace(true) // 忽略字段前的空格
                    .build()
                    .parse()
                // 把List转成响应式的Flux返回
                Flux.fromIterable(userList)
            }
            .doFinally {
                // 确保资源被正确释放
                DataBufferUtils.release(filePart.content())
            }
    }
}

方式二:手动解析每行(适合不需要实体类的场景)

如果只是想读取原始的CSV行数据,不需要映射到实体,可以用CSVReader手动处理:

import com.opencsv.CSVReader
import org.springframework.core.io.buffer.DataBufferUtils
import java.io.InputStreamReader

// 替换上面Controller里的flatMapMany部分
.flatMapMany { reader ->
    CSVReader(reader).use { csvReader ->
        // 跳过第一行表头(如果你的CSV有表头的话)
        val rows = csvReader.readAll().drop(1)
        Flux.fromIterable(rows)
    }
}

一些注意事项

  • 编码问题:一定要指定正确的文件编码(比如UTF-8),否则容易出现乱码
  • 大文件处理:上面的方式会把整个文件加载到内存,如果是超大CSV,建议用流式逐行解析,避免OOM。可以结合DataBufferUtils.readInputStream()和OpenCSV的流式API实现
  • 资源释放:WebFlux的DataBuffer和IO流都要注意释放,代码里的use块和doFinally已经帮我们处理了大部分场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 16:57:49