我正在尝试编写一个控制器来返回要下载的文件。
起初我用这种方式编码:
@RequestMapping(value = RESTConstants.SLASH + "{id}" + RESTConstants.SLASH + RESTConstants.EXPORT, method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@ResponseBody
public ResponseEntity<FileSystemResource> export(@PathVariable Long id, UriComponentsBuilder builder) throws IOException {
String filename = rolloutExportService.getDownloadFilename();
FileSystemResource fileSystemResource = rolloutExportService.export(id);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename);
int read = 0;
byte[] bytes = new byte[1024];
OutputStream outputStream = null;
InputStream inputStream = null;
ResponseEntity<FileSystemResource> responseEntity = new ResponseEntity<FileSystemResource>(fileSystemResource, responseHeaders, HttpStatus.OK);
try {
responseHeaders.add(HttpHeaders.CONTENT_LENGTH, Long.toString(fileSystemResource.contentLength()));
outputStream = responseEntity.getBody().getOutputStream();
inputStream = fileSystemResource.getInputStream();
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
} finally {
inputStream.close();
outputStream.flush();
outputStream.close();
}
return responseEntity;
}
但响应将是406此请求标识的资源只能根据请求“accept”标题生成具有不可接受特征的响应。
使用控制台日志说:
2014-11-05 01:18:39,403 DEBUG [DefaultHandlerExceptionResolver] Resolving exception from handler [public org.springframework.http.ResponseEntity<org.springframework.core.io.FileSystemResource> com.nsn.nitro.project.rest.controller.RolloutExportController.export(java.lang.Long,org.springframework.web.util.UriComponentsBuilder) throws java.io.IOException]: org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
2014-11-05 01:18:39,403 DEBUG [DispatcherServlet] Null ModelAndView returned to DispatcherServlet with name 'NITRo': assuming HandlerAdapter completed request handling
2014-11-05 01:18:39,403 DEBUG [DispatcherServlet] Successfully completed request
2014-11-05 01:18:39,405 DEBUG [ExceptionTranslationFilter] Chain processed normally
2014-11-05 01:18:39,405 DEBUG [SecurityContextPersistenceFilter] SecurityContextHolder now cleared, as request processing completed
所以我改变它不回复像:
@RequestMapping(value = RESTConstants.SLASH + "{id}" + RESTConstants.SLASH + RESTConstants.EXPORT, method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@ResponseBody
public void export(@PathVariable Long id, HttpServletResponse response) throws IOException {
String filename = rolloutExportService.getDownloadFilename();
FileSystemResource fileSystemResource = rolloutExportService.export(id);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename);
int read = 0;
byte[] bytes = new byte[1024];
OutputStream outputStream = null;
InputStream inputStream = null;
try {
responseHeaders.add(HttpHeaders.CONTENT_LENGTH, Long.toString(fileSystemResource.contentLength()));
outputStream = response.getOutputStream();
inputStream = fileSystemResource.getInputStream();
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
} finally {
inputStream.close();
outputStream.flush();
outputStream.close();
}
}
在两个控制器上,请求都是相同的,在Chromium浏览器中输入:
http://localhost:8080/nitro-project-rest/rollouts/3/export
但响应将是浏览器中显示的乱码内容: PKîeE/家庭/斯特凡的/ tmp / language.csv%E1 ÀÐÝÃô™uìÐHßT‰±ØûC....oy2Èy€l ¨ V8EWc /Ïñܪμ÷&GT;ú£¡.J <] @uåtmáò×PKC}:HOPKîeE/家/斯蒂芬/tmp/country.csvKÎOIμÎKÌMμÎÉ,.ñ/JI-âJͳvÍKÏIÌK±6äJ+²v+JÌKN²PK*9»¶--PKîeE /home/stephane/tmp/team.csvËKÌMμNI-N.Ê,,ÉÏÏN.JM1\KRK2sS¹BRs¬C2RJ
控制台说:
20. select team0_.id as id1_15_0_, team0_.version as version2_15_0_, team0_.creation_datetime as
creation3_15_0_, team0_.description as descript4_15_0_, team0_.name as name5_15_0_ from team
team0_ where team0_.id=2
2014-11-05 01:31:29,983 DEBUG [JpaTransactionManager] Initiating transaction commit
2014-11-05 01:31:29,983 DEBUG [JpaTransactionManager] Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@6569cc]
2014-11-05 01:31:29,988 DEBUG [JpaTransactionManager] Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@6569cc] after transaction
2014-11-05 01:31:29,988 DEBUG [EntityManagerFactoryUtils] Closing JPA EntityManager
2014-11-05 01:31:30,013 DEBUG [DispatcherServlet] Null ModelAndView returned to DispatcherServlet with name 'NITRo': assuming HandlerAdapter completed request handling
2014-11-05 01:31:30,013 DEBUG [DispatcherServlet] Successfully completed request
2014-11-05 01:31:30,021 DEBUG [ExceptionTranslationFilter] Chain processed normally
2014-11-05 01:31:30,021 DEBUG [SecurityContextPersistenceFilter] SecurityContextHolder now cleared, as request processing completed
我的最后一次尝试就是这个:
@RequestMapping(value = RESTConstants.SLASH + "{id}" + RESTConstants.SLASH + RESTConstants.EXPORT, method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@ResponseBody
public FileSystemResource export(@PathVariable Long id) throws IOException {
String filename = rolloutExportService.getDownloadFilename();
FileSystemResource fileSystemResource = rolloutExportService.export(id);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename);
responseHeaders.add(HttpHeaders.CONTENT_LENGTH, Long.toString(fileSystemResource.contentLength()));
responseHeaders.add(HttpHeaders.CONTENT_TYPE, "application/zip");
return fileSystemResource;
}
但它也给了我406回应。
从上次的上一次尝试中,我删除了属性:produce =
MediaType.APPLICATION_OCTET_STREAM_VALUE
浏览器发送的相同请求(在控制台中看到)看起来像:
Request URL:data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAQAAAD9sOO8AAAASUlEQVR4Xu3SMQoAIAzFUO/o/c+iY4fSSfgQyesgOESHrs9I0j7TEOL9pk5i/OmB/s9IvAYQH6DjxmtTWPEWBcS52zJPIJ4lSRfUZeB1c/cgSwAAAABJRU5ErkJggg==
Request Headers CAUTION: Provisional headers are shown.
User-Agent:Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/34.0.1847.116 Chrome/34.0.1847.116 Safari/537.36
使用服务器控制台日志说:
2014-11-05 12:08:35,938 DEBUG [ExceptionsHandler] org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.core.io.InputStreamResource["inputStream"]->java.io.FileInputStream["fd"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.core.io.InputStreamResource["inputStream"]->java.io.FileInputStream["fd"])
答案 0 :(得分:0)
您需要在控制器中设置正确的MIME类型。
如果您的文件是pdf:
response.setContentType("application/pdf");
如果您的文件是gif图片:
response.setContentType("image/gif");
如果您的文件是zip文件:
response.setContentType("application/zip");
您可能会找到正确的MIME类型here。
答案 1 :(得分:0)
您应该设置HttpResponse的内容类型,如下所示:
response.setContentType("application/zip");
或使用ContentType设置HttpHeaders,并将CONTENT_ENCODING设置为UTF-8,如下所示:
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set(HttpHeaders.CONTENT_TYPE, "application/zip");
responseHeaders.add(HttpHeaders.CONTENT_ENCODING, "UTF-8");
所以浏览器会知道他期待什么样的文件,请参阅本教程here,它解释了Http Headers。
希望有助于。
答案 2 :(得分:0)
我可以使用这个控制器:
@RequestMapping(value = RESTConstants.SLASH + "{id}" + RESTConstants.SLASH + RESTConstants.EXPORT, method = RequestMethod.GET)
public void doDownload(@PathVariable Long id, HttpServletRequest request, HttpServletResponse response) throws IOException {
String filename = rolloutExportService.export(id);
ServletContext context = request.getServletContext();
File downloadFile = new File(filename);
FileInputStream inputStream = new FileInputStream(downloadFile);
String mimeType = context.getMimeType(filename);
if (mimeType == null) {
mimeType = MediaType.APPLICATION_OCTET_STREAM.getType();
}
response.setContentType(mimeType);
response.setContentLength((int) downloadFile.length());
String headerValue = String.format("attachment; filename=\"%s\"", downloadFile.getName());
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, headerValue);
OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outStream.close();
}
发送请求
http://localhost:8080/nitro-project-rest/rollouts/3/expor
浏览器中的会弹出一个下载窗口。
答案 3 :(得分:0)
删除
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE
将推出通用二进制内容。如果你想从文件扩展名发送的内容然后在你的spring XML文件中放入
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
和
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean" />