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将图片插入到指定位置中,这也是可以实现的

  • 相关阅读:
    项目外部 property文件使用方法
    java JsonArray统一添加key
    java发送Http请求
    excel数据追加,java实现
    request.getParameter("name")获取参数为null和""空字符串的区别
    maven 配置jetty插件启动 及简单测试
    左右值编码实现树状存储
    Spring将classpath下的 .properties文件数据读出放到map中,在初始化时加载
    Ubuntu简单配置
    java.io.Serializable浅析
  • 原文地址:https://www.cnblogs.com/LeachBlog/p/12738642.html
Copyright © 2011-2022 走看看