Java 将xml模板动态填充数据转换为word文档

https://blog.csdn.net/abc231218/article/details/80512463

需要用到的jar包:

commons-codec-1.10.jar

freemarker-2.3.21.jar

jacob-1.6.jar

实现思路:

    1、先将word文档另存为 : Word 2003 XML文档(*.xml) 格式的模板文件;


    2、通过Java程序,使用freemarker.jar包转换为xml格式的word文档文件


    3、使用jacob包,将xml格式的word文档文件,转换为docx格式的文档文件


具体实现步骤:

一、模板编辑

       1、将word文档另存为xml模板:

    2、模板中需要动态改变的内容,通过freemarker标签:${variableName}

    说明:variableName是需要动态添加内容的一个标志符号,可自由命名

    注意:freemarker标签:${variableName},不能再word文档中直接输入,需要通过记事本,或者其他notePad++ 文本编辑工具先写好,然后再复制到文档中,否则在转换为xml模板时会出问题。具体问题可百度查找

    模板样式(参考):

    3、处理将要替换的图片,通过xml编辑工具打开xml模板文件:(可使用notePad++打开)

        两种替换图片方式,一种是直接动态插入一张图片,另一种是从数据库中读取,并循环插入图片

        (1)直接动态插入单张图片:(编辑xml模板文件)

                每个位置在保存模板前,放置一张图片,通过notePad++ 打开xml模板文件,找到对应的图片,在xml模板中,图片会发生转换,以base64的编码形式存在,只要找到一长串的字符就能确定这是一张图片;

        把红框中的内容(后面还有很长),删除掉,直接替换freemarker标签,另外一张图片同样操作,如图所示:

    (2)需要循环插入图片:(编辑xml模板文件)

                循环插图,需要加入freemarker循环标签,xml模板中:一对 ,为一行;我的模板设置了表格,需要循环插入表格,那么需要将循环标签包围到图片所在的 tr 标签:

图片中横线说明:

        (1)图片中因为有两个地方插入图片,所以需要将一个list对象中,要存两张图片的数据,

       (2)<#list loopImageList as imgList> :loopImageList 可自由命名,但是在Java代码中动态填充的数据对象名要一致,imageList 作为一个遍历的对象名,等于将loopImageList的内容赋值给imageList ,获取对象中的属性值,通过imageList.attr 获取

        (3)上面的 w:name= 后面是图片的名称,不能一致,必须存不同的文件名,所以,这个需要改动,否则一旦所有文件名称一致,则会出现问题。

        (4)如果需要合并第一列的单元格,需要在tr加入标签:

            具体合并方法:<#if imageList_index == 0><#else>

                    a、开始合并的行:

                    b、需要合并的行:

            上面的语句中,_index为imageList 的索引写法,因为需要合并,所以通过判断的方式,将第一个单元格作为合并起始行,其余需要合并的行需要添加结束标签。

        (5)如果不需要合并,则不用添加(4)中的语句

二、Java后台代码实现

    (1)创建一个封装图片对象的ImageBean类:

(由于list遍历中存了两张不同的图片,所以参数设计不太合理,可参考例子,自己进行优化)

package testXML;
/**
 * 图片bean
 */
public class ImageBean {
    // 图片1
    private Integer img1Index;
 
    private String imgName;
 
    private String img1Width;
 
    private String img1Height;
 
    private String img1Base64;
 
    // 图片2
    private Integer img2Index;
 
    private String img2Width;
 
    private String img2Height;
 
    private String img2Base64;
 
 
 
    public ImageBean(Integer img1Index, String imgName, String img1Width,
            String img1Height, String img1Base64, Integer img2Index,
            String img2Width, String img2Height,
            String img2Base64) {
        this.img1Index = img1Index;
        this.imgName = imgName;
        this.img1Width = img1Width;
        this.img1Height = img1Height;
        this.img1Base64 = img1Base64;
        this.img2Index = img2Index;
        this.img2Width = img2Width;
        this.img2Height = img2Height;
        this.img2Base64 = img2Base64;
    }
 
    public Integer getImg1Index() {
        return img1Index;
    }
 
    public void setImg1Index(Integer img1Index) {
        this.img1Index = img1Index;
    }
 
    public String getImgName() {
        return imgName;
    }
 
    public void setImgName(String imgName) {
        this.imgName = imgName;
    }
 
    public String getImg1Width() {
        return img1Width;
    }
 
