Rest 模板将响应作为流读取并传递给 spring 控制器(使用 rest 模板获取 InputStream)
Rest template read response as stream and pass to spring controller(Get InputStream with rest Template)
我有一个 url 下载大尺寸的 zip file.It returns 作为 stream.though 文件大小的响应首先它 returns 200(HTTPSTATUK.OK) 并继续下载。
我必须实现一个新的 spring 控制器,它通过 rest 调用上面的 url template.I 必须读取由 rest 模板编辑的响应 return 并传递给controller.initially 我已经用下面的方式实现了
@GetMapping("/export/downloadFile")
public ResponseEntity<byte[]> downloadData(Model model,
@ModelAttribute(EXCEPTION_COLLECTOR) ExceptionCollector exceptionCollector,
@RequestParam("userName") String userName,
@RequestParam("startDate") Date startDate,
@RequestParam("endDate") Date endDate,
@RequestParam("reason") String reason) {
URI uri = /building url here/;
return restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(httpHeaders), byte[].class);
}
由于我正在使用 ResponseEntity ,其余模板会等待整个文件加载到 memory.so 中,我经常遇到套接字超时问题。
我们是否有办法将响应作为流读取并 return 到控制器。
我发现了一些关于 restTemplate.execute 的事情。
restTemplate.execute(uri,HttpMethod.GET,requestCallBack,clientHttpResponse -> {
File ret = File.createTempFile("download", ".zip",new File("/Users/bokkavijay/Desktop"));
StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(ret));
return ret;
});
上面的代码片段可以在超时的情况下将文件复制到我们的本地,但这不是我需要的。
我们如何将 clientHttpResponse 中的流通过管道传输到控制器?
我找到了有效的实现
控制器
@GetMapping("/readResponseAsStream")
public ResponseEntity<StreamingResponseBody> downloadAsStream(Model model,HttpServletResponse response) {
HttpHeaders httpHeaders=new HttpHeaders();
httpHeaders.add("Transfer-Encoding","chunked");
httpHeaders.add("Content-Type","x-zip-compressed");
httpHeaders.add("Content-Disposition", "attachment;filename=sample.zip");
ServletOutputStream servletOutputStream=response.getOutputStream();
StreamingResponseBody downloadFile = out -> {
RequestCallback requestCallBack=request->{
request.getHeaders().add(//Add headers here);
};
ResponseExtractor<ServletOutputStream> responseExtractor = clientHttpResponse -> {
//code snippet if you want to write response stream to HttpServletResponse
byte[] buff = new byte[800000];
int bytesRead = 0;
while ((bytesRead = clientHttpResponse.getBody().read(buff)) != -1) {
servletOutputStream.write(buff, 0, bytesRead);
}
return servletOutputStream;
//Incase if you want to copy file to you local
File ret = File.createTempFile("download", ".zip",new File("Add Local system directory address here"));
StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(ret));
//You can copy the the clientHttpResponse.getBody() to ByteArrayInputStream and return
// Don't return clientHttpResponse.getBody() directly because rest template will close the inputStream(clientHttpResponse.getBody()) after .execute completed
//if you want to write restTemplate.execute in dao layer , pass servletOutputStream as a argument to method
};
restTemplate.execute(URL_ADDRESS,HttpMethod.GET,requestCallBack,responseExtractor);
};
return new ResponseEntity(downloadFile,httpHeaders,HttpStatus.OK);
}
如果你直接把response写到HttpServletResponse,controller在浏览器访问的时候下载文件
我有一个 url 下载大尺寸的 zip file.It returns 作为 stream.though 文件大小的响应首先它 returns 200(HTTPSTATUK.OK) 并继续下载。
我必须实现一个新的 spring 控制器,它通过 rest 调用上面的 url template.I 必须读取由 rest 模板编辑的响应 return 并传递给controller.initially 我已经用下面的方式实现了
@GetMapping("/export/downloadFile")
public ResponseEntity<byte[]> downloadData(Model model,
@ModelAttribute(EXCEPTION_COLLECTOR) ExceptionCollector exceptionCollector,
@RequestParam("userName") String userName,
@RequestParam("startDate") Date startDate,
@RequestParam("endDate") Date endDate,
@RequestParam("reason") String reason) {
URI uri = /building url here/;
return restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(httpHeaders), byte[].class);
}
由于我正在使用 ResponseEntity
我们是否有办法将响应作为流读取并 return 到控制器。
我发现了一些关于 restTemplate.execute 的事情。
restTemplate.execute(uri,HttpMethod.GET,requestCallBack,clientHttpResponse -> {
File ret = File.createTempFile("download", ".zip",new File("/Users/bokkavijay/Desktop"));
StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(ret));
return ret;
});
上面的代码片段可以在超时的情况下将文件复制到我们的本地,但这不是我需要的。
我们如何将 clientHttpResponse 中的流通过管道传输到控制器?
我找到了有效的实现
控制器
@GetMapping("/readResponseAsStream")
public ResponseEntity<StreamingResponseBody> downloadAsStream(Model model,HttpServletResponse response) {
HttpHeaders httpHeaders=new HttpHeaders();
httpHeaders.add("Transfer-Encoding","chunked");
httpHeaders.add("Content-Type","x-zip-compressed");
httpHeaders.add("Content-Disposition", "attachment;filename=sample.zip");
ServletOutputStream servletOutputStream=response.getOutputStream();
StreamingResponseBody downloadFile = out -> {
RequestCallback requestCallBack=request->{
request.getHeaders().add(//Add headers here);
};
ResponseExtractor<ServletOutputStream> responseExtractor = clientHttpResponse -> {
//code snippet if you want to write response stream to HttpServletResponse
byte[] buff = new byte[800000];
int bytesRead = 0;
while ((bytesRead = clientHttpResponse.getBody().read(buff)) != -1) {
servletOutputStream.write(buff, 0, bytesRead);
}
return servletOutputStream;
//Incase if you want to copy file to you local
File ret = File.createTempFile("download", ".zip",new File("Add Local system directory address here"));
StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(ret));
//You can copy the the clientHttpResponse.getBody() to ByteArrayInputStream and return
// Don't return clientHttpResponse.getBody() directly because rest template will close the inputStream(clientHttpResponse.getBody()) after .execute completed
//if you want to write restTemplate.execute in dao layer , pass servletOutputStream as a argument to method
};
restTemplate.execute(URL_ADDRESS,HttpMethod.GET,requestCallBack,responseExtractor);
};
return new ResponseEntity(downloadFile,httpHeaders,HttpStatus.OK);
}
如果你直接把response写到HttpServletResponse,controller在浏览器访问的时候下载文件