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中運行后結果:

 

 

 

 

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM