目录
问题
项目中需要将业务数据制成表格并插入word文档中,同时还需向word文档中插入图片,最后导出word文档。
如何解决
基于 poi 写了一个通用的doc操作类,支持插入表格和图片,最后导出。
代码
pom
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version>
</dependency>
doc操作类
public class PoiDocDo {
XWPFDocument xDoc;
String name;
public static PoiDocBuilder builder() { return new PoiDocBuilder();}
public PoiDocDo(PoiDocBuilder builder) {
xDoc = new XWPFDocument();
name = builder.name;
}
public static class PoiDocBuilder {
String name = "default";
public PoiDocDo build() {
return new PoiDocDo(this);
}
public PoiDocBuilder name(String name) {
this.name = name;
return this;
}
}
public PoiDocDo insertParagraph(String text) {
XWPFParagraph xPara = xDoc.createParagraph();
xPara.setAlignment(ParagraphAlignment.LEFT);
XWPFRun run = xPara.createRun();
run.setFontSize(20);
run.setText(text);
run.addCarriageReturn();
return this;
}
/**
* 往文档中插入表格
*
* @param columns 列头
* @param rows 内容行
*/
public PoiDocDo insertTable(List<Map<String, String>> columns,
List<Map<String, Object>> rows) {
XWPFTable xTable = xDoc.createTable(rows.size() + 1, columns.size());
centerTableContent(xTable, columns.size());
XWPFTableRow columnNameRow = xTable.getRow(0);
List<String> columnFields = new ArrayList<>();
Map<String, String> columnMap;
for (int i = 0; i < columns.size(); i++) {
columnMap = columns.get(i);
columnNameRow.getCell(i).setText(columnMap.get("name"));
columnFields.add(columnMap.get("field"));
}
XWPFTableRow contentRow;
Map<String, Object> rowMap;
for (int i = 1; i <= rows.size(); i++) {
contentRow = xTable.getRow(i);
rowMap = rows.get(i - 1);
for (int j = 0; j < columnFields.size(); j++) {
contentRow.getCell(j).setText(
rowMap.getOrDefault(columnFields.get(j), "").toString());
}
}
return this;
}
/**
* 表格内容居中,此方法为依次居中每个表格的内容
*
* @param xTable 表格
*/
private void centerTableContent(XWPFTable xTable, int numberOfColumns) {
for (int i = 0; i < xTable.getNumberOfRows(); i++) {
for (int j = 0; j < numberOfColumns; j++) {
XWPFTableCell cell = xTable.getRow(i).getCell(j);
CTTc cttc = cell.getCTTc();
CTTcPr ctPr = cttc.addNewTcPr();
ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
}
}
}
public PoiDocDo insertImage(List<Map<String, String>> imageInfoList) {
XWPFParagraph xPara;
XWPFRun run;
String imageName, imageData;
byte[] bytes;
for (Map<String, String> imageInfo : imageInfoList) {
imageName = imageInfo.get("imageName");
imageData = imageInfo.get("imageData");
bytes = Base64.getDecoder().decode(imageData);
xPara = xDoc.createParagraph();
xPara.setAlignment(ParagraphAlignment.LEFT);
run = xPara.createRun();
run.setFontSize(20);
run.setText(imageName);
run.addCarriageReturn();
try {
run.addPicture(new ByteArrayInputStream(bytes), XWPFDocument.PICTURE_TYPE_JPEG,
imageName, Units.toEMU(414), Units.toEMU(284));
}catch (Exception e){
e.printStackTrace();
}
}
return this;
}
public void export(OutputStream outputStream) {
try (OutputStream os = outputStream) {
xDoc.write(os);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void export(String desktopPath) {
String docName = (desktopPath + "\\" + name).replaceAll("\\\\+", "/");
try(OutputStream os = Files.newOutputStream(Paths.get(String.format("%s.docx", docName)))) {
xDoc.write(os);
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用示例
class PoiDocDoTest {
@Test
public void test() throws IOException {
PoiDocDo domainObj = PoiDocDo.builder().name("myDoc").build();
List<Map<String, String>> images = new ArrayList<>();
Map<String, String> imageMap = new HashMap<>();
images.add(imageMap);
imageMap.put("imageName", "test");
InputStream inputStream = Files.newInputStream(Paths.get("C:\\Users\\XXX\\Desktop\\XXX.png"));
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
imageMap.put("imageData", Base64.getEncoder().encodeToString(buffer.toByteArray()));
List<Map<String, String>> columns = new ArrayList<>();
Map<String, String> column = new HashMap<>();
columns.add(column);
column.put("name", "colum1");
column.put("field", "field1");
List<Map<String, Object>> rows = new ArrayList<>();
Map<String, Object> row = new HashMap<>();
rows.add(row);
row.put("field1", "abc");
domainObj.insertParagraph("This is a paragraph")
.insertParagraph("picture under me")
.insertImage(images)
.insertTable(columns, rows)
.export("C:\\Users\\XXX\\Desktop");
}
}