总结:<代码>响应
我正在为下载按钮编写一个控制器,该按钮将使用从另一个依赖项检索的数据生成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());
}
作为测试,我还尝试将主体设置为<代码>。正文(“案例ID,受让人”。getBytes(StandardCharsets.UTF\u 8))。这应等同于https://stackoverflow.com/a/34508533/10327093
在这两种情况下,我得到的回应都是Base64。示例(缩短):Q2FzZSBJRCxBc3NpZ25lZQ==
它看起来实际上不是Base64。使用. body(Base64.getDecoder(). decode(outputStream.toByteArray()))
给我java.lang.IllegalArgumentException:非法的base 64字符
如果我返回val
并将outputStream复制到response.getOutputStream()和IOUtils.write(outputStream.toByteArray(),response.getOutputStream());
,下载的文件是正确的(CSV)。
然而,我想避免呼叫响应。直接获取getOutputStream()。如果之后出现任何异常,我会得到一个错误,该错误已经在异常处理程序(ExceptionHandler)中为此响应调用了
编辑:Base64解码响应给我正确的值
System.out.println(new String(Base64.getDecoder().decode("Q2FzZSBJRCxBc3NpZ25lZQ==")));
// Case ID,Assignee
似乎字节[]在返回ResponseEntity和客户端之间进行了Base64编码(使用Postman和browser进行了尝试)。
不幸的是,我不能发表评论,所以我将作为答案发布,但这确实只是一些建议:
您是否尝试使用“应用程序/csv”而不是“文本”/csv?
不久前,我不得不做一些非常类似的事情,通过查看您的代码,我看不出有任何问题。
这是我所做的一个例子:
@GetMapping("/" , produces="application/vnd.ms-excel")
public ResponseEntity<Object> myMethod() {
String filename = "filename.xlsx";
byte[] bytes = getBytes();
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/vnd.ms-excel;");
headers.setContentDispositionFormData(filename, filename);
return new ResponseEntity<Object>(bytes, headers, HttpStatus.OK);
}
TL;DR:不要以字节[]的形式给出数据,而是以字符串的形式给出数据。
使用ResponseEntity时,Spring使用注册的HttpMessageConverter。
如果指定了内容类型为应用程序/八位字节流,主体类型为字节[],Spring将使用ByteArrayHttpMessageConverter,并按原样发送字节。
如果您指定的内容类型为文本,例如您正在指定的文本,正文类型为字符串,Spring将使用StringHttpMessageConverter对文本进行适当编码并发送。最好明确指定字符集,例如使用内容类型文本/csv;字符集=UTF-8,因此客户端知道服务器使用的字符集。
由于您指定的内容类型为文本/csv,但正文类型为字节[],Spring正在使用其他的HttpMessageConverter,可能是一个ObjecttoStringttpMessageConverter,带有一个将字节[]编码为字符串的转换服务,作为基64。
旁注:为了更好的性能,不要自动刷新每一行输出。关闭自动刷新,完成后只需执行最后的flush()
。
长话短说,既然您想要文本,就不要转换为字节[]。使用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());
}
}
由于从未使用过响应参数,因此已将其删除。
让我们看看下面这个简单的测试控制器(与Spring 4.0.3一起使用): 理论上,两个控制器方法都应该返回有效的JSON。调用第一个controller方法确实会返回以下JSON数组: 但第二个controller方法返回不带引号的字符串,该字符串不是有效的JSON字符串: 为什么会这样?可以配置吗?是虫子吗?还是一个我不懂的特征?
我一直在思考使用Spring MVC设计JSON API的最佳方法。众所周知,IO很昂贵,因此我不想让客户端进行多次API调用以获得他们需要的东西。然而,与此同时,我不一定想归还厨房水槽。 例如,我正在开发一个类似于IMDB的游戏API,但用于视频游戏。 如果我返回与游戏相关的所有内容,它将看起来像这样。 /api/game/1 然而,他们可能不需要所有这些信息,但他们可能需要这些信息。从I/O和
我的问题实质上是对这个问题的跟进。 在上面,Spring会将“hello world”添加到响应体中。如何将字符串作为JSON响应返回?我知道我可以加引号,但这感觉更像是一个黑客。 请提供任何例子来帮助解释这一概念。 注意:我不想直接写到HTTP响应体,我想返回JSON格式的字符串(我正在使用带有RestyGWT的控制器,它要求响应是有效的JSON格式)。
因此,我创建了我的对象数组,每个对象都被初始化为一个新字节[1024]: 然后,我遍历这个数组中的所有索引,执行如下操作: 在大多数情况下,一切都很好。但是,如果我希望每个字节数组都是可变长度的呢?也就是说,我希望字节数组的数组是“锯齿状”的。我将什么作为最后一个参数传递给NewObjectArray()作为初始值?我尝试传递0作为初始值,以防止在创建jobjectArray时进行初始化,然后分配
问题内容: 我正在研究Java ExtJS应用程序,需要在其中创建和下载CSV文件。 单击按钮后,我希望将CSV文件下载到客户端计算机上。 在按钮侦听器上,我正在使用AJAX调用servlet。在那里,我正在创建一个CSV文件。 我不希望将CSV文件保存在服务器中。我希望使用下载选项 动态 创建文件。我希望将文件的内容创建为字符串,然后将其作为 文件 提供,然后在浏览器中以下载模式打开该 文件 (
如果可以从Spring返回,我很好奇 这样做可以吗?我试过了,Spring返回的不是流的值。 我应该继续返回