1、Java操作word基本介绍
Java对Word文档的基本操作可以通过Apache POI库实现,主要包括以下几个方面:
- 创建Word文档:可以通过
创建XWPFDocument对象来创建一个空白的Word文档
。- 读取Word文档:可以通过XWPFDocument对象的
构造函数读取已有的Word文档
。- 插入段落:可以通过XWPFDocument对象的
createParagraph()方法创建一个段落
,然后设置段落的样式和内容。- 插入表格:可以通过XWPFDocument对象的
createTable()方法创建一个表格
,然后设置表格的样式和内容。- 插入图片:可以通过XWPFDocument对象的
createParagraph()方法创建一个段落
,然后使用XWPFRun对象的addPicture()方法插入图片。- 保存Word文档:可以通过XWPFDocument对象的
write()
方法将文档保存
到指定的文件路径。
2、添加maven依赖
<!-- 引入poi-ooxml依赖,2007+使用 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
3、示例一(创建新文档)
下面是一个简单的java操作word表格的示例,演示了如何创建一个Word文档并创建表格,以及
水平合并单元格
(合并列)、垂直合并单元格
(合并行)、单元格赋值
等操作。
3.1 创建新Word文档
// 创建一个新的Word文档
XWPFDocument document = new XWPFDocument();
3.2 创建新表格
// 创建一个新的表格,11行7列
XWPFTable table = document.createTable(11, 7);
3.3 设置表格样式
在Word文档中,表格样式是通过样式名称来定义的,例如"Table Grid"就是一种内置的表格样式。
// 设置表格样式
table.getCTTbl().addNewTblPr().addNewTblStyle().setVal("Table Grid");
3.4 设置表格宽度
// 设置表格宽度为100%
table.setWidth("100%");
3.5 循环填充单元格内容
// 填充表格内容
XWPFTableCell cell = null;
for (int row = 0; row < 11; row++) { // 循环遍历表格的行
for (int col = 0; col < 7; col++) { // 循环遍历表格的列
// 获取当前单元格
cell = table.getRow(row).getCell(col);
// 设置单元格内容垂直居中
cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
// 设置单元格内容水平居中(获取单元格中的第一个段落对象)
cell.getParagraphArray(0).setAlignment(ParagraphAlignment.CENTER);
// 设置单元格内容
cell.setText("行 " + (row + 1) + ", 列 " + (col + 1));
}
}
3.6 合并单元格
3.6.1 合并行
// 合并第1行的第2列到第4列
table.getRow(0).getCell(1).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
table.getRow(0).getCell(2).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
table.getRow(0).getCell(3).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
效果:
3.6.2 合并列
// 合并第1列的第3行到第4行
table.getRow(2).getCell(0).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
table.getRow(3).getCell(0).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
效果:
3.6.3 跨列跨行合并
跨行跨列合并是合并行、合并列的组合,因此需要按照一定的合并顺序来进行。下面是一个
合并第4行第4列、第5列、第5行第4列、第5列为一个单元格
的步骤。
// 合并第4行第4列、第5列、第5行第4列、第5列为一个单元格
// 1. 合并第4行的第4列到第5列
table.getRow(3).getCell(3).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
table.getRow(3).getCell(4).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
// 2. 合并第5行的第4列到第5列
table.getRow(4).getCell(3).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
table.getRow(4).getCell(4).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
// 3. 合并第4列的第4行到第5行
table.getRow(3).getCell(3).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
table.getRow(4).getCell(3).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
效果:
3.7 保存文档
// 输出流,用于将文档写入磁盘
FileOutputStream fos = new FileOutputStream("f:/test.docx");
// 将文档写入输出流
document.write(fos);
3.8 关闭输出流与文档
// 关闭输出流
fos.close();
// 关闭文档
document.close();
3.9 完整代码
3.9.1 源码
合并列和合并行的代码,这里进行了封装,优化了代码结构,具体内容可看以下代码:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
public class ToolWord {
public static void main(String[] args) {
test();
}
public static void test() {
// 1.创建一个新的Word文档
XWPFDocument document = new XWPFDocument();
FileOutputStream fos = null;
try {
// 2.创建一个新的表格,11行7列
XWPFTable table = document.createTable(11, 7);
// 3.设置表格样式
table.getCTTbl().addNewTblPr().addNewTblStyle().setVal("Table Grid");
table.setWidth("100%"); // 设置表格宽度为100%
// 4.填充表格内容
XWPFTableCell cell = null;
for (int row = 0; row < 11; row++) { // 循环遍历表格的行
for (int col = 0; col < 7; col++) { // 循环遍历表格的列
// 获取当前单元格
cell = table.getRow(row).getCell(col);
// 设置单元格内容垂直居中
cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
// 设置单元格内容水平居中(获取单元格中的第一个段落对象)
cell.getParagraphArray(0).setAlignment(ParagraphAlignment.CENTER);
// 设置单元格内容
cell.setText("行 " + (row + 1) + ", 列 " + (col + 1));
}
}
/**
// 5.合并单元格方式一 // 5.1 合并第1行的第2列到第4列
table.getRow(0).getCell(1).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
table.getRow(0).getCell(2).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
table.getRow(0).getCell(3).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
// 5.2 合并第1列的第3行到第4行
table.getRow(2).getCell(0).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
table.getRow(3).getCell(0).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
// 5.3 合并第4行第4列、第5列、第5行第4列、第5列为一个单元格 // 5.3.1 合并第4行的第4列到第5列
table.getRow(3).getCell(3).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
table.getRow(3).getCell(4).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
// 5.3.2 合并第5行的第4列到第5列
table.getRow(4).getCell(3).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
table.getRow(4).getCell(4).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
// 5.3.3 合并第4列的第4行到第5行
table.getRow(3).getCell(3).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
table.getRow(4).getCell(3).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
**/
// 6.合并单元格方式二(推荐)
// 6.1 水平合并第1行的第2列到第4列
mergeCellsByHorizontal(table, 0, 1, 3);
// 6.2 垂直合并第1列的第3行到第4行
mergeCellsByVertically(table, 0, 2, 3);
// 6.3 合并第4行第4列、第5列、第5行第4列、第5列为一个单元格
// 6.3.1 合并第4行的第4列到第5列
mergeCellsByHorizontal(table, 3, 3, 4);
// 6.3.2 合并第5行的第4列到第5列
mergeCellsByHorizontal(table, 4, 3, 4);
// 6.3.3 合并第4列的第4行到第5行
mergeCellsByVertically(table, 3, 3, 4);
// 保存文档
// 输出流,用于将文档写入磁盘
fos = new FileOutputStream("f:/test.docx");
// 将文档写入输出流
document.write(fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
// 关闭输出流
fos.close();
if (document != null) {
// 关闭Word文档
document.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("Word文档生成成功!");
}
// ==================== private method ====================
/**
* <h5>描述:水平方向合并单元格<h5>
* @param table 表格
* @param rowIndex 合并列所在的行下标(从0开始)
* @param startCellIndex 开始合并的列下标(从0开始)
* @param endCellIndex 结束合并的列下标(从0开始)
*/
private static void mergeCellsByHorizontal(XWPFTable table, int rowIndex, int startCellIndex, int endCellIndex) {
String str = "";
for (int i = startCellIndex; i <= endCellIndex; i++) {
XWPFTableCell cell = table.getRow(rowIndex).getCell(i);
str = "table.getRow("+rowIndex+").getCell("+i+")";
if (i == startCellIndex) {
// The first merged cell is set with RESTART merge value
cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
System.out.println(str + ".getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);");
} else {
// Cells which join (merge) the first one, are set with CONTINUE
cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
System.out.println(str + ".getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);");
}
}
}
/**
* <h5>描述:垂直方向合并单元格<h5>
* @param table 表格
* @param columnIndex 合并行所在列下标(从0开始)
* @param startCell 开始合并的行下标(从0开始)
* @param endCell 结束合并的行下标(从0开始)
*/
private static void mergeCellsByVertically(XWPFTable table, int columnIndex, int startRowIndex, int endRowIndex) {
String str = "";
for (int i = startRowIndex; i <= endRowIndex; i++) {
XWPFTableCell cell = table.getRow(i).getCell(columnIndex);
str = "table.getRow("+i+").getCell("+columnIndex+")";
if (i == startRowIndex) {
// The first merged cell is set with RESTART merge value
cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
System.out.println(str + ".getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);");
} else {
// Cells which join (merge) the first one, are set with CONTINUE
cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
System.out.println(str + ".getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);");
}
}
}
}
3.9.2 执行信息
3.9.3 效果
4、示例二(模板调用)
下面也是一个简单的java操作word表格的示例,演示了如何获取一个已存在的Word模板,并对表格进行插入新行、合并行、合并列、单元格赋值等操作。
4.1 word模板
4.2 读取Word模板文件
"f:/Word模板.docx"是word模板全路径
// 读取Word模板文件
XWPFDocument document = new XWPFDocument(new FileInputStream("f:/Word模板.docx"));
4.3 获取指定表格
表格下标都是从0开始,这里获取的是第1个表格
// 获取第一个表格(表格下标从0开始)
XWPFTable table = document.getTables().get(0);
4.4 指定位置添加行
添加行之后,至少要新建一个单元格,否则不会添加成功
int rowIndex = 3;
// 在指定行下面添加一行(下标从0开始),这里添加到第4行
XWPFTableRow newRow = table.insertNewTableRow(rowIndex);
// 新行创建单元格
for (int i = 0; i < 6; i++) {
if (i % 2 == 1) {
newRow.createCell(); // 仅创建新单元格
continue;
}
newRow.createCell().setText("新单元格" + (rowIndex + 1) + (i + 1)); // 创建新单元格并填充内容
}
4.5 填充表格内容
4.5.1 先新增再填充
插入了新行之后再填充表格内容,表格内容是连续的
// --------------------在指定行下面添加一行,并创建指定数量的单元格start--------------------
int rowIndex = 3;
// 在指定行下面添加一行(下标从0开始),这里添加到第4行
XWPFTableRow newRow = table.insertNewTableRow(rowIndex);
// 新行创建单元格
for (int i = 0; i < 6; i++) {
if (i % 2 == 1) {
newRow.createCell(); // 仅创建新单元格
continue;
}
newRow.createCell().setText("新单元格" + (rowIndex + 1) + (i + 1)); // 创建新单元格并填充内容
}
// --------------------在指定行下面添加一行,并创建指定数量的单元格end--------------------
// 填充表格内容
XWPFTableRow tableRow = null;
List<XWPFTableCell> cellList = null;
List<XWPFTableRow> rowList = table.getRows();
for (int i = 0; i < rowList.size(); i++) {
// 如果是刚才新添加的行,则不填充表格内容
if (i == rowIndex) {
continue;
}
tableRow = rowList.get(i);
cellList = tableRow.getTableCells();
for (int j = 0; j < cellList.size(); j++) {
cellList.get(j).setText("info " + (i + 1) + (j + 1));
}
}
效果:
4.5.2 先填充再新增
填充表格内容之后再插入新行,表格内容会从中间断开
// 填充表格内容
XWPFTableRow tableRow = null;
List<XWPFTableCell> cellList = null;
List<XWPFTableRow> rowList = table.getRows();
for (int i = 0; i < rowList.size(); i++) {
tableRow = rowList.get(i);
cellList = tableRow.getTableCells();
for (int j = 0; j < cellList.size(); j++) {
cellList.get(j).setText("info " + (i + 1) + (j + 1));
}
}
// --------------------在指定行下面添加一行,并创建指定数量的单元格start--------------------
int rowIndex = 5;
// 在指定行下面添加一行(下标从0开始),这里添加到第6行
XWPFTableRow newRow2 = table.insertNewTableRow(rowIndex);
// 新行创建单元格
for (int i = 0; i < 6; i++) {
if (i % 2 == 0) {
newRow2.createCell(); // 仅创建新单元格
continue;
}
newRow2.createCell().setText("新单元格" + (rowIndex + 1) + (i + 1)); // 创建新单元格并填充内容
}
// --------------------在指定行下面添加一行,并创建指定数量的单元格end--------------------
效果:
4.6 表格末尾添加行
添加行之后,至少要新建一个单元格,否则不会添加成功
// 表格末尾添加一行
XWPFTableRow newRow3 = table.createRow();
// 设置新行的单元格内容
newRow3.getCell(0).setText("新单元格 1");
newRow3.getCell(1).setText("新单元格 2");
newRow3.getCell(2).setText("新单元格 3");
效果:
4.7 保存文档
// 输出流,用于将文档写入磁盘
FileOutputStream fos = new FileOutputStream("f:/test.docx");
// 将文档写入输出流
document.write(fos);
4.8 关闭输出流与文档
// 关闭输出流
fos.close();
// 关闭文档
document.close();
4.9 完整代码
4.9.1 源码
代码结构进行了整合优化,与以上代码稍有不同,但不影响阅读
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
public class ToolWord {
public static void main(String[] args) {
readWord();
}
public static void readWord() {
XWPFDocument document = null;
FileOutputStream out = null;
try {
// 读取Word模板文件
document = new XWPFDocument(new FileInputStream("f:/Word模板.docx"));
// 获取第一个表格(表格下标从0开始)
XWPFTable table = document.getTables().get(0);
// --------------------在指定行下面添加一行,并创建指定数量的单元格start--------------------
int rowIndex = 3;
// 在指定行下面添加一行(下标从0开始),这里添加到第4行
XWPFTableRow newRow = table.insertNewTableRow(rowIndex);
// 新行创建单元格
for (int i = 0; i < 6; i++) {
if (i % 2 == 1) {
newRow.createCell(); // 仅创建新单元格
continue;
}
newRow.createCell().setText("新单元格" + (rowIndex + 1) + (i + 1)); // 创建新单元格并填充内容
}
// --------------------在指定行下面添加一行,并创建指定数量的单元格end--------------------
// 填充表格内容
XWPFTableRow tableRow = null;
List<XWPFTableCell> cellList = null;
List<XWPFTableRow> rowList = table.getRows();
for (int i = 0; i < rowList.size(); i++) {
// 如果是刚才新添加的行,则不填充表格内容
if (i == rowIndex) {
continue;
}
tableRow = rowList.get(i);
cellList = tableRow.getTableCells();
for (int j = 0; j < cellList.size(); j++) {
cellList.get(j).setText("info " + (i + 1) + (j + 1));
}
}
// --------------------在指定行下面添加一行,并创建指定数量的单元格start--------------------
rowIndex = 5;
// 在指定行下面添加一行(下标从0开始),这里添加到第6行
XWPFTableRow newRow2 = table.insertNewTableRow(rowIndex);
// 新行创建单元格
for (int i = 0; i < 6; i++) {
if (i % 2 == 0) {
newRow2.createCell(); // 仅创建新单元格
continue;
}
newRow2.createCell().setText("新单元格" + (rowIndex + 1) + (i + 1)); // 创建新单元格并填充内容
}
// --------------------在指定行下面添加一行,并创建指定数量的单元格end--------------------
// 表格末尾添加一行
XWPFTableRow newRow3 = table.createRow();
// 设置新行的单元格内容
newRow3.getCell(0).setText("新单元格 1");
newRow3.getCell(1).setText("新单元格 2");
newRow3.getCell(2).setText("新单元格 3");
// 保存修改后的Word文件
out = new FileOutputStream("f:/新word.docx");
document.write(out);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
// 关闭输出流
out.close();
if (document != null) {
// 关闭Word文档
document.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("新Word文档生成成功!");
}
}
4.9.2 执行信息
4.9.3 效果
可以很明显的看到,先新增行再填充数据的单元格数据是连续的,先填充数据再新增的行,单元格数据被从中间隔开了