    public void setImg1Width(String img1Width) {
        this.img1Width = img1Width;
    }
 
    public String getImg1Height() {
        return img1Height;
    }
 
    public void setImg1Height(String img1Height) {
        this.img1Height = img1Height;
    }
 
    public String getImg1Base64() {
        return img1Base64;
    }
 
    public void setImg1Base64(String img1Base64) {
        this.img1Base64 = img1Base64;
    }
 
    public Integer getImg2Index() {
        return img2Index;
    }
 
    public void setImg2Index(Integer img2Index) {
        this.img2Index = img2Index;
    }
 
    public String getImg2Width() {
        return img2Width;
    }
 
    public void setImg2Width(String img2Width) {
        this.img2Width = img2Width;
    }
 
    public String getImg2Height() {
        return img2Height;
    }
 
    public void setImg2Height(String img2Height) {
        this.img2Height = img2Height;
    }
 
    public String getImg2Base64() {
        return img2Base64;
    }
 
    public void setImg2Base64(String img2Base64) {
        this.img2Base64 = img2Base64;
    }
 
 
}
    (2)将xml模板生成word文档(本质是xml):(代码中存在通用工具处理类)

package testXML;
 
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import org.apache.commons.codec.binary.Base64;
 
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
 
public class XmlTemplate2Word {
    public static void main(String[] args) throws IOException, TemplateException{
        Map dataMap = new HashMap();
        dataMap.put("title", "测试转换word文档");
        dataMap.put("head", "头部信息");
        dataMap.put("content", "主要内容主要内容主要内容");
        dataMap.put("tableDescription", "表格描述内容");
        // 构造一个list,存放图片相关信息
        List list = new ArrayList();
        // 将图片转为base64编码格式 (实际运用中可通过循环处理)
        String imgBase64Str1 = getImgStr("C:/Users/admin/Desktop/签名/李燕萍.png");
        String imgBase64Str2 = getImgStr("C:/Users/admin/Desktop/签名/李燕萍2.png");
        String imgBase64Str3 = getImgStr("C:/Users/admin/Desktop/签名/彭玉婷.png");
        String imgBase64Str4 = getImgStr("C:/Users/admin/Desktop/签名/琪.png");
        String imgBase64Str5 = getImgStr("C:/Users/admin/Desktop/签名/婿丹.png");
        String imgBase64Str6 = getImgStr("C:/Users/admin/Desktop/签名/杨诗敏.png");
        
        list.add(new ImageBean(1,"图片1","101","35",imgBase64Str1,2,"101","35",imgBase64Str2));
        list.add(new ImageBean(3,"图片2","101","35",imgBase64Str3,4,"101","35",imgBase64Str4));
        list.add(new ImageBean(5,"图片3","101","35",imgBase64Str5,6,"101","35",imgBase64Str6));
        
        dataMap.put("loopImageList", list);
        // 模板文件路径:
        String templetFilePath = "C:/Users/admin/Desktop/测试模板.xml";
        // 目标文件存放路径
        String targetFilePath = "C:/Users/admin/Desktop/测试模板(xml格式).doc";
        // 将xml模板转换为后缀为doc文件,本质仍是属于xml
        xml2XmlDoc(dataMap,templetFilePath,targetFilePath);
    }
    /**
     * 将xml模板转换为后缀为doc文件,本质仍是属于xml
     * @param dataMap    需要填充到模板的数据
     * @param templetFilePath    模板文件路径
     * @param targetFilePath    目标文件保存路径
     * @throws IOException 
     * @throws TemplateException 
     */
    public static void xml2XmlDoc(Map dataMap, String templetFilePath, String targetFilePath) throws IOException, TemplateException{
        // 将模板文件路径拆分为文件夹路径和文件名称
        String tempLetDir = templetFilePath.substring(0,templetFilePath.lastIndexOf("/"));
        // 注意:templetFilePath.lastIndexOf("/")中,有的文件分隔符为:\ 要注意文件路径的分隔符
        String templetName = templetFilePath.substring(templetFilePath.lastIndexOf("/")+1);
        // 将目标文件保存路径拆分为文件夹路径和文件名称
        String targetDir = targetFilePath.substring(0,targetFilePath.lastIndexOf("/"));
        String targetName = targetFilePath.substring(targetFilePath.lastIndexOf("/")+1);
        Configuration configuration = new Configuration();
        configuration.setDefaultEncoding("UTF-8");
        // 如果目标文件目录不存在,则需要创建
        File file = new File(targetDir);
        if(!file.exists()){
            file.mkdirs();
        }
        // 加载模板数据(从文件路径中获取文件,其他方式,可百度查找)
        configuration.setDirectoryForTemplateLoading(new File(tempLetDir));
        // 获取模板实例
        Template template = configuration.getTemplate(templetName);
        File outFile = new File(targetDir + File.separator + targetName);
        //将模板和数据模型合并生成文件
        Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));
        //生成文件
        template.process(dataMap, out);
        out.flush();
        out.close();
    }
    
    /**
     * 将图片转换成Base64编码 (优化:在web工程下,可通过工程路径获取流的方式获取图片)
     * @param imgFile    图片路径
     * @return
     * @throws IOException 
     */ 
    public static String getImgStr(String imgFilePath) throws IOException{
        //将图片文件转化为字节数组字符串,并对其进行Base64编码处理
        InputStream in = null;
        byte[] data = null;
        //读取图片字节数组
            in = new FileInputStream(imgFilePath);        
            data = new byte[in.available()];
            in.read(data);
            in.close();
        return new String(Base64.encodeBase64(data));
    }
}
(3)模板准备好,模板路径正确后,运行程序,得到输出文件:文件内容如下。表格内容进行了替换,图片也循环填充到文档中,但是,这个文档,本质仍然属于xml.格式文档,打开之后,点击另存为会发现是xml格式。

    (4)通过调用转换docx方法,将xml格式的doc转换为docx的word文档格式:

    注意:此步骤,需要用到jacob的jar包,在进行此操作之前,需要将对应jacob包的dll文件,拷贝到系统盘的目录和jdk目目录下的 jre\lib\ 下面

