简体   繁体   English

Jackson ObjectWriter 仅写入 stream 中的第一个条目

[英]Jackson ObjectWriter only writes first entry from stream

I want to create a Spring Boot controller which creates a CSV file using data from a stream. I use Jackson CSV (jackson-dataformat-csv 2.12.1) to write the data stream from the DB to a StreamingResponseBody.我想创建一个Spring BOOT controller,它使用来自stream的数据创建一个CSV文件。我使用8824632847988 88247988 CSV888888888888888888888888(jacksondatraty888)

To keep it simple, I replaced the actual data from the DB with a list containing 1, 2, 3 .为简单起见,我用包含1, 2, 3的列表替换了数据库中的实际数据。 I want a CSV file which looks like this:我想要一个 CSV 文件,如下所示:

1
2
3

But it only contains the first entry ( 1 ).但它只包含第一个条目 ( 1 )。 Can someone help me to identify the problem?有人可以帮我找出问题所在吗?

Please not that I don't want to create the file somewhere on the server, I want to stream the content directly to the user.请注意,我不想在服务器上的某个地方创建文件,我想 stream 直接将内容发送给用户。

My code looks like this:我的代码如下所示:

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)
    }
}

With the help of Andriy's comment I was able to find the cause and the solution.在 Andriy 的评论的帮助下,我找到了原因和解决方案。 Jackson closes the stream when it's finished writing to it, see: ObjectMapper._writeValueAndClose . Jackson 在 stream 完成写入后关闭它,请参阅: ObjectMapper._writeValueAndClose

To change this behavior you have to set JsonGenerator.Feature.AUTO_CLOSE_TARGET to false like this:要更改此行为,您必须将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))

Note : There is no AUTO_CLOSE_TARGET option for the CsvGenerator but using the JsonGenerator setting also works for the CsvFactory .注意CsvGenerator没有AUTO_CLOSE_TARGET选项,但使用JsonGenerator设置也适用于CsvFactory

Didn't see the column formatter assigned while writing to the stream in your code.在您的代码中写入 stream 时没有看到分配的列格式化程序。 Can you try the following:-您可以尝试以下方法:-

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

There is a better alternative then setting AUTO_CLOSE_TARGET to false, which is to use SequenceWritter.有一个比将AUTO_CLOSE_TARGET设置为 false 更好的替代方法,即使用 SequenceWritter。

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)
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 spring jackson ObjectWriter forType没有这样的方法 - spring jackson ObjectWriter forType no such method Spring Boot应用程序异常java.lang.NoSuchMethodError:com.fasterxml.jackson.databind.ObjectWriter.forType - Spring boot application exception java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.ObjectWriter.forType Spring Jackson反序列化仅选择数组的第一项 - Spring Jackson deserialization only picks the first item of an array 防止Jackson解组器在第一个数据类型不匹配时引发异常 - Prevent Jackson unmarshaller from throwing exception on first datatype mismatch 将杰克逊从2.2.2升级到2.7.7时,Map.Entry的序列化发生了变化 - Serialization of Map.Entry changed while upgrading jackson from 2.2.2 to 2.7.7 Jackson 序列化问题。 只有同一实体的第一个对象序列化良好 - Jackson serialization issue. Only first object of the same entity serializes well 为什么 Jackson 2 不能识别第一个大写字母,如果前导驼峰词只有一个字母长? - Why does Jackson 2 not recognize the first capital letter if the leading camel case word is only a single letter long? Jackson ObjectMapper 仅接口已知 - Jackson ObjectMapper only interfaces known 杰克逊使用第一个非空别名 - Jackson use the first non-null alias Jackson json 只转换选中的字段和方法 - Jackson json only convert selected fields and methods
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM