您的位置:首页 > 其它

POI操作word模板并生成新的word.docx

2017-12-25 16:20 225 查看

XWPFDocument对象

POI是apache提供的可以操作word文档的第三方jar。POI能操作word是使用XWPFDocument对象。

XWPFDocument对象可以解析docx文件,在XWPFDocument对象通过输入流解析docx的时候,会获取到docx文档中的各种对象,例如表格,段落,图片等,通过操作XWPFDocument对象就可以修改模板内容
XWPFDocument API结构org.apache.poi.xwpf.usermodel.XWPFDocument
XWPFDocument 提供write(OutputStream stream)方法将修改后的对象重新写入xml并生成新的docx
通过XWPFDocument 可以获得的docx中的各种对象



要具体操作通过XWPFDocument 可以获得的docx中的各种对象,我们离不开一个对象为XWPFRun对象,API结构org.apache.poi.xwpf.usermodel.XWPFRun。其描述为:XWPFRun object defines a region of text with a common set of properties。通过描述我们不难理解其作用为设置文本对象的各种属性。

通过XWPFDocument 获取对象

//解析docx模板并获取document对象
XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
//获取整个文本对象
List<XWPFParagraph> allParagraph = document.getParagraphs();
//获取整个表格对象
List<XWPFTable> allTable = document.getTables();
//获取图片对象
XWPFPictureData pic = document.getPictureDataByID("PICId");
1
2
3
4
5
6
7
8
首先建一个很简单的word模板001.docx,我们通过操作对象获取word中的文本内容



下面demo的输出可以看出我们操作文本对象,成功获取了文本内容

