cn.hutool.poi.excel.cell.CellUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hutool-all Show documentation
Show all versions of hutool-all Show documentation
Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
package cn.hutool.poi.excel.cell;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.StyleSet;
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.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.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import org.apache.poi.ss.util.SheetUtil;
/**
* Excel表格中单元格工具类
*
* @author looly
* @since 4.0.7
*/
public class CellUtil {
/**
* 获取单元格值
*
* @param cell {@link Cell}单元格
* @return 值,类型可能为:Date、Double、Boolean、String
* @since 4.6.3
*/
public static Object getCellValue(Cell cell) {
return getCellValue(cell, false);
}
/**
* 获取单元格值
*
* @param cell {@link Cell}单元格
* @param isTrimCellValue 如果单元格类型为字符串,是否去掉两边空白符
* @return 值,类型可能为:Date、Double、Boolean、String
*/
public static Object getCellValue(Cell cell, boolean isTrimCellValue) {
if (null == cell) {
return null;
}
return getCellValue(cell, cell.getCellType(), isTrimCellValue);
}
/**
* 获取单元格值
*
* @param cell {@link Cell}单元格
* @param cellEditor 单元格值编辑器。可以通过此编辑器对单元格值做自定义操作
* @return 值,类型可能为:Date、Double、Boolean、String
*/
public static Object getCellValue(Cell cell, CellEditor cellEditor) {
return getCellValue(cell, null, cellEditor);
}
/**
* 获取单元格值
*
* @param cell {@link Cell}单元格
* @param cellType 单元格值类型{@link CellType}枚举
* @param isTrimCellValue 如果单元格类型为字符串,是否去掉两边空白符
* @return 值,类型可能为:Date、Double、Boolean、String
*/
public static Object getCellValue(Cell cell, CellType cellType, final boolean isTrimCellValue) {
return getCellValue(cell, cellType, isTrimCellValue ? new TrimEditor() : null);
}
/**
* 获取单元格值
* 如果单元格值为数字格式,则判断其格式中是否有小数部分,无则返回Long类型,否则返回Double类型
*
* @param cell {@link Cell}单元格
* @param cellType 单元格值类型{@link CellType}枚举,如果为{@code null}默认使用cell的类型
* @param cellEditor 单元格值编辑器。可以通过此编辑器对单元格值做自定义操作
* @return 值,类型可能为:Date、Double、Boolean、String
*/
public static Object getCellValue(Cell cell, CellType cellType, CellEditor cellEditor) {
if (null == cell) {
return null;
}
if (cell instanceof NullCell) {
return null == cellEditor ? null : cellEditor.edit(cell, null);
}
if (null == cellType) {
cellType = cell.getCellType();
}
// 尝试获取合并单元格,如果是合并单元格,则重新获取单元格类型
final Cell mergedCell = getMergedRegionCell(cell);
if (mergedCell != cell) {
cell = mergedCell;
cellType = cell.getCellType();
}
final Object value;
switch (cellType) {
case NUMERIC:
value = new NumericCellValue(cell).getValue();
break;
case BOOLEAN:
value = cell.getBooleanCellValue();
break;
case FORMULA:
value = getCellValue(cell, cell.getCachedFormulaResultType(), cellEditor);
break;
case BLANK:
value = StrUtil.EMPTY;
break;
case ERROR:
value = new ErrorCellValue(cell).getValue();
break;
default:
value = cell.getStringCellValue();
}
return null == cellEditor ? value : cellEditor.edit(cell, value);
}
/**
* 设置单元格值
* 根据传入的styleSet自动匹配样式
* 当为头部样式时默认赋值头部样式,但是头部中如果有数字、日期等类型,将按照数字、日期样式设置
*
* @param cell 单元格
* @param value 值
* @param styleSet 单元格样式集,包括日期等样式,null表示无样式
* @param isHeader 是否为标题单元格
*/
public static void setCellValue(Cell cell, Object value, StyleSet styleSet, boolean isHeader) {
if (null == cell) {
return;
}
if (null != styleSet) {
cell.setCellStyle(styleSet.getStyleByValueType(value, isHeader));
}
setCellValue(cell, value);
}
/**
* 设置单元格值
* 根据传入的styleSet自动匹配样式
* 当为头部样式时默认赋值头部样式,但是头部中如果有数字、日期等类型,将按照数字、日期样式设置
*
* @param cell 单元格
* @param value 值
* @param style 自定义样式,null表示无样式
*/
public static void setCellValue(Cell cell, Object value, CellStyle style) {
setCellValue(cell, (CellSetter) cell1 -> {
setCellValue(cell, value);
if (null != style) {
cell1.setCellStyle(style);
}
});
}
/**
* 设置单元格值
* 根据传入的styleSet自动匹配样式
* 当为头部样式时默认赋值头部样式,但是头部中如果有数字、日期等类型,将按照数字、日期样式设置
*
* @param cell 单元格
* @param value 值或{@link CellSetter}
* @since 5.6.4
*/
public static void setCellValue(Cell cell, Object value) {
if (null == cell) {
return;
}
// issue#1659@Github
// 在使用BigWriter(SXSSF)模式写出数据时,单元格值为直接值,非引用值(is标签)
// 而再使用ExcelWriter(XSSF)编辑时,会写出引用值,导致失效。
// 此处做法是先清空单元格值,再写入
if(CellType.BLANK != cell.getCellType()){
cell.setBlank();
}
CellSetterFactory.createCellSetter(value).setValue(cell);
}
/**
* 获取单元格,如果单元格不存在,返回{@link NullCell}
*
* @param row Excel表的行
* @param cellIndex 列号
* @return {@link Cell}
* @since 5.5.0
*/
public static Cell getCell(Row row, int cellIndex) {
if (null == row) {
return null;
}
final Cell cell = row.getCell(cellIndex);
if (null == cell) {
return new NullCell(row, cellIndex);
}
return cell;
}
/**
* 获取已有单元格或创建新单元格
*
* @param row Excel表的行
* @param cellIndex 列号
* @return {@link Cell}
* @since 4.0.2
*/
public static Cell getOrCreateCell(Row row, int cellIndex) {
if (null == row) {
return null;
}
Cell cell = row.getCell(cellIndex);
if (null == cell) {
cell = row.createCell(cellIndex);
}
return cell;
}
/**
* 判断指定的单元格是否是合并单元格
*
* @param sheet {@link Sheet}
* @param locationRef 单元格地址标识符,例如A11,B5
* @return 是否是合并单元格
* @since 5.1.5
*/
public static boolean isMergedRegion(Sheet sheet, 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(Cell cell) {
return isMergedRegion(cell.getSheet(), cell.getColumnIndex(), cell.getRowIndex());
}
/**
* 判断指定的单元格是否是合并单元格
*
* @param sheet {@link Sheet}
* @param x 列号,从0开始
* @param y 行号,从0开始
* @return 是否是合并单元格,如果提供的sheet为{@code null},返回{@code false}
*/
public static boolean isMergedRegion(Sheet sheet, int x, int y) {
if (sheet != null) {
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;
}
/**
* 获取合并单元格{@link CellRangeAddress},如果不是返回null
*
* @param sheet {@link Sheet}
* @param locationRef 单元格地址标识符,例如A11,B5
* @return {@link CellRangeAddress}
* @since 5.8.0
*/
public static CellRangeAddress getCellRangeAddress(Sheet sheet, String locationRef) {
final CellLocation cellLocation = ExcelUtil.toLocation(locationRef);
return getCellRangeAddress(sheet, cellLocation.getX(), cellLocation.getY());
}
/**
* 获取合并单元格{@link CellRangeAddress},如果不是返回null
*
* @param cell {@link Cell}
* @return {@link CellRangeAddress}
* @since 5.8.0
*/
public static CellRangeAddress getCellRangeAddress(Cell cell) {
return getCellRangeAddress(cell.getSheet(), cell.getColumnIndex(), cell.getRowIndex());
}
/**
* 获取合并单元格{@link CellRangeAddress},如果不是返回null
*
* @param sheet {@link Sheet}
* @param x 列号,从0开始
* @param y 行号,从0开始
* @return {@link CellRangeAddress}
* @since 5.8.0
*/
public static CellRangeAddress getCellRangeAddress(Sheet sheet, int x, int y) {
if (sheet != null) {
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 ca;
}
}
}
return null;
}
/**
* 设置合并单元格样式,如果不是则不设置
*
* @param cell {@link Cell}
* @param cellStyle {@link CellStyle}
*/
public static void setMergedRegionStyle(Cell cell, CellStyle cellStyle) {
final CellRangeAddress cellRangeAddress = getCellRangeAddress(cell);
if (cellRangeAddress != null) {
setMergeCellStyle(cellStyle, cellRangeAddress, cell.getSheet());
}
}
/**
* 合并单元格,可以根据设置的值来合并行和列
*
* @param sheet 表对象
* @param firstRow 起始行,0开始
* @param lastRow 结束行,0开始
* @param firstColumn 起始列,0开始
* @param lastColumn 结束列,0开始
* @return 合并后的单元格号
*/
public static int mergingCells(Sheet sheet, int firstRow, int lastRow, int firstColumn, int lastColumn) {
return mergingCells(sheet, firstRow, lastRow, firstColumn, lastColumn, null);
}
/**
* 合并单元格,可以根据设置的值来合并行和列
*
* @param sheet 表对象
* @param firstRow 起始行,0开始
* @param lastRow 结束行,0开始
* @param firstColumn 起始列,0开始
* @param lastColumn 结束列,0开始
* @param cellStyle 单元格样式,只提取边框样式,null表示无样式
* @return 合并后的单元格号
*/
public static int mergingCells(Sheet sheet, int firstRow, int lastRow, int firstColumn, int lastColumn, CellStyle cellStyle) {
final CellRangeAddress cellRangeAddress = new CellRangeAddress(//
firstRow, // first row (0-based)
lastRow, // last row (0-based)
firstColumn, // first column (0-based)
lastColumn // last column (0-based)
);
setMergeCellStyle(cellStyle, cellRangeAddress, sheet);
return sheet.addMergedRegion(cellRangeAddress);
}
/**
* 获取合并单元格的值
* 传入的x,y坐标(列行数)可以是合并单元格范围内的任意一个单元格
*
* @param sheet {@link Sheet}
* @param locationRef 单元格地址标识符,例如A11,B5
* @return 合并单元格的值
* @since 5.1.5
*/
public static Object getMergedRegionValue(Sheet sheet, String locationRef) {
final CellLocation cellLocation = ExcelUtil.toLocation(locationRef);
return getMergedRegionValue(sheet, cellLocation.getX(), cellLocation.getY());
}
/**
* 获取合并单元格的值
* 传入的x,y坐标(列行数)可以是合并单元格范围内的任意一个单元格
*
* @param sheet {@link Sheet}
* @param x 列号,从0开始,可以是合并单元格范围中的任意一列
* @param y 行号,从0开始,可以是合并单元格范围中的任意一行
* @return 合并单元格的值
* @since 4.6.3
*/
public static Object getMergedRegionValue(Sheet sheet, int x, int y) {
// 合并单元格的识别在getCellValue已经集成,无需重复获取合并单元格
return getCellValue(SheetUtil.getCell(sheet, x, y));
}
/**
* 获取合并单元格
* 传入的x,y坐标(列行数)可以是合并单元格范围内的任意一个单元格
*
* @param cell {@link Cell}
* @return 合并单元格
* @since 5.1.5
*/
public static Cell getMergedRegionCell(Cell cell) {
if (null == cell) {
return null;
}
return ObjectUtil.defaultIfNull(
getCellIfMergedRegion(cell.getSheet(), cell.getColumnIndex(), cell.getRowIndex()),
cell);
}
/**
* 获取合并单元格
* 传入的x,y坐标(列行数)可以是合并单元格范围内的任意一个单元格
*
* @param sheet {@link Sheet}
* @param x 列号,从0开始,可以是合并单元格范围中的任意一列
* @param y 行号,从0开始,可以是合并单元格范围中的任意一行
* @return 合并单元格,如果非合并单元格,返回坐标对应的单元格
* @since 5.1.5
*/
public static Cell getMergedRegionCell(Sheet sheet, int x, int y) {
return ObjectUtil.defaultIfNull(
getCellIfMergedRegion(sheet, x, y),
() -> SheetUtil.getCell(sheet, y, x));
}
/**
* 为特定单元格添加批注
*
* @param cell 单元格
* @param commentText 批注内容
* @param commentAuthor 作者
* @param anchor 批注的位置、大小等信息,null表示使用默认
* @since 5.4.8
*/
public static void setComment(Cell cell, String commentText, String commentAuthor, ClientAnchor anchor) {
final Sheet sheet = cell.getSheet();
final Workbook wb = sheet.getWorkbook();
final Drawing> drawing = sheet.createDrawingPatriarch();
final CreationHelper factory = wb.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);
// 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.nullToEmpty(commentAuthor));
cell.setCellComment(comment);
}
// -------------------------------------------------------------------------------------------------------------- Private method start
/**
* 获取合并单元格,非合并单元格返回{@code null}
* 传入的x,y坐标(列行数)可以是合并单元格范围内的任意一个单元格
*
* @param sheet {@link Sheet}
* @param x 列号,从0开始,可以是合并单元格范围中的任意一列
* @param y 行号,从0开始,可以是合并单元格范围中的任意一行
* @return 合并单元格,如果非合并单元格,返回{@code null}
* @since 5.4.5
*/
private static Cell getCellIfMergedRegion(Sheet sheet, int x, int y) {
for (final CellRangeAddress ca : sheet.getMergedRegions()) {
if (ca.isInRange(y, x)) {
return SheetUtil.getCell(sheet, ca.getFirstRow(), ca.getFirstColumn());
}
}
return null;
}
/**
* 根据{@link CellStyle}设置合并单元格边框样式
*
* @param cellStyle {@link CellStyle}
* @param cellRangeAddress {@link CellRangeAddress}
* @param sheet {@link Sheet}
*/
private static void setMergeCellStyle(CellStyle cellStyle, CellRangeAddress cellRangeAddress, Sheet sheet) {
if (null != cellStyle) {
RegionUtil.setBorderTop(cellStyle.getBorderTop(), cellRangeAddress, sheet);
RegionUtil.setBorderRight(cellStyle.getBorderRight(), cellRangeAddress, sheet);
RegionUtil.setBorderBottom(cellStyle.getBorderBottom(), cellRangeAddress, sheet);
RegionUtil.setBorderLeft(cellStyle.getBorderLeft(), cellRangeAddress, sheet);
RegionUtil.setTopBorderColor(cellStyle.getTopBorderColor(), cellRangeAddress, sheet);
RegionUtil.setRightBorderColor(cellStyle.getRightBorderColor(), cellRangeAddress, sheet);
RegionUtil.setLeftBorderColor(cellStyle.getLeftBorderColor(), cellRangeAddress, sheet);
RegionUtil.setBottomBorderColor(cellStyle.getBottomBorderColor(), cellRangeAddress, sheet);
}
}
// -------------------------------------------------------------------------------------------------------------- Private method end
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy