add ExcelImgType

This commit is contained in:
Looly
2024-08-11 19:08:19 +08:00
parent eef88779cf
commit 7a1983235f
8 changed files with 274 additions and 138 deletions

View File

@@ -0,0 +1,79 @@
/*
* 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;
import org.apache.poi.ss.usermodel.Workbook;
/**
* Excel支持的图片类型枚举
*
* @author Looly
* @see Workbook#PICTURE_TYPE_EMF
* @see Workbook#PICTURE_TYPE_WMF
* @see Workbook#PICTURE_TYPE_PICT
* @see Workbook#PICTURE_TYPE_JPEG
* @see Workbook#PICTURE_TYPE_PNG
* @see Workbook#PICTURE_TYPE_DIB
* @since 6.0.0
*/
public enum ExcelImgType {
/**
* Extended windows meta file
*/
EMF(Workbook.PICTURE_TYPE_EMF),
/**
* Windows Meta File
*/
WMF(Workbook.PICTURE_TYPE_WMF),
/**
* Mac PICT format
*/
PICT(Workbook.PICTURE_TYPE_PICT),
/**
* JPEG format
*/
JPEG(Workbook.PICTURE_TYPE_JPEG),
/**
* PNG format
*/
PNG(Workbook.PICTURE_TYPE_PNG),
/**
* Device independent bitmap
*/
DIB(Workbook.PICTURE_TYPE_DIB);
private final int value;
/**
* 构造
*
* @param value 类型编码
*/
ExcelImgType(final int value) {
this.value = value;
}
/**
* 获取类型编码
*
* @return 编码
*/
public int getValue() {
return this.value;
}
}

View File

