apache poi word 水平合并单元格在wps2019和钉钉预览中展示不正常的问题及解决方案

背景

apache poi小白,使用的版本是4.1.1,项目要导出一个doc文档,文档中有个表格,表格的前两行是表头,有横向和竖向合并单元格的要求,在网上搜了一下,就是使用如下示意的代码来控制单元格合并

	XWPFDocument document = new XWPFDocument();
	XWPFTable table = document.createTable();
	XWPFTableRow row = table.getRow(0);
    XWPFTableCell cell = row.getCell(0);
    cell.setText("11111");
    // 设置单元格竖直合并开始
    cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
    // 设置单元格竖直继续合并
    cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
    // 设置单元格水平合并开始
	row.addNewTableCell().getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
	// 设置单元格水平继续合并
    row.addNewTableCell().getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);

出来的文档,在最新版本的wps上面没有问题
正常的图片

,但是在wps2019和钉钉预览中都展示的不正常

不正常的图片

解决办法

stackoverflow中找到一批文章How to colspan a table in word with APACHE POI
其中的一个答题者给了一段代码,我拷过来试了一下,可以解决上述问题。以下是对方的源码:

import java.io.File;
import java.io.FileOutputStream;

import java.math.BigInteger;

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.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;

public class CreateWordTableMerge {

 static void mergeCellVertically(XWPFTable table, int col, int fromRow, int toRow) {
  for(int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
   XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
   CTVMerge vmerge = CTVMerge.Factory.newInstance();
   if(rowIndex == fromRow){
    // The first merged cell is set with RESTART merge value
    vmerge.setVal(STMerge.RESTART);
   } else {
    // Cells which join (merge) the first one, are set with CONTINUE
    vmerge.setVal(STMerge.CONTINUE);
    // and the content should be removed
    for (int i = cell.getParagraphs().size(); i > 0; i--) {
     cell.removeParagraph(0);
    }
    cell.addParagraph();
   }
   // Try getting the TcPr. Not simply setting an new one every time.
   CTTcPr tcPr = cell.getCTTc().getTcPr();
   if (tcPr == null) tcPr = cell.getCTTc().addNewTcPr();
   tcPr.setVMerge(vmerge);
  }
 }

 //merging horizontally by setting grid span instead of using CTHMerge
 static void mergeCellHorizontally(XWPFTable table, int row, int fromCol, int toCol) {
  XWPFTableCell cell = table.getRow(row).getCell(fromCol);
  // Try getting the TcPr. Not simply setting an new one every time.
  CTTcPr tcPr = cell.getCTTc().getTcPr();
  if (tcPr == null) tcPr = cell.getCTTc().addNewTcPr();
  // The first merged cell has grid span property set
  if (tcPr.isSetGridSpan()) {
   tcPr.getGridSpan().setVal(BigInteger.valueOf(toCol-fromCol+1));
  } else {
   tcPr.addNewGridSpan().setVal(BigInteger.valueOf(toCol-fromCol+1));
  }
  // Cells which join (merge) the first one, must be removed
  for(int colIndex = toCol; colIndex > fromCol; colIndex--) {
   table.getRow(row).getCtRow().removeTc(colIndex);
   table.getRow(row).removeCell(colIndex);
  }
 }

