java利用Freemarker模板生成docx格式的word文档(全过程)

参考:https://my.oschina.net/u/3737136/blog/2958421?tdsourcetag=s_pcqq_aiomsg

具体思路

 

1.创建一个docx文档模板,其中的英文是根据自己需要填充的内容。

 

 

 

 

 

 

 

2.把docx文档修改为ZIP格式(修改.docx后缀名为.zip),然后把zip解压到当前目录

3.修改word目录下document.xml文档,把如下原来是time改为${time},改好后放入项目中,用于后边内容填充。【有时候一个单词可能会被拆分,自己要做相应的调整】

 

 

 <#list minuteList as minute></#list>  可用于循环填充,相当于 for (Minute minte:minuteList),示列如下:

 <#list minuteList as minute>
              <w:p w14:paraId="3BB7AF6B" w14:textId="2AD2E958" w:rsidR="00D80192" w:rsidRDefault="00C4552D" w:rsidP="00E47882">
                <w:pPr>
                  <w:pStyle w:val="a6"/>
                  <w:numPr>
                    <w:ilvl w:val="0"/>
                    <w:numId w:val="2"/>
                  </w:numPr>
                  <w:ind w:firstLineChars="0"/>
                </w:pPr>
                <w:proofErr w:type="spellStart"/>
                <w:r w:rsidRPr="00C4552D">
                  <w:t>${minute.meeting_decision_content}</w:t>
                </w:r>
                <w:proofErr w:type="spellEnd"/>
                <w:r>
                  <w:t xml:space="preserve"> </w:t>
                </w:r>
                <w:bookmarkStart w:id="0" w:name="_GoBack"/>
                <w:bookmarkEnd w:id="0"/>
                <w:r>
                  <w:rPr>
                    <w:rFonts w:hint="eastAsia"/>
                  </w:rPr>
                  <w:t>交由</w:t>
                </w:r>
                <w:proofErr w:type="spellStart"/>
                <w:r w:rsidRPr="00C4552D">
                  <w:t>${minute.meeting_decision_executor} </w:t>
                </w:r>
                <w:proofErr w:type="spellEnd"/>
                <w:r>
                  <w:rPr>
                    <w:rFonts w:hint="eastAsia"/>
                  </w:rPr>
                  <w:t>负责,在</w:t>
                </w:r>
                <w:proofErr w:type="spellStart"/>
                <w:r w:rsidRPr="00C4552D">
                  <w:t>${minute.meeting_decision_deadline} </w:t>
                </w:r>
                <w:proofErr w:type="spellEnd"/>
                <w:r>
                  <w:rPr>
                    <w:rFonts w:hint="eastAsia"/>
                  </w:rPr>
                  <w:t>前完成。</w:t>
                </w:r>
              </w:p>
          </#list>

---------下边思路在代码中实现------------

4..把内容填充到document.xml里
5.在输入docx文档的时候把填充过内容的的 document.xml用流的方式写入zip(详见下面代码)。
6.输出docx文档
docx模板修改成zip格式后的信息如下(因为word文档本身就是ZIP格式实现的)

注:【在文档里边加入图片须进行rels文档的相关操作,我这里没用到,如有需要可以查看上边的参考链接】

 

 

---------代码部分------------

 

pom中导入依赖:

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
        </dependency>

 

 

项目结构:【箭头指向才是用到的,其他部分的测试目前没有删】

 

 

FreeMarkUtils类
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.util.Map;

public class FreeMarkUtils {
    private static Logger logger = LoggerFactory.getLogger(FreeMarkUtils.class);

    public static Configuration getConfiguration(){
        //创建配置实例
        Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
        //设置编码
        configuration.setDefaultEncoding("utf-8");
        configuration.setClassForTemplateLoading(FreeMarkUtils.class, "/templates/wordTemplates");//换成自己对应的目录
        return configuration;
    }

