大图合并、进度计划导出
This commit is contained in:
@ -0,0 +1,40 @@
|
||||
package org.dromara.common.excel.handler;
|
||||
|
||||
import com.alibaba.excel.write.handler.CellWriteHandler;
|
||||
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class LockColumnHandler implements CellWriteHandler {
|
||||
|
||||
private final Set<Integer> lockColumns;
|
||||
|
||||
public LockColumnHandler(Collection<Integer> lockColumns) {
|
||||
this.lockColumns = new HashSet<>(lockColumns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCellDispose(CellWriteHandlerContext context) {
|
||||
Cell cell = context.getCell();
|
||||
if (cell == null) return;
|
||||
|
||||
Workbook workbook = cell.getSheet().getWorkbook();
|
||||
|
||||
// 必须为所有单元格创建一个新的 CellStyle
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
|
||||
// 锁定指定列
|
||||
if (lockColumns.contains(cell.getColumnIndex())) {
|
||||
style.setLocked(true);
|
||||
} else {
|
||||
style.setLocked(false); // 非锁定列必须明确设置为 false!
|
||||
}
|
||||
|
||||
cell.setCellStyle(style);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package org.dromara.common.excel.handler;
|
||||
|
||||
import com.alibaba.excel.write.handler.SheetWriteHandler;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
|
||||
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025-11-14 15:05
|
||||
*/
|
||||
public class SheetProtectHandler implements SheetWriteHandler {
|
||||
|
||||
private final String password;
|
||||
|
||||
public SheetProtectHandler(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder,
|
||||
WriteSheetHolder writeSheetHolder) {
|
||||
Sheet sheet = writeSheetHolder.getSheet();
|
||||
sheet.protectSheet(password); // 可为空字符串
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,10 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.resource.ClassPathResource;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.ExcelReader;
|
||||
import com.alibaba.excel.ExcelWriter;
|
||||
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
|
||||
import com.alibaba.excel.read.metadata.ReadSheet;
|
||||
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
|
||||
import com.alibaba.excel.write.metadata.WriteSheet;
|
||||
import com.alibaba.excel.write.metadata.fill.FillConfig;
|
||||
@ -14,26 +17,27 @@ import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.core.utils.file.FileUtils;
|
||||
import org.dromara.common.excel.convert.ExcelBigNumberConvert;
|
||||
import org.dromara.common.excel.core.*;
|
||||
import org.dromara.common.excel.handler.DataWriteHandler;
|
||||
import org.dromara.common.excel.handler.LockColumnHandler;
|
||||
import org.dromara.common.excel.handler.SheetProtectHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Excel相关处理
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ExcelUtil {
|
||||
|
||||
@ -47,6 +51,41 @@ public class ExcelUtil {
|
||||
return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync();
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步读取 Excel(支持读取多个 Sheet)
|
||||
*
|
||||
* @param is 输入流(一次性读取)
|
||||
* @param clazz Excel 映射实体类
|
||||
* @return 所有 Sheet 的数据汇总
|
||||
*/
|
||||
public static <T> List<T> importExcelAllSheet(InputStream is, Class<T> clazz) {
|
||||
// 用于存放所有 sheet 的数据
|
||||
List<T> allData = new ArrayList<>();
|
||||
// 1. 构建 ExcelReader
|
||||
ExcelReaderBuilder readerBuilder = EasyExcel.read(is);
|
||||
ExcelReader reader = readerBuilder.build();
|
||||
// 2. 获取 Excel 中全部 Sheet 信息(包含 SheetNo、页名等)
|
||||
List<ReadSheet> readSheets = reader.excelExecutor().sheetList();
|
||||
// 3. 遍历每一个 Sheet
|
||||
for (ReadSheet sheet : readSheets) {
|
||||
// 为每个 Sheet 创建独立监听器,用于接收读取结果
|
||||
DefaultExcelListener<T> listener = new DefaultExcelListener<>(false);
|
||||
// 4. 构建当前 Sheet 的读取器 使用 sheet.getSheetNo() 指定当前 sheet
|
||||
ReadSheet readSheet = EasyExcel.readSheet(sheet.getSheetNo())
|
||||
// 设置头映射实体类
|
||||
.head(clazz)
|
||||
// 注册读取监听器
|
||||
.registerReadListener(listener)
|
||||
.build();
|
||||
// 5. 开始读取当前 Sheet
|
||||
reader.read(readSheet);
|
||||
// 6. 收集当前 Sheet 读取的数据
|
||||
allData.addAll(listener.getExcelResult().getList());
|
||||
}
|
||||
// 7. 关闭读取器,释放资源
|
||||
reader.finish();
|
||||
return allData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用校验监听器 异步导入 同步返回
|
||||
@ -204,6 +243,37 @@ public class ExcelUtil {
|
||||
builder.doWrite(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出excel
|
||||
*
|
||||
* @param list 导出数据集合
|
||||
* @param sheetName 工作表的名称
|
||||
* @param clazz 实体类
|
||||
* @param lockColumns 锁定列
|
||||
* @param merge 是否合并单元格
|
||||
* @param os 输出流
|
||||
*/
|
||||
public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, List<Integer> lockColumns,
|
||||
boolean merge, OutputStream os, List<DropDownOptions> options) {
|
||||
ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz)
|
||||
.registerWriteHandler(new LockColumnHandler(lockColumns)) // 锁定第3列
|
||||
.registerWriteHandler(new SheetProtectHandler("dawdawdwad")) // 保护整张 sheet
|
||||
.autoCloseStream(false)
|
||||
// 自动适配
|
||||
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
|
||||
// 大数值自动转换 防止失真
|
||||
.registerConverter(new ExcelBigNumberConvert())
|
||||
.registerWriteHandler(new DataWriteHandler(clazz))
|
||||
.sheet(sheetName);
|
||||
if (merge) {
|
||||
// 合并处理器
|
||||
builder.registerWriteHandler(new CellMergeStrategy(list, true));
|
||||
}
|
||||
// 添加下拉框操作
|
||||
builder.registerWriteHandler(new ExcelDownHandler(options));
|
||||
builder.doWrite(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出多sheet excel(增强版,解决XML安全问题)
|
||||
*
|
||||
@ -212,7 +282,9 @@ public class ExcelUtil {
|
||||
* @param clazz 实体类
|
||||
* @param optionsList 级联下拉选内容列表
|
||||
*/
|
||||
public static <T> void exportMultiSheetExcelEnhanced(List<List<T>> sheetData, List<String> sheetNames, Class<T> clazz, List<List<DropDownOptions>> optionsList, HttpServletResponse response) throws IOException {
|
||||
public static <T> void exportMultiSheetExcelEnhanced(List<List<T>> sheetData, List<String> sheetNames,
|
||||
Class<T> clazz, List<List<DropDownOptions>> optionsList,
|
||||
HttpServletResponse response) throws IOException {
|
||||
resetResponse("file", response);
|
||||
ExcelWriter excelWriter = null;
|
||||
ServletOutputStream os = response.getOutputStream();
|
||||
@ -254,12 +326,71 @@ public class ExcelUtil {
|
||||
excelWriter.finish();
|
||||
} catch (Exception e) {
|
||||
// 记录日志但不中断主流程
|
||||
e.printStackTrace();
|
||||
log.error("Excel 导出错误", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出多sheet excel(增强版,解决XML安全问题)
|
||||
*
|
||||
* @param sheetData 多个sheet的数据
|
||||
* @param sheetNames 多个sheet的名称
|
||||
* @param clazz 实体类
|
||||
* @param optionsList 级联下拉选内容列表
|
||||
*/
|
||||
public static <T> void exportExcel(List<List<T>> sheetData, List<String> sheetNames, List<Integer> lockColumns,
|
||||
Class<T> clazz, List<List<DropDownOptions>> optionsList,
|
||||
HttpServletResponse response) throws IOException {
|
||||
resetResponse("file", response);
|
||||
ExcelWriter excelWriter = null;
|
||||
ServletOutputStream os = response.getOutputStream();
|
||||
|
||||
try {
|
||||
// 使用SXSSFWorkbook避免内存问题,并减少XML处理复杂度
|
||||
excelWriter = EasyExcel.write(os)
|
||||
.head(clazz)
|
||||
.registerWriteHandler(new LockColumnHandler(lockColumns)) // 锁定第3列
|
||||
// .registerWriteHandler(new SheetProtectHandler("dawdawdwad")) // 保护整张 sheet
|
||||
.autoCloseStream(false)
|
||||
.registerConverter(new ExcelBigNumberConvert())
|
||||
// 自动适配
|
||||
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
|
||||
.registerWriteHandler(new DataWriteHandler(clazz))
|
||||
.build();
|
||||
|
||||
|
||||
// 为每个sheet写入数据
|
||||
for (int i = 0; i < sheetData.size(); i++) {
|
||||
// 创建基本sheet配置
|
||||
WriteSheet writeSheet = EasyExcel.writerSheet(i, sheetNames.get(i))
|
||||
.head(clazz)
|
||||
.build();
|
||||
|
||||
// 添加下拉选项(如果存在)
|
||||
if (optionsList != null && optionsList.size() > i && optionsList.get(i) != null) {
|
||||
ExcelDownHandler handler = new ExcelDownHandler(optionsList.get(i));
|
||||
writeSheet.setCustomWriteHandlerList(
|
||||
Collections.singletonList(handler));
|
||||
}
|
||||
|
||||
// 写入数据
|
||||
excelWriter.write(sheetData.get(i), writeSheet);
|
||||
}
|
||||
|
||||
} finally {
|
||||
// 确保资源正确释放
|
||||
if (excelWriter != null) {
|
||||
try {
|
||||
excelWriter.finish();
|
||||
} catch (Exception e) {
|
||||
// 记录日志但不中断主流程
|
||||
log.error("Excel 导出错误", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 单表多数据模板导出 模板格式为 {.属性}
|
||||
|
||||
Reference in New Issue
Block a user