flying-saucer-pdf预览及下载

版权声明:本文为博主书香代码原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010138825/article/details/80732786

使用这个库的初衷

找阿里编程规范的时候在github上搜索到的,觉得pdf像书籍一样的翻页比较自由,也是手痒吧。
启发开源项目github-pdf-demo

国人的EditMD比较不错我弄了一个MarkDown写作

页面是自己凑凑的看一下图:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

pdf模板页面

<!DOCTYPE html>
<html>
<head lang="en">
    <title>${title} - PDF</title>
    <link href="http://localhost:8080/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
    <link href="http://localhost:8080/css/pdfPage.css" rel="stylesheet" type="text/css"/>
    <link href="http://localhost:8080/editormd/css/editormd.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: "Bamboo © 版权所有";
                font-family: SimSun;
                font-size: 12px;
                color: #000;
            };
            @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: SimSun;">
<div class="container">
        <div class="projects-header page-header">
            <h2 id="pdftitle" class="text-center" style=" width: 70%;">${title!获取标题失败}</h2>
            <p id="pdflen" class="text-center" style=" width: 70%;">字数:${len!'0'}</p>
        </div>
        <div class="row" style="white-space:normal;word-wrap:break-word;word-break:break-all;width: 70%;">${content!'获取内容失败'}
        </div>
    </div>
</body>
</html>

github项目工具类

package com.bamboo.markdown.paper.common;

import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import freemarker.template.Template;
import freemarker.template.TemplateException;
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;

/**
 * Created by admin on 2018/6/18.
 * ftl模板转pdf处理工具类
 */
public class FtlTransPdfUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(FtlTransPdfUtils.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);
            }
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            return builder.parse(new ByteArrayInputStream(stringWriter.toString().getBytes()));
        } 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) {
        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();
        try {
            fontResolver.addFont("typeface/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        } catch (DocumentException e) {
            LOGGER.error("S1DocumentException" + e.getMessage());
        } catch (IOException e) {
            LOGGER.error("S2IOException" + e.getMessage());
        }
        //展现和输出pdf
        renderer.layout();
        try {
            renderer.createPDF(out, false);
        } catch (DocumentException e) {
            LOGGER.error("S3DocumentException" + e.getMessage());
        }

        //根据参数集个数循环调用模板,追加到同一个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();
            try {
                renderer.writeNextDocument(); //写下一个pdf页面
            } catch (DocumentException e) {
                LOGGER.error("S4DocumentException" + e.getMessage());
            }
        }
        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 {
            response.setHeader("Content-Disposition", "attachment;fileName=" +
                    new String(fileName.getBytes("gb2312"), "ISO8859-1"));
        } catch (UnsupportedEncodingException e) {
            LOGGER.error("X1" + e.getMessage());
        }
        try (ServletOutputStream out = response.getOutputStream()) {
            generateAll(configurer, templateName, out, listVars);
            out.flush();
        } catch (Exception e) {
            LOGGER.error("X2" + e.getMessage());
            //X2java.io.IOException: 远程主机强迫关闭了一个现有的连接。
        }
    }

    /**
     * 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);
        }
    }
}

获取内容

package com.bamboo.markdown.paper.controller;

import com.bamboo.markdown.paper.common.FtlTransPdfUtils;
import com.bamboo.markdown.paper.entity.vo.ArticleView;
import com.bamboo.markdown.paper.repository.ArticleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.xml.sax.SAXException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by admin on 2018/6/18.
 */
@Controller
@RequestMapping(value = "/pdf")
public class PdfController {

    @Autowired
    private FreeMarkerConfigurer configurer;
    @Autowired
    private ArticleRepository articleRepository;

