openxml文书工具 Aspose 工具 word to pdf

aspose模板生成(文书工具)

动态数据

${info}
${list.id}
${list.name}
${list.address}
${list.date}
${list.danwei}
${list.number}
${list.remark}
${imgBase64}
${xw.ask}
${xw.ans}

格式

openxml
openxml
openxml

大坑:!!!!
word转xml记得转这种格式:Word XML文档(xml)

图片

存图片 先用一个照片作为占位符,然后去xml中将那一段base64 代替掉 ${imgBase64}
<pkg:part pkg:name="/word/media/image1.png" pkg:contentType="image/png">
pkg:binaryData${imgBase64}</pkg:binaryData>
</pkg:part>
但是word中保存图片文件的标签必须要连着写,不能出现换行或者空白,否则就会出现找不到图片的问题

图片的大小也是可以动态设置的 ${xxx}

遍历list

使用list遍历 (可以用来遍历生成表格,或者问答形式也可以)
只需要 在外面嵌套一层标签
<#list lists(参数) as list>
xxxxxx${list.id}xxxxxxxxxxxx${list.name}
</#list>

页脚

只在最后一页添加页脚、解决方式:
在指定位置加上一个文本框,然后给他设置为 上下环绕型、不允许重叠、然后把边框改为无边框即可



如果生成的pdf格式不对,或者多了一些字一些横线,就去xml中删除即可
删除这几个标签 endnotes 、、 footnotes 这两个是结尾多出来的横线
另一种情况:可能是因为页眉生成了横线,去xml中删除 head 标签

符号

一些特殊符号
https://www.jb51.cc/xml/541196.html

复选框

关于复选框 xxx = 1 就是选中 xxx = 0 就是未选中 这里直接传值就可以了 ${checked} (如果出现xml选中后是R或其他而不是显示√ 可以先在word中打钩先然后去xml给0)
w14:checkbox
<w14:checked w14:val= "${checked}"/>
<w14:checkedState w14:val="2612" w14:font="MS Gothic"/>
<w14:uncheckedState w14:val="2610" w14:font="MS Gothic"/>
</w14:checkbox>


集成SpringBoot中

相关依赖

<!--xml数据填充所需依赖 author: mao-->
<dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>1.6.1</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!--这里需要引入外部的包 maven仓库没有 存在resources下的lib包下-->
<dependency>
    <groupId>com.aspose.words</groupId>
    <artifactId>aspose-words-jdk16</artifactId>
    <version>15.8.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/src/main/resources/lib/aspose-words-jdk16-15.8.0.jar</systemPath>
</dependency>

Aspose Jar包下载:

蓝奏云:https://wwzv.lanzoue.com/iK7eu0t8twti
密码:1736

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.1.1.RELEASE</version>
    <configuration>
        <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
        <includeSystemScope>true</includeSystemScope> <!-- 引入外部的jar包 -->
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

true

DocToPdf

package com.nongyeservice.paper.utils;

import com.aspose.words.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.Base64;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author mao
 * @program paperUtil
 * @description word转pdf核心代码
 * @description aspose文书工具所需参数(新文书工具)
 * @createDate 2023-03-23 16:50:05
 **/
@Component
@Slf4j
public class DocToPdf {

    /**
     * 模板文件存放的路径(绝对路径哈)
     */
    @Value("${aspose.defaultTemplatePath}")
    public String baseUrl;

    // private String baseUrl2 = System.getProperty("java.io.tmpdir");

    @Autowired
    XmlToDocx xmlToDocx;


