zoukankan      html  css  js  c++  java
  • HtmlToPdfUtils [请参照码云上 https://gitee.com/bbevis/html-to-pdf 最新版]

    <!-- freemarker依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-freemarker</artifactId>
            </dependency>
    
            <!-- web基础依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
            </dependency>
    <!-- FlyingSaucer依赖
            https://mvnrepository.com/artifact/org.xhtmlrenderer/flying-saucer-pdf -->
            <dependency>
                <groupId>org.xhtmlrenderer</groupId>
                <artifactId>flying-saucer-pdf</artifactId>
                <version>9.1.12</version>
            </dependency>
    /*
     * 
     * 
     */
    package cn.com.utils;
    
    import com.lowagie.text.pdf.BaseFont;
    import freemarker.template.Template;
    import freemarker.template.TemplateException;
    import org.apache.commons.io.FileUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.util.CollectionUtils;
    import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
    import org.w3c.dom.Document;
    import org.xhtmlrenderer.pdf.ITextFontResolver;
    import org.xhtmlrenderer.pdf.ITextRenderer;
    
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletResponse;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import java.io.*;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 功能:pdf处理工具类
     *
     * @author qust
     * @version 1.0 2018/2/23 17:21
     */
    public class PdfUtils {
        private PdfUtils() {
        }
    
        private static final Logger LOGGER = LoggerFactory.getLogger(PdfUtils.class);
    
        /**
         * 按模板和参数生成html字符串,再转换为flying-saucer识别的Document
         *
         * @param templateName freemarker模板名称
         * @param variables    freemarker模板参数
         * @return Document
         */
        private static Document generateDoc(FreeMarkerConfigurer configurer, String templateName, Map<String, Object> variables)  {
            Template tp;
            try {
                tp = configurer.getConfiguration().getTemplate(templateName);
            } catch (IOException e) {
                LOGGER.error(e.getMessage(), e);
                return null;
            }
    
            StringWriter stringWriter = new StringWriter();
            try(BufferedWriter writer = new BufferedWriter(stringWriter)) {
                try {
                    tp.process(variables, writer);
                    writer.flush();
                } catch (TemplateException e) {
                    LOGGER.error("模板不存在或者路径错误", e);
                } catch (IOException e) {
                    LOGGER.error("IO异常", e);
                }
                DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

                  // 防止XXE攻击
                  String FEATURE = null;
                  FEATURE = "http://javax.xml.XMLConstants/feature/secure-processing";
                  documentBuilderFactory.setFeature(FEATURE, true);
                  FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
                  documentBuilderFactory.setFeature(FEATURE, false);
                  FEATURE = "http://xml.org/sax/features/external-parameter-entities";
                  documentBuilderFactory.setFeature(FEATURE, false);
                  FEATURE = "http://xml.org/sax/features/external-general-entities";
                  documentBuilderFactory.setFeature(FEATURE, false);
                  FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
                  documentBuilderFactory.setFeature(FEATURE, false);
                  documentBuilderFactory.setXIncludeAware(false);
                  documentBuilderFactory.setExpandEntityReferences(false);
                  // 防止XXE攻击

    
                DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
                byte[] bytes = stringWriter.toString().getBytes();
                try(ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes)) {
                    Document document = builder.parse(byteArrayInputStream);
                    return document;
                } catch (Exception e) {
                    LOGGER.error(e.getMessage(), e);
                    return null;
                }
            }catch (Exception e){
                LOGGER.error(e.getMessage(), e);
                return null;
            }
        }
    
        /**
         * 核心: 根据freemarker模板生成pdf文档
         *
         * @param configurer   freemarker配置
         * @param templateName freemarker模板名称
         * @param out          输出流
         * @param listVars     freemarker模板参数
         * @throws Exception 模板无法找到、模板语法错误、IO异常
         */
        private static void generateAll(FreeMarkerConfigurer configurer, String templateName, OutputStream out, List<Map<String, Object>> listVars) throws Exception {
            if (CollectionUtils.isEmpty(listVars)) {
                LOGGER.warn("警告:freemarker模板参数为空!");
                return;
            }
    
            ITextRenderer renderer = new ITextRenderer();
            Document doc = generateDoc(configurer, templateName, listVars.get(0));
            renderer.setDocument(doc, null);
            //设置字符集(宋体),此处必须与模板中的<body style="font-family: SimSun">一致,区分大小写,不能写成汉字"宋体"
            ITextFontResolver fontResolver = renderer.getFontResolver();
            //加载linux系统中文字体
            //fontResolver.addFontDirectory("/usr/share/fonts/chinese", BaseFont.NOT_EMBEDDED); 

    // 默认路径 srcmain esourcessimsun.ttf fontResolver.addFont("simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); //展现和输出pdf renderer.layout(); renderer.createPDF(out, false); //根据参数集个数循环调用模板,追加到同一个pdf文档中 //(注意:此处从1开始,因为第0是创建pdf,从1往后则向pdf中追加内容) for (int i = 1; i < listVars.size(); i++) { Document docAppend = generateDoc(configurer, templateName, listVars.get(i)); renderer.setDocument(docAppend, null); renderer.layout(); renderer.writeNextDocument(); //写下一个pdf页面 } renderer.finishPDF(); //完成pdf写入 } /** * pdf下载 * * @param configurer freemarker配置 * @param templateName freemarker模板名称(带后缀.ftl) * @param listVars 模板参数集 * @param response HttpServletResponse * @param fileName 下载文件名称(带文件扩展名后缀) */ public static void download(FreeMarkerConfigurer configurer, String templateName, List<Map<String, Object>> listVars, HttpServletResponse response, String fileName) { // 设置编码、文件ContentType类型、文件头、下载文件名 response.setCharacterEncoding("utf-8"); response.setContentType("multipart/form-data"); try { String finalFileName = ""; if(StringUtils.isNotBlank(fileName)) { finalFileName = new String(fileName.getBytes("gb2312"), "ISO8859-1"); } if(StringUtils.isBlank(finalFileName)) { throw new RuntimeException("下载文件名fileName为空!"); } response.setHeader("Content-Disposition", "attachment;fileName=" + finalFileName); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } try (ServletOutputStream out = response.getOutputStream()) { generateAll(configurer, templateName, out, listVars); out.flush(); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } } /** * pdf预览 * * @param configurer freemarker配置 * @param templateName freemarker模板名称(带后缀.ftl) * @param listVars 模板参数集 * @param response HttpServletResponse */ public static void preview(FreeMarkerConfigurer configurer, String templateName, List<Map<String, Object>> listVars, HttpServletResponse response) { try (ServletOutputStream out = response.getOutputStream()) { generateAll(configurer, templateName, out, listVars); out.flush(); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } } /** * pdf转换为File * * @param configurer freemarker配置 * @param templateName freemarker模板名称(带后缀.ftl) * @param listVars 模板参数集 * @param file file */ public static void toFile(FreeMarkerConfigurer configurer, String templateName, List<Map<String, Object>> listVars, File file) { try (OutputStream out = FileUtils.openOutputStream(file)) { generateAll(configurer, templateName, out, listVars); out.flush(); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } } }
    package cn.com.utils;
    
    import org.apache.pdfbox.pdmodel.PDDocument;
    import org.apache.pdfbox.rendering.PDFRenderer;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import javax.imageio.ImageIO;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    
    public class PDFToImgUtil {
        private static Logger logger = LoggerFactory.getLogger(PDFToImgUtil.class);
    
    
        /**
         * 获取PDF总页数
         * @throws IOException
         */
        public static int getPDFNum(String fileUrl) throws IOException {
            PDDocument pdDocument = null;
            int pages = 0;
            try {
                pdDocument = getPDDocument(fileUrl);
                pages = pdDocument.getNumberOfPages();
            } catch (Exception e) {
                e.printStackTrace();
                logger.error(e.getMessage(),e);
            } finally {
                if (pdDocument != null) {
                    pdDocument.close();
                }
            }
            return pages;
        }
    
    
        /**
         * PDF转图片 根据页码一页一页转
         * @throws IOException
         * imgType:转换后的图片类型 jpg,png
         */
        public static void PDFToImg(OutputStream sos, String fileUrl, int page, String imgType) throws IOException {
            PDDocument pdDocument = null;
            /* dpi越大转换后越清晰,相对转换速度越慢 */
            int dpi = 100;
            try {
                pdDocument = getPDDocument(fileUrl);
                PDFRenderer renderer = new PDFRenderer(pdDocument);
                int pages = pdDocument.getNumberOfPages();
                if (page <= pages && page > 0) {
                    BufferedImage image = renderer.renderImageWithDPI(page,dpi);
                    ImageIO.write(image, imgType, sos);
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.error(e.getMessage(),e);
            } finally {
                if (pdDocument != null) {
                    pdDocument.close();
                }
            }
    
        }
        /**
         * 转换全部的pdf
         * @param fileAddress 文件地址
         * @param filename PDF文件名
         * @param type 图片类型
         */
        public static void pdf2png(String fileAddress,String filename,String type,int pageCount) {
            // 将pdf装图片 并且自定义图片得格式大小
            File file = new File(fileAddress + "\" + filename + ".pdf");
            try {
                PDDocument doc = PDDocument.load(file);
                PDFRenderer renderer = new PDFRenderer(doc);
                for (int i = 0; i < pageCount; i++) {
                    BufferedImage image = renderer.renderImageWithDPI(i, 140); // Windows native DPI
                    // BufferedImage srcImage = resize(image, 240, 240);//产生缩略图
                    ImageIO.write(image, type, new File(fileAddress + "\" + filename + "_" + (i + 9) + "." + type));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        private static PDDocument getPDDocument(String fileUrl) throws IOException {
            File file = new File(fileUrl);
            FileInputStream inputStream = new FileInputStream(file);
            return PDDocument.load(inputStream);
        }
    
    
    }
    /*
     *
     * 
     */
    package com.controller;
    
    import com.Utils.PdfUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 功能:pdf预览、下载
     *
     * @author 
     * @version 
     */
    @Controller
    @RequestMapping(value = "/pdf")
    public class PdfController {
    
        @Autowired
        private FreeMarkerConfigurer configurer;
    
        /**
         * pdf预览
         *
         * @param request  HttpServletRequest
         * @param response HttpServletResponse
         */
        @RequestMapping(value = "/preview", method = RequestMethod.GET)
        public void preview(HttpServletRequest request, HttpServletResponse response) {
            // 构造freemarker模板引擎参数
            List<Map<String,Object>> listVars = new ArrayList<>();
            Map<String,Object> variables = new HashMap<>();
            variables.put("userName","小明");
            listVars.add(variables);
    // 默认路径 srcmain esources emplatese-prop-pdf.ftl PdfUtils.preview(configurer,
    "e-prop-pdf.ftl",listVars,response); } /** * pdf下载 * * @param request HttpServletRequest * @param response HttpServletResponse */ @RequestMapping(value = "/download", method = RequestMethod.GET) public void download(HttpServletRequest request, HttpServletResponse response) { List<Map<String,Object>> listVars = new ArrayList<>(); Map<String,Object> variables = new HashMap<>(); variables.put("title","测试下载ASGX!"); listVars.add(variables);
    // 默认路径 srcmain esources emplatese-prop-pdf.ftl PdfUtils.download(configurer,
    "e-prop-pdf.ftl",listVars,response,"测试.pdf"); } }
    <!DOCTYPE html>
    <html>
    <head lang="en">
        <title>Spring Boot Demo - PDF</title>
        <link href="http://localhost:8999/css/index.css" rel="stylesheet" type="text/css"/>
        <link href="http://localhost:8999/css/pdf.css" rel="stylesheet" type="text/css"/>
        <style>
            @page {
                size: 210mm 297mm; /*设置纸张大小:A4(210mm 297mm)、A3(297mm 420mm) 横向则反过来*/
                margin: 0.25in;
                padding: 1em;
                @bottom-center{
                    content:"XXXXX © 版权所有";
                    font-family: SimSun;
                    font-size: 12px;
                    color:red;
                };
                @top-center { content: element(header) };
                @bottom-right{
                    content:"第" counter(page) "页  共 " counter(pages) "页";
                    font-family: SimSun;
                    font-size: 12px;
                    color:#000;
                };
            }
        </style>
    </head>
    <#-- 这样配置不中文不会显示 -->
    <#--<body style="font-family: 宋体">-->
    <body style="font-family: 'SimSun'">
    <div>1.标题-中文</div>
    <h2>${title}</h2>
    
    <div>2.按钮:按钮的边框需要写css渲染</div>
    <button class="a" style="border: 1px solid #000000"> click me t-p</button>
    <div id="divsub"></div>
    
    <div>3.普通div</div>
    <div id="myheader">Alice's Adventures in Wonderland</div>
    
    <div>4.图片 绝对定位到左上角(注意:图片必须用全路径或者http://开头的路径,否则无法显示)</div>
    <div id="signImg"></div>
    
    <div>5.普通table表格</div>
    <div>
        <table>
            <tr>
                <td>1</td>
                <td>2</td>
                <td>2</td>
                <td>2</td>
                <td>2</td>
            </tr>
            <tr>
                <td>1</td>
                <td>2</td>
                <td>2</td>
                <td>2</td>
                <td>2</td>
            </tr>
            <tr>
                <td>1</td>
                <td>2</td>
                <td>2</td>
                <td>2</td>
                <td>2</td>
            </tr>
        </table>
    
    </div>
    
    <div>6.input控件,边框需要写css渲染 (在模板中一般不用input,因为不存在输入操作)</div>
    <div>
        <label>姓名:</label>
        <input id="input1" aria-label="dasdasd" type="text" value="123你是"/>
    </div>
    </body>
    </html>
    .trialPresentation .pdfContent .clientLetter {
          height: 42px;
          line-height: 42px;
          background: url(data:image/png;base64,iVBORw0KGgoAAAA...=) center no-repeat;
          border-radius: 21px;
          font-size: 22px;
          margin: 0 auto;
          color: #fff;
          width: 240px;
          text-align: center;
          position: relative;
        }
    /*解决自动分页  分页符在元素上 造成样式错乱问题*/
    div {page-break-after:auto;}
  • 相关阅读:
    sqlalchemy访问Oracle数据库报错:UnicodeDecodeError: 'big5' codec can't decode byte 0xfb in position 2: illegal multibyte sequence
    Mac如何安装FastDfs
    Django执行Sql语句笔记
    跑DRF框架分页源码笔记
    Python Paginator分页学习
    Python Excel笔记
    npm run dev报错解决方法
    npm install --global vue-cli 报错 [..................] / rollbackFailedOptional: verb npm-session abfa82f3041ebc02
    MS17_010漏洞攻击Windows7
    虚拟机启动黑屏
  • 原文地址:https://www.cnblogs.com/bevis-byf/p/12432952.html
Copyright © 2011-2022 走看看