@Component("xWPRUNTest")
public class XWPRUNTest {
//模板文件地址
private static String inputUrl = "C:\\Users\\zhihe\\Desktop\\demo\\001.docx";
public void runTest(){

try {
//解析docx模板并获取document对象
XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
//获取整个文本对象
List<XWPFParagraph> allParagraph = document.getParagraphs();

//获取XWPFRun对象输出整个文本内容
StringBuffer tempText = new StringBuffer();
for (XWPFParagraph xwpfParagraph : allParagraph) {
List<XWPFRun> runList = xwpfParagraph.getRuns();
for (XWPFRun xwpfRun : runList) {
tempText.append(xwpfRun.toString());
}
}
System.out.println(tempText.toString());

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class runTest {

@Resource
private XWPRUNTest xWPRUNTest;

@Test
public void runTest(){
xWPRUNTest.runTest();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
控制台输出结果



在这里发现操作文本对象的时候并没有获取到表格文本,所以如果我们需要获取到表格文本还需要另外的操作

@Component("xWPRUNTableTest")
public class XWPRUNTableTest {

//模板文件地址
private static String inputUrl = "C:\\Users\\zhihe\\Desktop\\demo\\001.docx";

public void tableTest(){

try {

StringBuffer tableText = new StringBuffer();

//解析docx模板并获取document对象
XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
//获取全部表格对象
List<XWPFTable> allTable = document.getTables();

for (XWPFTable xwpfTable : allTable) {
//获取表格行数据
List<XWPFTableRow> rows = xwpfTable.getRows();
for (XWPFTableRow xwpfTableRow : rows) {
//获取表格单元格数据
List<XWPFTableCell> cells = xwpfTableRow.getTableCells();
for (XWPFTableCell xwpfTableCell : cells) {
List<XWPFParagraph> paragraphs = xwpfTableCell.getParagraphs();
for (XWPFParagraph xwpfParagraph : paragraphs) {
List<XWPFRun> runs = xwpfParagraph.getRuns();
for(int i = 0; i < runs.size();i++){
XWPFRun run = runs.get(i);
tableText.append(run.toString());
}
}
}
}
}

System.out.println(tableText.toString());

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
测试

成功获取表格



下面我们来对一个wrod进行简单的修改,首先有个模板word,里面只有几个字



代码

public class FirstWordTest {

//模板文件地址
private static String inputUrl = "C:\\Users\\zhihe\\Desktop\\demo\\001.docx";
//新生产的模板文件
private static String outputUrl = "C:\\Users\\zhihe\\Desktop\\demo\\test.docx";

/**
*
* @param inputUrl 模板路径
* @param outputUrl 模板保存路径
*/
public static void changeWord(String inputUrl, String outputUrl ){

try {
//获取word文档解析对象
XWPFDocument doucument = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
//获取段落文本对象
List<XWPFParagraph> paragraph = doucument.getParagraphs();
//获取首行run对象
XWPFRun run = paragraph.get(0).getRuns().get(0);
//设置文本内容
run.setText("修改了的word");
//生成新的word
File file = new File(outputUrl);

FileOutputStream stream = new FileOutputStream(file);
doucument.write(stream);
stream.close();

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public static void main(String[] args) {
changeWord(inputUrl,outputUrl);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
测试

运行后生成新的word



但是在实际项目中并没有这么简单,模板文档中可能需要替换文本中的文字,也可能需要替换表格对象中的文字,或者在指定表格中插入数据,下面我们就仿照实际情况来做个简单的模板。

首先创建一个word的模板



工具类

package com.lovo.utils.wordToPdf;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.poi.POIXMLDocument;
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模板生成新的word工具类
*
* @author zhiheng
*
*/
public class WorderToNewWordUtils {

/**
* 根据模板生成新word文档
* 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
* @param inputUrl 模板存放地址
* @param outPutUrl 新文档存放地址
* @param textMap 需要替换的信息集合
* @param tableList 需要插入的表格信息集合
* @return 成功返回true,失败返回false
*/
public static boolean changWord(String inputUrl, String outputUrl,
Map<String, String> textMap, List<String[]> tableList) {

//模板转换默认成功
boolean changeFlag = true;
try {
//获取docx解析对象
XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
//解析替换文本段落对象
WorderToNewWordUtils.changeText(document, textMap);
//解析替换表格对象
WorderToNewWordUtils.changeTable(document, textMap, tableList);

//生成新的word
File file = new File(outputUrl);
FileOutputStream stream = new FileOutputStream(file);
document.write(stream);
stream.close();

} catch (IOException e) {
e.printStackTrace();
changeFlag = false;
}

return changeFlag;

}

/**
* 替换段落文本
* @param document docx解析对象
* @param textMap 需要替换的信息集合
*/
public static void changeText(XWPFDocument document, Map<String, String> textMap){
//获取段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();

for (XWPFParagraph paragraph : paragraphs) {
//判断此段落时候需要进行替换
String text = paragraph.getText();
if(checkText(text)){
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替换模板原来位置
run.setText(changeValue(run.toString(), textMap),0);
}
}
}

}

/**
* 替换表格对象方法
* @param document docx解析对象
* @param textMap 需要替换的信息集合
* @param tableList 需要插入的表格信息集合
*/
public static void changeTable(XWPFDocument document, Map<String, String> textMap,
List<String[]> tableList){
//获取表格对象集合
List<XWPFTable> tables = document.getTables();
for (int i = 0; i < tables.size(); i++) {
//只处理行数大于等于2的表格,且不循环表头
XWPFTable table = tables.get(i);
if(table.getRows().size()>1){
//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入
if(checkText(table.getText())){
List<XWPFTableRow> rows = table.getRows();
//遍历表格,并替换模板
eachTable(rows, textMap);
}else{
//                  System.out.println("插入"+table.getText());
insertTable(table, tableList);
}
}
}
}

/**
* 遍历表格
* @param rows 表格行对象
* @param textMap 需要替换的信息集合
*/
public static void eachTable(List<XWPFTableRow> rows ,Map<String, String> textMap){
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
//判断单元格是否需要替换
if(checkText(cell.getText())){
List<XWPFParagraph> paragraphs = cell.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
run.setText(changeValue(run.toString(), textMap),0);
}
}
}
}
}
}

/**
* 为表格插入数据,行数不够添加新行
* @param table 需要插入数据的表格
* @param tableList 插入数据集合
*/
public static void insertTable(XWPFTable table, List<String[]> tableList){
//创建行,根据需要插入的数据添加新行,不处理表头
for(int i = 1; i < tableList.size(); i++){
XWPFTableRow row =table.createRow();
}
//遍历表格插入数据
List<XWPFTableRow> rows = table.getRows();
for(int i = 1; i < rows.size(); 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 text 文本
* @return 包含返回true,不包含返回false
*/
public static boolean checkText(String text){
boolean check  =  false;
if(text.indexOf("$")!= -1){
check = true;
}
return check;

}

/**
* 匹配传入信息集合与模板
* @param value 模板需要替换的区域
* @param textMap 传入信息集合
* @return 模板需要替换区域信息集合对应值
*/
public static String changeValue(String value, Map<String, String> textMap){
Set<Entry<String, String>> textSets = textMap.entrySet();
for (Entry<String, String> textSet : textSets) {
//匹配模板与替换值 格式${key}
String key = "${"+textSet.getKey()+"}";
if(value.indexOf(key)!= -1){
value = textSet.getValue();
}
}
//模板未匹配到区域替换为空
if(checkText(value)){
value = "";
}
return value;
}

public static void main(String[] args) {
//模板文件地址
String inputUrl = "C:\\Users\\zhihe\\Desktop\\demo\\001.docx";
//新生产的模板文件
String outputUrl = "C:\\Users\\zhihe\\Desktop\\demo\\test.docx";

Map<String, String> testMap = new HashMap<String, String>();
testMap.put("name", "小明");
testMap.put("sex", "男");
testMap.put("address", "软件园");
testMap.put("phone", "88888888");

List<String[]> testList = new ArrayList<String[]>();
testList.add(new String[]{"1","1AA","1BB","1CC"});
testList.add(new String[]{"2","2AA","2BB","2CC"});
testList.add(new String[]{"3","3AA","3BB","3CC"});
testList.add(new String[]{"4","4AA","4BB","4CC"});

WorderToNewWordUtils.changWord(inputUrl, outputUrl, testMap, testList);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
测试



这么我们就实现了个简单的POI操作模板完成替换和插入的功能,本来还准备实现固定位置插入图片的功能,不过发现这是个巨坑,暂时未实现其功能,等以后有空再进行完善,此代码以docx格式进行演示操作
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: