zoukankan      html  css  js  c++  java
  • 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中运行后结果:



  • 相关阅读:
    mac上python3安装HTMLTestRunner
    双目深度估计传统算法流程及OpenCV的编译注意事项
    深度学习梯度反向传播出现Nan值的原因归类
    1394. Find Lucky Integer in an Array
    1399. Count Largest Group
    1200. Minimum Absolute Difference
    999. Available Captures for Rook
    509. Fibonacci Number
    1160. Find Words That Can Be Formed by Characters
    1122. Relative Sort Array
  • 原文地址:https://www.cnblogs.com/ssyh/p/12494626.html
Copyright © 2011-2022 走看看