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中运行后结果:



  • 相关阅读:
    引用数据类型scanner和random
    java 基本类型,数据类型转换,关键字
    SpringMVC类型转换
    SpringMVC异常处理
    SpringMVC转发与重定向
    SpringMVC处理器返回值Object
    SpringMVC处理器方法返回值void ajax方式
    SpringMVC解决乱码
    SpringMVC路径变量和校正参数名称
    SpringMVC注解式开发
  • 原文地址:https://www.cnblogs.com/ssyh/p/12494626.html
Copyright © 2011-2022 走看看