diff --git a/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/ExcelImgUtil.java b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/ExcelImgUtil.java
index 40df5eedb..e16e1610f 100644
--- a/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/ExcelImgUtil.java
+++ b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/ExcelImgUtil.java
@@ -81,27 +81,6 @@ public class ExcelImgUtil {
}
}
- /**
- * 写出图片,本方法只是将数据写入Workbook中的Sheet,并不写出到文件
- * 添加图片到当前sheet中
- *
- * @param sheet {@link Sheet}
- * @param pictureData 数据bytes
- * @param imgType 图片类型,对应poi中Workbook类中的图片类型2-7变量
- * @param clientAnchor 图片的位置和大小信息
- * @author vhukze
- * @since 6.0.0
- */
- public static void writeImg(final Sheet sheet, final byte[] pictureData,
- final ExcelImgType imgType, final SimpleClientAnchor clientAnchor) {
- final Drawing> patriarch = sheet.createDrawingPatriarch();
- final Workbook workbook = sheet.getWorkbook();
- final ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
- clientAnchor.copyTo(anchor);
-
- patriarch.createPicture(anchor, workbook.addPicture(pictureData, imgType.getValue()));
- }
-
// -------------------------------------------------------------------------------------------------------------- Private method start
/**
diff --git a/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/SheetUtil.java b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/SheetUtil.java
index c8c2e227d..37d504b30 100644
--- a/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/SheetUtil.java
+++ b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/SheetUtil.java
@@ -12,11 +12,15 @@
package org.dromara.hutool.poi.excel;
+import org.apache.poi.ss.usermodel.IgnoredErrorType;
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.cellwalk.CellHandler;
import org.apache.poi.ss.util.cellwalk.CellWalk;
+import org.apache.poi.xssf.streaming.SXSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.dromara.hutool.core.reflect.FieldUtil;
import org.dromara.hutool.core.text.StrUtil;
/**
@@ -82,6 +86,18 @@ public class SheetUtil {
return null == sheet || (sheet.getLastRowNum() == 0 && sheet.getPhysicalNumberOfRows() == 0);
}
+ /**
+ * 遍历Sheet中的所有单元格
+ *
+ * @param sheet {@link Sheet}
+ * @param cellHandler 单元格处理器
+ */
+ public static void walk(final Sheet sheet, final CellHandler cellHandler) {
+ walk(sheet,
+ new CellRangeAddress(0, sheet.getLastRowNum(), 0, sheet.getLastRowNum()),
+ cellHandler);
+ }
+
/**
* 遍历Sheet中的指定区域单元格
*
@@ -93,4 +109,28 @@ public class SheetUtil {
final CellWalk cellWalk = new CellWalk(sheet, range);
cellWalk.traverse(cellHandler);
}
+
+ /**
+ * 设置忽略错误,即Excel中的绿色警告小标,只支持XSSFSheet和SXSSFSheet
+ * 见:https://stackoverflow.com/questions/23488221/how-to-remove-warning-in-excel-using-apache-poi-in-java
+ *
+ * @param sheet {@link Sheet}
+ * @param cellRangeAddress 指定单元格范围
+ * @param ignoredErrorTypes 忽略的错误类型列表
+ * @throws UnsupportedOperationException 如果sheet不是XSSFSheet
+ * @since 5.8.28
+ */
+ public static void addIgnoredErrors(final Sheet sheet, final CellRangeAddress cellRangeAddress, final IgnoredErrorType... ignoredErrorTypes) throws UnsupportedOperationException {
+ if (sheet instanceof XSSFSheet) {
+ ((XSSFSheet) sheet).addIgnoredErrors(cellRangeAddress, ignoredErrorTypes);
+ } else if (sheet instanceof SXSSFSheet) {
+ // SXSSFSheet并未提供忽略错误方法,获得其内部_sh字段设置
+ final XSSFSheet xssfSheet = (XSSFSheet) FieldUtil.getFieldValue(sheet, "_sh");
+ if (null != xssfSheet) {
+ xssfSheet.addIgnoredErrors(cellRangeAddress, ignoredErrorTypes);
+ }
+ } else {
+ throw new UnsupportedOperationException("Only XSSFSheet supports addIgnoredErrors");
+ }
+ }
}
diff --git a/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/cell/setters/ImgCellSetter.java b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/cell/setters/ImgCellSetter.java
index 209d8d6c1..57ae2cc47 100644
--- a/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/cell/setters/ImgCellSetter.java
+++ b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/cell/setters/ImgCellSetter.java
@@ -17,6 +17,7 @@ import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.poi.excel.ExcelImgType;
import org.dromara.hutool.poi.excel.ExcelImgUtil;
import org.dromara.hutool.poi.excel.SimpleClientAnchor;
+import org.dromara.hutool.poi.excel.writer.ExcelDrawingUtil;
import java.io.File;
@@ -69,7 +70,7 @@ public class ImgCellSetter implements CellSetter {
final int columnIndex = cell.getColumnIndex();
final int rowIndex = cell.getRowIndex();
- ExcelImgUtil.writeImg(sheet, this.pictureData, this.imgType,
+ ExcelDrawingUtil.drawingImg(sheet, this.pictureData, this.imgType,
new SimpleClientAnchor(columnIndex, rowIndex, columnIndex + 1, rowIndex + 1));
}
}
diff --git a/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/DataValidationUtil.java b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/DataValidationUtil.java
new file mode 100644
index 000000000..627b89564
--- /dev/null
+++ b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/DataValidationUtil.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.poi.excel.writer;
+
+import org.apache.poi.ss.usermodel.DataValidation;
+import org.apache.poi.ss.usermodel.DataValidationConstraint;
+import org.apache.poi.ss.usermodel.DataValidationHelper;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.xssf.usermodel.XSSFDataValidation;
+
+/**
+ * Excel数据验证相关工具
+ *
+ * @author Looly
+ * @since 6.0.0
+ */
+public class DataValidationUtil {
+
+ /**
+ * 增加下拉列表
+ *
+ * @param sheet {@link Sheet}
+ * @param regions {@link CellRangeAddressList} 指定下拉列表所占的单元格范围
+ * @param selectList 下拉列表内容
+ * @since 4.6.2
+ */
+ public static void addSelect(final Sheet sheet, final CellRangeAddressList regions, final String... selectList) {
+ final DataValidationHelper validationHelper = sheet.getDataValidationHelper();
+ final DataValidationConstraint constraint = validationHelper.createExplicitListConstraint(selectList);
+
+ //设置下拉框数据
+ final DataValidation dataValidation = validationHelper.createValidation(constraint, regions);
+
+ //处理Excel兼容性问题
+ if (dataValidation instanceof XSSFDataValidation) {
+ dataValidation.setSuppressDropDownArrow(true);
+ dataValidation.setShowErrorBox(true);
+ } else {
+ dataValidation.setSuppressDropDownArrow(false);
+ }
+
+ sheet.addValidationData(dataValidation);
+ }
+}
diff --git a/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/SimpleShapeUtil.java b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/ExcelDrawingUtil.java
similarity index 59%
rename from hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/SimpleShapeUtil.java
rename to hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/ExcelDrawingUtil.java
index 5a4be7cfa..48b92f206 100644
--- a/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/SimpleShapeUtil.java
+++ b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/ExcelDrawingUtil.java
@@ -15,25 +15,45 @@ package org.dromara.hutool.poi.excel.writer;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.apache.poi.hssf.usermodel.HSSFSimpleShape;
-import org.apache.poi.ss.usermodel.ClientAnchor;
-import org.apache.poi.ss.usermodel.Drawing;
-import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSimpleShape;
+import org.dromara.hutool.poi.excel.ExcelImgType;
import org.dromara.hutool.poi.excel.SimpleClientAnchor;
import org.dromara.hutool.poi.excel.style.ShapeConfig;
import java.awt.Color;
/**
- * 简单形状工具类
+ * Excel绘制工具类
* 用于辅助写出指定的图形
*
* @author Looly
* @since 6.0.0
*/
-public class SimpleShapeUtil {
+public class ExcelDrawingUtil {
+
+ /**
+ * 写出图片,本方法只是将数据写入Workbook中的Sheet,并不写出到文件
+ * 添加图片到当前sheet中
+ *
+ * @param sheet {@link Sheet}
+ * @param pictureData 数据bytes
+ * @param imgType 图片类型,对应poi中Workbook类中的图片类型2-7变量
+ * @param clientAnchor 图片的位置和大小信息
+ * @author vhukze
+ * @since 6.0.0
+ */
+ public static void drawingImg(final Sheet sheet, final byte[] pictureData,
+ final ExcelImgType imgType, final SimpleClientAnchor clientAnchor) {
+ final Drawing> patriarch = sheet.createDrawingPatriarch();
+ final Workbook workbook = sheet.getWorkbook();
+ final ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
+ clientAnchor.copyTo(anchor);
+
+ patriarch.createPicture(anchor, workbook.addPicture(pictureData, imgType.getValue()));
+ }
/**
* 绘制简单形状
@@ -43,7 +63,7 @@ public class SimpleShapeUtil {
* @param shapeConfig 形状配置,包括形状类型、线条样式、线条宽度、线条颜色、填充颜色等
* @since 6.0.0
*/
- public static void writeSimpleShape(final Sheet sheet, final SimpleClientAnchor clientAnchor, ShapeConfig shapeConfig) {
+ public static void drawingSimpleShape(final Sheet sheet, final SimpleClientAnchor clientAnchor, ShapeConfig shapeConfig) {
final Drawing> patriarch = sheet.createDrawingPatriarch();
final ClientAnchor anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
clientAnchor.copyTo(anchor);
@@ -72,4 +92,25 @@ public class SimpleShapeUtil {
throw new UnsupportedOperationException("Unsupported patriarch type: " + patriarch.getClass().getName());
}
}
+
+ /**
+ * 添加批注
+ *
+ * @param cell {@link Cell}
+ * @param clientAnchor 绘制区域信息
+ * @param content 内容
+ */
+ public static void drawingCellComment(final Cell cell, final SimpleClientAnchor clientAnchor, final String content){
+ final Sheet sheet = cell.getSheet();
+ final Drawing> patriarch = sheet.createDrawingPatriarch();
+ final Workbook workbook = sheet.getWorkbook();
+ final ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
+ clientAnchor.copyTo(anchor);
+
+ final RichTextString richTextString = workbook.getCreationHelper().createRichTextString(content);
+ final Comment cellComment = patriarch.createCellComment(anchor);
+ cellComment.setString(richTextString);
+
+ cell.setCellComment(cellComment);
+ }
}
diff --git a/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/ExcelWriter.java b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/ExcelWriter.java
index 8ec35b0f0..9e437b560 100644
--- a/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/ExcelWriter.java
+++ b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/ExcelWriter.java
@@ -17,9 +17,6 @@ import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.ss.util.CellReference;
-import org.apache.poi.xssf.streaming.SXSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFDataValidation;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.io.IORuntimeException;
@@ -29,7 +26,6 @@ import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
import org.dromara.hutool.core.map.multi.Table;
-import org.dromara.hutool.core.reflect.FieldUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.poi.excel.*;
import org.dromara.hutool.poi.excel.cell.CellRangeUtil;
@@ -67,11 +63,15 @@ public class ExcelWriter extends ExcelBase {
*/
private Map headLocationCache;
/**
- * 当前行
+ * 当前行,用于标记初始可写数据的行和部分写完后当前的行
*/
private final AtomicInteger currentRow;
+ /**
+ * 模板上下文,存储模板中变量及其位置信息
+ */
+ private TemplateContext templateContext;
- // region Constructors
+ // region ----- Constructors
/**
* 构造,默认生成xlsx格式的Excel文件
@@ -148,8 +148,11 @@ public class ExcelWriter extends ExcelBase {
if (!FileUtil.exists(targetFile)) {
this.targetFile = targetFile;
+ } else{
+ // 如果是已经存在的文件,则作为模板加载,此时不能写出到模板文件
+ // 初始化模板
+ this.templateContext = new TemplateContext(this.sheet);
}
- // 如果是已经存在的文件,则作为模板加载,此时不能写出到模板文件
}
/**
@@ -389,9 +392,6 @@ public class ExcelWriter extends ExcelBase {
return this;
}
- //region header alias
- //endregion
-
/**
* 设置窗口冻结,之前冻结的窗口会被覆盖,如果rowSplit为0表示取消冻结
*
@@ -502,19 +502,8 @@ public class ExcelWriter extends ExcelBase {
* @since 5.8.28
*/
public ExcelWriter addIgnoredErrors(final CellRangeAddress cellRangeAddress, final IgnoredErrorType... ignoredErrorTypes) throws UnsupportedOperationException {
- final Sheet sheet = this.sheet;
- if (sheet instanceof XSSFSheet) {
- ((XSSFSheet) sheet).addIgnoredErrors(cellRangeAddress, ignoredErrorTypes);
- return this;
- } else if (sheet instanceof SXSSFSheet) {
- // SXSSFSheet并未提供忽略错误方法,获得其内部_sh字段设置
- final XSSFSheet xssfSheet = (XSSFSheet) FieldUtil.getFieldValue(sheet, "_sh");
- if (null != xssfSheet) {
- xssfSheet.addIgnoredErrors(cellRangeAddress, ignoredErrorTypes);
- }
- }
-
- throw new UnsupportedOperationException("Only XSSFSheet supports addIgnoredErrors");
+ SheetUtil.addIgnoredErrors(this.sheet, cellRangeAddress, ignoredErrorTypes);
+ return this;
}
/**
@@ -539,21 +528,8 @@ public class ExcelWriter extends ExcelBase {
* @since 4.6.2
*/
public ExcelWriter addSelect(final CellRangeAddressList regions, final String... selectList) {
- final DataValidationHelper validationHelper = this.sheet.getDataValidationHelper();
- final DataValidationConstraint constraint = validationHelper.createExplicitListConstraint(selectList);
-
- //设置下拉框数据
- final DataValidation dataValidation = validationHelper.createValidation(constraint, regions);
-
- //处理Excel兼容性问题
- if (dataValidation instanceof XSSFDataValidation) {
- dataValidation.setSuppressDropDownArrow(true);
- dataValidation.setShowErrorBox(true);
- } else {
- dataValidation.setSuppressDropDownArrow(false);
- }
-
- return addValidationData(dataValidation);
+ DataValidationUtil.addSelect(this.sheet, regions, selectList);
+ return this;
}
/**
@@ -568,6 +544,7 @@ public class ExcelWriter extends ExcelBase {
return this;
}
+ // region ----- merge
/**
* 合并当前行的单元格
*
@@ -656,7 +633,9 @@ public class ExcelWriter extends ExcelBase {
}
return this;
}
+ // endregion
+ // region ----- write
/**
* 写出数据,本方法只是将数据写入Workbook中的Sheet,并不写出到文件
* 写出的起始行为当前行号,可使用{@link #getCurrentRow()}方法调用,根据写出的的行数,当前行号自动增加
@@ -744,6 +723,7 @@ public class ExcelWriter extends ExcelBase {
}
return this;
}
+ // endregion
// region ----- writeImg
@@ -805,7 +785,7 @@ public class ExcelWriter extends ExcelBase {
* @since 6.0.0
*/
public ExcelWriter writeImg(final byte[] pictureData, final ExcelImgType imgType, final SimpleClientAnchor clientAnchor) {
- ExcelImgUtil.writeImg(this.sheet, pictureData, imgType, clientAnchor);
+ ExcelDrawingUtil.drawingImg(this.sheet, pictureData, imgType, clientAnchor);
return this;
}
@@ -843,7 +823,7 @@ public class ExcelWriter extends ExcelBase {
* @since 6.0.0
*/
public ExcelWriter writeSimpleShape(final SimpleClientAnchor clientAnchor, final ShapeConfig shapeConfig) {
- SimpleShapeUtil.writeSimpleShape(this.sheet, clientAnchor, shapeConfig);
+ ExcelDrawingUtil.drawingSimpleShape(this.sheet, clientAnchor, shapeConfig);
return this;
}
// endregion
diff --git a/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/TemplateContext.java b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/TemplateContext.java
new file mode 100644
index 000000000..c2796710d
--- /dev/null
+++ b/hutool-poi/src/main/java/org/dromara/hutool/poi/excel/writer/TemplateContext.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.poi.excel.writer;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.dromara.hutool.core.collection.CollUtil;
+import org.dromara.hutool.core.regex.ReUtil;
+import org.dromara.hutool.core.text.StrUtil;
+import org.dromara.hutool.poi.excel.SheetUtil;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * 模板上下文,记录了模板中变量所在的Cell
+ *
+ * @author Looly
+ * @since 6.0.0
+ */
+public class TemplateContext {
+
+ /**
+ * 变量正则
+ *
+ * - 变量名只能包含字母、数字、下划线、$符号、.符号,不能以数字开头
+ * - 变量以 { 开始,以 } 结束
+ * - \{表示转义,非变量符号
+ * - .开头的变量表示列表,.出现在中间,表示表达式子对象
+ *
+ */
+ private static final Pattern VAR_PATTERN = Pattern.compile("(? varMap = new HashMap<>();
+
+ /**
+ * 构造
+ *
+ * @param templateSheet 模板sheet
+ */
+ public TemplateContext(final Sheet templateSheet) {
+ init(templateSheet);
+ }
+
+ /**
+ * 获取变量对应的单元格,列表变量以.开头
+ *
+ * @param varName 变量名
+ * @return 单元格
+ */
+ public Cell getCell(final String varName) {
+ return varMap.get(varName);
+ }
+
+ /**
+ * 初始化,提取变量及位置,并将转义的变量回填
+ *
+ * @param templateSheet 模板sheet
+ */
+ private void init(final Sheet templateSheet) {
+ SheetUtil.walk(templateSheet, (cell, ctx) -> {
+ if (CellType.STRING == cell.getCellType()) {
+ // 只读取字符串类型的单元格
+ final String cellValue = cell.getStringCellValue();
+
+ // 字符串中可能有多个变量
+ final List vars = ReUtil.findAllGroup1(VAR_PATTERN, cellValue);
+ if (CollUtil.isNotEmpty(vars)) {
+ // 模板变量
+ for (final String var : vars) {
+ varMap.put(var, cell);
+ }
+ }
+
+ // 替换转义的变量
+ final String str = ReUtil.replaceAll(cellValue, ESCAPE_VAR_PATTERN, (matcher) -> "{" + matcher.group(1) + "}");
+ if (!StrUtil.equals(cellValue, str)) {
+ cell.setCellValue(str);
+ }
+ }
+ });
+ }
+}
diff --git a/hutool-poi/src/test/java/org/dromara/hutool/poi/excel/writer/TemplateContextTest.java b/hutool-poi/src/test/java/org/dromara/hutool/poi/excel/writer/TemplateContextTest.java
new file mode 100644
index 000000000..eed4f4acb
--- /dev/null
+++ b/hutool-poi/src/test/java/org/dromara/hutool/poi/excel/writer/TemplateContextTest.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.poi.excel.writer;
+
+import org.dromara.hutool.poi.excel.ExcelUtil;
+import org.junit.jupiter.api.Test;
+
+public class TemplateContextTest {
+ @Test
+ void readTemplate() {
+ final ExcelWriter writer = ExcelUtil.getWriter("d:/test/template.xlsx");
+ final TemplateContext templateContext = new TemplateContext(writer.getSheet());
+ }
+}
diff --git a/hutool-poi/src/test/java/org/dromara/hutool/poi/excel/writer/WriteCommentTest.java b/hutool-poi/src/test/java/org/dromara/hutool/poi/excel/writer/WriteCommentTest.java
new file mode 100644
index 000000000..65b3e99d6
--- /dev/null
+++ b/hutool-poi/src/test/java/org/dromara/hutool/poi/excel/writer/WriteCommentTest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.poi.excel.writer;
+
+import org.dromara.hutool.poi.excel.ExcelUtil;
+import org.dromara.hutool.poi.excel.SimpleClientAnchor;
+import org.junit.jupiter.api.Test;
+
+public class WriteCommentTest {
+ @Test
+ void writeCommentTest() {
+ final ExcelWriter writer = ExcelUtil.getWriter("d:/test/comments.xlsx");
+ final SimpleClientAnchor clientAnchor = new SimpleClientAnchor(0, 0, 1, 1);
+ ExcelDrawingUtil.drawingCellComment(writer.getOrCreateCell(5, 6), clientAnchor, "测试内容");
+ writer.close();
+ }
+}