itext7 实现模板PDF填充、HTML转PDF

本文档介绍了在Java SpringBoot环境中,使用iText7库处理PDF,包括模板PDF填充和HTML转PDF。在填充PDF时,需要注意字体嵌入以避免乱码。HTML转PDF支持本地HTML文件和HTML压缩包转换,涉及文件的解压缩操作。解压缩部分提供了zip和rar文件的处理方法。
摘要由CSDN通过智能技术生成

一、实验环境

  1. java版本:1.8
  2. springboot版本:2.6.6
  3. jar依赖(maven):
 		<dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext7-core</artifactId>
            <version>${itext.version}</version>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>font-asian</artifactId>
            <version>${itext.version}</version>
            <scope>test</scope>
        </dependency>

4、压缩文件解压依赖(zip(zip使用JDK实现)、rar(只支持rar4))

 <!-- rar 文件解压 -->
        <dependency>
            <groupId>com.github.junrar</groupId>
            <artifactId>junrar</artifactId>
            <version>7.5.0</version>
        </dependency>

二、模板PDF填充PDF

此方式适用于需动态填充数据到PDF中

2.1 编辑PDF(笔者使用 万兴PDF编辑)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 填充PDF代码示例

/**
     * 填充PDF
     *
     * @param content 填充内容
     * @return 保存位置
     */
    public static String fillPdf(String content) {
        PdfDocument pdfDoc = null;
        String completePath = null;
        String fileName = null;
        try {
            ClassPathResource classPathResource = null;

            classPathResource = new ClassPathResource("templates/word-model-file.pdf");
            fileName = "word-model-file-convert";

            InputStream inputStream = null;
            try {
                inputStream = classPathResource.getInputStream();
            } catch (IOException e) {
                logger.error("获取模板文件失败:{}", e.getMessage());
            }

            completePath = CommonConfig.getFileSavePath() + "pdf/" + fileName + ".pdf";
            File out = new File(completePath);
            if (!out.exists()) {
                out.getParentFile().mkdir();
            }
            pdfDoc = new PdfDocument(new PdfReader(inputStream),
                    new PdfWriter(completePath));
        } catch (IOException e) {
            logger.error("填充PDF失败:{}", e.getMessage());
        }

        //详细使用方法请参考itext7官方文档
        //https://kb.itextpdf.com/home/it7kb/ebooks/itext-7-jump-start-tutorial-for-java/chapter-6-reusing-existing-pdf-documents
        PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, false);

        Map<String, PdfFormField> fields = form.getFormFields();


        ClassPathResource robotoPath = new ClassPathResource("fonts/Roboto-Bold.ttf");


        try {
            PdfFont robotoRegularFont = PdfFontFactory.createFont(robotoPath.getPath(), PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.FORCE_EMBEDDED, true);

            //填充内容 字体   字体大小 颜色
            fields.get("content").setValue(content + new Date()).setFont(robotoRegularFont).setFontSize(12).setColor(new DeviceRgb(51, 51, 51));


        } catch (Exception e) {
            logger.error("PDF模板填充失败:" + e.getMessage());
        }

        form.flattenFields();

        pdfDoc.close();

        return completePath;
    }

1、中文转换可能会存在乱码或不显示的情况,此情况多数是无此字体造成,可查看官方文档,嵌入使用字体
2、itext7还可创建PDF,编辑等操作,请参考官方文档:https://kb.itextpdf.com/home/it7kb/ebooks

三、HTML转PDF

笔者实现了本地HTML转换,和HTML压缩包转换的操作

