在 Spring 中通过 ClassPathResource 不正确的编码服务二进制 (pdf) 文件

Arj*_*jan 1 java pdf binary encoding spring

我一直在为以下问题苦苦挣扎两天,无法解决它。

我正在尝试在 Spring Boot rest 应用程序中提供静态 pdf。它应该非常简单,但我无法让它工作。

首先,我只是将 pdf 放在资源文件夹中,并尝试直接从 javascript 代码加载它,如下所示:

var newWindow = window.open(/pdf/test.pdf, ''); 
Run Code Online (Sandbox Code Playgroud)

这导致了一个带有 pdf 的新窗口没有显示任何内容。

从浏览器将 pdf 保存到磁盘并调查内容后发现它们与原始文件不同。我正在展示来自 Atom 的屏幕截图(首先是原始的),采用 ISO-8859-1 编码:

来自原始pdf的片段 相同的部分,从浏览器保存的 pdf

到目前为止,我的结论是:Spring 或 Tomcat 以某种方式更改了二进制内容。也许它正在编码它?在 Base64 中?

然后我尝试在服务器端实现它,看看发生了什么。我实现了一个可以提供 pdf 内容的休息控制器。

一个有趣的发现是它最初给出了与直接方法相同的结果。我使用 classPathResource 来获取 pdf 文件的句柄。

但是当我使用 FileInputStream 和 File 直接从路径加载 pdf 时,它可以工作。见下面的代码:

    @RequestMapping(value = "/test.pdf", method = RequestMethod.GET, produces = "application/pdf")
public void getFile(HttpServletResponse response) {
    try {
        DefaultResourceLoader loader = new DefaultResourceLoader();

        /* does not work
        ClassPathResource pdfFile = new ClassPathResource("test.pdf");
        InputStream is = pdfFile.getInputStream();
        */

        /* works */
        InputStream is = new FileInputStream(new File("z:\\downloads\\test.pdf"));


        IOUtils.copy(is, response.getOutputStream());

        response.setHeader("Content-Disposition", "inline; filename=test.pdf");
        response.setContentType("application/pdf");

        response.flushBuffer();

    } catch (IOException ex) {
        throw new RuntimeException("IOError writing file to output stream");
    }
}
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?为什么 Spring/Tomcat 在使用 ClassPathResource 或直接提供服务时会更改二进制数据?

我会很感激这里的一些帮助。我不能使用直接路径,因为 pdf 最终会在一个 jar 文件中,所以我需要 ClassPathResource 或其他一些 ResourceLoader。

Arj*_*jan 5

好吧,终于找到罪魁祸首了,而且是在一个完全出乎意料的角落。

我在这个项目中使用 IntelliJ 和 Maven,事实证明,IntelliJ 在将它复制到 /target 文件夹时损坏了 pdf 的内容。当然,tomcat 正在为这个文件提供服务,而不是 /src 文件夹中的那个……所以它与 ClassPathResource 或 Spring 无关。是马文。

我不得不在 pom.xml 中禁用对(二进制)pdf 的过滤:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <configuration>
                <nonFilteredFileExtensions>
                    <nonFilteredFileExtension>pdf</nonFilteredFileExtension>
                </nonFilteredFileExtensions>
            </configuration>
        </plugin>
Run Code Online (Sandbox Code Playgroud)

这解决了这个问题。现在直接请求文件 (localhost:8080/test.pdf) 以及其余控制器方法工作。@Andy Brown:感谢您的快速回复,尽管它没有解决问题。