    /**
     * pdf预览
     *
     * @param request  HttpServletRequest
     * @param response HttpServletResponse
     */
    @RequestMapping(value = "/preview/{id}", method = RequestMethod.GET)
    public void preview(HttpServletRequest request, HttpServletResponse response, @PathVariable Integer id) throws IOException, SAXException {
        ArticleView articleView = new ArticleView(articleRepository.findById(id));
        // 构造freemarker模板引擎参数,listVars.size()个数对应pdf页数
        List<Map<String, Object>> listVars = new ArrayList<>();
        Map<String, Object> variables = new HashMap<>();
        variables.put("title", articleView.getTitle());
        //补充修正
        String htmlContent = articleView.getHtmlMaterial().replace("<br>", "<br/>");
        //匹配img标签的正则表达式
        String regxpForImgTag = "<img\\s[^>]+>";
        Pattern pattern = Pattern.compile(regxpForImgTag);
        Matcher matcher = pattern.matcher(htmlContent);
        StringBuffer sbr = new StringBuffer();
        while (matcher.find()) {
            String temp = matcher.group();
            matcher.appendReplacement(sbr, temp.replace(">", " />"));
        }
        matcher.appendTail(sbr);
        String htmlMaterial = sbr.toString();
        ////
        String regxpForImgTag2 = "<pre><code\\s[^>]+>";
        Pattern pattern2 = Pattern.compile(regxpForImgTag2);
        Matcher matcher2 = pattern2.matcher(htmlMaterial);
        StringBuffer sbr2 = new StringBuffer();
        while (matcher2.find()) {
            String temp2 = matcher2.group();
            matcher2.appendReplacement(sbr2, temp2.replace(
                    "<pre><code class=\"lang-java\">",
                    " <pre class=\"prettyprint linenums prettyprinted\" style=\"\"><code class=\"lang-java\">"));
        }
        matcher2.appendTail(sbr2);
        variables.put("content", sbr2.toString());
        variables.put("len", htmlMaterial.length());
        listVars.add(variables);
        //
        FtlTransPdfUtils.preview(configurer, "pdf/pdfPage.ftl", listVars, response);
    }

    /**
     * pdf下载
     *
     * @param request  HttpServletRequest
     * @param response HttpServletResponse
     */
    @RequestMapping(value = "/download/{id}", method = RequestMethod.GET)
    public void download(HttpServletRequest request, HttpServletResponse response, @PathVariable Integer id) {
        ArticleView articleView = new ArticleView(articleRepository.findById(id));
        List<Map<String, Object>> listVars = new ArrayList<>();
        Map<String, Object> variables = new HashMap<>();
        variables.put("title", articleView.getTitle());
        //补充修正
        String htmlContent = articleView.getHtmlMaterial().replace("<br>", "<br/>");
        //匹配img标签的正则表达式
        String regxpForImgTag = "<img\\s[^>]+>";
        Pattern pattern = Pattern.compile(regxpForImgTag);
        Matcher matcher = pattern.matcher(htmlContent);
        StringBuffer sbr = new StringBuffer();
        while (matcher.find()) {
            String temp = matcher.group();
            matcher.appendReplacement(sbr, temp.replace(">", " />"));
        }
        matcher.appendTail(sbr);
        String htmlMaterial = sbr.toString();
        ////
        String regxpForImgTag2 = "<pre><code\\s[^>]+>";
        Pattern pattern2 = Pattern.compile(regxpForImgTag2);
        Matcher matcher2 = pattern2.matcher(htmlMaterial);
        StringBuffer sbr2 = new StringBuffer();
        while (matcher2.find()) {
            String temp2 = matcher2.group();
            matcher2.appendReplacement(sbr2, temp2.replace(
                    "<pre><code class=\"lang-java\">",
                    " <pre class=\"prettyprint linenums prettyprinted\" style=\"\"><code class=\"lang-java\">"));
        }
        matcher2.appendTail(sbr2);
        variables.put("content", sbr2.toString());
        variables.put("len", htmlMaterial.length());
        listVars.add(variables);
        FtlTransPdfUtils.download(configurer, "pdf/pdfPage.ftl", listVars, response, articleView.getTitle() + ".pdf");
    }
}

资源文件图,字体在github那个项目获得

这里写图片描述

猜你喜欢

转载自blog.csdn.net/u010138825/article/details/80732786
今日推荐