    /**
     * 获取模板字符串输入流
     * @param dataMap   参数
     * @param templateName  模板名称
     * @return
     */
    public static ByteArrayInputStream getFreemarkerContentInputStream(Map dataMap, String templateName) {
        ByteArrayInputStream in = null;
        try {
            //获取模板
            Template template = getConfiguration().getTemplate(templateName);
            StringWriter swriter = new StringWriter();
            //生成文件
            template.process(dataMap, swriter);

            in = new ByteArrayInputStream(swriter.toString().getBytes("utf-8"));//这里一定要设置utf-8编码 否则导出的word中中文会是乱码
        } catch (Exception e) {
            logger.error("模板生成错误!");
        }
        return in;
    }
}
FreemarkerTest类
import com.example.meeting.util.FreeMarkUtils;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class FreemarkerTest {
    private static String document="document.xml";
    //outputStream 输出流可以自己定义 浏览器或者文件输出流
    public static void createDocx(Map dataMap, OutputStream outputStream) {
        ZipOutputStream zipout = null;
        try {
            /*//图片配置文件模板
            ByteArrayInputStream documentXmlRelsInput = FreeMarkUtils.getFreemarkerContentInputStream(dataMap, documentXmlRels);*/

            //内容模板
            ByteArrayInputStream documentInput = FreeMarkUtils.getFreemarkerContentInputStream(dataMap, document);
            //最初设计的模板
            //File docxFile = new File(WordUtils.class.getClassLoader().getResource(template).getPath());
            File docxFile = new File("xxxx\\会议纪要.zip");//换成自己的zip路径
            if (!docxFile.exists()) {
                docxFile.createNewFile();
            }
            ZipFile zipFile = new ZipFile(docxFile);
            Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();
            zipout = new ZipOutputStream(outputStream);
            //开始覆盖文档------------------
            int len = -1;
            byte[] buffer = new byte[1024];
            while (zipEntrys.hasMoreElements()) {
                ZipEntry next = zipEntrys.nextElement();
                InputStream is = zipFile.getInputStream(next);
                if (next.toString().indexOf("media") < 0) {
                    zipout.putNextEntry(new ZipEntry(next.getName()));
                    if ("word/document.xml".equals(next.getName())) {//如果是word/document.xml由我们输入
                        if (documentInput != null) {
                            while ((len = documentInput.read(buffer)) != -1) {
                                zipout.write(buffer, 0, len);
                            }
                            documentInput.close();
                        }
                    } else {
                        while ((len = is.read(buffer)) != -1) {
                            zipout.write(buffer, 0, len);
                        }
                        is.close();
                    }
                }
            }

        } catch (Exception e) {
            System.out.println("word导出失败:"+e.getStackTrace());
            //logger.error();
        }finally {
            if(zipout!=null){
                try {
                    zipout.close();
                } catch (IOException e) {
                    System.out.println("io异常");

                }
            }
            if(outputStream!=null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    System.out.println("io异常");
                }
            }
        }
    }
    public static void main(String arg[]){
        Map dataMap=new HashMap();
        ArrayList minuteList=new ArrayList();
        MinuteTest minuteTest1=new MinuteTest();
        minuteTest1.setMeeting_decision_content("决策1");
        minuteTest1.setMeeting_decision_executor("执行者1");
        minuteTest1.setMeeting_decision_deadline("截至日期1");
        minuteList.add(minuteTest1);

        MinuteTest minuteTest2=new MinuteTest();
        minuteTest2.setMeeting_decision_content("决策2");
        minuteTest2.setMeeting_decision_executor("执行者2");
        minuteTest2.setMeeting_decision_deadline("截至日期2");
        minuteList.add(minuteTest2);

        dataMap.put("meeting_name", "如何使象牙山发展得更加美好");
        dataMap.put("time", "2019-09-15 15:30");
        dataMap.put("site", "会议室212");
        dataMap.put("organizer", "张三");
        dataMap.put("department", "策划部");
        dataMap.put("attendee", "谢大脚、谢广坤、刘能");
        dataMap.put("meeting_content", "关于象牙山发展中的每个人的义务");
        dataMap.put("recorder", "王五");
        dataMap.put("checker", "大老板");
        dataMap.put("minuteList",minuteList);


        //指定输出docx路径
        File outFile = new File("xxx\\test.docx") ;
        try {
            createDocx(dataMap,new FileOutputStream(outFile));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}
MinuteTest实体类
public class MinuteTest {
    private String meeting_decision_content;
    private String meeting_decision_executor;
    private String meeting_decision_deadline;


    public String getMeeting_decision_content() {
        return meeting_decision_content;
    }

    public void setMeeting_decision_content(String meeting_decision_content) {
        this.meeting_decision_content = meeting_decision_content;
    }

    public String getMeeting_decision_executor() {
        return meeting_decision_executor;
    }

    public void setMeeting_decision_executor(String meeting_decision_executor) {
        this.meeting_decision_executor = meeting_decision_executor;
    }

    public String getMeeting_decision_deadline() {
        return meeting_decision_deadline;
    }

    public void setMeeting_decision_deadline(String meeting_decision_deadline) {
        this.meeting_decision_deadline = meeting_decision_deadline;
    }
}

在FreemarkerTest中运行后结果:

 

 

 

 

 



posted @ 2020-03-14 21:57  旁光  阅读(11926)  评论(12编辑  收藏  举报