提问者:小点点

UTF-8个字符未显示在通过飞碟和thymeleaf从html模板生成的PDF中


我试图通过飞碟和thymeleaf生成包含中文UTF-8个字符的pdf。但是生成的pdf忽略了所有的中文字符(拉丁文很好)。这是Thymeleaf配置

@Configuration
public class ThymeleafConfig {

    @Bean
    public ClassLoaderTemplateResolver fileTemplateResolver(){
        ClassLoaderTemplateResolver fileTemplateResolver = new ClassLoaderTemplateResolver();
        fileTemplateResolver.setPrefix("templates/");
        fileTemplateResolver.setTemplateMode("HTML");
        fileTemplateResolver.setSuffix(".html");
        fileTemplateResolver.setCharacterEncoding("UTF-8");
        fileTemplateResolver.setOrder(1);
        return fileTemplateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine(){
        SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
        springTemplateEngine.setEnableSpringELCompiler(true);
        springTemplateEngine.setTemplateResolver(fileTemplateResolver());
        return springTemplateEngine;
    }

    @Bean
    public ThymeleafViewResolver thymeleafViewResolver() {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(templateEngine());
        resolver.setCharacterEncoding("UTF-8");
        return resolver;
    }
}

如您所见,我已将模板解析器和视图解析器的字符编码设置为UTF-8。

PDFUtil用于生成pdf

public class PDFUtil {

    @Autowired
    private TemplateEngine templateEngine;

    public String createPdf(String templatename, String fileName, String modelName, Object model) throws IOException, DocumentException  {
        String fileNameUrl = "";
        Context ctx = new Context();

        ctx.setVariable(modelName, model);

        String processedHtml = templateEngine.process(templatename, ctx);
        FileOutputStream outputStream = null;

        try {
            final File outputFile = File.createTempFile(fileName, ".pdf");
            outputStream = new FileOutputStream(outputFile);

            ITextRenderer renderer = new ITextRenderer();
            ITextFontResolver resolver = renderer.getFontResolver();

            final ClassPathResource fonts = new ClassPathResource("fonts/PingFangSCRegular.ttf");
            String test = fonts.getFilename();
            resolver.addFont(fonts.getPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

            renderer.setDocumentFromString(processedHtml);
            renderer.layout();
            renderer.createPDF(outputStream, false);
            renderer.finishPDF();
            FileSystemResource resource = new FileSystemResource(outputFile);
            fileNameUrl = resource.getURL().toString();
        }
        finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) { }
            }
        }

        return fileNameUrl;
    }
}

在这里,我已经将中文字体添加到解析器中。

这是模板html头

<head th:fragment="html_head">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Title</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script src="https://unpkg.com/jsbarcode@latest/dist/JsBarcode.all.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/fontawesome.min.css" />
    <style type="text/css">
        @font-face {
            font-family: 'PingFang SC Regular';
            src: url('/fonts/PingFangSCRegular.ttf');
            -fs-pdf-font-embed: embed;
            -fs-pdf-font-encoding: Identity-H;
        }
    </style>

</head>

所以我试着声明字符集是UTF-8,字体系列是平方SC常规。但是毫不奇怪,这不起作用。

这是我添加到springboot项目中的maven依赖项

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>9.1.22</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13.3</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.5.13.3</version>
        </dependency>

我要渲染的html主体

<body>
    <div th:fragment="header(model)">
        <div class="row">
            <div class="col-4">
                <img id="barcode" alt="111"/>
            </div>
            <div class="col-4">
                <h3>啊啊啊啊啊啊aaa[[${model.title}]]</h3>
                <p id="print-time">[[${model.printTime}]]</p>
            </div>
        </div>
    </div>
</body>

有人能弄清楚为什么UTF-8字符没有显示在生成的pdf中吗?任何想法都将不胜感激。


共1个答案

匿名用户

在您的模板中,您声明了font-face,但没有将其应用于页面的内容。

您只需声明应使用字体:

body {font-family: 'PingFang SC Regular';}

此外,您不需要在模板中使用@font-face,因为您已将字体添加到渲染器(使用解析器. addFont)。

以下超文本标记语言应该可以正常工作:

<html>
    <head>
        <style>
            body {font-family: 'PingFang SC Regular';}
        </style>
    </head>
    <body>
        <h3>啊啊啊啊啊啊</h3>
    </body>
</html>