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

然而,我的主要问题是如何允许用户通过Spring控制器下载文件?


当前回答

您应该能够直接在响应上写入文件。类似的

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

然后在response.getOutputStream()上将该文件写入二进制流。记得在最后执行response.flush(),这样就可以了。

其他回答

如下图所示

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

我能很快想到的是,生成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 = "/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");

下面的解决方案对我很有效

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

    }

在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);
}

如果你的PDF框架(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);
}