Jackson objectwwriter只写来自流的第一个条目



我想创建一个Spring Boot控制器,它使用来自流的数据创建CSV文件。我使用Jackson CSV (Jackson -dataformat- CSV 2.12.1)将数据流从DB写入StreamingResponseBody。

为了简单起见,我用包含1, 2, 3的列表替换了DB中的实际数据。我想要一个CSV文件,看起来像这样:

1
2
3

但是它只包含第一个条目(1)。有人能帮我找出问题所在吗?

请不要说我不想在服务器的某个地方创建文件,我想将内容直接流式传输给用户。

我的代码是这样的:

import com.fasterxml.jackson.dataformat.csv.CsvMapper
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody
import javax.servlet.http.HttpServletResponse
@RestController
@RequestMapping(value = ["/test"], produces = [MediaType.TEXT_HTML_VALUE])
class TestController {
@GetMapping("/download", produces = [MediaType.TEXT_EVENT_STREAM_VALUE])
fun download(response: HttpServletResponse): ResponseEntity<StreamingResponseBody>? {
response.setHeader("Content-Disposition", "attachment;filename=download.csv")
response.status = HttpServletResponse.SC_OK
val mapper = CsvMapper()
val schema = mapper.schemaFor(Int::class.java)
val writer = mapper.writer(schema)
val input = listOf(1, 2, 3).stream()
val stream = StreamingResponseBody { outputStream ->
input.forEach { entity ->
writer.writeValue(outputStream, entity)
}
}
return ResponseEntity
.ok()
.header("Content-Disposition", "attachment;filename=download.csv")
.body(stream)
}
}

在Andriy的评论的帮助下,我能够找到原因和解决方案。当Jackson完成对流的写入时关闭流,参见:ObjectMapper._writeValueAndClose.

要改变这种行为,你必须将JsonGenerator.Feature.AUTO_CLOSE_TARGET设置为false,像这样:

val jsonFactory = CsvFactory().configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false)
val mapper = ObjectMapper(jsonFactory)
val writer = mapper.writer(CsvMapper().schemaFor(Int::class.java))

注意:CsvGenerator没有AUTO_CLOSE_TARGET选项,但使用JsonGenerator设置也适用于CsvFactory

在代码中写入流时没有看到分配的列格式化程序。你可以试试下面这些吗:-

CsvMapper mapper = new CsvMapper();
CsvSchema schema = mapper.schemaFor(Dymmy.class);
schema = schema.withColumnSeparator('t');

有一个更好的替代方案,然后设置AUTO_CLOSE_TARGET为false,这是使用sequencewriter

val stream = StreamingResponseBody { outputStream ->
val mapper = CsvMapper()
val sequenceWriter = mapper.writer(mapper.schemaFor(Int::class.java).withHeader())
.writeValues(outputStream)
input.forEach { entity ->
sequenceWriter.write(entity)
}
}

我在pojo中遇到了类似的问题(只有第一条记录会写入文件)。

下面是我的代码在POJO中的样子:
@JsonProperty("userName")
@Nullable
private Double getUserName() {
return user().getName();
}

我的问题是user()是@Nullable,我没有在getter方法中首先检查null。

添加空检查有效,所有记录都写入CSV:

@JsonProperty("userName")
@Nullable
private Double getUserName() {
if (user() == null) {
return null;
}
return user().getName();
}

相关内容

  • 没有找到相关文章

最新更新