在需要使用word模板来动态生成合同、协议等文件时,可以利用Java POI来实现动态替换。
例如一下情况:
下面展示一些 内联代码片
。
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poiartifactId>
<version>3.9version>
dependency>
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poi-ooxmlartifactId>
<version>3.9version>
dependency>
public void aucLotDownLoad(HttpServletResponse response) {
SimpleDateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
//获取模板文件的目录地址
String fileDir = new File("C:\\Users\\issuser\\Documents").getCanonicalPath();
//获取模板文件
File demoFile = new File(fileDir + "/template.docx");
FileInputStream in = new FileInputStream(demoFile);
XWPFDocument hdt = new XWPFDocument(in);
//替换读取到的word模板内容的指定字段
Map<String, Object> map = new HashMap<String, Object>();
map.put("firstParty", "123");
map.put("secondParty", "456");
map.put("date", dateFormater.format(new Date()));
replaceParams(hdt,map);
//此处为表格中数据
Map<String, Object> tableMap = new HashMap<String, Object>();
tableMap.put("position","pe");
tableMap.put("workTime","20");
tableMap.put("wages",12345);
replaceTableParams(hdt,tableMap);
//!!若还有其他表格则继续按以上格式生成对应关键字的map做替换。
//输出word内容文件流,提供下载
response.setContentType("application/vnd.ms-word;charset=utf-8");
response.setCharacterEncoding("utf-8");
response.addHeader("Cache-Control", "no-cache");
String fileName = "文件名";
// Content-disposition属性设置成以附件方式进行下载
// URLEncoder.encode解决中文名乱码(attachment;filename=中文文件名)
try {
response.setHeader("Content-disposition", "attachment;filename="+ URLEncoder.encode(fileName, "UTF-8")+".docx");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
OutputStream outputStream = response.getOutputStream();
outputStream.flush();
hdt.write(outputStream);
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
以下为函数方法,可直接复制使用(转于https://www.cnblogs.com/faxi/p/15143820.html)
/**
* 替换段落里面的变量
*
* @param doc 要替换的文档
* @param params 参数
*/
private static void replaceParams(XWPFDocument doc, Map<String, Object> params) {
Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
XWPFParagraph paragraph;
while (iterator.hasNext()) {
paragraph = iterator.next();
replaceParam(paragraph, params);
}
}
/**
* @param doc docx解析对象
* @param params 需要替换的信息集合
* @param tableIndex 第几个表格
* @param tableList 需要插入的表格信息集合
*/
public static void changeTable(XWPFDocument doc, Map<String, Object> params, int tableIndex, List<String[]> tableList) {
//获取表格对象集合
List<XWPFTable> tables = doc.getTables();
//获取第一个表格 根据实际模板情况 决定去第几个word中的表格
XWPFTable table = tables.get(tableIndex);
//替换表格中的参数
replaceTableParams(doc, params);
//在表格中插入数据
insertTable(table, tableList);
}
/**
* 替换表格里面的变量
*
* @param doc 要替换的文档
* @param params 参数
*/
private static void replaceTableParams(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();
//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
if (matcher(table.getText()).find()) {
rows = table.getRows();
for (XWPFTableRow row : rows) {
cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
paras = cell.getParagraphs();
for (XWPFParagraph para : paras) {
replaceParam(para, params);
}
}
}
}
}
}
/**
* 为表格插入行数,此处不处理表头,所以从第二行开始
*
* @param table 需要插入数据的表格
* @param tableList 插入数据集合
*/
private static void insertTable(XWPFTable table, List<String[]> tableList) {
//创建与数据一致的行数
for (int i = 0; i < tableList.size(); i++) {
table.createRow();
}
int length = table.getRows().size();
for (int i = 1; i < length; i++) {
XWPFTableRow newRow = table.getRow(i);
List<XWPFTableCell> cells = newRow.getTableCells();
for (int j = 0; j < cells.size(); j++) {
XWPFTableCell cell = cells.get(j);
cell.setText(tableList.get(i - 1)[j]);
}
}
}
/**
* 替换段落里面的变量
*
* @param paragraph 要替换的段落
* @param params 参数
*/
private static void replaceParam(XWPFParagraph paragraph, Map<String, Object> params) {
List<XWPFRun> runs;
Matcher matcher;
String runText = "";
if (matcher(paragraph.getParagraphText()).find()) {
runs = paragraph.getRuns();
int j = runs.size();
for (int i = 0; i < j; i++) {
runText += runs.get(0).toString();
//保留最后一个段落,在这段落中替换值,保留段落样式
if (!((j - 1) == i)) {
paragraph.removeRun(0);
}
}
matcher = matcher(runText);
if (matcher.find()) {
while ((matcher = matcher(runText)).find()) {
runText = matcher.replaceFirst(String.valueOf(params.get(matcher.group(1))));
}
runs.get(0).setText(runText, 0);
}
}
}
/**
* 正则匹配字符串
*
* @param str
* @return
*/
private static Matcher matcher(String str) {
Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
return matcher;
}
在word 2007及以后使用的是.docx格式,使用此处的XWPFDocument 即可,若是03版本的.doc格式,则需要换成HWPFDocument。
主要方法如下:
String fileDir = new File(base.getFile(), "../../../../../../doc/").getCanonicalPath();
//获取模板文件
File demoFile=new File(fileDir + "/1.doc");
FileInputStream in = new FileInputStream(demoFile);
HWPFDocument hdt = new HWPFDocument(in);
//替换读取到的word模板内容的指定字段
Range range = hdt.getRange();
Map<String, String> map = new HashMap<String, String>();
map.put("$PMBD$", goodsName);
map.put("$PMKSSJ$", dateFormater.format(startTime));
map.put("$MSRHP$", brandNo);
map.put("$PMCJJ$", numberToHanZiUtility.number2CNMontrayUnit(dealPrice));
map.put("$PMYJ$", numberToHanZiUtility.number2CNMontrayUnit(clientCommison));
map.put("$HJ$", numberToHanZiUtility.number2CNMontrayUnit(totalPrice));
map.put("$HJXX$", totalPrice + "");
map.put("$PMJSSJ$", dateFormater.format(endTime));
for (Map.Entry<String,String> entry:map.entrySet()) {
range.replaceText(entry.getKey(),entry.getValue());
可参考https://www.cnblogs.com/mr-wuxiansheng/p/6131494.html