 public static void main(String[] args) throws Exception {

  XWPFDocument document= new XWPFDocument();

  XWPFParagraph paragraph = document.createParagraph();
  XWPFRun run=paragraph.createRun();  
  run.setText("The table:");

  //create table
  XWPFTable table = document.createTable(3,5);

  for (int row = 0; row < 3; row++) {
   for (int col = 0; col < 5; col++) {
    table.getRow(row).getCell(col).setText("row " + row + ", col " + col);
   }
  }

  //create CTTblGrid for this table with widths of the 5 columns. 
  //necessary for Libreoffice/Openoffice to accept the column widths.
  //values are in unit twentieths of a point (1/1440 of an inch)
  //first column = 1 inches width
  table.getCTTbl().addNewTblGrid().addNewGridCol().setW(BigInteger.valueOf(1*1440));
  //other columns (2 in this case) also each 1 inches width
  for (int col = 1 ; col < 5; col++) {
   table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1*1440));
  }

  //create and set column widths for all columns in all rows
  //most examples don't set the type of the CTTblWidth but this
  //is necessary for working in all office versions
  for (int col = 0; col < 5; col++) {
   CTTblWidth tblWidth = CTTblWidth.Factory.newInstance();
   tblWidth.setW(BigInteger.valueOf(1*1440));
   tblWidth.setType(STTblWidth.DXA);
   for (int row = 0; row < 3; row++) {
    CTTcPr tcPr = table.getRow(row).getCell(col).getCTTc().getTcPr();
    if (tcPr != null) {
     tcPr.setTcW(tblWidth);
    } else {
     tcPr = CTTcPr.Factory.newInstance();
     tcPr.setTcW(tblWidth);
     table.getRow(row).getCell(col).getCTTc().setTcPr(tcPr);
    }
   }
  }

  //using the merge methods
  mergeCellVertically(table, 0, 0, 1); 
  mergeCellHorizontally(table, 1, 2, 3); 
  mergeCellHorizontally(table, 2, 1, 4); 

  paragraph = document.createParagraph();

  FileOutputStream out = new FileOutputStream("create_table.docx"); 
  document.write(out);
  out.close();

  System.out.println("create_table.docx written successully");
 }
}

经过我的实验,除了我一开始写的代码的部分,解决我的问题的部分是

	
  //create and set column widths for all columns in all rows
  //most examples don't set the type of the CTTblWidth but this
  //is necessary for working in all office versions
  for (int col = 0; col < 5; col++) {
   CTTblWidth tblWidth = CTTblWidth.Factory.newInstance();
   tblWidth.setW(BigInteger.valueOf(1*1440));
   tblWidth.setType(STTblWidth.DXA);
   for (int row = 0; row < 3; row++) {
    CTTcPr tcPr = table.getRow(row).getCell(col).getCTTc().getTcPr();
    if (tcPr != null) {
     tcPr.setTcW(tblWidth);
    } else {
     tcPr = CTTcPr.Factory.newInstance();
     tcPr.setTcW(tblWidth);
     table.getRow(row).getCell(col).getCTTc().setTcPr(tcPr);
    }
   }
  }

给表格中每个元素都设置一个CTTblWidth对象,这个对象内部是单元格的宽度值自动伸缩

要获取Word Doc表格的合并单元格,可以使用Apache POI的XWPFTable类和XWPFTableCell类。 以下是一个示例代码,可以通过它来获取表格合并单元格: ```java import org.apache.poi.xwpf.usermodel.*; import java.util.List; public class WordTableMergeCellsExample { public static void main(String[] args) throws Exception { // Load the document XWPFDocument doc = new XWPFDocument(new FileInputStream("example.docx")); // Get the first table in the document XWPFTable table = doc.getTables().get(0); // Iterate through the rows in the table for (XWPFTableRow row : table.getRows()) { // Iterate through the cells in the row for (XWPFTableCell cell : row.getTableCells()) { // Get the list of merged cells List<XWPFTableCell> mergedCells = table.getTableCellsBeingMerged(cell); // If the current cell is merged with other cells if (mergedCells.size() > 1) { System.out.println("Cell at row " + row.getRowNum() + ", column " + cell.getColumnIndex() + " is merged with:"); // Print the merged cells for (XWPFTableCell mergedCell : mergedCells) { System.out.println(" Row " + table.getRow(mergedCell).getRowNum() + ", column " + mergedCell.getColumnIndex()); } } } } // Close the document doc.close(); } } ``` 该代码将遍历表格的所有单元格,并检查每个单元格是否与其他单元格合并。如果单元格合并,则该代码将打印出该单元格合并单元格的位置信息。 请注意,该代码假定文档至少有一个表格。如果您的文档没有表格,或者您想获取其他表格合并单元格,请相应地修改代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值