3.1本地HTML转PDF


    /**
     * 本地html 转 PDF
     *
     * @param width  PDF宽度 单位 pt
     * @param height PDF高度 单位pt
     * @return 生成的文件路径
     */
    public static String html2pdfLocalFile(Float width, Float height, String newFileName) {

        String path = String.format("%shtml/pdf/%s.pdf", CommonConfig.getFileSavePath(), newFileName);

        File file = new File(path);
        file.getParentFile().mkdirs();

        try {
//            PdfWriter writer = new PdfWriter(path,
//                    new WriterProperties().setFullCompressionMode(true));


            //TODO 如需按照页面分页生成, 则需在CSS中定义分页,如下所示:
            /*
            *
            *  @page {
                @bottom-right {
                    content: "Page " counter(page) " of " counter(pages);
                }
            }
            *
            * */
            PdfWriter writer = new PdfWriter(path);
            PdfDocument pdf = new PdfDocument(writer);
            pdf.setTagged();
            PageSize pageSize = new PageSize(width, height);
            pdf.setDefaultPageSize(pageSize);
            ConverterProperties properties = new ConverterProperties();
            //此根路径为html的根路径
            properties.setBaseUri(CommonConfig.getFileSavePath() + "html/html");

            //如果在代码中使用了相对路径的方式,则需要配置绝对路径
            HtmlConverter.convertToPdf(new FileInputStream(CommonConfig.getFileSavePath() + "html/html/Untitled-1.html"), pdf, properties);

        } catch (IOException e) {
            logger.error("html2pdf 失败:{}", e.getMessage());
        }

        return path;
    }

3.2HTML压缩包转换PDF

 /**
     * html 转 PDF
     *
     * @param width          PDF宽度 单位 pt
     * @param height         PDF高度 单位pt
     * @param multipartFile  上传的打包文件
     * @param htmlFolderName html文件夹名称
     * @param htmlName       html名称
     * @return 生成的文件路径
     */
    public static String html2pdf(Float width,
                                  Float height,
                                  MultipartFile multipartFile,
                                  String htmlFolderName,
                                  String htmlName) {



        /* html文件打包转换思路

         * 1、上传打包文件
         * 2、解压文件
         * 3、执行html转pdf
         * */

        //上传文件到服务器
        String upFilePath = FileUpload.upload(multipartFile);
        logger.info("upFilePath:{}", upFilePath);
        String name = multipartFile.getOriginalFilename();
        String suffix = name.substring(name.lastIndexOf(".") + 1);

        String unZipPath = getUnZipPath();
        logger.info("unZipPath:{}", unZipPath);

        if ("zip".equals(suffix)) {
            //zip解压
            try {
                UZipFile.unZipFiles(new File(upFilePath), unZipPath);
            } catch (IOException e) {
                logger.error("zip 文件解压失败:{}", e.getMessage());
            }
        } else if ("rar".equals(suffix)) {
            //rar解压 只支持 rar4
            try {
                UnRARUtil.unrarFile(upFilePath, unZipPath);
            } catch (IOException | RarException e) {
                logger.error("rar 文件解压失败:{}", e.getMessage());
            }
        }


        String relativelyPath = String.format("pdf/%s.pdf", getCtm());
        String path = CommonConfig.getFileSavePath() + relativelyPath;

        logger.info("localPath:{}", path);
        logger.info("relativelyPath:{}", relativelyPath);

        File file = new File(path);
        file.getParentFile().mkdirs();

        try {
//            PdfWriter writer = new PdfWriter(path,
//                    new WriterProperties().setFullCompressionMode(true));

            //TODO 如需按照页面分页生成, 则需在CSS中定义分页,如下所示:
            /*
            *
            *  @page {
                @bottom-right {
                    content: "Page " counter(page) " of " counter(pages);
                }
            }
            *
            * */
            PdfWriter writer = new PdfWriter(path);
            PdfDocument pdf = new PdfDocument(writer);
            pdf.setTagged();
            PageSize pageSize = new PageSize(width, height);
            pdf.setDefaultPageSize(pageSize);

            ConverterProperties properties = new ConverterProperties();

            //此根路径为html的根路径 需为物理路径,不能使用虚拟路径
            logger.info("unZipPath:{}", unZipPath);

            logger.info("htmlPath:{}", unZipPath + "/" + htmlFolderName + "/" + htmlName);
            logger.info("BaseUri:{}", unZipPath + "/" + htmlFolderName);

            properties.setBaseUri(unZipPath + "/" + htmlFolderName);

            //如果在代码中使用了相对路径的方式,则需要配置绝对路径
            HtmlConverter.convertToPdf(new FileInputStream(unZipPath + "/" + htmlFolderName + "/" + htmlName), pdf, properties);

        } catch (IOException e) {
            logger.error("html2pdf 失败:{}", e.getMessage());
        }

        logger.error("http://" + CommonUtils.getLocalIp() + ":" + serverPort + "/" + relativelyPath);

        return getServerBasePath() + relativelyPath;
    }

