SpringBoot操作XWPFTable(3)合并单元格

原文链接:SpringBoot操作XWPFTable(3)合并单元格 – 每天进步一点点

 

0.前言

前面的文章介绍了在word中创建表格的行,这一篇中简单介绍一下合并单元格以及修改样式的一些方法。

1.合并单元格

分为合并行和合并列两种方式


    void testXWPFTable1(){
        System.out.println("开始执行");
        try {
            //定义word
            XWPFDocument doc = new XWPFDocument();
            //在word中创建一个表格(2行,3列)
            XWPFTable table = doc.createTable(3,3);
            //第一行数据
            table.getRow(0).getCell(0).setText("1");
            table.getRow(0).getCell(1).setText("2");
            table.getRow(0).getCell(2).setText("3");
            table.getRow(1).getCell(0).setText("4");
            table.getRow(1).getCell(1).setText("5");
            table.getRow(1).getCell(2).setText("6");
            table.getRow(2).getCell(0).setText("7");
            table.getRow(2).getCell(1).setText("8");
            table.getRow(2).getCell(2).setText("9");
            //横向合并,第一行的0和1
            table.getRow(0).getCell(0).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
            table.getRow(0).getCell(1).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
            //竖向合并,
            table.getRow(1).getCell(0).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
            table.getRow(2).getCell(0).getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
            //导出
            String path = "C:\\";  //文件路径
            String name = "test1";  //文件名
            path = path + "/" + name + ".docx";
            File file = new File(path);
            if (!file.exists()) {
                file.createNewFile();
            }
            FileOutputStream out = new FileOutputStream(file);
            doc.write(out);
        }catch (IOException  e){
            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
/**
  * @Description: 跨列合并
  * table
  * row:行
  * fromCell:开始列
  * toCell:结束列
  */
 public  void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) {
     for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {
         XWPFTableCell cell = table.getRow(row).getCell(cellIndex);
         if ( cellIndex == fromCell ) {
             // The first merged cell is set with RESTART merge value
             cell.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);
         }
     }
 }
 /**
  * @Description: 跨行合并
  * table
  * col:列
  * formRow:开始行
  * toRow:结束行
  */
 public  void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {
     for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
         XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
         if ( rowIndex == fromRow ) {
             // The first merged cell is set with RESTART merge value
             cell.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);
         }
     }
 }

再测试一下导入word中合并单元格的方法

要导入的表格如下:

测试代码:

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
void testXWPFTable2(){
     System.out.println("开始执行");
     try {
         InputStream is = new FileInputStream("C:\\test.docx");
         //定义word
         XWPFDocument doc = new XWPFDocument(is);
         //获取word中所有的表格
         List<XWPFTable> tableList  = doc.getTables();
         XWPFTable table1 = tableList.get(0);  //表格中第一个表
         table1.createRow(); //创建一行
         //合并单元格
         mergeCellsHorizontal(table1,0,0,2);
         mergeCellsVertically(table1,1,1,2);
 
         //导出
         String path = "C:\\"//文件路径
         String name = "test2"//文件名
         path = path + "/" + name + ".docx";
         File file = new File(path);
         if (!file.exists()) {
             file.createNewFile();
         }
         FileOutputStream out = new FileOutputStream(file);
         doc.write(out);
     }catch (IOException  e){
         e.printStackTrace();
     }
 }

效果:

2.addRow合并的问题:

上面验证了合并单元格的一些方式不论是手动创建表格,还是读取表格后,都能正常合并。包括使用createRow这个方法后,也能正常合并。但是使用addRow方法后,发现并不能正常使用。例子如下:

我们先读取一个本地文件

我们在红色箭头处通过addRow方法插入一个新行,然后执行合并操作,看看效果。

参考代码:

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
void testXWPFTable2(){
       System.out.println("开始执行");
       try {
           InputStream is = new FileInputStream("C:\\test.docx"); //读取了一个4*4的表格
           //定义word
           XWPFDocument doc = new XWPFDocument(is);
           //获取word中所有的表格
           List<XWPFTable> tableList  = doc.getTables();
           XWPFTable table1 = tableList.get(0);  //表格中第一个表
 
           CTRow ctrow = null;
           try {
               ctrow = CTRow.Factory.parse(table1.getRow(0).getCtRow().newInputStream());  //复制
           } catch (XmlException e) {
               e.printStackTrace();
           } catch (IOException e) {
               e.printStackTrace();
           }
           XWPFTableRow newRow = new XWPFTableRow(ctrow, table1);
           newRow.getCell(0).setText("A");
           newRow.getCell(1).setText("B");
           newRow.getCell(2).setText("C");
           table1.addRow(newRow,1);
 
           mergeCellsHorizontal(table1,0,1,3);  //合并列(未涉及新增行)
           mergeCellsHorizontal(table1,1,0,1);  //合并列(涉及新增行)
           mergeCellsVertically(table1,2,1,4);  //合并行(涉及新增行)
           mergeCellsVertically(table1,0,0,2);  //合并行(涉及新增行)
            
           //导出
           String path = "C:\\"//文件路径
           String name = "test2"//文件名
           path = path + "/" + name + ".docx";
           File file = new File(path);
           if (!file.exists()) {
               file.createNewFile();
           }
           FileOutputStream out = new FileOutputStream(file);
           doc.write(out);
       }catch (IOException  e){
           e.printStackTrace();
       }
   }

