項目開發過程當中,客戶提出一堆導出報表的需求,須要導出word格式,頁眉還須要加上客戶公司的logo,試了幾種方案,最後選擇了用 Apache poi 加上自定義標籤的方式實現。html
目前功能還比較簡單,一些複雜的表格作不了,可是已經基本知足項目需求了。java
使用poi讀取word模板,替換word中的{text}標籤,並根據自定義標籤循環生成表格或表格中的行。
代碼示例下載:https://download.csdn.net/download/u012775558/10306308
注意,僅支持docx格式的word文件,大概是word2010及之後版本,doc格式不支持。apache
word模板須要有固定的格式,下面是幾個示例與代碼實現.app
只是最基礎的文本替換less
注意:maven
能夠給表格加上表頭和表尾數據,只須要把數據放入parametersMap(存儲報表中不循環的數據)中便可。工具
你也能夠給行加上序號,可是不能直接輸入序號,而是經過word的插入編號的功能插入編號,生成的表格纔會有編號。this
也能夠給表格加上表頭和表尾數據,只須要把數據放入parametersMap(存儲報表中不循環的數據)中便可。spa
注意:.net
使用maven搭建項目,引入poi相關jar包。
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.13</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.13</version> </dependency>
/** * @Title: WordTemplate2.java * @Package: com.highdata.templateTools * @Description: TODO * @author: Juveniless * @date: 2017年11月27日 下午3:23:13 */ package com.hidata.tool; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.poi.xwpf.usermodel.BodyElementType; import org.apache.poi.xwpf.usermodel.IBodyElement; import org.apache.poi.xwpf.usermodel.PositionInParagraph; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.apache.poi.xwpf.usermodel.XWPFTableRow; /** * * 對docx文件中的文本及表格中的內容進行替換 --模板僅支持對 {key} 標籤的替換 * * @ClassName: WordTemplate * @Description: TODO(!!!使用word2013 docx文件) * @author Juveniless * @date: 2017年11月27日 下午3:25:56 * <br>(1)word模板注意頁邊距的問題,存在問題:好比頁邊距默認爲3cm,畫表格時,仍然能夠經過 * 拖拽,把表格邊框拖動到看起來就像頁邊距只有1cm的樣子,可是實際上此時頁邊距仍是3cm,生成的 * word報表的頁邊距仍是會按照3cm來生成。解決辦法,在word文件裏,設置好頁邊距,若是須要表格 * 兩邊頁邊距很窄,須要在word裏設置頁邊距窄一點,而不是直接拖動表格邊框來實現。 * */ public class WordTemplate { private XWPFDocument document; public XWPFDocument getDocument() { return document; } public void setDocument(XWPFDocument document) { this.document = document; } /** * 初始化模板內容 * * @author Juveniless * @date 2017年11月27日 下午3:59:22 * @param inputStream * 模板的讀取流(docx文件) * @throws IOException * */ public WordTemplate(InputStream inputStream) throws IOException { document = new XWPFDocument(inputStream); } /** * 將處理後的內容寫入到輸出流中 * * @param outputStream * @throws IOException */ public void write(OutputStream outputStream) throws IOException { document.write(outputStream); } /** * 根據dataMap對word文件中的標籤進行替換; <br><br> * !!!!***須要注意dataMap的數據格式***!!!! <br><br> * 對於須要替換的普通標籤數據標籤(不須要循環)-----必須在dataMap中存儲一個key爲parametersMap的map, * 來存儲這些不須要循環生成的數據,好比:表頭信息,日期,製表人等。 <br><br> * 對於須要循環生成的表格數據------key自定義,value爲 --ArrayList<Map<String, String>> * @author Juveniless * @date 2017年11月27日 下午3:29:27 * @param dataMap * */ public void replaceDocument(Map<String, Object> dataMap) { if (!dataMap.containsKey("parametersMap")) { System.out.println("數據源錯誤--數據源(parametersMap)缺失"); return; } @SuppressWarnings("unchecked") Map<String, Object> parametersMap = (Map<String, Object>) dataMap .get("parametersMap"); List<IBodyElement> bodyElements = document.getBodyElements();// 全部對象(段落+表格) int templateBodySize = bodyElements.size();// 標記模板文件(段落+表格)總個數 int curT = 0;// 當前操做表格對象的索引 int curP = 0;// 當前操做段落對象的索引 for (int a = 0; a < templateBodySize; a++) { IBodyElement body = bodyElements.get(a); if (BodyElementType.TABLE.equals(body.getElementType())) {// 處理表格 XWPFTable table = body.getBody().getTableArray(curT); List<XWPFTable> tables = body.getBody().getTables(); table = tables.get(curT); if (table != null) { // 處理表格 List<XWPFTableCell> tableCells = table.getRows().get(0).getTableCells();// 獲取到模板表格第一行,用來判斷表格類型 String tableText = table.getText();// 表格中的全部文本 if (tableText.indexOf("##{foreach") > -1) { // 查找到##{foreach標籤,該表格須要處理循環 if (tableCells.size() != 2 || tableCells.get(0).getText().indexOf("##{foreach") < 0 || tableCells.get(0).getText().trim().length() == 0) { System.out .println("文檔中第" + (curT + 1) + "個表格模板錯誤,模板表格第一行須要設置2個單元格," + "第一個單元格存儲表格類型(##{foreachTable}## 或者 ##{foreachTableRow}##),第二個單元格定義數據源。"); return; } String tableType = tableCells.get(0).getText(); String dataSource = tableCells.get(1).getText(); System.out.println("讀取到數據源:"+dataSource); if (!dataMap.containsKey(dataSource)) { System.out.println("文檔中第" + (curT + 1) + "個表格模板數據源缺失"); return; } @SuppressWarnings("unchecked") List<Map<String, Object>> tableDataList = (List<Map<String, Object>>) dataMap .get(dataSource); if ("##{foreachTable}##".equals(tableType)) { // System.out.println("循環生成表格"); addTableInDocFooter(table, tableDataList, parametersMap, 1); } else if ("##{foreachTableRow}##".equals(tableType)) { // System.out.println("循環生成表格內部的行"); addTableInDocFooter(table, tableDataList, parametersMap, 2); } } else if (tableText.indexOf("{") > -1) { // 沒有查找到##{foreach標籤,查找到了普通替換數據的{}標籤,該表格只須要簡單替換 addTableInDocFooter(table, null, parametersMap, 3); } else { // 沒有查找到任何標籤,該表格是一個靜態表格,僅須要複製一個便可。 addTableInDocFooter(table, null, null, 0); } curT++; } } else if (BodyElementType.PARAGRAPH.equals(body.getElementType())) {// 處理段落 // System.out.println("獲取到段落"); XWPFParagraph ph = body.getBody().getParagraphArray(curP); if (ph != null) { // htmlText = htmlText+readParagraphX(ph); addParagraphInDocFooter(ph, null, parametersMap, 0); curP++; } } } // 處理完畢模板,刪除文本中的模板內容 for (int a = 0; a < templateBodySize; a++) { document.removeBodyElement(0); } } /** * 根據 模板表格 和 數據list 在word文檔末尾生成表格 * @author Juveniless * @date 2017年12月6日 上午10:12:05 * @param templateTable 模板表格 * @param list 循環數據集 * @param parametersMap 不循環數據集 * @param flag (0爲靜態表格,1爲表格總體循環,2爲表格內部行循環,3爲表格不循環僅簡單替換標籤便可) * */ public void addTableInDocFooter(XWPFTable templateTable, List<Map<String, Object>> list, Map<String, Object> parametersMap, int flag) { if (flag == 1) {// 表格總體循環 for (Map<String, Object> map : list) { List<XWPFTableRow> templateTableRows = templateTable.getRows();// 獲取模板表格全部行 XWPFTable newCreateTable = document.createTable();// 建立新表格,默認一行一列 for (int i = 1; i < templateTableRows.size(); i++) { XWPFTableRow newCreateRow = newCreateTable.createRow(); CopyTableRow(newCreateRow, templateTableRows.get(i));// 複製模板行文本和樣式到新行 } newCreateTable.removeRow(0);// 移除多出來的第一行 document.createParagraph();// 添加回車換行 replaceTable(newCreateTable, map);//替換標籤 } } else if (flag == 2) {// 表格表格內部行循環 XWPFTable newCreateTable = document.createTable();// 建立新表格,默認一行一列 List<XWPFTableRow> TempTableRows = templateTable.getRows();// 獲取模板表格全部行 int tagRowsIndex = 0;// 標籤行indexs for (int i = 0, size = TempTableRows.size(); i < size; i++) { String rowText = TempTableRows.get(i).getCell(0).getText();// 獲取到表格行的第一個單元格 if (rowText.indexOf("##{foreachRows}##") > -1) { tagRowsIndex = i; break; } } /* 複製模板行和標籤行以前的行 */ for (int i = 1; i < tagRowsIndex; i++) { XWPFTableRow newCreateRow = newCreateTable.createRow(); CopyTableRow(newCreateRow, TempTableRows.get(i));// 複製行 replaceTableRow(newCreateRow, parametersMap);// 處理不循環標籤的替換 } /* 循環生成模板行 */ XWPFTableRow tempRow = TempTableRows.get(tagRowsIndex + 1);// 獲取到模板行 for (int i = 0; i < list.size(); i++) { XWPFTableRow newCreateRow = newCreateTable.createRow(); CopyTableRow(newCreateRow, tempRow);// 複製模板行 replaceTableRow(newCreateRow, list.get(i));// 處理標籤替換 } /* 複製模板行和標籤行以後的行 */ for (int i = tagRowsIndex + 2; i < TempTableRows.size(); i++) { XWPFTableRow newCreateRow = newCreateTable.createRow(); CopyTableRow(newCreateRow, TempTableRows.get(i));// 複製行 replaceTableRow(newCreateRow, parametersMap);// 處理不循環標籤的替換 } newCreateTable.removeRow(0);// 移除多出來的第一行 document.createParagraph();// 添加回車換行 } else if (flag == 3) { //表格不循環僅簡單替換標籤 List<XWPFTableRow> templateTableRows = templateTable.getRows();// 獲取模板表格全部行 XWPFTable newCreateTable = document.createTable();// 建立新表格,默認一行一列 for (int i = 0; i < templateTableRows.size(); i++) { XWPFTableRow newCreateRow = newCreateTable.createRow(); CopyTableRow(newCreateRow, templateTableRows.get(i));// 複製模板行文本和樣式到新行 } newCreateTable.removeRow(0);// 移除多出來的第一行 document.createParagraph();// 添加回車換行 replaceTable(newCreateTable, parametersMap); } else if (flag == 0) { List<XWPFTableRow> templateTableRows = templateTable.getRows();// 獲取模板表格全部行 XWPFTable newCreateTable = document.createTable();// 建立新表格,默認一行一列 for (int i = 0; i < templateTableRows.size(); i++) { XWPFTableRow newCreateRow = newCreateTable.createRow(); CopyTableRow(newCreateRow, templateTableRows.get(i));// 複製模板行文本和樣式到新行 } newCreateTable.removeRow(0);// 移除多出來的第一行 document.createParagraph();// 添加回車換行 } } /** * 根據 模板段落 和 數據 在文檔末尾生成段落 * * @author Juveniless * @date 2017年11月27日 上午11:49:42 * @param templateParagraph * 模板段落 * @param list * 循環數據集 * @param parametersMap * 不循環數據集 * @param flag * (0爲不循環替換,1爲循環替換) * */ public void addParagraphInDocFooter(XWPFParagraph templateParagraph, List<Map<String, String>> list, Map<String, Object> parametersMap, int flag) { if (flag == 0) { XWPFParagraph createParagraph = document.createParagraph(); // 設置段落樣式 createParagraph.getCTP().setPPr(templateParagraph.getCTP().getPPr()); // 移除原始內容 for (int pos = 0; pos < createParagraph.getRuns().size(); pos++) { createParagraph.removeRun(pos); } // 添加Run標籤 for (XWPFRun s : templateParagraph.getRuns()) { XWPFRun targetrun = createParagraph.createRun(); CopyRun(targetrun, s); } replaceParagraph(createParagraph, parametersMap); } else if (flag == 1) { // 暫無實現 } } /** * 根據map替換段落元素內的{**}標籤 * @author Juveniless * @date 2017年12月4日 下午3:09:00 * @param xWPFParagraph * @param parametersMap * */ public void replaceParagraph(XWPFParagraph xWPFParagraph, Map<String, Object> parametersMap) { List<XWPFRun> runs = xWPFParagraph.getRuns(); String xWPFParagraphText = xWPFParagraph.getText(); String regEx = "\\{.+?\\}"; Pattern pattern = Pattern.compile(regEx); Matcher matcher = pattern.matcher(xWPFParagraphText);//正則匹配字符串{****} if (matcher.find()) { // 查找到有標籤才執行替換 int beginRunIndex = xWPFParagraph.searchText("{", new PositionInParagraph()).getBeginRun();// 標籤開始run位置 int endRunIndex = xWPFParagraph.searchText("}", new PositionInParagraph()).getEndRun();// 結束標籤 StringBuffer key = new StringBuffer(); if (beginRunIndex == endRunIndex) { // {**}在一個run標籤內 XWPFRun beginRun = runs.get(beginRunIndex); String beginRunText = beginRun.text(); int beginIndex = beginRunText.indexOf("{"); int endIndex = beginRunText.indexOf("}"); int length = beginRunText.length(); if (beginIndex == 0 && endIndex == length - 1) { // 該run標籤只有{**} XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex); insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr()); // 設置文本 key.append(beginRunText.substring(1, endIndex)); insertNewRun.setText(getValueBykey(key.toString(),parametersMap)); xWPFParagraph.removeRun(beginRunIndex + 1); } else { // 該run標籤爲**{**}** 或者 **{**} 或者{**}**,替換key後,還須要加上原始key先後的文本 XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex); insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr()); // 設置文本 key.append(beginRunText.substring(beginRunText.indexOf("{")+1, beginRunText.indexOf("}"))); String textString=beginRunText.substring(0, beginIndex) + getValueBykey(key.toString(),parametersMap) + beginRunText.substring(endIndex + 1); insertNewRun.setText(textString); xWPFParagraph.removeRun(beginRunIndex + 1); } }else { // {**}被分紅多個run //先處理起始run標籤,取得第一個{key}值 XWPFRun beginRun = runs.get(beginRunIndex); String beginRunText = beginRun.text(); int beginIndex = beginRunText.indexOf("{"); if (beginRunText.length()>1 ) { key.append(beginRunText.substring(beginIndex+1)); } ArrayList<Integer> removeRunList = new ArrayList<>();//須要移除的run //處理中間的run for (int i = beginRunIndex + 1; i < endRunIndex; i++) { XWPFRun run = runs.get(i); String runText = run.text(); key.append(runText); removeRunList.add(i); } // 獲取endRun中的key值 XWPFRun endRun = runs.get(endRunIndex); String endRunText = endRun.text(); int endIndex = endRunText.indexOf("}"); //run中**}或者**}** if (endRunText.length()>1 && endIndex!=0) { key.append(endRunText.substring(0,endIndex)); } //******************************************************************* //取得key值後替換標籤 //先處理開始標籤 if (beginRunText.length()==2 ) { // run標籤內文本{ XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex); insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr()); // 設置文本 insertNewRun.setText(getValueBykey(key.toString(),parametersMap)); xWPFParagraph.removeRun(beginRunIndex + 1);//移除原始的run }else { // 該run標籤爲**{**或者 {** ,替換key後,還須要加上原始key前的文本 XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex); insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr()); // 設置文本 String textString=beginRunText.substring(0,beginRunText.indexOf("{"))+getValueBykey(key.toString(),parametersMap); insertNewRun.setText(textString); xWPFParagraph.removeRun(beginRunIndex + 1);//移除原始的run } //處理結束標籤 if (endRunText.length()==1 ) { // run標籤內文本只有} XWPFRun insertNewRun = xWPFParagraph.insertNewRun(endRunIndex); insertNewRun.getCTR().setRPr(endRun.getCTR().getRPr()); // 設置文本 insertNewRun.setText(""); xWPFParagraph.removeRun(endRunIndex + 1);//移除原始的run }else { // 該run標籤爲**}**或者 }** 或者**},替換key後,還須要加上原始key後的文本 XWPFRun insertNewRun = xWPFParagraph.insertNewRun(endRunIndex); insertNewRun.getCTR().setRPr(endRun.getCTR().getRPr()); // 設置文本 String textString=endRunText.substring(endRunText.indexOf("}")+1); insertNewRun.setText(textString); xWPFParagraph.removeRun(endRunIndex + 1);//移除原始的run } //處理中間的run標籤 for (int i = 0; i < removeRunList.size(); i++) { XWPFRun xWPFRun = runs.get(removeRunList.get(i));//原始run XWPFRun insertNewRun = xWPFParagraph.insertNewRun(removeRunList.get(i)); insertNewRun.getCTR().setRPr(xWPFRun.getCTR().getRPr()); insertNewRun.setText(""); xWPFParagraph.removeRun(removeRunList.get(i) + 1);//移除原始的run } }// 處理${**}被分紅多個run replaceParagraph( xWPFParagraph, parametersMap); }//if 有標籤 } /** * 複製表格行XWPFTableRow格式 * * @param target * 待修改格式的XWPFTableRow * @param source * 模板XWPFTableRow */ private void CopyTableRow(XWPFTableRow target, XWPFTableRow source) { int tempRowCellsize = source.getTableCells().size();// 模板行的列數 for (int i = 0; i < tempRowCellsize - 1; i++) { target.addNewTableCell();// 爲新添加的行添加與模板表格對應行行相同個數的單元格 } // 複製樣式 target.getCtRow().setTrPr(source.getCtRow().getTrPr()); // 複製單元格 for (int i = 0; i < target.getTableCells().size(); i++) { copyTableCell(target.getCell(i), source.getCell(i)); } } /** * 複製單元格XWPFTableCell格式 * * @author Juveniless * @date 2017年11月27日 下午3:41:02 * @param newTableCell * 新建立的的單元格 * @param templateTableCell * 模板單元格 * */ private void copyTableCell(XWPFTableCell newTableCell, XWPFTableCell templateTableCell) { // 列屬性 newTableCell.getCTTc().setTcPr(templateTableCell.getCTTc().getTcPr()); // 刪除目標 targetCell 全部文本段落 for (int pos = 0; pos < newTableCell.getParagraphs().size(); pos++) { newTableCell.removeParagraph(pos); } // 添加新文本段落 for (XWPFParagraph sp : templateTableCell.getParagraphs()) { XWPFParagraph targetP = newTableCell.addParagraph(); copyParagraph(targetP, sp); } } /** * 複製文本段落XWPFParagraph格式 * * @author Juveniless * @date 2017年11月27日 下午3:43:08 * @param newParagraph * 新建立的的段落 * @param templateParagraph * 模板段落 * */ private void copyParagraph(XWPFParagraph newParagraph, XWPFParagraph templateParagraph) { // 設置段落樣式 newParagraph.getCTP().setPPr(templateParagraph.getCTP().getPPr()); // 添加Run標籤 for (int pos = 0; pos < newParagraph.getRuns().size(); pos++) { newParagraph.removeRun(pos); } for (XWPFRun s : templateParagraph.getRuns()) { XWPFRun targetrun = newParagraph.createRun(); CopyRun(targetrun, s); } } /** * 複製文本節點run * @author Juveniless * @date 2017年11月27日 下午3:47:17 * @param newRun * 新建立的的文本節點 * @param templateRun * 模板文本節點 * */ private void CopyRun(XWPFRun newRun, XWPFRun templateRun) { newRun.getCTR().setRPr(templateRun.getCTR().getRPr()); // 設置文本 newRun.setText(templateRun.text()); } /** * 根據參數parametersMap對錶格的一行進行標籤的替換 * * @author Juveniless * @date 2017年11月23日 下午2:09:24 * @param tableRow * 表格行 * @param parametersMap * 參數map * */ public void replaceTableRow(XWPFTableRow tableRow, Map<String, Object> parametersMap) { List<XWPFTableCell> tableCells = tableRow.getTableCells(); for (XWPFTableCell xWPFTableCell : tableCells) { List<XWPFParagraph> paragraphs = xWPFTableCell.getParagraphs(); for (XWPFParagraph xwpfParagraph : paragraphs) { replaceParagraph(xwpfParagraph, parametersMap); } } } /** * 根據map替換表格中的{key}標籤 * @author Juveniless * @date 2017年12月4日 下午2:47:36 * @param xwpfTable * @param parametersMap * */ public void replaceTable(XWPFTable xwpfTable,Map<String, Object> parametersMap){ List<XWPFTableRow> rows = xwpfTable.getRows(); for (XWPFTableRow xWPFTableRow : rows ) { List<XWPFTableCell> tableCells = xWPFTableRow.getTableCells(); for (XWPFTableCell xWPFTableCell : tableCells ) { List<XWPFParagraph> paragraphs2 = xWPFTableCell.getParagraphs(); for (XWPFParagraph xWPFParagraph : paragraphs2) { replaceParagraph(xWPFParagraph, parametersMap); } } } } private String getValueBykey(String key, Map<String, Object> map) { String returnValue=""; if (key != null) { try { returnValue=map.get(key)!=null ? map.get(key).toString() : ""; } catch (Exception e) { // TODO: handle exception System.out.println("key:"+key+"***"+e); returnValue=""; } } return returnValue; } }
package com.hidata.tool; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Test { public static void main(String[] args) throws IOException { Map<String, Object> wordDataMap = new HashMap<String, Object>();// 存儲報表所有數據 Map<String, Object> parametersMap = new HashMap<String, Object>();// 存儲報表中不循環的數據 List<Map<String, Object>> table1 = new ArrayList<Map<String, Object>>(); Map<String, Object> map1=new HashMap<>(); map1.put("name", "張三"); map1.put("age", "23"); map1.put("email", "12121@qq.com"); Map<String, Object> map2=new HashMap<>(); map2.put("name", "李四"); map2.put("age", "45"); map2.put("email", "45445@qq.com"); Map<String, Object> map3=new HashMap<>(); map3.put("name", "Tom"); map3.put("age", "34"); map3.put("email", "6767@qq.com"); table1.add(map1); table1.add(map2); table1.add(map3); List<Map<String, Object>> table2 = new ArrayList<Map<String, Object>>(); Map<String, Object> map4=new HashMap<>(); map4.put("name", "tom"); map4.put("number", "sd1234"); map4.put("address", "上海"); Map<String, Object> map5=new HashMap<>(); map5.put("name", "seven"); map5.put("number", "sd15678"); map5.put("address", "北京"); Map<String, Object> map6=new HashMap<>(); map6.put("name", "lisa"); map6.put("number", "sd9078"); map6.put("address", "廣州"); table2.add(map4); table2.add(map5); table2.add(map6); parametersMap.put("userName", "JUVENILESS"); parametersMap.put("time", "2018-03-24"); parametersMap.put("sum", "3"); wordDataMap.put("table1", table1); wordDataMap.put("table2", table2); wordDataMap.put("parametersMap", parametersMap); File file = new File("D:\\Workspaces\\Eclipse 2017\\wordTemplate\\doc\\模板.docx");//改爲你本地文件所在目錄 // 讀取word模板 FileInputStream fileInputStream = new FileInputStream(file); WordTemplate template = new WordTemplate(fileInputStream); // 替換數據 template.replaceDocument(wordDataMap); //生成文件 File outputFile=new File("D:\\Workspaces\\Eclipse 2017\\wordTemplate\\doc\\輸出.docx");//改爲你本地文件所在目錄 FileOutputStream fos = new FileOutputStream(outputFile); template.getDocument().write(fos); } }