@@ -12,25 +12,15 @@
package org.dromara.hutool.poi.excel; package org.dromara.hutool.poi.excel;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.dromara.hutool.core.collection.CollUtil; import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.io.file.FileTypeUtil; import org.dromara.hutool.core.io.file.FileTypeUtil;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.map.multi.ListValueMap; import org.dromara.hutool.core.map.multi.ListValueMap;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFPictureData;
import org.apache.poi.hssf.usermodel.HSSFShape;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFPicture;
import org.apache.poi.xssf.usermodel.XSSFShape;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker; import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
import java.io.File; import java.io.File;
@@ -51,22 +41,22 @@ public class ExcelImgUtil {
* @return 图片类型默认PNG * @return 图片类型默认PNG
* @since 6.0.0 * @since 6.0.0
*/ */
public static int getImgType(final File imgFile) { public static ExcelImgType getImgType(final File imgFile) {
final String type = FileTypeUtil.getType(imgFile); final String type = FileTypeUtil.getType(imgFile);
if (StrUtil.equalsAnyIgnoreCase(type, "jpg", "jpeg")) { if (StrUtil.equalsAnyIgnoreCase(type, "jpg", "jpeg")) {
return Workbook.PICTURE_TYPE_JPEG; return ExcelImgType.JPEG;
} else if (StrUtil.equalsAnyIgnoreCase(type, "emf")) { } else if (StrUtil.equalsAnyIgnoreCase(type, "emf")) {
return Workbook.PICTURE_TYPE_EMF; return ExcelImgType.EMF;
} else if (StrUtil.equalsAnyIgnoreCase(type, "wmf")) { } else if (StrUtil.equalsAnyIgnoreCase(type, "wmf")) {
return Workbook.PICTURE_TYPE_WMF; return ExcelImgType.WMF;
} else if (StrUtil.equalsAnyIgnoreCase(type, "pict")) { } else if (StrUtil.equalsAnyIgnoreCase(type, "pict")) {
return Workbook.PICTURE_TYPE_PICT; return ExcelImgType.PICT;
} else if (StrUtil.equalsAnyIgnoreCase(type, "dib")) { } else if (StrUtil.equalsAnyIgnoreCase(type, "dib")) {
return Workbook.PICTURE_TYPE_DIB; return ExcelImgType.DIB;
} }
// 默认格式 // 默认格式
return Workbook.PICTURE_TYPE_PNG; return ExcelImgType.PNG;
} }
/** /**
@@ -91,6 +81,27 @@ public class ExcelImgUtil {
} }
} }
/**
* 写出图片本方法只是将数据写入Workbook中的Sheet并不写出到文件<br>
* 添加图片到当前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 // -------------------------------------------------------------------------------------------------------------- Private method start
/** /**

View File

@@ -261,7 +261,7 @@ public class ExcelUtil {
/** /**
* 获得{@link ExcelWriter}默认写出到第一个sheet<br> * 获得{@link ExcelWriter}默认写出到第一个sheet<br>
* 不传入写出的Excel文件路径只能调用ExcelWriter#flush(OutputStream)方法写出到流<br> * 不传入写出的Excel文件路径只能调用ExcelWriter#flush(OutputStream)方法写出到流<br>
* 若写出到文件,还需调用{@link ExcelWriter#setDestFile(File)}方法自定义写出的文件,然后调用{@link ExcelWriter#flush()}方法写出到文件 * 若写出到文件,还需调用{@link ExcelWriter#setTargetFile(File)}方法自定义写出的文件,然后调用{@link ExcelWriter#flush()}方法写出到文件
* *
* @return {@link ExcelWriter} * @return {@link ExcelWriter}
* @since 3.2.1 * @since 3.2.1
@@ -277,7 +277,7 @@ public class ExcelUtil {
/** /**
* 获得{@link ExcelWriter}默认写出到第一个sheet<br> * 获得{@link ExcelWriter}默认写出到第一个sheet<br>
* 不传入写出的Excel文件路径只能调用ExcelWriter#flush(OutputStream)方法写出到流<br> * 不传入写出的Excel文件路径只能调用ExcelWriter#flush(OutputStream)方法写出到流<br>
* 若写出到文件,还需调用{@link ExcelWriter#setDestFile(File)}方法自定义写出的文件,然后调用{@link ExcelWriter#flush()}方法写出到文件 * 若写出到文件,还需调用{@link ExcelWriter#setTargetFile(File)}方法自定义写出的文件,然后调用{@link ExcelWriter#flush()}方法写出到文件
* *
* @param isXlsx 是否为xlsx格式 * @param isXlsx 是否为xlsx格式
* @return {@link ExcelWriter} * @return {@link ExcelWriter}
@@ -370,7 +370,7 @@ public class ExcelUtil {
/** /**
* 获得{@link BigExcelWriter}默认写出到第一个sheet<br> * 获得{@link BigExcelWriter}默认写出到第一个sheet<br>
* 不传入写出的Excel文件路径只能调用ExcelWriter#flush(OutputStream)方法写出到流<br> * 不传入写出的Excel文件路径只能调用ExcelWriter#flush(OutputStream)方法写出到流<br>
* 若写出到文件,还需调用{@link BigExcelWriter#setDestFile(File)}方法自定义写出的文件,然后调用{@link BigExcelWriter#flush()}方法写出到文件 * 若写出到文件,还需调用{@link BigExcelWriter#setTargetFile(File)}方法自定义写出的文件,然后调用{@link BigExcelWriter#flush()}方法写出到文件
* *
* @return {@link BigExcelWriter} * @return {@link BigExcelWriter}
* @since 4.1.13 * @since 4.1.13
@@ -386,7 +386,7 @@ public class ExcelUtil {
/** /**
* 获得{@link BigExcelWriter}默认写出到第一个sheet<br> * 获得{@link BigExcelWriter}默认写出到第一个sheet<br>
* 不传入写出的Excel文件路径只能调用ExcelWriter#flush(OutputStream)方法写出到流<br> * 不传入写出的Excel文件路径只能调用ExcelWriter#flush(OutputStream)方法写出到流<br>
* 若写出到文件,还需调用{@link BigExcelWriter#setDestFile(File)}方法自定义写出的文件,然后调用{@link BigExcelWriter#flush()}方法写出到文件 * 若写出到文件,还需调用{@link BigExcelWriter#setTargetFile(File)}方法自定义写出的文件,然后调用{@link BigExcelWriter#flush()}方法写出到文件
* *
* @param rowAccessWindowSize 在内存中的行数 * @param rowAccessWindowSize 在内存中的行数
* @return {@link BigExcelWriter} * @return {@link BigExcelWriter}

View File

@@ -14,7 +14,9 @@ package org.dromara.hutool.poi.excel.cell.setters;
import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.*;
import org.dromara.hutool.core.io.file.FileUtil; 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.ExcelImgUtil;
import org.dromara.hutool.poi.excel.SimpleClientAnchor;
import java.io.File; import java.io.File;
@@ -27,7 +29,7 @@ import java.io.File;
public class ImgCellSetter implements CellSetter { public class ImgCellSetter implements CellSetter {
private final byte[] pictureData; private final byte[] pictureData;
private final int imgType; private final ExcelImgType imgType;
// region ----- 构造 // region ----- 构造
@@ -37,7 +39,7 @@ public class ImgCellSetter implements CellSetter {
* @param pictureData 图片数据 * @param pictureData 图片数据
*/ */
public ImgCellSetter(final byte[] pictureData) { public ImgCellSetter(final byte[] pictureData) {
this(pictureData, Workbook.PICTURE_TYPE_PNG); this(pictureData, ExcelImgType.PNG);
} }
/** /**
@@ -55,7 +57,7 @@ public class ImgCellSetter implements CellSetter {
* @param pictureData 图片数据 * @param pictureData 图片数据
* @param imgType 图片类型 * @param imgType 图片类型
*/ */
public ImgCellSetter(final byte[] pictureData, final int imgType) { public ImgCellSetter(final byte[] pictureData, final ExcelImgType imgType) {
this.pictureData = pictureData; this.pictureData = pictureData;
this.imgType = imgType; this.imgType = imgType;
} }
@@ -64,18 +66,10 @@ public class ImgCellSetter implements CellSetter {
@Override @Override
public void setValue(final Cell cell) { public void setValue(final Cell cell) {
final Sheet sheet = cell.getSheet(); final Sheet sheet = cell.getSheet();
final Workbook workbook = sheet.getWorkbook();
final Drawing<?> patriarch = sheet.createDrawingPatriarch();
final ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
final int columnIndex = cell.getColumnIndex(); final int columnIndex = cell.getColumnIndex();
final int rowIndex = cell.getRowIndex(); final int rowIndex = cell.getRowIndex();
// 填充当前单元格
anchor.setCol1(columnIndex);
anchor.setRow1(rowIndex);
anchor.setCol2(columnIndex + 1);
anchor.setRow2(rowIndex + 1);
patriarch.createPicture(anchor, workbook.addPicture(this.pictureData, this.imgType)); ExcelImgUtil.writeImg(sheet, this.pictureData, this.imgType,
new SimpleClientAnchor(columnIndex, rowIndex, columnIndex + 1, rowIndex + 1));
} }
} }