目前我测试的版本有:jacob-1.6.jar、jacob-1.14.3.jar

1.6版本对应的dll : jacob-1.17-M2-x64.dll

1.14.3版本对应的dll : jacob-1.14.3-x64.dll

我展示的展示的是64位操作系统的,具体32位的到网上查找,不懂的可评论留言我看到会回复

具体的资源文件jar包,可自行到网上找,或者到maven仓库中下载。

/**
     * xml形式的doc文件转换为Docx格式
     * @param sourcePath 被转换文件的路径
     * @param targetPath 目标文件路径
     * @return
     * @author lixs 
     * @Date 2018年5月29日16:24:08
     */
    public static void docToDocx(String sourcePath, String targetPath){
        //Word.Application代表COM OLE编程标识,可查询MSDN得到  
        ActiveXComponent app = new ActiveXComponent("Word.Application");  
        //设置Word不可见  
        app.setProperty("Visible",false);  
        //调用Application对象的Documents属性,获得Documents对象  
        Dispatch docs = app.getProperty("Documents").toDispatch();  
        //Dispatch doc = Dispatch.call(docs,"Open",sourcePath,new Variant(false),new Variant(true)).getDispatch();  
        Dispatch doc = Dispatch.call(docs,"Open",sourcePath).getDispatch(); 
        Dispatch.call(doc,"SaveAS",targetPath,12);  
        //关闭打开的Word文件  
        Dispatch.call(doc,"Close",false);  
        //关闭Word应用程序  
        app.invoke("Quit",0);  
    }
(5)有的需要将word文档转换为PDF文件,这里提供一个转PDF的通用方法,:

/**
     * @Description: word文件转pdf文件
     * @param sourcePath 被转换word文档路径
     * @param targetPath 目标PDF文件路径路径
     * @return boolean
     * @date 2018年5月22日15:19:48
     */
    public static boolean word2pdf(String sourcePath, String targetPath) {
        ActiveXComponent app = null;
        try {
            app = new ActiveXComponent("Word.Application");
            app.setProperty("Visible", false);
            Dispatch docs = app.getProperty("Documents").toDispatch();
            Dispatch doc = Dispatch.call(docs, "Open", sourcePath, false, true).toDispatch();
            File tofile = new File(targetPath);
            if (tofile.exists()) {
                tofile.delete();
            }
            Dispatch.call(doc, "SaveAs", targetPath, 17); // word转PDF格式
            Dispatch.call(doc, "Close", false);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            if (app != null) {
                app.invoke("Quit", 0); // 不保存待定的更改
            }
        }
    }

————————————————
版权声明:本文为CSDN博主「abc231218」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/abc231218/article/details/80512463

你可能感兴趣的:(javaSE基础)