首页 文章

从 spring 控制器下载文件

提问于
浏览
304

我有一个要求,我需要从网站上下载PDF . PDF需要在代码中生成,我认为这将是freemarker和像iText这样的PDF生成框架的组合 . 有更好的方法吗?

但是,我的主要问题是如何允许用户通过Spring Controller下载文件?

10 回答

  • 270
    @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");
    
  • 16

    通过使用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)); 
    }
    
  • 53

    您应该能够直接在响应上写入文件 . 就像是

    response.setContentType("application/pdf");      
    response.setHeader("Content-Disposition", "attachment; filename=\"somefile.pdf\"");
    

    然后在 response.getOutputStream() 上将文件写为二进制流 . 记得最后做 response.flush() ,应该这样做 .

  • 69

    使用Spring 3.0,您可以使用 HttpEntity 返回对象 . 如果使用它,那么控制器不需要 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);
    }
    

    If the return type of your PDF Framework (documentBbody) is not already a byte array (也没有 ByteArrayInputStream )那么首先将它作为字节数组是明智的 NOT . 相反,最好使用:

    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);
    }
    
  • 1

    如果你:

    • 不希望在发送到响应之前将整个文件加载到 byte[] 中;

    • 想要/需要通过 InputStream 发送/下载;

    • 希望完全控制发送的Mime类型和文件名;

    • 让其他 @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的文档 .

  • 5

    这个代码可以正常工作,从 spring 控制器上点击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();
        }
    
    }
    
  • 74

    下面的代码为我生成和下载文本文件 .

    @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);
    }
    
  • 9

    我可以很快想到的是,生成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";
    
  • 342

    类似下面的东西

    @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或下载示例here

  • 0

    以下解决方案适合我

    @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());
            }
    
        }
    

相关问题