从弹簧控制器下载文件
我有一个要求,我需要从网站上下载PDF文件。 PDF需要在代码中生成,我认为这是Freemarker和PDF生成框架(如iText)的结合。 更好的方法?
但是,我的主要问题是如何让用户通过Spring Controller下载文件?
@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()
,你可以在那里写任何东西。 您可以将此输出stream作为放置生成PDF的位置传递给您的生成器。 另外,如果你知道你正在发送什么文件types,你可以设置
response.setContentType("application/pdf");
通过使用ResourceHttpMessageConverter中的内置支持,我能够stream化线。 这将设置内容长度和内容types,如果它可以确定MIMEtypes
@RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET) @ResponseBody public FileSystemResource getFile(@PathVariable("file_name") String fileName) { return new FileSystemResource(myService.getFileFor(fileName)); }
您应该能够直接在响应中写入文件。 就像是
response.setContentType("application/pdf"); response.setHeader("Content-Disposition", "attachment; filename=\"somefile.pdf\"");
然后将该文件作为二进制stream写入response.getOutputStream()
。 记得在最后做response.flush()
,应该这样做。
使用Spring 3.0,您可以使用HttpEntity
返回对象。 如果你使用这个,那么你的控制器不需要一个HttpServletResponse
对象,因此testing起来就比较容易。 除此之外,这个答案相对于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框架( documentBbody
)的返回types不是一个字节数组 (也不是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); }
如果你:
- 发送到响应之前,不希望将整个文件加载到一个
byte[]
; - 需要/需要通过
InputStream
发送/下载; - 想要完全控制发送的MIMEtypes和文件名;
- 让其他
@ControllerAdvice
为你挑选例外。
下面的代码是你需要的:
@RequestMapping(value = "/stuff/{stuffId}", method = RequestMethod.GET) public ResponseEntity<InputStreamResource> downloadStuff(@PathVariable int stuffId) throws IOException { String fullPath = stuffService.figureOutFileNameFor(stuffId); File file = new File(fullPath); HttpHeaders respHeaders = new HttpHeaders(); respHeaders.setContentType("application/pdf"); respHeaders.setContentLength(12345678); respHeaders.setContentDispositionFormData("attachment", "fileNameIwant.pdf"); InputStreamResource isr = new InputStreamResource(new FileInputStream(file)); return new ResponseEntity<InputStreamResource>(isr, respHeaders, HttpStatus.OK); }
另外请注意,为了避免读取整个文件来计算它的长度,最好先存储它。 确保你检查了InputStreamResource
的文档。
此代码工作正常,从弹簧控制器上单击jsp上的链接自动下载文件。
@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(); } }
我可以很快想到的是,生成pdf并将其存储在代码中的webapp / downloads / <RANDOM-FILENAME> .pdf中,并使用HttpServletRequest发送到此文件
request.getRequestDispatcher("/downloads/<RANDOM-FILENAME>.pdf").forward(request, response);
或者如果你可以configuration你的视图parsing器的东西,
<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", 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); }
像下面的东西
@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或下载示例