    public boolean getLicense() {
        boolean result = false;
        try {
            // aspose需要的签名文件名称
            InputStream is = DocToPdf.class.getClassLoader().getResourceAsStream("license.xml");
            // InputStream is = new FileInputStream(path);
            License aposeLic = new License();
            aposeLic.setLicense(is);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * @param params       需要填充的数据
     * @param templateName 模板的文件名
     * @param savePdfName  最后保存的pdf文件 可以用 文书名+文书业务id 来命名
     * @return 最后生成的文书pdf文件保存路径
     * @throws Exception
     */
    public String doDocToPdf(Map<String, Object> params, String templateName, String savePdfName){
        try {
            if (!getLicense()) { // 验证License 若不验证则转化出的pdf文档会有水印产生
                return null;
            }
            // String templateUUId = UUID.randomUUID().toString();
            String xml = baseUrl + savePdfName + ".xml";
            String docx = baseUrl + savePdfName + ".docx";
            // XmlToDocx.toDocx(documentXmlName, docTemplatePath + documentDocName, xml, baseUrl + templateUUId + ".docx", params);
            boolean b = xmlToDocx.toDocx(templateName + ".xml", baseUrl + templateName + ".docx", xml, docx, params);
            if(!b) {
                log.error("pdf生成失败,Method:xmlToDocx.toDocx()");
                return null;
            }
            // 新建一个空白pdf文档
            String pdf = baseUrl + savePdfName + ".pdf";
            File file = new File(pdf);
            FileOutputStream os = new FileOutputStream(file);
            // docx是将要被转化的word文档
            Document doc = new Document(docx);
            String osName = isWindows();
            String fonts[] = null;
            /**
             * 适配字体文件
             */
            if (osName.equals("linux")) {
                // fonts = new String[]{"/usr/share/fonts/chinese/", "/usr/share/fonts/simsun/", "/usr/share/fonts/"};
                fonts = new String[]{"/usr/share/fonts/win/Fonts/"};
            } else if (osName.equals("mac")) {
                fonts = new String[]{"/Users/fonts/chinese/", "/Users/fonts/simsun/", "/Users/fonts/black/", "/Users/fonts/wingdings/"};
            } else if (osName.equals("windows")) {
                fonts = new String[]{"C:/Windows/Fonts/"};
            }
            FontSettings.setFontsFolders(fonts, true);
            // 保存pdf
            // replace(params,docx,docx);
            doc.save(os, SaveFormat.PDF);
            if (os != null) {
                os.close();
            }
            delete(xml, docx);//删除文件
            log.info(templateName + "文书pdf已生成至:" + pdf);
            return pdf;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private String isWindows() {
        String osName = System.getProperties().getProperty("os.name").toUpperCase();
        if (osName.indexOf("WINDOWS") != -1) {
            return "windows";
        } else if (osName.indexOf("MAC") != -1) {
            return "mac";
        } else {
            return "linux";
        }
    }

    private static String isWindowss() {
        String osName = System.getProperties().getProperty("os.name").toUpperCase();
        if (osName.indexOf("WINDOWS") != -1) {
            return "windows";
        } else if (osName.indexOf("MAC") != -1) {
            return "mac";
        } else {
            return "linux";
        }
    }

    /**
     * 删除生成的多余文件
     */
    public void delete(String xmlPath, String wordPath) {
        File file = new File(xmlPath);
        if (file.exists()) {
            file.delete();
        }
        File wordFile = new File(wordPath);
        if (wordFile.exists()) {
            wordFile.delete();
        }
    }

    /**
     * aspose word 替换文字/图片。
     * @param url  原文件路径
     * @param saveurl 保存路径
     * @param params {key:value,"$年份$":"2020","$签字1$":"$pic:d/qz1.jpg"} key 为要被替换的字符串,value 为替换为的字符串,替换为图片,则value为$pic:+图片路径
     * 图片的传参:   params.put("[$pic$]", "$pic:C:\\Users\\86153\\Pictures\\jackChen.jpg");
     * @return
     */
    public boolean replace(Map<String, Object> params, String url,String saveurl){
        if(!getLicense()){
            return false;
        }
        File file = new File(url);
        if(!file.exists()){
            return false;
        }
        try {
            Document doc = new Document(url);
            Range range = doc.getRange();
            for(String key:params.keySet()){
                if (params.get(key) == null) continue;
                String value = params.get(key).toString();
                if(value.startsWith("$pic:")){
                    value = value.substring(5);
                    key = key.replace("\\", "\\\\");
                    key = key.replace("$", "\\$");
                    key = key.replace("[", "\\[");
                    key = key.replace("]", "\\]");
                    key = key.replace("(", "\\(");
                    key = key.replace(")", "\\)");
                    key = key.replace("|", "\\|");
                    key = key.replace("+", "\\+");
                    key = key.replace("?", "\\?");
                    key = key.replace("*", "\\*");
                    range.replace( Pattern.compile(key),new ReplaceAndInsertImage(value) , false);
                }else{
                    range.replace(key, value, true, false);
                }
            }
            doc.save(saveurl);

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * @param imgFile 文件的路径
     * @return 文件转为base64 二进制流
     */
    public static String fileToBase64(String imgFile) {

        // 将图片文件转化为二进制流
        InputStream in = null;
        byte[] data = null;
        // 读取图片字节数组
        try {
            in = new FileInputStream(imgFile);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 图片头
        //String imghead = "data:image/jpeg;base64,";
        // return Base64.encodeBase64String(data);
        // mac/linux下base64生成的base64码,换行符是\n,而word原生图片里的base64换行符是\r\n,
        // return Base64.getEncoder().encodeToString(data).replace("\n", "\r\n").replace("\r\r\n", "\r\n");
        return Base64.getEncoder().encodeToString(data);
    }


    /**
     * @param templateName 模板的文件名
     * @param savePdfName  最后保存的pdf文件 可以用 文书名+文书业务id 来命名
     * @return 最后生成的文书pdf文件保存路径
     * @throws Exception
     */
    public static void doDocToPdf(String templateName, String savePdfName) throws Exception {
        try {
            try {
                // aspose需要的签名文件名称
                InputStream is = DocToPdf.class.getClassLoader().getResourceAsStream("license.xml");
                // InputStream is = new FileInputStream(path);
                License aposeLic = new License();
                aposeLic.setLicense(is);
            } catch (Exception e) {
                e.printStackTrace();
            }
            File file = new File(savePdfName);
            FileOutputStream os = new FileOutputStream(file);
            // docx是将要被转化的word文档
            Document doc = new Document(templateName);
            String osName = isWindowss();
            String fonts[] = null;
            /**
             * 适配字体文件
             */
            if (osName.equals("linux")) {
                // fonts = new String[]{"/usr/share/fonts/chinese/", "/usr/share/fonts/simsun/", "/usr/share/fonts/"};
                fonts = new String[]{"/usr/share/fonts/win/Fonts/"};
            } else if (osName.equals("mac")) {
                fonts = new String[]{"/Users/fonts/chinese/", "/Users/fonts/simsun/", "/Users/fonts/black/", "/Users/fonts/wingdings/"};
            } else if (osName.equals("windows")) {
                fonts = new String[]{"C:/Windows/Fonts/"};
            }
            FontSettings.setFontsFolders(fonts, true);
            // 保存pdf
            // replace(params,docx,docx);
            doc.save(os, SaveFormat.PDF);
            if (os != null) {
                os.close();
            }
//             delete(null, docx);//删除文件
            log.info(templateName + "文书pdf已生成");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

XmlToDocx

package com.nongyeservice.paper.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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;


/**
 * @author mao
 * @program paperUtil
 * @description word动态填充数据核心类
 * @createDate 2023-03-23 16:50:05
 **/
@Component
@Slf4j
public class XmlToDocx {

    @Autowired
    XmlTplUtil xmlTplUtil;

    /**
     * @param xmlTemplate  xml的文件名
     * @param docxTemplate docx的路径和文件名
     * @param xmlTemp      填充完数据的临时xml
     * @param toFilePath   目标文件名
     * @param map          需要动态传入的数据
     * @throws IOException
     */
    public boolean toDocx(String xmlTemplate, String docxTemplate, String xmlTemp, String toFilePath, Map map) {
        try {
            // 1.map是动态传入的数据
            // 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
            Writer w1 = new OutputStreamWriter(new FileOutputStream(xmlTemp), "utf-8");
            // 2.把map中的数据动态由freemarker传给xml
            xmlTplUtil.process(xmlTemplate, map, w1);
            // 3.把填充完成的xml写入到docx中
            XmlToDocx xtd = new XmlToDocx();
            xtd.outDocx(new File(xmlTemp), docxTemplate, toFilePath);
            w1.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("XML to Word Failed {}" , e.getMessage());
            return false;
        }
    }

    /**
     * @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 {
        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();
        zipFile.close();
    }


}

XmlTplUtil

package com.nongyeservice.paper.utils;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

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

/**
 * @author mao
 * @program paperUtil
 * @description  word动态填充工具类
 * @createDate 2023-03-23 16:50:05
 **/
@Component
public class XmlTplUtil {

    @Value("${aspose.defaultTemplatePath}")
    public String baseUrl;

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


    private XmlTplUtil() {
        // cfg = new Configuration();
        // try {
        //     cfg.setDirectoryForTemplateLoading(new File(baseUrl));
        // } catch (Exception e) {
        //     e.printStackTrace();
        // }
    }

    private Template getTemplate(String name) throws IOException {
        if (tplm == null) {
            // tplm = new XmlTplUtil();
            cfg = new Configuration();
            try {
                cfg.setDirectoryForTemplateLoading(new File(baseUrl));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Template template = cfg.getTemplate(name,"utf-8");
        return template;
    }

    /**
     * @param templatefile 模板文件
     * @param param        需要填充的内容
     * @param out          填充完成输出的文件
     * @throws IOException
     * @throws TemplateException
     */
    public void process(String templatefile, Map param, Writer out) throws IOException, TemplateException {
        // 获取模板
        Template template = getTemplate(templatefile);
        template.setOutputEncoding("utf-8");
        // 合并数据
        template.process(param, out);
        if (out != null) {
            out.close();
        }
    }

}

ReplaceAndInsertImage 只需要改word即可

DocToPdf中有一个replace()方法,需要用到这个类

package com.nongyeservice.paper.utils;

import com.aspose.words.*;

public class ReplaceAndInsertImage implements IReplacingCallback{
    public String url;
    public ReplaceAndInsertImage(String url){
        this.url = url;
    }
    @Override
    public int replacing(ReplacingArgs e) throws Exception {
        //获取当前节点
        Node node = e.getMatchNode();
        //获取当前文档
        Document document =  (Document) node.getDocument();
        DocumentBuilder builder = new DocumentBuilder(document);
//        //将光标移动到指定节点
        builder.moveTo(node);
//        //插入图片
        builder.insertImage(url);
        return ReplaceAction.REPLACE;
    }
}

license.xml aspose所需要的证书

<License>
  <Data>
    <Products>
      <Product>Aspose.Total for Java</Product>
      <Product>Aspose.Words for Java</Product>
    </Products>
    <EditionType>Enterprise</EditionType>
    <SubscriptionExpiry>20991231</SubscriptionExpiry>
    <LicenseExpiry>20991231</LicenseExpiry>
    <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>
  </Data>
  <Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature>
</License>
posted @ 2023-04-10 15:52  没有烦恼的猫猫  阅读(201)  评论(0编辑  收藏  举报