3.2.1 zip文件解压


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;


public class UZipFile {
    private static Logger log = LoggerFactory.getLogger(UZipFile.class);

    /**
     * 解压文件
     */
    @SuppressWarnings("rawtypes")
    public static List<String> unZipFiles(File zipFile, String descDir) throws IOException {
        List<String> pathList = new ArrayList<>();
        File pathFile = new File(descDir);
        if (!pathFile.exists()) {
            pathFile.mkdirs();
        }
        //解决zip文件中有中文目录或者中文文件
        ZipFile zip = new ZipFile(zipFile, Charset.forName("GBK"));
        for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) {
            ZipEntry entry = (ZipEntry) entries.nextElement();
            String zipEntryName = entry.getName();
            InputStream in = zip.getInputStream(entry);
            String outPath = (descDir + "/" + zipEntryName).replaceAll("\\*", "/");

            //判断路径是否存在,不存在则创建文件路径
            File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
            if (!file.exists()) {
                file.mkdirs();
            }
            //判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
            if (new File(outPath).isDirectory()) {
                continue;
            }
            //输出文件路径信息
            pathList.add(outPath);
            log.info("解压文件路径为:" + outPath);
            OutputStream out = new FileOutputStream(outPath);
            byte[] buf1 = new byte[1024];
            int len;
            while ((len = in.read(buf1)) > 0) {
                out.write(buf1, 0, len);
            }
            in.close();
            out.close();
        }
        log.info("******************解压完毕********************");
        return pathList;

    }
}

3.2.2 rar文件解压


import com.github.junrar.Archive;
import com.github.junrar.exception.RarException;
import com.github.junrar.rarfile.FileHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

 
public class UnRARUtil {

    private static Logger log = LoggerFactory.getLogger(UnRARUtil.class);


    public static void unrarFile(String rarPath, String dstDirectoryPath) throws IOException, RarException {
        File dstDiretory = new File(dstDirectoryPath);

        if (!dstDiretory.exists()) {
            dstDiretory.mkdirs();
        }
        Archive a = new Archive(new File(rarPath));
        ArrayList<String> filepathList = new ArrayList<>();

        if (a != null) {

            a.getMainHeader().print(); //打印文件信息.

            FileHeader fh = a.nextFileHeader();

//            fileName=  fh.getFileNameW().trim();
//            if(!existZH(fileName)){
//                fileName = fh.getFileNameString().trim();
//            }
            while (fh != null) {
                // 判断编码,解决中文乱码的问题
                String localpath = fh.isUnicode() ? fh.getFileNameW() : fh.getFileNameString();
                //文件

                File out = new File(dstDirectoryPath + File.separator + localpath.trim());
                String outPath = out.getAbsolutePath().replaceAll("\\*", "/");
                ;
                //判断路径是否存在,不存在则创建文件路径
                File file = new File(outPath.substring(0, outPath.lastIndexOf('\\')));
                if (!file.exists()) {
                    file.mkdirs();
                }
                //判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
                if (new File(outPath).isDirectory()) {
                    break;
                }
                //输出文件路径信息
                if (fh != null) {
                    filepathList.add(out.getAbsolutePath());
                }
                FileOutputStream os = new FileOutputStream(out);

                a.extractFile(fh, os);

                os.close();

                fh = a.nextFileHeader();

            }

        }

        a.close();
        log.info("******************解压完毕********************");
    }

}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值