zoukankan      html  css  js  c++  java
  • Java生成pdf,兼富文本

    Java生成pdf,兼容富文本内容

     

    使用技术,freemark + jsoup + flying saucer 

    使用freemark替换模板文件中指定的占位符,生成一个完整的的html字符串,

    使用jsoup对html进行格式化,

    使用flying saucer 将整个html进行pdf转换(flying saucer对css的支持不是很完整,存在连续中文换行问题,需要在转换的时候特殊处理)

     

    1. maven地址

    <!--freemarker-->

    <!--https://mvnrepository.com/artifact/org.freemarker/freemarker-->

    <dependency>

      <groupId>org.freemarker</groupId>

      <artifactId>freemarker</artifactId>

      <version>2.3.23</version>

    </dependency>

    <!--JavaHTMLParser-->

    <!--https://mvnrepository.com/artifact/org.jsoup/jsoup-->

    <dependency>

      <groupId>org.jsoup</groupId>

      <artifactId>jsoup</artifactId>

      <version>1.10.2</version>

    </dependency>

     

    <dependency>

      <groupId>org.xhtmlrenderer</groupId>

      <artifactId>flying-saucer-pdf</artifactId>

      <version>9.0.8</version>

    </dependency>

     

    <dependency>

      <groupId>org.xhtmlrenderer</groupId>

      <artifactId>flying-saucer-pdf-itext5</artifactId>

      <version>9.1.5</version>

    </dependency>

     

    1. 模板文件生成
      1. 先将wrod的格式内容定义好,如果需要插入参数的地方以${xxx}为表示,例:${product}

    模板例子:

     

     

        2. 将word文档另存为 “筛选过的网页(*.htm;*.html)” 的文件,打开该文件检查每个变量(${product})是否完整,有可能在${}中出现其他代码,需要删除。

        3. 检查文件没问题之后,将文件改成后缀为ftl的文件,引入到项目中,和生成的word的模板文件不同,html模板不需要引入图片字段占位符,html可以直接通过img标签展示图片

      2. 获取模板文件,生成html

        freemark获取模板

        下面这种方式能获取模板,但是在项目打包之后无法获取jar包内的文件

          Configuration configuration=newConfiguration(Configuration.getVersion());

          configuration.setDefaultEncoding(StandardCharsets.UTF_8.toString());

          configuration.setDirectoryForTemplateLoading(newFile(templatePath));

          Template template=configuration.getTemplate("xxx.ftl");

     

        通过流的形式直接创建模板对象

          Configuration configuration=newConfiguration(Configuration.getVersion());

          configuration.setDefaultEncoding(StandardCharsets.UTF_8.toString());

          configuration.setDirectoryForTemplateLoading(newFile(templatePath));

          InputStream inputStream=newFileInputStream(newFile(templatePath+"/"+templateName));

          InputStreamReader inputStreamReader=newInputStreamReader(inputStream,StandardCharsets.UTF_8);

          Template template=newTemplate("xxx.ftl",inputStreamReader,configuration);

     

     

    1. 通过template替换ftl中的占位符,再将结果写入字符流中,返回结果字符串

        dataMap为Map格式,占位符为key,结果值为value

     

        StringWriter stringWriter = new StringWriter();

        BufferedWriter wirter = new BufferedWriter(stringWriter);

        template.process(dataMap,writer);

        return writer.toString();

     

    1. flying saucer对html有严格的检查,必须要以<a></a>的形式存在,使用 jsoup 对html进行格式化操作

        Document doc = Jsoup.parse(htmlStr);

        Elements imageElements = doc.select("img");

        For(Element ele : Elements  ) {    

          …

        }

     

    Jsoup对html有很好的支持,可以对一些代码添加、修改样式。

    flying saucer 是基于Itext的包,itext存在连续中文不换行的问题,可以通过 jsoup 修改所有的文字,在文字后面加上空格,这样就能修复无法自动换行的问题

     

    1. 加载中文字体

        flying saucer 不支持中文,需要加载中文字体。

        在ftl的模板文件中的body标签引入字体

        例: <body  style="font-family:'Arial Unicode MS'">

     

      在代码中字体文件:

     

        ITextRenderer renderer = new ITextRenderer();

     

        // mac

        renderer .getFontResolver().addFont("/library/fonts/Arial Unicode.ttf",  BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);    

     

        // linux:

        renderer .getFontResolver().addFont("/usr/share/fonts/TTF/ARIALUNI.TTF",   BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);     

     

         // windows:

        renderer .getFontResolver().addFont("C:/Windows/Fonts/ARIALUNI.TTF",     BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);   

     

      在项目中文字可以放在项目目录里面  

        ClassPathResource resource = new ClassPathResource("ARIALUNI.TTF");

        renderer .getFontResolver().addFont(resource.getPath(),  BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);     

     

     

     

     

      源码如下:

     

     

    <<CreateHtmlByFreemarker.java>>

    package org.java.export.plugin.example;

    import java.io.*;
    import java.util.HashMap;
    import java.util.Map;

    import freemarker.core.ParseException;
    import freemarker.template.Configuration;
    import freemarker.template.MalformedTemplateNameException;
    import freemarker.template.Template;
    import freemarker.template.TemplateException;
    import freemarker.template.TemplateNotFoundException;

    public class CreateHtmlByFreemarker {


    public static void main(String[] args) {
    String str = getHtmlStr();
    System.out.println(str);
    }

    public static String getHtmlStr(){
    // step1 创建freeMarker配置实例
    Configuration configuration = new Configuration();
    StringWriter stringWriter = new StringWriter();
    BufferedWriter writer = new BufferedWriter(stringWriter);
    try {
    // step2 获取模版路径
    String templatePath = Class.class.getResource("/ftl").getPath();
    templatePath = java.net.URLDecoder.decode(templatePath,"utf-8");//这里我的路径有空格添加此处理
    configuration.setDirectoryForTemplateLoading(new File(templatePath));
    StringBuilder sb = new StringBuilder();
    sb.append("<div>");
    sb.append("<img style='height:100px;200px;display:block;' src='https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2534506313,1688529724&fm=26&gp=0.jpg' />");
    sb.append("</br><span>wesley 演示 导出富文本!@@#######¥¥%%%%………………&&&**~~~~~~&&&&&&&&、、、、、、、、</span>");
    sb.append("</br><span>----多图分割线---</span>");
    sb.append("<img style='height:100px;200px;display:block;' src='https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2534506313,1688529724&fm=26&gp=0.jpg' />");
    sb.append("</br><span>中国梦,幸福梦!</span>");
    sb.append("</div>");
    sb.append("<table style='border: 0.5px solid #000' border='0' cellspacing='0' cellpadding='0'>");
    sb.append("<tr>");
    sb.append(" <th style='border: 0.5px solid #000'>Month</th>");
    sb.append("<th style='border: 0.5px solid #000'>Savings</th>");
    sb.append("</tr>");
    sb.append("<tr>");
    sb.append("<td style='border: 0.5px solid #000'>January</td>");
    sb.append("<td style='border: 0.5px solid #000'>$100</td>");
    sb.append("</tr>");
    sb.append("</table>");

    // step3 创建数据模型
    Map<String, Object> dataMap = new HashMap<String, Object>();
    dataMap.put("name", "wesley");
    dataMap.put("datetime","2017-05-10");
    dataMap.put("title","演示demo");
    dataMap.put("context1", sb.toString());
    dataMap.put("context2", sb.toString());
    dataMap.put("context3", sb.toString());
    dataMap.put("context4", sb.toString());
    dataMap.put("context5", sb.toString());
    dataMap.put("context6", sb.toString());
    // step4 加载模版文件
    Template template = configuration.getTemplate("title.ftl");
    // step5 生成数据
    template.process(dataMap, writer);
    String htmlStr = stringWriter.toString();
    System.out.println("^^^^^^^^^^^^^^^^^^^^^^^^user.ftl 文件创建成功 !");
    return htmlStr;
    } catch (Exception e) {
    e.printStackTrace();
    }
    return null;
    }

    }

     

      <<CreatePDFByHtml.java>>

      

    package org.java.export.plugin.example;

    import com.itextpdf.text.pdf.BaseFont;
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    import org.jsoup.select.Elements;
    import org.xhtmlrenderer.pdf.ITextFontResolver;
    import org.xhtmlrenderer.pdf.ITextRenderer;

    import java.io.*;

    public class CreatePDFByHtml {

    public static void main(String[] args) throws IOException {
    String pdfPath = "/Users/liqi/Desktop/1.pdf";
    String htmlFilePath = "/Users/liqi/Desktop/1586671323385.html";
    createPDFByHtml( pdfPath,htmlFilePath);
    }

    /**
    * 该方法用来将指定的word文件转换成pdf文件(使用flying saucer技术)
    * @param pdfPath:生成后的pdf所在目录,包括目录+pdf名称+.+pdf
    * @param htmlFilePath:需要进行转换的html文件所在目录,包括目录+html名称+.+html
    * */
    public static boolean createPDFByHtml(String pdfPath, String htmlFilePath){
    boolean result = false;
    //1、判断给定的文件是否是html文件:是htm格式结尾,或者以html格式结尾
    if(htmlFilePath.toUpperCase().endsWith(".HTM") ||
    htmlFilePath.toUpperCase().endsWith(".HTML")){//两种格式都是扫描文件格式
    try {
    OutputStream os = new FileOutputStream(pdfPath);
    ITextRenderer renderer = new ITextRenderer();
    String str = CreateHtmlByFreemarker.getHtmlStr();
    System.out.println(str);
    System.out.println("--------------=============");
    Document doc = Jsoup.parse(str);

    System.out.println(doc.html());
    Elements elements = doc.select("img");
    int i=0;
    for (Element element : elements){
    element.attr("id",i+"");
    i++;
    }


    String content=doc.html();
    content = content.replace("&nbsp;","&#160;");
    content = content.replace("<meta http-equiv="Content-Type" content="text/html; charset=utf-8">","<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>");
    content = content.replace("(filtered)">","(filtered)"></meta>");
    content = content.replaceAll("<br>","<br></br>");
    for (Element element : elements){
    String startStr = element.outerHtml();
    String endStr = element.outerHtml()+"</img>";
    content = content.replace(startStr,endStr);
    }


    ITextFontResolver fontResolver = renderer.getFontResolver();

    // fontResolver.addFont("/Users/liqi/ideaWorkspace/java-export-word-plugin-master/PluginExample/src/main/resources/ftl/simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
    //fontResolver.addFont("/Users/liqi/ideaWorkspace/java-export-word-plugin-master/PluginExample/src/main/resources/ftl/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);



    /* // mac
    fontResolver.addFont("/library/fonts/Arial Unicode.ttf",
    BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

    // linux:
    fontResolver.addFont("/usr/share/fonts/TTF/ARIALUNI.TTF",
    BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

    // windows:
    fontResolver.addFont("C:/Windows/Fonts/ARIALUNI.TTF",
    BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); */


    // 解决中文支持问题
    fontResolver.addFont("/library/fonts/Arial Unicode.ttf",
    BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

    renderer.setDocumentFromString(content);

    renderer.layout();
    renderer.createPDF(os);
    os.close();
    result = true;
    } catch (Exception e) {
    result = false;
    e.printStackTrace();
    }
    }else{
    result = false;
    }
    return result ;
    }
    }

     

    还有另一种方案也能实现该功能

    使用Itext绘制pdf表格,前端使用canvas将富文本生成图片,在使用IText将图片插入到指定位置中,这也是可以实现的

  • 相关阅读:
    Shared Memory in Windows NT
    Layered Memory Management in Win32
    软件项目管理的75条建议
    Load pdbs when you need it
    Stray pointer 野指针
    About the Rebase and Bind operation in the production of software
    About "Serious Error: No RTTI Data"
    Realizing 4 GB of Address Space[MSDN]
    [bbk4397] 第1集 第一章 AMS介绍
    [bbk3204] 第67集 Chapter 17Monitoring and Detecting Lock Contention(00)
  • 原文地址:https://www.cnblogs.com/LeachBlog/p/12738642.html
Copyright © 2011-2022 走看看