POI动态插入数据到Word文档

模板制作

制作word模版,${xxxx}是要替换的内容。注意${xxxx}是一个整体,中间不能断开,因为利用POI的API程序操作时,判断是否有这个${xxxx}才进行替换。

依赖的包

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>

<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>

操作docx文件

POI在读写word docx文件时是通过xwpf模块来进行的,其核心是XWPFDocument。一个XWPFDocument代表一个docx文档,其可以用来读docx文档,也可以用来写docx文档。XWPFDocument中主要包含下面这几种对象:

  • XWPFParagraph:代表一个段落。

  • XWPFRun:代表具有相同属性的一段文本。

  • XWPFTable:代表一个表格。

  • XWPFTableRow:表格的一行。

  • XWPFTableCell:表格对应的一个单元格。

具体代码:

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
/** 
* 根据指定的参数值、模板,生成 word 文档
* @param param 需要替换的变量,key值与模板里${xxxx}的xxx一样
* @param template 模板,docx文档
*/
public CustomXWPFDocument generateWord(Map<String, Object> param, String template) {
CustomXWPFDocument doc = null;
try {
OPCPackage pack = POIXMLDocument.openPackage(template);
doc = new CustomXWPFDocument(pack);
if (param != null && param.size() > 0) {
//处理段落
List<XWPFParagraph> paragraphList = doc.getParagraphs();
processParagraphs(paragraphList, param, doc);

//处理表格
Iterator<XWPFTable> it = doc.getTablesIterator();
while (it.hasNext()) {
XWPFTable table = it.next();
List<XWPFTableRow> rows = table.getRows();
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
List<XWPFParagraph> paragraphListTable = cell.getParagraphs();
processParagraphs(paragraphListTable, param, doc);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return doc;
}
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
/** 
* 处理段落
* @param paragraphList
*/
public void processParagraphs(List<XWPFParagraph> paragraphList,Map<String, Object> param,CustomXWPFDocument doc){
if(paragraphList != null && paragraphList.size() > 0){
for(XWPFParagraph paragraph : paragraphList){
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String text = run.getText(0);
if(text != null){
boolean isSetText = false;
for (Entry<String, Object> entry : param.entrySet()) {
String key = "${"+ entry.getKey() +"}";
if(text.indexOf(key) != -1){
isSetText = true;
Object value = entry.getValue();
if (value instanceof String) {//文本替换
text = text.replace(key, value.toString());
//System.out.println(text);
} else if (value instanceof Double) {
text = text.replace(key, value.toString());
} else if (value instanceof Map) {//图片替换
text = text.replace(key, "");
Map pic = (Map)value;
int width = Integer.parseInt(pic.get("width").toString());
int height = Integer.parseInt(pic.get("height").toString());
int picType = getPictureType(pic.get("type").toString());
byte[] byteArray = (byte[]) pic.get("content");
ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
try {
String ind = doc.addPictureData(byteInputStream, picType);
int id = doc.getNextPicNameNumber(picType);
createPicture(id, ind, width , height, run);
//System.out.println("图片替换");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
if(isSetText){
run.setText(text,0);
}
}
}
}
}
}


/**
* 根据图片类型,取得对应的图片类型代码
* @param picType
* @return int
*/
private int getPictureType(String picType){
int res = CustomXWPFDocument.PICTURE_TYPE_PICT;
if(picType != null){
if(picType.equalsIgnoreCase("png")){
res = CustomXWPFDocument.PICTURE_TYPE_PNG;
}else if(picType.equalsIgnoreCase("dib")){
res = CustomXWPFDocument.PICTURE_TYPE_DIB;
}else if(picType.equalsIgnoreCase("emf")){
res = CustomXWPFDocument.PICTURE_TYPE_EMF;
}else if(picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")){
res = CustomXWPFDocument.PICTURE_TYPE_JPEG;
}else if(picType.equalsIgnoreCase("wmf")){
res = CustomXWPFDocument.PICTURE_TYPE_WMF;
}
}
return res;
}


/**
* @param id
* @param width 宽
* @param height 高
* @param run 段落
*/
public void createPicture(int id, String blipId, int width, int height,XWPFRun run) {
final int EMU = 9525;
width *= EMU;
height *= EMU;

CTInline inline = run.getCTR().addNewDrawing().addNewInline();
String picXml = ""
+ "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
+ " <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
+ " <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
+ " <pic:nvPicPr>" + " <pic:cNvPr id=\""
+ id
+ "\" name=\"Generated\"/>"
+ " <pic:cNvPicPr/>"
+ " </pic:nvPicPr>"
+ " <pic:blipFill>"
+ " <a:blip r:embed=\""
+ blipId
+ "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
+ " <a:stretch>"
+ " <a:fillRect/>"
+ " </a:stretch>"
+ " </pic:blipFill>"
+ " <pic:spPr>"
+ " <a:xfrm>"
+ " <a:off x=\"0\" y=\"0\"/>"
+ " <a:ext cx=\""
+ width
+ "\" cy=\""
+ height
+ "\"/>"
+ " </a:xfrm>"
+ " <a:prstGeom prst=\"rect\">"
+ " <a:avLst/>"
+ " </a:prstGeom>"
+ " </pic:spPr>"
+ " </pic:pic>"
+ " </a:graphicData>" + "</a:graphic>";

inline.addNewGraphic().addNewGraphicData();
XmlToken xmlToken = null;
try {
xmlToken = XmlToken.Factory.parse(picXml);
} catch (XmlException xe) {
xe.printStackTrace();
}
inline.set(xmlToken);

inline.setDistT(0);
inline.setDistB(0);
inline.setDistL(0);
inline.setDistR(0);

CTPositiveSize2D extent = inline.addNewExtent();
extent.setCx(width);
extent.setCy(height);

CTNonVisualDrawingProps docPr = inline.addNewDocPr();
docPr.setId(id);
docPr.setName("图片" + id);
docPr.setDescr("测试");
}

输出docx文档

把返回的XWPFDocument写入到对应的流中。

1
2
FileOutputStream fopts = new FileOutputStream("E://andy.docx");
doc.write(fopts);

转pdf文档

相关包的依赖:

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.poi.xwpf.converter.core</artifactId>
<version>2.0.1</version>
</dependency>

<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.poi.xwpf.converter.pdf</artifactId>
<version>2.0.1</version>
</dependency>

把XWPFDocument转成PDF:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
FileOutputStream fopts = new FileOutputStream(new FIle("E://andy.pdf"));
PdfOptions options = PdfOptions.create();
options.fontProvider(new IFontProvider() {
@Override
public Font getFont(String s, String s1, float v, int i, Color color) {
try {
BaseFont bfChinese = BaseFont.createFont(rootPath + "wordtemplate/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
Font fontChinese = new Font(bfChinese, v, i, color);
if (s != null) {
fontChinese.setFamily(s);
}
return fontChinese;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
});
PdfConverter.getInstance().convert(doc, fopts, options);

其中doc就是要转的XWPFDocument。simsun.ttf 是字体文件。

最后测试后模板的处理结果:

参考资料

http://alexgl.iteye.com/blog/2326665

http://elim.iteye.com/blog/2049110

https://blog.csdn.net/qq_32918555/article/details/77606215

https://blog.csdn.net/ztt_1119/article/details/69390807

https://www.cnblogs.com/duanrantao/p/8682897.html

http://53873039oycg.iteye.com/category/302596