gpt4 book ai didi

java - 创建 CSV 并以 byte[] 形式返回,以便在 Spring Controller 中下载

转载 作者:太空宇宙 更新时间:2023-11-04 09:21:54 26 4
gpt4 key购买 nike

摘要:ResponseEntity<byte[]>包含 CSV 的内容不会以 CSV 形式返回

<小时/>

我正在为下载按钮编写一个 Controller ,该按钮将生成一个 CSV 文件,其中包含从另一个依赖项检索到的数据。

    @PostMapping(BASE_ROUTE + "/download")
public ResponseEntity<byte[]> downloadCases(@RequestBody RequestType request, final HttpServletResponse response) throws IOException {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
PrintWriter writer = new PrintWriter(outputStreamWriter, true)) {
String nextPageToken = null;
do {
ServiceResponse serviceResponse = makeServiceCall(request.getParam());
// write a String of comma separated values
writer.println(serviceResponse.getLine());
// eventually null
nextPageToken = serviceResponse.getToken();
} while (nextPageToken != null);

return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, "text/csv")
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"report.csv\"")
.body(outputStream.toByteArray());
}

作为测试,我还尝试将正文设置为 .body("Case ID,Assignee".getBytes(StandardCharsets.UTF_8)) 。这应该相当于 https://stackoverflow.com/a/34508533/10327093

在这两种情况下,我得到的响应看起来都像 Base64。示例(缩短):Q2FzZSBJRCxBc3NpZ25lZQ==

它似乎实际上并不是 Base64。使用.body(Base64.getDecoder().decode(outputStream.toByteArray()))给我java.lang.IllegalArgumentException: Illegal base64 character

如果我回来void并将输出流复制到response.getOutputStream() IOUtils.write(outputStream.toByteArray(), response.getOutputStream()); ,下载的文件是正确的(CSV)。

但是我想避免直接调用response.getOutputStream()。如果之后出现任何异常,我会收到错误 getOutputStream() has already been called for this response@ExceptionHandler

编辑:Base64 解码响应给我正确的值

System.out.println(new String(Base64.getDecoder().decode("Q2FzZSBJRCxBc3NpZ25lZQ==")));
// Case ID,Assignee

似乎 byte[] 在返回 ResponseEntity 和客户端之间进行了 Base64 编码(使用 Postman 和浏览器进行了尝试)。

最佳答案

TL;DR: 不要以 byte[] 形式提供数据,而应以 String 形式提供数据。

<小时/>

当使用ResponseEntity时,Spring使用注册的HttpMessageConverter .

如果您指定内容类型为 application/octet-stream,主体类型为 byte[],Spring 将使用 ByteArrayHttpMessageConverter并且会按原样发送字节。

如果您指定内容类型为 text/*,例如您指定的 text/csv,主体类型为 String,Spring 将使用 StringHttpMessageConverter ,它将对文本进行适当的编码,然后发送。最好明确指定字符集,例如使用内容类型 text/csv; charset=UTF-8,这样客户端就知道服务器使用的字符集。

由于您指定了 text/csv 内容类型,但正文类型为 byte[],Spring 正在使用其他一些 HttpMessageConverter ,可能是 ObjectToStringHttpMessageConverter ,带有 ConversionServicebyte[] 编码为 String 作为 Base-64。

旁注:为了获得更好的性能,不要自动刷新每一行输出。关闭自动刷新并在完成后执行最后的 flush() 操作。

长话短说,因为您需要文本,所以不要转换为 byte[]。使用StringWriter将所有内容保留为文本:

@PostMapping(path = BASE_ROUTE + "/download", produces = "text/csv; charset=UTF-8")
public ResponseEntity<String> downloadCases(@RequestBody RequestType request) throws IOException {
try (StringWriter stringWriter = new StringWriter();
PrintWriter writer = new PrintWriter(stringWriter)) {
String nextPageToken = null;
do {
ServiceResponse serviceResponse = makeServiceCall(request.getParam());
// write a String of comma separated values
writer.println(serviceResponse.getLine());
// eventually null
nextPageToken = serviceResponse.getToken();
} while (nextPageToken != null);
writer.flush();

return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, "text/csv; charset=UTF-8")
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"report.csv\"")
.body(stringWriter.toString());
}
}

由于您从未使用过 response 参数,因此它已被删除。

关于java - 创建 CSV 并以 byte[] 形式返回,以便在 Spring Controller 中下载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58227921/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com