This commit is contained in:
Looly
2023-03-12 13:13:13 +08:00
parent d80747f9d5
commit d9f6de720a
3 changed files with 156 additions and 68 deletions

View File

@@ -5,7 +5,12 @@ import org.apache.poi.ss.usermodel.Cell;
/**
* 单元格编辑器接口<br>
* 在读取Excel值时有时我们需要针对所有单元格统一处理结果值如null转默认值的情况实现接口并调用<br>
* reader.setCellEditor()设置编辑器
* reader.setCellEditor()设置编辑器<br>
* 此接口可完成以下功能:
* <ul>
* <li>对单元格进行编辑,如修改样式等。</li>
* <li>对单元格的值进行编辑,如根据单元格修改不同值,然后返回</li>
* </ul>
*
* @author Looly
*/
@@ -17,7 +22,7 @@ public interface CellEditor {
*
* @param cell 单元格对象,可以获取单元格行、列样式等信息
* @param value 单元格值
* @return 编辑后的对象
* @return 编辑后的
*/
Object edit(Cell cell, Object value);
}

View File

@@ -1,23 +1,14 @@
package cn.hutool.poi.excel.cell;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.StyleSet;
import cn.hutool.poi.excel.cell.editors.TrimEditor;
import cn.hutool.poi.excel.cell.setters.CellSetterFactory;
import cn.hutool.poi.excel.cell.values.ErrorCellValue;
import cn.hutool.poi.excel.cell.values.NumericCellValue;
import cn.hutool.poi.excel.cell.editors.TrimEditor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import org.apache.poi.ss.util.SheetUtil;
@@ -30,6 +21,7 @@ import org.apache.poi.ss.util.SheetUtil;
*/
public class CellUtil {
// region ----- getCellValue
/**
* 获取单元格值
*
@@ -128,7 +120,9 @@ public class CellUtil {
return null == cellEditor ? value : cellEditor.edit(cell, value);
}
// endregion
// region ----- setCellValue
/**
* 设置单元格值<br>
* 根据传入的styleSet自动匹配样式<br>
@@ -182,6 +176,27 @@ public class CellUtil {
return;
}
if (null != cellEditor) {
value = cellEditor.edit(cell, value);
}
setCellValue(cell, value);
}
/**
* 设置单元格值<br>
* 根据传入的styleSet自动匹配样式<br>
* 当为头部样式时默认赋值头部样式,但是头部中如果有数字、日期等类型,将按照数字、日期样式设置
*
* @param cell 单元格
* @param value 值或{@link CellSetter}
* @since 5.6.4
*/
public static void setCellValue(final Cell cell, final Object value) {
if (null == cell) {
return;
}
// issue#1659@Github
// 在使用BigWriter(SXSSF)模式写出数据时单元格值为直接值非引用值is标签
// 而再使用ExcelWriter(XSSF)编辑时,会写出引用值,导致失效。
@@ -190,12 +205,11 @@ public class CellUtil {
cell.setBlank();
}
if (null != cellEditor) {
value = cellEditor.edit(cell, value);
}
CellSetterFactory.createCellSetter(value).setValue(cell);
}
// endregion
// region ----- getCell
/**
* 获取单元格,如果单元格不存在,返回{@link NullCell}
*
@@ -233,52 +247,9 @@ public class CellUtil {
}
return cell;
}
// endregion
/**
* 判断指定的单元格是否是合并单元格
*
* @param sheet {@link Sheet}
* @param locationRef 单元格地址标识符例如A11B5
* @return 是否是合并单元格
* @since 5.1.5
*/
public static boolean isMergedRegion(final Sheet sheet, final String locationRef) {
final CellLocation cellLocation = ExcelUtil.toLocation(locationRef);
return isMergedRegion(sheet, cellLocation.getX(), cellLocation.getY());
}
/**
* 判断指定的单元格是否是合并单元格
*
* @param cell {@link Cell}
* @return 是否是合并单元格
* @since 5.1.5
*/
public static boolean isMergedRegion(final Cell cell) {
return isMergedRegion(cell.getSheet(), cell.getColumnIndex(), cell.getRowIndex());
}
/**
* 判断指定的单元格是否是合并单元格
*
* @param sheet {@link Sheet}
* @param x 列号从0开始
* @param y 行号从0开始
* @return 是否是合并单元格
*/
public static boolean isMergedRegion(final Sheet sheet, final int x, final int y) {
final int sheetMergeCount = sheet.getNumMergedRegions();
CellRangeAddress ca;
for (int i = 0; i < sheetMergeCount; i++) {
ca = sheet.getMergedRegion(i);
if (y >= ca.getFirstRow() && y <= ca.getLastRow()
&& x >= ca.getFirstColumn() && x <= ca.getLastColumn()) {
return true;
}
}
return false;
}
// region ----- getCellRangeAddress
/**
* 获取合并单元格{@link CellRangeAddress}如果不是返回null
*
@@ -326,7 +297,53 @@ public class CellUtil {
}
return null;
}
// endregion
// region ----- merging 合并单元格
/**
* 判断指定的单元格是否是合并单元格
*
* @param sheet {@link Sheet}
* @param locationRef 单元格地址标识符例如A11B5
* @return 是否是合并单元格
* @since 5.1.5
*/
public static boolean isMergedRegion(final Sheet sheet, final String locationRef) {
final CellLocation cellLocation = ExcelUtil.toLocation(locationRef);
return isMergedRegion(sheet, cellLocation.getX(), cellLocation.getY());
}
/**
* 判断指定的单元格是否是合并单元格
*
* @param cell {@link Cell}
* @return 是否是合并单元格
* @since 5.1.5
*/
public static boolean isMergedRegion(final Cell cell) {
return isMergedRegion(cell.getSheet(), cell.getColumnIndex(), cell.getRowIndex());
}
/**
* 判断指定的单元格是否是合并单元格
*
* @param sheet {@link Sheet}
* @param x 列号从0开始
* @param y 行号从0开始
* @return 是否是合并单元格
*/
public static boolean isMergedRegion(final Sheet sheet, final int x, final int y) {
final int sheetMergeCount = sheet.getNumMergedRegions();
CellRangeAddress ca;
for (int i = 0; i < sheetMergeCount; i++) {
ca = sheet.getMergedRegion(i);
if (y >= ca.getFirstRow() && y <= ca.getLastRow()
&& x >= ca.getFirstColumn() && x <= ca.getLastColumn()) {
return true;
}
}
return false;
}
/**
* 合并单元格,可以根据设置的值来合并行和列
@@ -426,6 +443,7 @@ public class CellUtil {
getCellIfMergedRegion(sheet, x, y),
() -> SheetUtil.getCell(sheet, y, x));
}
// endregion
/**
* 为特定单元格添加批注
@@ -433,29 +451,46 @@ public class CellUtil {
* @param cell 单元格
* @param commentText 批注内容
* @param commentAuthor 作者
*/
public static void setComment(final Cell cell, final String commentText, final String commentAuthor) {
setComment(cell, commentText, commentAuthor, null);
}
/**
* 为特定单元格添加批注
*
* @param cell 单元格
* @param commentText 批注内容
* @param commentAuthor 作者,{@code null}表示无作者
* @param anchor 批注的位置、大小等信息null表示使用默认
* @since 5.4.8
*/
public static void setComment(final Cell cell, final String commentText, final String commentAuthor, ClientAnchor anchor) {
final Sheet sheet = cell.getSheet();
final Workbook wb = sheet.getWorkbook();
final Drawing<?> drawing = sheet.createDrawingPatriarch();
final CreationHelper factory = wb.getCreationHelper();
final CreationHelper factory = sheet.getWorkbook().getCreationHelper();
if (anchor == null) {
anchor = factory.createClientAnchor();
// 默认位置,在注释的单元格的右方
anchor.setCol1(cell.getColumnIndex() + 1);
anchor.setCol2(cell.getColumnIndex() + 3);
anchor.setRow1(cell.getRowIndex());
anchor.setRow2(cell.getRowIndex() + 2);
// 自适应
anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
}
final Comment comment = drawing.createCellComment(anchor);
final Comment comment = sheet.createDrawingPatriarch().createCellComment(anchor);
// https://stackoverflow.com/questions/28169011/using-sxssfapache-poi-and-adding-comment-does-not-generate-proper-excel-file
// 修正在XSSFCell中未设置地址导致错位问题
comment.setAddress(cell.getAddress());
comment.setString(factory.createRichTextString(commentText));
comment.setAuthor(StrUtil.emptyIfNull(commentAuthor));
if(null != commentAuthor){
comment.setAuthor(commentAuthor);
}
cell.setCellComment(comment);
}
// -------------------------------------------------------------------------------------------------------------- Private method start
/**
* 获取合并单元格,非合并单元格返回{@code null}<br>
* 传入的x,y坐标列行数可以是合并单元格范围内的任意一个单元格

View File

@@ -0,0 +1,48 @@
package cn.hutool.poi.excel;
import cn.hutool.poi.excel.cell.CellUtil;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.junit.Ignore;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
/**
* https://gitee.com/dromara/hutool/issues/I6MBS5<br>
* 经过测试发现BigExcelWriter中的comment会错位<br>
* 修正方式见: https://stackoverflow.com/questions/28169011/using-sxssfapache-poi-and-adding-comment-does-not-generate-proper-excel-file
*/
public class IssueI6MBS5Test {
@Test
@Ignore
public void setCommentTest() {
final ExcelWriter writer = ExcelUtil.getBigWriter("d:/test/setCommentTest.xlsx");
final Cell cell = writer.getOrCreateCell(0, 0);
CellUtil.setCellValue(cell, "cellValue");
CellUtil.setComment(cell, "commonText", "ascend");
writer.close();
}
@Test
@Ignore
public void setCommentTest2() {
final File file = new File("D:\\test\\CellUtilTest.xlsx");
try (final Workbook workbook = WorkbookUtil.createBook(true)) {
final Sheet sheet = workbook.createSheet();
final Row row = sheet.createRow(0);
final Cell cell = row.createCell(0);
CellUtil.setCellValue(cell, "cellValue");
CellUtil.setComment(cell, "commonText", "ascend", null);
workbook.write(Files.newOutputStream(file.toPath()));
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
}