itext7 +thymeleaf实现html转pdf, 模板动态填值,解决linux环境兼容问题

前言:  springboot项目实现html转pdf功能,踩过一些坑,记录遇到的问题。 附java代码,html代码,字体库下载地址,可直接运行main方法,生成pdf。

1.导入需要使用的包


    com.itextpdf
    html2pdf
    3.0.0


    org.thymeleaf
    thymeleaf
    3.0.11.RELEASE

2.转行工具类

package com.example.demo.controller;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider;
import com.itextpdf.layout.font.FontProvider;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.core.io.ClassPathResource;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import java.io.*;

/**
 * @Author: yh
 * @Date: 2023/6/5 12:05
 * @Description:
 */
public class PdfItext {

    /**
     * @param templatePath 模板全路径
     * @param path         生成pdf文件夹
     * @param fileName     生成pdf文件名
     * @param context      填充参数
     */
    public static void htmlToPdf(String templatePath, String path, String fileName, Context context) {
        String linuxPath = PdfItext.getFileAbsolutePath(templatePath, "/mnt/pdf/templates/template1.html", true);
        ConverterProperties converterProperties = new ConverterProperties();
        FontProvider dfp = new DefaultFontProvider();
//      dfp.addSystemFonts(); //添加中文字体库 方式a   -window环境有自带字体 linux环境需要安装中文字体,可参考 https://www.zhihu.com/question/423159370/answer/2706867741
        //添加中文字体库 方式b 使用项目导入的字体库 (已验证linux环境不安装中文字体,能正常显示中文)
        dfp.addFont(getFileAbsolutePath("/templates/simhei.ttf", "/mnt/pdf/templates/simhei.ttf", false));
        converterProperties.setFontProvider(dfp);
        //将本地的模板转换成字符串
        String htmlStr = toHtmlString(new File(linuxPath));
        //模板参数替换
        String replaceHtmlStr = new TemplateEngine().process(htmlStr, context);
        File destDir = new File(path);
        if (!destDir.exists()) {
            destDir.mkdirs();
        }
        try (OutputStream out = new FileOutputStream(new File(path + fileName))) {
            HtmlConverter.convertToPdf(replaceHtmlStr, out, converterProperties);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("pdf转换异常3{}"+ e);
        }
    }

    public static void main(String[] args) throws Exception {
        //模板内容填充参数
        Context context = new Context();
        context.setVariable("name2", "晨曦话java");
        context.setVariable("name1", "晨曦话三国");
        PdfItext.htmlToPdf("/templates/template.html", "/mnt/pdf/", "temp.pdf", context);
    }

    /**
     *  读取本地html文件里的html代码
     * @param file  File file=new File("文件的绝对路径")
     * @return
     */
    public static String toHtmlString(File file) {
        // 获取HTML文件流
        StringBuffer htmlSb = new StringBuffer();
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    new FileInputStream(file), "utf-8"));
            while (br.ready()) {
                htmlSb.append(br.readLine());
            }
            br.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // HTML文件字符串
        String htmlStr = htmlSb.toString();
        // 返回经过清洁的html文本
        return htmlStr;
    }

    /**
     * 解决linux下运行jar,无法加载jar包下文件(window环境能正常加载)
     *
     * @param templatePath 模板路径 传相对路径 比如 /templates/template.htm
     * @param createPath   生成路径  比如  /mnt/pdf/templates/template.html
     * @param isConvered  是否覆盖模板,默认false.  如模板变化,需覆盖生成
     * @return 返回的路径就是放在linux服务器上的文件路径
     */
    public static String getFileAbsolutePath(String templatePath, String createPath, boolean isConvered) {
        try {
            // 创建临时文件,获取jar里面的配置文件
            File file = new File(createPath);
            if (file.exists() && !isConvered) {
                return file.getAbsolutePath();
            }
            InputStream inputStream = null;
            try {
                ClassPathResource resource = new ClassPathResource(templatePath);
                inputStream = resource.getInputStream();
                byte[] buffer = new byte[inputStream.available()];
                inputStream.read(buffer);
                OutputStream outStream = new FileOutputStream(file);
                outStream.write(buffer);
                return file.getAbsolutePath();
            } finally {
                IOUtils.closeQuietly(inputStream);
            }
        } catch (Exception e) {
            System.out.println("FileUtil getFilePath Fail cause by:"+ e);
        }
        return null;
    }
}

3.原模板放在项目资源目录下:resources/templates  linux环境不能加载jar包下模板文件/templates/simhei.ttf,/templates/template1.html,解决方法,将模板文件生成在服务器磁盘指定位置,再读取,笔者生成在\mnt\pdf\templates目录下,如果html模板发生变化,需要覆盖生成,或者先删掉原来生成的,再生成。

itext7 +thymeleaf实现html转pdf, 模板动态填值,解决linux环境兼容问题_第1张图片

 4.中文字体不显示问题,方式a. dfp.addSystemFonts()可加载中文字体库,window环境有自带的字体库; linux环境需要安装中文字体库 ,可参考 https://www.zhihu.com/question/423159370/answer/2706867741

  方式b  dfp.addFont("/templates/simhei.ttf") 使用项目导入的字体库(已验证linux环境不安装中文字体库也能正常线上中文)

  simhei.ttf字体网上下载资源比较多,比如,http://xiazaiziti.com/210356.html

5.生成pdf文件位置:D:\mnt\pdf\temp.pdf,效果:

itext7 +thymeleaf实现html转pdf, 模板动态填值,解决linux环境兼容问题_第2张图片

itext7 +thymeleaf实现html转pdf, 模板动态填值,解决linux环境兼容问题_第3张图片

6.感谢ui和前端大佬画的html文件,效果炸裂。由于需要显示的内容比较多, pdf有默认边距,会换页。以下代码调整边距,使其在一页纸显示@page{ margin:10pt 25pt 0pt 25pt;}

html代码:




  
  
  
  
    
  
  
  业财一体化智能管理平台




  

明细:

金额(元) 额(元) 总金额(元)
金额(元)
1
2 0 0.00
3
4
(5)
6
7
8
9
10
11
AA 金额
a
a
a
a
a
a
合计
ZZ ZZ
ZZ
ZZ 0.00
ZZ 0.00
ZZ 0.00
ZZ 0.00
ZZ 0.00
ZZ 0.00
ZZ 0.00
v 0.00
ZZ 0.00
ZZ 0.00

ZZ:

ZZ ZZ ZZ
ZZ 2023-06-01 23:59:59
ZZ
ZZ ww
ZZ
ZZ ww

你可能感兴趣的:(html,pdf,linux)