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

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


当前回答

Do

从处理程序方法返回ResponseEntity<Resource> 指定内容类型 如果需要,设置Content-Disposition: 文件名 类型 内联以强制在浏览器中预览 附件强制下载

例子

@Controller
public class DownloadController {
    @GetMapping("/downloadPdf.pdf")
    // 1.
    public ResponseEntity<Resource> downloadPdf() {
        FileSystemResource resource = new FileSystemResource("/home/caco3/Downloads/JMC_Tutorial.pdf");
        // 2.
        MediaType mediaType = MediaTypeFactory
                .getMediaType(resource)
                .orElse(MediaType.APPLICATION_OCTET_STREAM);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(mediaType);
        // 3
        ContentDisposition disposition = ContentDisposition
                // 3.2
                .inline() // or .attachment()
                // 3.1
                .filename(resource.getFilename())
                .build();
        headers.setContentDisposition(disposition);
        return new ResponseEntity<>(resource, headers, HttpStatus.OK);
    }
}

解释

返回ResponseEntity <资源>

当您返回ResponseEntity<Resource>时,ResourceHttpMessageConverter将写入文件内容

资源实现的例子:

基于字节的ByteArrayResource [] FileSystemResource—用于文件或路径 UrlResource -从java.net.URL检索 GridFsResource—存储在MongoDB中的blob ClassPathResource—用于类路径中的文件,例如资源目录中的文件。我对“从Spring Boot中的资源文件夹中读取文件”问题的回答详细解释了如何在类路径中定位资源

显式指定Content-Type:

原因:请参阅“FileSystemResource返回内容类型为json”问题

选项:

硬编码头文件 使用Spring中的MediaTypeFactory。MediaTypeFactory使用/org/springframework/http/mime将Resource映射到MediaType。类型文件 使用第三方库,如Apache Tika

如果需要,设置Content-Disposition:

关于Content-Disposition头:

HTTP上下文中的第一个参数要么是内联(默认值,表明它可以在Web页面中显示,也可以作为Web页面显示),要么是附件(表明应该下载它;大多数浏览器会显示一个“另存为”对话框,如果存在的话,会预先填充文件名参数的值)。

在应用中使用ContentDisposition:

在浏览器中预览文件: 性格=性格 .inline () .filename (resource.getFilename ()) .build (); 强制下载: 性格=性格 .attachment () .filename (resource.getFilename ()) .build ();

小心使用InputStreamResource:

使用HttpHeaders#setContentLength方法指定Content-Length,如果:

长度是已知的 使用InputStreamResource

原因:Spring不会为InputStreamResource写Content-Length,因为Spring不能确定资源的长度。下面是来自ResourceHttpMessageConverter的一段代码:

@Override
protected Long getContentLength(Resource resource, @Nullable MediaType contentType) throws IOException {
    // Don't try to determine contentLength on InputStreamResource - cannot be read afterwards...
    // Note: custom InputStreamResource subclasses could provide a pre-calculated content length!
    if (InputStreamResource.class == resource.getClass()) {
        return null;
    }
    long contentLength = resource.contentLength();
    return (contentLength < 0 ? null : contentLength);
}

在其他情况下,Spring设置Content-Length:

~ $ curl -I localhost:8080/downloadPdf.pdf  | grep "Content-Length"
Content-Length: 7554270

其他回答

下面的代码为我生成和下载一个文本文件工作。

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

我必须加上这个才能下载任何文件

    response.setContentType("application/octet-stream");
    response.setHeader("Content-Disposition",
            "attachment;filename="+"file.txt");

所有的代码:

@Controller
public class FileController {

@RequestMapping(value = "/file", method =RequestMethod.GET)
@ResponseBody
public FileSystemResource getFile(HttpServletResponse response) {

    final File file = new File("file.txt");
    response.setContentType("application/octet-stream");
    response.setHeader("Content-Disposition",
            "attachment;filename="+"file.txt");
    return new FileSystemResource(file);
 }
}

Do

从处理程序方法返回ResponseEntity<Resource> 指定内容类型 如果需要,设置Content-Disposition: 文件名 类型 内联以强制在浏览器中预览 附件强制下载

例子

@Controller
public class DownloadController {
    @GetMapping("/downloadPdf.pdf")
    // 1.
    public ResponseEntity<Resource> downloadPdf() {
        FileSystemResource resource = new FileSystemResource("/home/caco3/Downloads/JMC_Tutorial.pdf");
        // 2.
        MediaType mediaType = MediaTypeFactory
                .getMediaType(resource)
                .orElse(MediaType.APPLICATION_OCTET_STREAM);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(mediaType);
        // 3
        ContentDisposition disposition = ContentDisposition
                // 3.2
                .inline() // or .attachment()
                // 3.1
                .filename(resource.getFilename())
                .build();
        headers.setContentDisposition(disposition);
        return new ResponseEntity<>(resource, headers, HttpStatus.OK);
    }
}

解释

返回ResponseEntity <资源>

当您返回ResponseEntity<Resource>时,ResourceHttpMessageConverter将写入文件内容

资源实现的例子:

基于字节的ByteArrayResource [] FileSystemResource—用于文件或路径 UrlResource -从java.net.URL检索 GridFsResource—存储在MongoDB中的blob ClassPathResource—用于类路径中的文件,例如资源目录中的文件。我对“从Spring Boot中的资源文件夹中读取文件”问题的回答详细解释了如何在类路径中定位资源

显式指定Content-Type:

原因:请参阅“FileSystemResource返回内容类型为json”问题

选项:

硬编码头文件 使用Spring中的MediaTypeFactory。MediaTypeFactory使用/org/springframework/http/mime将Resource映射到MediaType。类型文件 使用第三方库,如Apache Tika

如果需要,设置Content-Disposition:

关于Content-Disposition头:

HTTP上下文中的第一个参数要么是内联(默认值,表明它可以在Web页面中显示,也可以作为Web页面显示),要么是附件(表明应该下载它;大多数浏览器会显示一个“另存为”对话框,如果存在的话,会预先填充文件名参数的值)。

在应用中使用ContentDisposition:

在浏览器中预览文件: 性格=性格 .inline () .filename (resource.getFilename ()) .build (); 强制下载: 性格=性格 .attachment () .filename (resource.getFilename ()) .build ();

小心使用InputStreamResource:

使用HttpHeaders#setContentLength方法指定Content-Length,如果:

长度是已知的 使用InputStreamResource

原因:Spring不会为InputStreamResource写Content-Length,因为Spring不能确定资源的长度。下面是来自ResourceHttpMessageConverter的一段代码:

@Override
protected Long getContentLength(Resource resource, @Nullable MediaType contentType) throws IOException {
    // Don't try to determine contentLength on InputStreamResource - cannot be read afterwards...
    // Note: custom InputStreamResource subclasses could provide a pre-calculated content length!
    if (InputStreamResource.class == resource.getClass()) {
        return null;
    }
    long contentLength = resource.contentLength();
    return (contentLength < 0 ? null : contentLength);
}

在其他情况下,Spring设置Content-Length:

~ $ curl -I localhost:8080/downloadPdf.pdf  | grep "Content-Length"
Content-Length: 7554270

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

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

    }