将自定义字体与飞碟一起使用会导致 PDF 损坏

Using custom font with flying saucer gives corrupt PDF

我有一个使用 Flying Saucer 生成的工作 PDF。但是,当我现在想要添加自定义字体时,生成的 PDF 会损坏。浏览器没有下载文件,而是显示各种奇怪的符号。

通过在类路径中添加 ttf 字体文件并调用 addFont:

添加自定义字体
            renderer.getFontResolver().addFont("/fonts/Montserrat-Regular.ttf", BaseFont.IDENTITY_H, true);
            renderer.getFontResolver().addFont("/fonts/Montserrat-Italic.ttf", BaseFont.IDENTITY_H, true);
            renderer.getFontResolver().addFont("/fonts/Montserrat-Bold.ttf", BaseFont.IDENTITY_H, true);
            renderer.getFontResolver().addFont("/fonts/Montserrat-BoldItalic.ttf", BaseFont.IDENTITY_H, true);

并在CSS中指定字体:

html {
  font-family: 'Montserrat', sans-serif;
  font-size: 14px;
}

问题是由于在将 PDF 生成到响应的输出流后设置了响应 header。

我的控制器是这样的:

    @GetMapping("/{id}/download-pdf")
    @Secured(Roles.ADMIN)
    public void downloadPDFResource(@PathVariable("id") EntityId entityId,
                                    HttpServletRequest request, HttpServletResponse response,
                                    Locale locale) throws IOException {
        byte[] pdf = pdfService.generatePdf("details-pdf", context);
        response.getOutputStream().write(pdf);
        response.setContentType("application/pdf");
        response.addHeader("Content-Disposition",
                           "attachment; filename=" + "document.pdf");

        response.getOutputStream().flush();
    }

解决方法是将内容类型的设置和 header 移动到方法的顶部:

    @GetMapping("/{id}/download-pdf")
    @Secured(Roles.ADMIN)
    public void downloadPDFResource(@PathVariable("id") EntityId entityId,
                                    HttpServletRequest request, HttpServletResponse response,
                                    Locale locale) throws IOException {
        response.setContentType("application/pdf");
        response.addHeader("Content-Disposition",
                           "attachment; filename=" + "document.pdf");

        byte[] pdf = pdfService.generatePdf("details-pdf", context);
        response.getOutputStream().write(pdf);

        response.getOutputStream().flush();
    }