【Apache POI】Java Web根據模板匯出word檔案
阿新 • • 發佈:2019-02-20
最近工作中遇到一個需求:根據word模板文件匯出word檔案。
查閱了一些資料,發現Apache POI可以實現文件讀寫的功能,於是就研究了一下,總結如下:
POI詳細介紹:
Apache POI是一個開源的Java讀寫Excel、WORD等微軟OLE2元件文件的專案。目前POI已經有了Ruby版本。結構:
-
HSSF - 提供讀寫Microsoft Excel XLS格式檔案的功能。
-
XSSF - 提供讀寫Microsoft Excel OOXML XLSX格式檔案的功能。
-
HWPF - 提供讀寫Microsoft Word DOC97格式檔案的功能。
-
XWPF - 提供讀寫Microsoft Word DOC2003格式檔案的功能。
-
HSLF - 提供讀寫Microsoft PowerPoint格式檔案的功能。
-
HDGF - 提供讀Microsoft Visio格式檔案的功能。
-
HPBF - 提供讀Microsoft Publisher格式檔案的功能。
-
HSMF - 提供讀Microsoft Outlook格式檔案的功能。
Java Web根據模板匯出word檔案
基本實現原理: 1、首先,將模板中需要用到的引數組裝為一個Map集合; 2、然後讀取模板文件,使用POI API解析文件輸入流; 3、將Map集合中的內容寫入模板文件。
功能使用了springMVC的相關功能,點選匯出按鈕,呼叫前臺JS,JS程式碼根據springMVC的註解功能實現對後臺匯出方法的呼叫,controller控制類如下:
import java.io.InputStream; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import com.lmb.word.util.XwpfUtil; /** * Java Web根據模板匯出word檔案(spring MVC controller實現) * @author lmb * @date 2017-3-14 * */ public class ExportControl { private static final Logger logger = Logger.getLogger(ExportControl.class); /** * 匯出word * @param param * @param request * @param response */ public void exportWord(String param,HttpServletRequest request,HttpServletResponse response){ logger.debug("匯出word檔案開始>>>>>>>>>>>>>"); Map<String,Object> params = packageObject(); /*params格式如下: { ${interfacetype11}=ecsClient, ${time1}=2017/03/14 14:36:15,${code2}=4114030153, ${interfacetype10}=ecsClient, ${percentagecode10}=6.43%, ${percentagecode11}=17.74%, ${text9}=返回欠費不能辦理, ${percentagecode8}=67.71%, ${mainpercentage1}=98.57%, ${code1}=2107000024, ${svcname8}=GUSERBRAND, ${text8}=2G使用者主產品不在省份上報的列表中, ${start1}=2017-03-13 , ${svcname9}=GUSERBRAND, ${percentagecode2}=18.06%, ${text10}=使用者狀態不處於有效期, ${percentagecode1}=78.39%, ${text2}=4114030153, ${interfacename1}=cu.tran.fusionflowquery, ${svctext1}=3G流量包查詢, ${svctext2}=3G流量包查詢, ${svctext8}=使用者品牌查詢,${svctext9}=使用者品牌查詢,${svctext10}=使用者品牌查詢, ${svctext11}=使用者品牌查詢, ${text11}=4114030153, ${interfacetype8}=ecsClient, ${svcname11}=GUSERBRAND, ${end1}=2017-03-13 , ${interfacename10}=cu.tran.fusionflowquery, ${interfacetype9}=ecsClient, ${svcname10}=GUSERBRAND, ${text1}=2G使用者主產品不在省份上報的列表中, ${interfacename2}=cu.tran.fusionflowquery, ${interfacename11}=cu.tran.fusionflowquery, ${code8}=2107000024, ${namelist1}= 1、3G流量包查詢:24.26% 2、使用者品牌查詢:37.52%, ${date1}=2017-03-13 , ${code9}=2114000061, ${code11}=4114030153, ${svcname1}=G3GFLUX, ${code10}=2114000066, ${svcname2}=G3GFLUX, ${interfacetype1}=ecsClient, ${percentagecode9}=4.12%, ${interfacetype2}=ecsClient, ${interfacename9}=cu.tran.fusionflowquery, ${indexprovince1}=陝西, ${interfacename8}=cu.tran.fusionflowquery } */ XwpfUtil xwpfUtil = new XwpfUtil(); //讀入word模板 InputStream is = getClass().getClassLoader().getResourceAsStream("wordTemplate.docx"); xwpfUtil.exportWord(params,is,request,response,xwpfUtil); logger.debug("匯出word檔案完成>>>>>>>>>>>>>"); } /** * 組裝word文件中需要顯示資料的集合 * @return */ public Map<String, Object> packageObject() { Map<String,Object> params = new HashMap<String,Object>(); params.put("${date1}", "");//資料查詢時間 params.put("${time1}", "");//生成檔案時間 params.put("${indexprovince1}", "");//省份 //報告時間範圍 params.put("${mainpercentage1}", "");//省份成功率 params.put("${start1}", "");//開始時間 params.put("${end1}", ""); params.put("${namelist1}", ""); // …… return params; } }
控制器中用到的匯出方法工具類:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
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;
/**
* 根據模板匯出word檔案工具類
* @author lmb
* @date 2017-3-14
*/
public class XwpfUtil {
private static final Logger logger = Logger.getLogger(XwpfUtil.class);
/**
* 匯出word檔案
* @param params
* @param is
* @param request
* @param response
* @param xwpfUtil
*/
public void exportWord(Map<String, Object> params, InputStream is,
HttpServletRequest request, HttpServletResponse response,
XwpfUtil xwpfUtil) {
XWPFDocument doc = new XWPFDocument();
xwpfUtil.replaceInPara(doc,params);
xwpfUtil.replaceInTable(doc,params);
try {
OutputStream os = response.getOutputStream();
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-disposition","attachment;filename=exportWord.docx");//檔名中文不顯示
//把構造好的文件寫入輸出流
doc.write(os);
//關閉流
xwpfUtil.close(os);
xwpfUtil.close(is);
os.flush();
os.close();
} catch (IOException e) {
logger.error("檔案匯出錯誤");
}
}
/**
* 替換word模板文件段落中的變數
* @param doc 要替換的文件
* @param params 引數
*/
public void replaceInPara(XWPFDocument doc, Map<String, Object> params) {
Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
XWPFParagraph para;
while(iterator.hasNext()){
para = iterator.next();
this.replaceInPara(para,params);
}
}
/**
* 替換段落中的變數
* @param para 要替換的段落
* @param params 替換引數
*/
public void replaceInPara(XWPFParagraph para, Map<String, Object> params) {
List<XWPFRun> runs;
if (((Matcher) this.matcher(para.getParagraphText())).find()) {
runs = para.getRuns();
int start = -1;
int end = -1;
String str = "";
for (int i = 0; i < runs.size(); i++) {
XWPFRun run = runs.get(i);
String runText = run.toString().trim();
if (StringUtils.isNotBlank(runText)&&'$' == runText.charAt(0)&&'{' == runText.charAt(1)) {
start = i;
}
if (StringUtils.isNotBlank(runText)&&(start != -1)) {
str += runText;
}
if (StringUtils.isNotBlank(runText)&&'}' == runText.charAt(runText.length() - 1)) {
if (start != -1) {
end = i;
break;
}
}
}
for (int i = start; i <= end; i++) {
para.removeRun(i);
i--;
end--;
System.out.println("remove i="+i);
}
if(StringUtils.isBlank(str)){
String temp = para.getParagraphText();
str = temp.trim().substring(temp.indexOf("${"),temp.indexOf("}")+1);
}
for (String key : params.keySet()) {
if (str.equals(key)) {
para.createRun().setText(String.valueOf(params.get(key)) );
break;
}
}
}
}
/**
* 替換word模板文件表格中的變數
* @param doc 要替換的文件
* @param params 引數
*/
public void replaceInTable(XWPFDocument doc, Map<String, Object> params) {
Iterator<XWPFTable> iterator = doc.getTablesIterator();
XWPFTable table;
List<XWPFTableRow> rows;
List<XWPFTableCell> cells;
List<XWPFParagraph> paras;
while (iterator.hasNext()) {
table = iterator.next();
rows = table.getRows();
for (XWPFTableRow row : rows) {
cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
paras = cell.getParagraphs();
for (XWPFParagraph para : paras) {
this.replaceInPara(para, params);
}
}
}
}
}
/**
* 正則匹配字串
* @param paragraphText
* @return
*/
public Object matcher(String str) {
Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
return null;
}
/**
* 關閉輸入流
* @param is
*/
public void close(InputStream is) {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 關閉輸出流
* @param is
*/
public void close(OutputStream os) {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}