zoukankan      html  css  js  c++  java
  • freemarker动态生成word并将生成的word转为PDF,openoffice转换word乱码

    之前项目有个需求,需要先动态生成word内容,然后再预览生成word的内容(不能修改).整理一下,方便以后使用.

    网上参考了好多大神的博客.具体也忘了参考谁的了,如有侵权,请告知修改.

    思路一:

    将目标word文件另存为xml文件,将里面的需要动态生成的内容用freemarker的表达式${}替换.

    用freemarker生成word的工具类,动态生成word. 这样生成的word实际上是xml文件,用办公软件能正常打开使用.

    但是转PDF的时候发现转不成功.转过之后的PDF显示的不是word的格式字符,而是像xml文件的标签及字符,失败!

    思路二:

    word的docx文件其实属于zip的一种. 这里只需要对它的核心内容部分进行操作.其他数据不动.具体做法为:

    1.用办公软件(wps/office)打开模板文件,将需要修改的内容,用freemarker的表达式${}替换.

    (注意:需要循环展示的内容还需要在xml文件中处理)如下:

     

    2.将模板docx文件重命名为.zip的压缩文件.

    3.用解压工具打开,取出word/document.xml 文件.

     

    4.此时用文本工具打开document.xml,内容不太好看,将文件格式化一下.(我这里没找到好的格式化工具,使用notepad没格好,最后用idea还行).格式化后如下.

     

    5.在xml中需要循环的内容前增加如下标签:

     

    6.说明

    word中要填充的数据为map格式,${}中为map的key.如果还需要循环填充可以如下操作:

    map1   map2   list

    map1.put("userName",name);

    list.add(map1);

    map2.put("list",list);

    map2.put("title",title);

    map2即为要填充的所有数据.这样给list一个别名listKey 后,${}中如下填写即可.

     

    7.将模板文件与xml文件保存到一个固定位置.我这里保存到了项目中:

     

    8.准备工作完成,生成word工具类如下:

    import freemarker.template.TemplateException;

    import java.io.*;
    import java.util.Enumeration;
    import java.util.Map;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipException;
    import java.util.zip.ZipFile;
    import java.util.zip.ZipOutputStream;

    /**
    * 其实docx属于zip的一种,这里只需要操作word/document.xml中的数据,其他的数据不用动
    *
    * @author
    *
    */
    public class XmlToDocx {

    /**
    *
    * @param xmlTemplate xml的文件名
    * @param docxTemplate docx的路径和文件名
    * @param xmlTemp 填充完数据的临时xml
    * @param toFilePath 目标文件名
    * @param map 需要动态传入的数据
    * @throws IOException
    * @throws TemplateException
    */
    public static void toDocx(String xmlTemplate,String docxTemplate,String xmlTemp ,String toFilePath,Map map) {
    try {
    // 1.map是动态传入的数据
    // 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
    Writer w1 = new OutputStreamWriter(new FileOutputStream(xmlTemp), "gb2312");
    // 2.把map中的数据动态由freemarker传给xml
    XmlTplUtil.process(xmlTemplate, map, w1);
    // 3.把填充完成的xml写入到docx中
    XmlToDocx xtd = new XmlToDocx();
    xtd.outDocx(new File(xmlTemp), docxTemplate, toFilePath);
    }catch (Exception e) {
    e.printStackTrace();
    }
    }
    /**
    *
    * @param documentFile 动态生成数据的docunment.xml文件
    * @param docxTemplate docx的模板
    * @param toFilePath 需要导出的文件路径
    * @throws ZipException
    * @throws IOException
    */

    public void outDocx(File documentFile, String docxTemplate, String toFilePath) throws ZipException, IOException {

    try {
    File docxFile = new File(docxTemplate);
    ZipFile zipFile = new ZipFile(docxFile);
    Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
    ZipOutputStream zipout = new ZipOutputStream(new FileOutputStream(toFilePath));
    int len = -1;
    byte[] buffer = new byte[1024];
    while (zipEntrys.hasMoreElements()) {
    ZipEntry next = zipEntrys.nextElement();
    InputStream is = zipFile.getInputStream(next);
    // 把输入流的文件传到输出流中 如果是word/document.xml由我们输入
    zipout.putNextEntry(new ZipEntry(next.toString()));
    if ("word/document.xml".equals(next.toString())) {
    InputStream in = new FileInputStream(documentFile);
    while ((len = in.read(buffer)) != -1) {
    zipout.write(buffer, 0, len);
    }
    in.close();
    } else {
    while ((len = is.read(buffer)) != -1) {
    zipout.write(buffer, 0, len);
    }
    is.close();
    }
    }
    zipout.close();

    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    9.生成PDF工具类


    import com.artofsolving.jodconverter.DocumentConverter;
    import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection;
    import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;
    import com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter;
    import org.apache.poi.xwpf.converter.pdf.PdfConverter;
    import org.apache.poi.xwpf.converter.pdf.PdfOptions;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;

    import java.io.*;


    public class XMlToDoc {

    /**
    * 生成pdf
    */
    public static String makePdfByXcode(String docx) {
    String filename = null;
    File outFile = null;
    try {

    // document.setParagraph(new Pa );
    if (docx.contains(".docx")) {
    XWPFDocument document=new XWPFDocument(new FileInputStream(new File(docx)));
    outFile=new File(docx.replace(".docx",".pdf"));
    filename=docx.replace(".docx",".pdf");

    outFile.getParentFile().mkdirs();
    OutputStream out=new FileOutputStream(outFile);
    // IFontProvider fontProvider = new AbstractFontRegistry();
    PdfOptions options= PdfOptions.create(); //gb2312
    PdfConverter.getInstance().convert(document,out,options);

    } else {
    File inputFile = new File(docx);
    outFile = new File(docx.replace(".doc", ".pdf"));
    filename = docx.replace(".doc", ".pdf");
    outFile.getParentFile().mkdirs();

    OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);
    connection.connect();

    // convert
    DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
    converter.convert(inputFile, outFile);

    // close the connection
    connection.disconnect();
    }


    }catch (IllegalArgumentException e){
    System.err.println("未知文件格式");
    }
    catch (Exception e) {
    e.printStackTrace();
    }
    return filename;

    }


    }
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    import freemarker.template.TemplateException;

    import java.io.File;
    import java.io.IOException;
    import java.io.Writer;
    import java.util.Map;

    public class XmlTplUtil {

    private static XmlTplUtil tplm = null;
    private Configuration cfg = null;

    private XmlTplUtil() {
    cfg = new Configuration();
    try {
    // 注册tmlplate的load路径
    // 这的路径是xml的路径
    String pathName = XmlTplUtil.class.getClassLoader().getResource("").getPath();
    String path = pathName.substring(1, pathName.lastIndexOf("/"));
    String parentPath1 = new File(path).getParent();//获取项目的上一级目录
    String parentPath2 = new File(parentPath1).getParent();//获取项目的上一级目录
    String xmlPath = parentPath2 + "/static/excelModel";
    cfg.setDirectoryForTemplateLoading(new File(xmlPath));
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    private static Template getTemplate(String name) throws IOException {
    if (tplm == null) {
    tplm = new XmlTplUtil();
    }
    Template template = tplm.cfg.getTemplate(name);
    return template;
    }

    /**
    *
    * @param templatefile 模板文件
    * @param param 需要填充的内容
    * @param out 填充完成输出的文件
    * @throws IOException
    * @throws TemplateException
    */
    public static void process(String templatefile, Map param, Writer out) throws IOException, TemplateException {
    // 获取模板
    Template template = XmlTplUtil.getTemplate(templatefile);
    template.setOutputEncoding("GBK");
    // 合并数据
    template.process(param, out);
    if (out != null) {
    out.close();
    }
    }
    }
    注意:生成PDF需要安装openoffice 软件,安装完成后,

    cd openoffice目录下有个OpenOffice 4program

    然后输入命令

      soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard 

    就ok了.

    10.用到的maven包

    <dependency>
    <groupId>com.artofsolving</groupId>
    <artifactId>jodconverter</artifactId>
    <version>2.2.1</version>
    </dependency>
    <!--openoffice-->
    <dependency>
    <groupId>org.openoffice</groupId>
    <artifactId>jurt</artifactId>
    <version>3.0.1</version>
    </dependency>
    <dependency>
    <groupId>org.openoffice</groupId>
    <artifactId>ridl</artifactId>
    <version>3.0.1</version>
    </dependency>
    <dependency>
    <groupId>org.openoffice</groupId>
    <artifactId>juh</artifactId>
    <version>3.0.1</version>
    </dependency>
    <dependency>
    <groupId>org.openoffice</groupId>
    <artifactId>unoil</artifactId>
    <version>3.0.1</version>
    </dependency>
    <dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
    <version>1.0.6</version>
    </dependency>
    <dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.22</version>
    </dependency>
    ---------------------
    作者:菜鸟-也-想飞
    来源:CSDN
    原文:https://blog.csdn.net/qq_21306669/article/details/84313569

    注意:springboot打成jar无法放入webapp下生成,

  • 相关阅读:
    Linux环境下安装python3
    软件测试类型
    系统测试分类
    测试级别
    测试对象的介绍
    软件测试基本介绍
    简易留言板(还有一些小bug,修复ing...)
    Hosting static website on AWS
    Add a dependency in Android Studio
    Python good tutorials
  • 原文地址:https://www.cnblogs.com/liran123/p/10772357.html
Copyright © 2011-2022 走看看