Answers:
@RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
public void getFile(
@PathVariable("file_name") String fileName,
HttpServletResponse response) {
try {
// get your file as InputStream
InputStream is = ...;
// copy it to response's OutputStream
org.apache.commons.io.IOUtils.copy(is, response.getOutputStream());
response.flushBuffer();
} catch (IOException ex) {
log.info("Error writing file to output stream. Filename was '{}'", fileName, ex);
throw new RuntimeException("IOError writing file to output stream");
}
}
一般来说,当您拥有时response.getOutputStream()
,您可以在其中编写任何内容。您可以将此输出流作为将生成的PDF放置到生成器的地方传递。另外,如果您知道要发送的文件类型,则可以设置
response.setContentType("application/pdf");
IOUtils
而不是Spring的任何特殊原因FileCopyUtils
?
通过使用Spring的ResourceHttpMessageConverter中的内置支持,我能够简化这一过程。如果可以确定mime类型,则将设置content-length和content-type
@RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
@ResponseBody
public FileSystemResource getFile(@PathVariable("file_name") String fileName) {
return new FileSystemResource(myService.getFileFor(fileName));
}
Content-Disposition
用这种方法设置标题?
您应该能够直接在响应上写文件。就像是
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"somefile.pdf\"");
然后将文件作为二进制流写入response.getOutputStream()
。记住要response.flush()
在最后做,那应该做。
@RequestMapping(value = "/foo/bar", produces = "application/pdf")
在Spring 3.0中,您可以使用HttpEntity
return对象。如果使用此选项,则控制器不需要HttpServletResponse
对象,因此测试起来更容易。
除此之外,这个答案相对于Infeligo之一。
如果您的pdf框架的返回值是一个字节数组(请参阅我的答案的第二部分以获取其他返回值):
@RequestMapping(value = "/files/{fileName}", method = RequestMethod.GET)
public HttpEntity<byte[]> createPdf(
@PathVariable("fileName") String fileName) throws IOException {
byte[] documentBody = this.pdfFramework.createPdf(filename);
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_PDF);
header.set(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=" + fileName.replace(" ", "_"));
header.setContentLength(documentBody.length);
return new HttpEntity<byte[]>(documentBody, header);
}
如果您的PDF Framework(documentBbody
)的返回类型还不是字节数组(并且也没有ByteArrayInputStream
),那么最好不要先使其成为字节数组。相反,最好使用:
InputStreamResource
,PathResource
(从Spring 4.0开始)或FileSystemResource
, 的示例FileSystemResource
:
@RequestMapping(value = "/files/{fileName}", method = RequestMethod.GET)
public HttpEntity<byte[]> createPdf(
@PathVariable("fileName") String fileName) throws IOException {
File document = this.pdfFramework.createPdf(filename);
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_PDF);
header.set(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=" + fileName.replace(" ", "_"));
header.setContentLength(document.length());
return new HttpEntity<byte[]>(new FileSystemResource(document),
header);
}
return new ResponseEntity<byte[]>(documentBody, headers, HttpStatus.CREATED)
ResponseEntity
是HttpEntity
(但我理解)的子类201 CREATED不是我只返回数据视图时要使用的东西。(请参阅w3.org/Protocols/rfc2616/rfc2616-sec10.html了解“ 201创建”)
如果你:
byte[]
在发送到响应之前将整个文件加载到中;InputStream
; 发送/下载@ControllerAdvice
为您(或没有)提供其他接机例外。下面的代码是您需要的:
@RequestMapping(value = "/stuff/{stuffId}", method = RequestMethod.GET)
public ResponseEntity<FileSystemResource> downloadStuff(@PathVariable int stuffId)
throws IOException {
String fullPath = stuffService.figureOutFileNameFor(stuffId);
File file = new File(fullPath);
long fileLength = file.length(); // this is ok, but see note below
HttpHeaders respHeaders = new HttpHeaders();
respHeaders.setContentType("application/pdf");
respHeaders.setContentLength(fileLength);
respHeaders.setContentDispositionFormData("attachment", "fileNameIwant.pdf");
return new ResponseEntity<FileSystemResource>(
new FileSystemResource(file), respHeaders, HttpStatus.OK
);
}
关于文件长度部分:File#length()
在一般情况下应该足够好,但是我认为我会做这个观察,因为它确实很慢,在这种情况下,您应该事先将其存储(例如,存储在数据库中)。可能很慢的情况包括:如果文件很大,特别是如果文件在远程系统中或类似的东西(例如数据库)中。
InputStreamResource
如果您的资源不是文件,例如,您从数据库中提取数据,则应使用InputStreamResource
。例:
InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
return new ResponseEntity<InputStreamResource>(isr, respHeaders, HttpStatus.OK);
FileSystemResource
那里使用它。如果您的资源是文件,甚至是可取的。在此示例中,FileSystemResource
可以在哪里使用InputStreamResource
。
File#length()
在一般情况下应该足够好。我刚刚提到它是因为它的速度可能很慢,特别是如果文件位于远程系统中或诸如此类的更复杂的数据库中?但是,只担心是否会成为问题(或者如果您有确凿的证据会成为问题),就不必担心。要点是:您正在努力流式传输文件,如果必须在之前预加载所有文件,则流式传输最终没有任何影响,是吗?
在单击jsp上的链接时,该代码可以很好地从spring控制器自动下载文件。
@RequestMapping(value="/downloadLogFile")
public void getLogFile(HttpSession session,HttpServletResponse response) throws Exception {
try {
String filePathToBeServed = //complete file name with path;
File fileToDownload = new File(filePathToBeServed);
InputStream inputStream = new FileInputStream(fileToDownload);
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment; filename="+fileName+".txt");
IOUtils.copy(inputStream, response.getOutputStream());
response.flushBuffer();
inputStream.close();
} catch (Exception e){
LOGGER.debug("Request could not be completed at this moment. Please try again.");
e.printStackTrace();
}
}
下面的代码为我工作,以生成和下载文本文件。
@RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity<byte[]> getDownloadData() throws Exception {
String regData = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";
byte[] output = regData.getBytes();
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("charset", "utf-8");
responseHeaders.setContentType(MediaType.valueOf("text/html"));
responseHeaders.setContentLength(output.length);
responseHeaders.set("Content-disposition", "attachment; filename=filename.txt");
return new ResponseEntity<byte[]>(output, responseHeaders, HttpStatus.OK);
}
我可以快速想到的是,生成pdf并将其从代码存储在webapp / downloads / <RANDOM-FILENAME> .pdf中,然后使用HttpServletRequest将其转发给该文件
request.getRequestDispatcher("/downloads/<RANDOM-FILENAME>.pdf").forward(request, response);
或者,如果您可以配置视图解析器,例如
<bean id="pdfViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="order" value=”2″/>
<property name="prefix" value="/downloads/" />
<property name="suffix" value=".pdf" />
</bean>
然后返回
return "RANDOM-FILENAME";
以下解决方案为我工作
@RequestMapping(value="/download")
public void getLogFile(HttpSession session,HttpServletResponse response) throws Exception {
try {
String fileName="archivo demo.pdf";
String filePathToBeServed = "C:\\software\\Tomcat 7.0\\tmpFiles\\";
File fileToDownload = new File(filePathToBeServed+fileName);
InputStream inputStream = new FileInputStream(fileToDownload);
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment; filename="+fileName);
IOUtils.copy(inputStream, response.getOutputStream());
response.flushBuffer();
inputStream.close();
} catch (Exception exception){
System.out.println(exception.getMessage());
}
}
像下面这样
@RequestMapping(value = "/download", method = RequestMethod.GET)
public void getFile(HttpServletResponse response) {
try {
DefaultResourceLoader loader = new DefaultResourceLoader();
InputStream is = loader.getResource("classpath:META-INF/resources/Accepted.pdf").getInputStream();
IOUtils.copy(is, response.getOutputStream());
response.setHeader("Content-Disposition", "attachment; filename=Accepted.pdf");
response.flushBuffer();
} catch (IOException ex) {
throw new RuntimeException("IOError writing file to output stream");
}
}
您可以在此处显示PDF或下载示例
如果有帮助的话。您可以执行Infeligo所接受的答案所建议的操作,但只需在代码中多加一点即可进行强制下载。
response.setContentType("application/force-download");
就我而言,我是按需生成一些文件,因此还必须生成url。
对我来说,是这样的:
@RequestMapping(value = "/files/{filename:.+}", method = RequestMethod.GET, produces = "text/csv")
@ResponseBody
public FileSystemResource getFile(@PathVariable String filename) {
String path = dataProvider.getFullPath(filename);
return new FileSystemResource(new File(path));
}
非常重要的是要输入mime,produces
而且文件的名称是链接的一部分,因此您必须使用@PathVariable
。
HTML代码如下所示:
<a th:href="@{|/dbreport/files/${file_name}|}">Download</a>
凡${file_name}
由Thymeleaf在控制器生成并即:result_20200225.csv,让整个URL behing链接:example.com/aplication/dbreport/files/result_20200225.csv
。
单击链接浏览器后,询问我如何处理文件-保存或打开。