View File

@@ -49,7 +49,7 @@ public class BigExcelWriter extends ExcelWriter {
/** /**
* 构造默认生成xlsx格式的Excel文件<br> * 构造默认生成xlsx格式的Excel文件<br>
* 此构造不传入写出的Excel文件路径只能调用{@link #flush(java.io.OutputStream)}方法写出到流<br> * 此构造不传入写出的Excel文件路径只能调用{@link #flush(java.io.OutputStream)}方法写出到流<br>
* 若写出到文件,还需调用{@link #setDestFile(File)}方法自定义写出的文件,然后调用{@link #flush()}方法写出到文件 * 若写出到文件,还需调用{@link #setTargetFile(File)}方法自定义写出的文件,然后调用{@link #flush()}方法写出到文件
*/ */
public BigExcelWriter() { public BigExcelWriter() {
this(DEFAULT_WINDOW_SIZE); this(DEFAULT_WINDOW_SIZE);
@@ -136,7 +136,7 @@ public class BigExcelWriter extends ExcelWriter {
/** /**
* 构造<br> * 构造<br>
* 此构造不传入写出的Excel文件路径只能调用{@link #flush(java.io.OutputStream)}方法写出到流<br> * 此构造不传入写出的Excel文件路径只能调用{@link #flush(java.io.OutputStream)}方法写出到流<br>
* 若写出到文件,还需调用{@link #setDestFile(File)}方法自定义写出的文件,然后调用{@link #flush()}方法写出到文件 * 若写出到文件,还需调用{@link #setTargetFile(File)}方法自定义写出的文件,然后调用{@link #flush()}方法写出到文件
* *
* @param workbook {@link SXSSFWorkbook} * @param workbook {@link SXSSFWorkbook}
* @param sheetName sheet名做为第一个sheet名并写出到此sheet例如sheet1 * @param sheetName sheet名做为第一个sheet名并写出到此sheet例如sheet1
@@ -148,7 +148,7 @@ public class BigExcelWriter extends ExcelWriter {
/** /**
* 构造<br> * 构造<br>
* 此构造不传入写出的Excel文件路径只能调用{@link #flush(java.io.OutputStream)}方法写出到流<br> * 此构造不传入写出的Excel文件路径只能调用{@link #flush(java.io.OutputStream)}方法写出到流<br>
* 若写出到文件,还需调用{@link #setDestFile(File)}方法自定义写出的文件,然后调用{@link #flush()}方法写出到文件 * 若写出到文件,还需调用{@link #setTargetFile(File)}方法自定义写出的文件,然后调用{@link #flush()}方法写出到文件
* *
* @param sheet {@link Sheet} * @param sheet {@link Sheet}
* @since 4.0.6 * @since 4.0.6

View File

@@ -14,9 +14,14 @@ package org.dromara.hutool.poi.excel.writer;
import org.dromara.hutool.core.comparator.IndexedComparator; import org.dromara.hutool.core.comparator.IndexedComparator;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.map.TableMap;
import org.dromara.hutool.core.map.multi.RowKeyTable;
import org.dromara.hutool.core.map.multi.Table;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.poi.excel.ExcelConfig; import org.dromara.hutool.poi.excel.ExcelConfig;
import java.util.Comparator; import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -85,4 +90,31 @@ public class ExcelWriteConfig extends ExcelConfig {
} }
return aliasComparator; return aliasComparator;
} }
/**
* 为指定的key列表添加标题别名如果没有定义key的别名在onlyAlias为false时使用原key<br>
* key为别名value为字段值
*
* @param rowMap 一行数据
* @return 别名列表
*/
public Table<?, ?, ?> aliasTable(final Map<?, ?> rowMap) {
final Table<Object, Object, Object> filteredTable = new RowKeyTable<>(new LinkedHashMap<>(), TableMap::new);
if (MapUtil.isEmpty(headerAlias)) {
rowMap.forEach((key, value) -> filteredTable.put(key, key, value));
} else {
rowMap.forEach((key, value) -> {
final String aliasName = headerAlias.get(StrUtil.toString(key));
if (null != aliasName) {
// 别名键值对加入
filteredTable.put(key, aliasName, value);
} else if (!onlyAlias) {
// 保留无别名设置的键值对
filteredTable.put(key, key, value);
}
});
}
return filteredTable;
}
} }

View File

@@ -13,15 +13,13 @@
package org.dromara.hutool.poi.excel.writer; package org.dromara.hutool.poi.excel.writer;
import org.apache.poi.common.usermodel.Hyperlink; import org.apache.poi.common.usermodel.Hyperlink;
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.*; import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFSheet; import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.usermodel.*; 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.bean.BeanUtil;
import org.dromara.hutool.core.collection.ListUtil; import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.io.IORuntimeException; import org.dromara.hutool.core.io.IORuntimeException;
@@ -29,9 +27,7 @@ import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.io.file.FileUtil; import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.map.MapUtil; import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.map.TableMap;
import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap; import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
import org.dromara.hutool.core.map.multi.RowKeyTable;
import org.dromara.hutool.core.map.multi.Table; import org.dromara.hutool.core.map.multi.Table;
import org.dromara.hutool.core.reflect.FieldUtil; import org.dromara.hutool.core.reflect.FieldUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
@@ -60,7 +56,6 @@ import java.util.concurrent.atomic.AtomicInteger;
* @author Looly * @author Looly
* @since 3.2.0 * @since 3.2.0
*/ */
@SuppressWarnings("resource")
public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> { public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
/** /**
@@ -81,7 +76,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
/** /**
* 构造默认生成xlsx格式的Excel文件<br> * 构造默认生成xlsx格式的Excel文件<br>
* 此构造不传入写出的Excel文件路径只能调用{@link #flush(OutputStream)}方法写出到流<br> * 此构造不传入写出的Excel文件路径只能调用{@link #flush(OutputStream)}方法写出到流<br>
* 若写出到文件,还需调用{@link #setDestFile(File)}方法自定义写出的文件,然后调用{@link #flush()}方法写出到文件 * 若写出到文件,还需调用{@link #setTargetFile(File)}方法自定义写出的文件,然后调用{@link #flush()}方法写出到文件
* *
* @since 3.2.1 * @since 3.2.1
*/ */
@@ -145,18 +140,22 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
/** /**
* 构造 * 构造
* *
* @param destFile 目标文件,可以不存在 * @param targetFile 目标文件,可以不存在
* @param sheetName sheet名做为第一个sheet名并写出到此sheet例如sheet1 * @param sheetName sheet名做为第一个sheet名并写出到此sheet例如sheet1
*/ */
public ExcelWriter(final File destFile, final String sheetName) { public ExcelWriter(final File targetFile, final String sheetName) {
this(WorkbookUtil.createBookForWriter(destFile), sheetName); this(WorkbookUtil.createBookForWriter(targetFile), sheetName);
this.targetFile = destFile;
if (!FileUtil.exists(targetFile)) {
this.targetFile = targetFile;
}
// 如果是已经存在的文件,则作为模板加载,此时不能写出到模板文件
} }
/** /**
* 构造<br> * 构造<br>
* 此构造不传入写出的Excel文件路径只能调用{@link #flush(OutputStream)}方法写出到流<br> * 此构造不传入写出的Excel文件路径只能调用{@link #flush(OutputStream)}方法写出到流<br>
* 若写出到文件,还需调用{@link #setDestFile(File)}方法自定义写出的文件,然后调用{@link #flush()}方法写出到文件 * 若写出到文件,还需调用{@link #setTargetFile(File)}方法自定义写出的文件,然后调用{@link #flush()}方法写出到文件
* *
* @param workbook {@link Workbook} * @param workbook {@link Workbook}
* @param sheetName sheet名做为第一个sheet名并写出到此sheet例如sheet1 * @param sheetName sheet名做为第一个sheet名并写出到此sheet例如sheet1
@@ -168,7 +167,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
/** /**
* 构造<br> * 构造<br>
* 此构造不传入写出的Excel文件路径只能调用{@link #flush(OutputStream)}方法写出到流<br> * 此构造不传入写出的Excel文件路径只能调用{@link #flush(OutputStream)}方法写出到流<br>
* 若写出到文件,还需调用{@link #setDestFile(File)}方法自定义写出的文件,然后调用{@link #flush()}方法写出到文件 * 若写出到文件,还需调用{@link #setTargetFile(File)}方法自定义写出的文件,然后调用{@link #flush()}方法写出到文件
* *
* @param sheet {@link Sheet} * @param sheet {@link Sheet}
* @since 4.0.6 * @since 4.0.6
@@ -188,16 +187,16 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
@Override @Override
public ExcelWriter setSheet(final int sheetIndex) { public ExcelWriter setSheet(final int sheetIndex) {
super.setSheet(sheetIndex);
// 切换到新sheet需要重置开始行 // 切换到新sheet需要重置开始行
reset(); return reset();
return super.setSheet(sheetIndex);
} }
@Override @Override
public ExcelWriter setSheet(final String sheetName) { public ExcelWriter setSheet(final String sheetName) {
super.setSheet(sheetName);
// 切换到新sheet需要重置开始行 // 切换到新sheet需要重置开始行
reset(); return reset();
return super.setSheet(sheetName);
} }
/** /**
@@ -205,15 +204,14 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* *
* <pre> * <pre>
* 1. 当前行游标归零 * 1. 当前行游标归零
* 2. 清空别名比较器 * 2. 清除标题缓存
* 3. 清除标题缓存
* </pre> * </pre>
* *
* @return this * @return this
*/ */
public ExcelWriter reset() { public ExcelWriter reset() {
resetRow(); this.headLocationCache.clear();
return this; return resetRow();
} }
/** /**
@@ -250,6 +248,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* @return this * @return this
* @since 4.0.12 * @since 4.0.12
*/ */
@SuppressWarnings("resource")
public ExcelWriter autoSizeColumnAll(final boolean useMergedCells, final float widthRatio) { public ExcelWriter autoSizeColumnAll(final boolean useMergedCells, final float widthRatio) {
final int columnCount = this.getColumnCount(); final int columnCount = this.getColumnCount();
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
@@ -379,13 +378,14 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
} }
/** /**
* 设置写出的目标文件 * 设置写出的目标文件<br>
* 注意这个文件不能存在,存在则{@link #flush()}时会被覆盖
* *
* @param destFile 目标文件 * @param targetFile 目标文件
* @return this * @return this
*/ */
public ExcelWriter setDestFile(final File destFile) { public ExcelWriter setTargetFile(final File targetFile) {
this.targetFile = destFile; this.targetFile = targetFile;
return this; return this;
} }
@@ -600,6 +600,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* @return this * @return this
* @since 4.0.10 * @since 4.0.10
*/ */
@SuppressWarnings("resource")
public ExcelWriter merge(final int lastColumn, final Object content, final boolean isSetHeaderStyle) { public ExcelWriter merge(final int lastColumn, final Object content, final boolean isSetHeaderStyle) {
Assert.isFalse(this.isClosed, "ExcelWriter has been closed!"); Assert.isFalse(this.isClosed, "ExcelWriter has been closed!");
@@ -696,6 +697,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* @param isWriteKeyAsHead 是否强制写出标题行Map或Bean * @param isWriteKeyAsHead 是否强制写出标题行Map或Bean
* @return this * @return this
*/ */
@SuppressWarnings("resource")
public ExcelWriter write(final Iterable<?> data, final boolean isWriteKeyAsHead) { public ExcelWriter write(final Iterable<?> data, final boolean isWriteKeyAsHead) {
Assert.isFalse(this.isClosed, "ExcelWriter has been closed!"); Assert.isFalse(this.isClosed, "ExcelWriter has been closed!");
boolean isFirst = true; boolean isFirst = true;
@@ -723,7 +725,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* @return this * @return this
* @since 3.2.3 * @since 3.2.3
*/ */
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked", "resource"})
public ExcelWriter write(final Iterable<?> data, final Comparator<String> comparator) { public ExcelWriter write(final Iterable<?> data, final Comparator<String> comparator) {
Assert.isFalse(this.isClosed, "ExcelWriter has been closed!"); Assert.isFalse(this.isClosed, "ExcelWriter has been closed!");
boolean isFirstRow = true; boolean isFirstRow = true;
@@ -787,7 +789,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* @author vhukze * @author vhukze
* @since 6.0.0 * @since 6.0.0
*/ */
public ExcelWriter writeImg(final File imgFile, final int imgType, final SimpleClientAnchor clientAnchor) { public ExcelWriter writeImg(final File imgFile, final ExcelImgType imgType, final SimpleClientAnchor clientAnchor) {
return writeImg(FileUtil.readBytes(imgFile), imgType, clientAnchor); return writeImg(FileUtil.readBytes(imgFile), imgType, clientAnchor);
} }
@@ -802,12 +804,8 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* @author vhukze * @author vhukze
* @since 6.0.0 * @since 6.0.0
*/ */
public ExcelWriter writeImg(final byte[] pictureData, final int imgType, final SimpleClientAnchor clientAnchor) { public ExcelWriter writeImg(final byte[] pictureData, final ExcelImgType imgType, final SimpleClientAnchor clientAnchor) {
final Drawing<?> patriarch = this.sheet.createDrawingPatriarch(); ExcelImgUtil.writeImg(this.sheet, pictureData, imgType, clientAnchor);
final ClientAnchor anchor = this.workbook.getCreationHelper().createClientAnchor();
clientAnchor.copyTo(anchor);
patriarch.createPicture(anchor, this.workbook.addPicture(pictureData, imgType));
return this; return this;
} }
@@ -844,34 +842,8 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* @return this * @return this
* @since 6.0.0 * @since 6.0.0
*/ */
public ExcelWriter writeSimpleShape(final SimpleClientAnchor clientAnchor, ShapeConfig shapeConfig) { public ExcelWriter writeSimpleShape(final SimpleClientAnchor clientAnchor, final ShapeConfig shapeConfig) {
final Drawing<?> patriarch = this.sheet.createDrawingPatriarch(); SimpleShapeUtil.writeSimpleShape(this.sheet, clientAnchor, shapeConfig);
final ClientAnchor anchor = this.workbook.getCreationHelper().createClientAnchor();
clientAnchor.copyTo(anchor);
if (null == shapeConfig) {
shapeConfig = ShapeConfig.of();
}
final Color lineColor = shapeConfig.getLineColor();
if (patriarch instanceof HSSFPatriarch) {
final HSSFSimpleShape simpleShape = ((HSSFPatriarch) patriarch).createSimpleShape((HSSFClientAnchor) anchor);
simpleShape.setShapeType(shapeConfig.getShapeType().ooxmlId);
simpleShape.setLineStyle(shapeConfig.getLineStyle().getValue());
simpleShape.setLineWidth(shapeConfig.getLineWidth());
if (null != lineColor) {
simpleShape.setLineStyleColor(lineColor.getRed(), lineColor.getGreen(), lineColor.getBlue());
}
} else if (patriarch instanceof XSSFDrawing) {
final XSSFSimpleShape simpleShape = ((XSSFDrawing) patriarch).createSimpleShape((XSSFClientAnchor) anchor);
simpleShape.setShapeType(shapeConfig.getShapeType().ooxmlId);
simpleShape.setLineStyle(shapeConfig.getLineStyle().getValue());
simpleShape.setLineWidth(shapeConfig.getLineWidth());
if (null != lineColor) {
simpleShape.setLineStyleColor(lineColor.getRed(), lineColor.getGreen(), lineColor.getBlue());
}
} else {
throw new UnsupportedOperationException("Unsupported patriarch type: " + patriarch.getClass().getName());
}
return this; return this;
} }
// endregion // endregion
@@ -914,6 +886,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* @param rowData 一行的数据 * @param rowData 一行的数据
* @return this * @return this
*/ */
@SuppressWarnings("resource")
public ExcelWriter writeSecHeadRow(final Iterable<?> rowData) { public ExcelWriter writeSecHeadRow(final Iterable<?> rowData) {
final Row row = RowUtil.getOrCreateRow(this.sheet, this.currentRow.getAndIncrement()); final Row row = RowUtil.getOrCreateRow(this.sheet, this.currentRow.getAndIncrement());
final Iterator<?> iterator = rowData.iterator(); final Iterator<?> iterator = rowData.iterator();
@@ -994,6 +967,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* @param isWriteKeyAsHead 为true写出两行Map的keys做为一行values做为第二行否则只写出一行values * @param isWriteKeyAsHead 为true写出两行Map的keys做为一行values做为第二行否则只写出一行values
* @return this * @return this
*/ */
@SuppressWarnings("resource")
public ExcelWriter writeRow(final Map<?, ?> rowMap, final boolean isWriteKeyAsHead) { public ExcelWriter writeRow(final Map<?, ?> rowMap, final boolean isWriteKeyAsHead) {
Assert.isFalse(this.isClosed, "ExcelWriter has been closed!"); Assert.isFalse(this.isClosed, "ExcelWriter has been closed!");
if (MapUtil.isEmpty(rowMap)) { if (MapUtil.isEmpty(rowMap)) {
@@ -1001,7 +975,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
return passCurrentRow(); return passCurrentRow();
} }
final Table<?, ?, ?> aliasTable = aliasTable(rowMap); final Table<?, ?, ?> aliasTable = this.config.aliasTable(rowMap);
if (isWriteKeyAsHead) { if (isWriteKeyAsHead) {
// 写出标题行,并记录标题别名和列号的关系 // 写出标题行,并记录标题别名和列号的关系
writeHeadRow(aliasTable.columnKeys()); writeHeadRow(aliasTable.columnKeys());
@@ -1075,6 +1049,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* @param isWriteKeyAsHead 是否将Map的Key作为表头输出如果为True第一行为表头紧接着为values * @param isWriteKeyAsHead 是否将Map的Key作为表头输出如果为True第一行为表头紧接着为values
* @return this * @return this
*/ */
@SuppressWarnings("resource")
public ExcelWriter writeCol(final Map<?, ? extends Iterable<?>> colMap, int startColIndex, final boolean isWriteKeyAsHead) { public ExcelWriter writeCol(final Map<?, ? extends Iterable<?>> colMap, int startColIndex, final boolean isWriteKeyAsHead) {
for (final Object k : colMap.keySet()) { for (final Object k : colMap.keySet()) {
final Iterable<?> v = colMap.get(k); final Iterable<?> v = colMap.get(k);
@@ -1112,6 +1087,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* @param isResetRowIndex 如果为true写入完毕后Row index 将会重置为写入之前的未知如果为false写入完毕后Row index将会在写完的数据下方 * @param isResetRowIndex 如果为true写入完毕后Row index 将会重置为写入之前的未知如果为false写入完毕后Row index将会在写完的数据下方
* @return this * @return this
*/ */
@SuppressWarnings("resource")
public ExcelWriter writeCol(final Object headerVal, final int colIndex, final Iterable<?> colData, final boolean isResetRowIndex) { public ExcelWriter writeCol(final Object headerVal, final int colIndex, final Iterable<?> colData, final boolean isResetRowIndex) {
Assert.isFalse(this.isClosed, "ExcelWriter has been closed!"); Assert.isFalse(this.isClosed, "ExcelWriter has been closed!");
int currentRowIndex = currentRow.get(); int currentRowIndex = currentRow.get();
@@ -1297,7 +1273,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
/** /**
* 将Excel Workbook刷出到预定义的文件<br> * 将Excel Workbook刷出到预定义的文件<br>
* 如果用户未自定义输出的文件,将抛出{@link NullPointerException}<br> * 如果用户未自定义输出的文件,将抛出{@link NullPointerException}<br>
* 预定义文件可以通过{@link #setDestFile(File)} 方法预定义,或者通过构造定义 * 预定义文件可以通过{@link #setTargetFile(File)} 方法预定义,或者通过构造定义
* *
* @return this * @return this
* @throws IORuntimeException IO异常 * @throws IORuntimeException IO异常
@@ -1360,6 +1336,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
* 关闭工作簿<br> * 关闭工作簿<br>
* 如果用户设定了目标文件,先写出目标文件后给关闭工作簿 * 如果用户设定了目标文件,先写出目标文件后给关闭工作簿
*/ */
@SuppressWarnings("resource")
@Override @Override
public void close() { public void close() {
if (null != this.targetFile) { if (null != this.targetFile) {
@@ -1378,36 +1355,4 @@ public class ExcelWriter extends ExcelBase<ExcelWriter, ExcelWriteConfig> {
// 清空对象 // 清空对象
this.styleSet = null; this.styleSet = null;
} }
// region ----- Private method start
/**
* 为指定的key列表添加标题别名如果没有定义key的别名在onlyAlias为false时使用原key<br>
* key为别名value为字段值
*
* @param rowMap 一行数据
* @return 别名列表
*/
private Table<?, ?, ?> aliasTable(final Map<?, ?> rowMap) {
final Table<Object, Object, Object> filteredTable = new RowKeyTable<>(new LinkedHashMap<>(), TableMap::new);
final Map<String, String> headerAlias = this.config.getHeaderAlias();
final boolean onlyAlias = this.config.onlyAlias;
if (MapUtil.isEmpty(headerAlias)) {
rowMap.forEach((key, value) -> filteredTable.put(key, key, value));
} else {
rowMap.forEach((key, value) -> {
final String aliasName = headerAlias.get(StrUtil.toString(key));
if (null != aliasName) {
// 别名键值对加入
filteredTable.put(key, aliasName, value);
} else if (!onlyAlias) {
// 保留无别名设置的键值对
filteredTable.put(key, key, value);
}
});
}
return filteredTable;
}
// endregion
} }

View File

@@ -0,0 +1,75 @@
/*
* 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.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.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSimpleShape;
import org.dromara.hutool.poi.excel.SimpleClientAnchor;
import org.dromara.hutool.poi.excel.style.ShapeConfig;
import java.awt.Color;
/**
* 简单形状工具类<br>
* 用于辅助写出指定的图形
*
* @author Looly
* @since 6.0.0
*/
public class SimpleShapeUtil {
/**
* 绘制简单形状
*
* @param sheet {@link Sheet}
* @param clientAnchor 绘制区域信息
* @param shapeConfig 形状配置,包括形状类型、线条样式、线条宽度、线条颜色、填充颜色等
* @since 6.0.0
*/
public static void writeSimpleShape(final Sheet sheet, final SimpleClientAnchor clientAnchor, ShapeConfig shapeConfig) {
final Drawing<?> patriarch = sheet.createDrawingPatriarch();
final ClientAnchor anchor = sheet.getWorkbook().getCreationHelper().createClientAnchor();
clientAnchor.copyTo(anchor);
if (null == shapeConfig) {
shapeConfig = ShapeConfig.of();
}
final Color lineColor = shapeConfig.getLineColor();
if (patriarch instanceof HSSFPatriarch) {
final HSSFSimpleShape simpleShape = ((HSSFPatriarch) patriarch).createSimpleShape((HSSFClientAnchor) anchor);
simpleShape.setShapeType(shapeConfig.getShapeType().ooxmlId);
simpleShape.setLineStyle(shapeConfig.getLineStyle().getValue());
simpleShape.setLineWidth(shapeConfig.getLineWidth());
if (null != lineColor) {
simpleShape.setLineStyleColor(lineColor.getRed(), lineColor.getGreen(), lineColor.getBlue());
}
} else if (patriarch instanceof XSSFDrawing) {
final XSSFSimpleShape simpleShape = ((XSSFDrawing) patriarch).createSimpleShape((XSSFClientAnchor) anchor);
simpleShape.setShapeType(shapeConfig.getShapeType().ooxmlId);
simpleShape.setLineStyle(shapeConfig.getLineStyle().getValue());
simpleShape.setLineWidth(shapeConfig.getLineWidth());
if (null != lineColor) {
simpleShape.setLineStyleColor(lineColor.getRed(), lineColor.getGreen(), lineColor.getBlue());
}
} else {
throw new UnsupportedOperationException("Unsupported patriarch type: " + patriarch.getClass().getName());
}
}
}