效果如下:

可以看到,我们使用addRow新增的行是无法进行合并的,即使合并的单元格中包含也会被忽略掉。

官方文档中并没有详细说明过这个问题,但是应该是跟我们复制有关。

最后终于找到了解决办法,加入一个函数commitTabkeRows,在合并完调用这个函数即可。

static void commitTableRows(XWPFTable table) {
  int rowNr = 0;
  for (XWPFTableRow tableRow : table.getRows()) {
   table.getCTTbl().setTrArray(rowNr++, tableRow.getCtRow());
  }
 }

那么,合并以后调用即可:

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
void testXWPFTable2(){
       System.out.println("开始执行");
       try {
           InputStream is = new FileInputStream("C:\\test.docx"); //读取了一个4*4的表格
           //定义word
           XWPFDocument doc = new XWPFDocument(is);
           //获取word中所有的表格
           List<XWPFTable> tableList  = doc.getTables();
           XWPFTable table1 = tableList.get(0);  //表格中第一个表
 
           CTRow ctrow = null;
           try {
               ctrow = CTRow.Factory.parse(table1.getRow(0).getCtRow().newInputStream());  //复制
           } catch (XmlException e) {
               e.printStackTrace();
           } catch (IOException e) {
               e.printStackTrace();
           }
           XWPFTableRow newRow = new XWPFTableRow(ctrow, table1);
           newRow.getCell(0).setText("A");
           newRow.getCell(1).setText("B");
           newRow.getCell(2).setText("C");
           table1.addRow(newRow,1);
 
           mergeCellsHorizontal(table1,0,1,3);  //合并列(未涉及新增行)
           mergeCellsHorizontal(table1,1,0,1);  //合并列(涉及新增行)
           mergeCellsVertically(table1,2,1,4);  //合并行(涉及新增行)
           mergeCellsVertically(table1,0,0,2);  //合并行(涉及新增行)
           commitTableRows(table1);
           //导出
           String path = "C:\\";  //文件路径
           String name = "test2";  //文件名
           path = path + "/" + name + ".docx";
           File file = new File(path);
           if (!file.exists()) {
               file.createNewFile();
           }
           FileOutputStream out = new FileOutputStream(file);
           doc.write(out);
       }catch (IOException  e){
           e.printStackTrace();
       }
   }

效果:

3.总结

上面用到了很多封装好的函数,在此总结一下

1.跨列合并

/**
* @Description: 跨列合并
* table
* row:行
* fromCell:开始列
* toCell:结束列
*/
public void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) {
for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {
XWPFTableCell cell = table.getRow(row).getCell(cellIndex);
if ( cellIndex == fromCell ) {
// The first merged cell is set with RESTART merge value
cell.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);
}
}
}

2.跨行合并

/**
* @Description: 跨行合并
* table
* col:列
* formRow:开始行
* toRow:结束行
*/
public void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {
for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
if ( rowIndex == fromRow ) {
// The first merged cell is set with RESTART merge value
cell.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);
}
}
}

3.addRow方法封装

/**
* 复制一行到一个新位置插入
* @param sourceTableRow 要复制的行
* @param pos 要插入的位置
* @return
* @throws Exception
*/
static XWPFTableRow insertNewTableRow(XWPFTableRow sourceTableRow, int pos) throws Exception {
XWPFTable table = sourceTableRow.getTable();
CTRow newCTRrow = CTRow.Factory.parse(sourceTableRow.getCtRow().newInputStream());
XWPFTableRow tableRow = new XWPFTableRow(newCTRrow, table);
table.addRow(tableRow, pos);
return tableRow;
}

4.重新合并单元格

 
/**
* 合并单元格,在使用过addRow方法并合并单元格后再调用
* @param table
*/
static void commitTableRows(XWPFTable table) {
int rowNr = 0;
for (XWPFTableRow tableRow : table.getRows()) {
table.getCTTbl().setTrArray(rowNr++, tableRow.getCtRow());
}
}
 

posted on   longkui  阅读(13)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具

导航

< 2025年3月 >
23 24 25 26 27 28 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 1 2 3 4 5
点击右上角即可分享
微信分享提示