天天看點

java項目使用wkhtmltopdf實作模闆導出pdf

wkhtmltopdf介紹

wkhtmltopdf是一款安裝在服務端的pdf導出插件,隻需要通過指令行就能調用,将html檔案轉換成pdf檔案;

使用這款插件,java程式中不需要額外引入任何依賴。

使用前準備

去官網【https://wkhtmltopdf.org/】下載下傳安裝插件

使用方法

一、控制台簡單使用

  1. 準備好一個用來導出的html檔案
  2. 打開插件安裝的目錄,并在此處打開控制台視窗
    java項目使用wkhtmltopdf實作模闆導出pdf
/**
 * HTML轉PDF工具類(WK實作,樣式更完善)
 *
 * @author wangmeng
 * @since 2021/7/15
 */
@Slf4j
public class Html2PdfUtils {

    /**
     * 根據模闆導出pdf檔案(A4尺寸)
     *
     * @param templateName 模闆名稱
     * @param data         用來渲染的頁面資料
     * @param savePath     導出路徑
     * @param fileName     pdf名稱
     */
    public static void makePdf(String templateName, Object data, String savePath, String fileName) {
        makePdf(templateName, data, savePath, fileName, PageSize.defaultSize);
    }


    /**
     * 根據模闆導出pdf檔案
     *
     * @param templateName 模闆名稱
     * @param data         用來渲染的頁面資料
     * @param savePath     導出路徑
     * @param fileName     pdf名稱
     * @param pageSize     頁面尺寸
     */
    public static void makePdf(String templateName, Object data, String savePath, String fileName, PageSize pageSize) {
        FileUtils.createFileFolder(savePath);
        String htmlData = getContent(templateName, data);
        try {
            createPdf(htmlData, savePath, fileName, pageSize);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new CustomException("導出pdf檔案失敗!");
        }
    }

    /**
     * 擷取pdf模闆
     *
     * @param templateName 模闆名稱
     * @param data         用來渲染的頁面資料
     * @return 渲染後的頁面
     */
    private static String getContent(String templateName, Object data) {
        if (StringUtils.isBlank(templateName)) {
            throw new CustomException("模闆路徑和模闆名稱不能為空!");
        }
        //使用資料渲染模闆
        try (StringWriter writer = new StringWriter()) {
            //FreeMarker配置
            Configuration config = new Configuration(Configuration.VERSION_2_3_25);
            config.setDefaultEncoding("UTF-8");
            config.setDirectoryForTemplateLoading(new File(ConfigUtils.getPdfTemplatePath())); //設定讀取模闆的目錄
            config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
            config.setLogTemplateExceptions(false);
            Template template = config.getTemplate(templateName);//根據模闆名稱 擷取對應模闆
            template.process(data, writer);
            writer.flush();
            return writer.toString();
        } catch (IOException | TemplateException ioException) {
            log.error(ioException.getMessage());
            throw new CustomException(GlobalI18nConstant.TEMPLATE_ERROR);
        }
    }

    /**
     * 根據html檔案生成pdf
     *
     * @param htmlContent html
     * @param savePath    導出路徑
     * @param fileName    檔案名
     * @param pageSize    尺寸
     * @throws IOException
     */
    private static void createPdf(String htmlContent, String savePath, String fileName, PageSize pageSize) throws IOException {
        //建立臨時檔案夾,存放渲染完的html檔案
        String time = DateUtils.toString(new Date(), DateUtils.YYYY_MM_DD_HH_MM_SS3);
        String tempPath = ConfigUtils.getBaseDir() + ConfigUtils.getBaseTempDir() + File.separator + time + IdUtils.uuid();
        FileUtils.createFileFolder(tempPath);
        FileOutputStream fileoutputstream = null;
        String space = GlobalConstant.SPACE;
        //臨時檔案名,防止檔案名中帶空格
        String tempFileName = IdUtils.uuid() + ".pdf";
        try {
            File tempHtml = new File(tempPath + File.separator + "temp.html");
            fileoutputstream = new FileOutputStream(tempHtml);
            fileoutputstream.write(htmlContent.getBytes(StandardCharsets.UTF_8));
            StringBuilder cmd = new StringBuilder();
            cmd.append(ConfigUtils.getWkhtmltopdf()).append(space);
            //優先枚舉尺寸類型
            if (pageSize.getSize() != null) {
                cmd.append("--page-size").append(space).append(pageSize.getSize());
            } else {
                cmd.append("--page-width").append(space).append(pageSize.getWidth()).append(space)
                        .append("--page-height").append(space).append(pageSize.getHeight());
            }
            // 若PDF有圖檔标簽 下載下傳SRC路徑位址下的圖檔
            cmd.append(space).append("--image-quality 94");
            cmd.append(space).append(tempPath).append(File.separator).append("temp.html").append(space).append(savePath).append(File.separator).append(tempFileName);
            Runtime runtime = Runtime.getRuntime();
            Process proc = runtime.exec(cmd.toString());
            proc.waitFor();

            //修改檔案名
            File pdf = new File(savePath + File.separator + tempFileName);
            File newFile = new File(pdf.getParent() + File.separator + fileName);
            int i = 1;
            int index = fileName.lastIndexOf(".");
            String prefix = fileName.substring(0, index);
            String suffix = fileName.substring(index);
            while (newFile.exists()) {
                newFile = new File(pdf.getParent() + File.separator + prefix + '(' + i + ')' + suffix);
                i++;
            }
            if (!pdf.renameTo(newFile)) {
                throw new CustomException("檔案重命名失敗!");
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            if (fileoutputstream != null) {
                fileoutputstream.close();
            }
            //删除臨時檔案夾
            FileUtils.deleteDirectory(tempPath);
        }
    }
}