Files
ks/ruoyi-bussiness/src/main/java/com/ruoyi/cms/util/EasyExcelUtils.java

198 lines
7.8 KiB
Java
Raw Normal View History

package com.ruoyi.cms.util;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
/**
* EasyExcel 工具类基于 alibaba easyexcel 3.x+
*/
public class EasyExcelUtils {
/**
* 读取 Excel 文件一次性读取所有数据
*
* @param file 上传的 Excel 文件
* @param head 实体类字节码需使用 @ExcelProperty 注解映射表头
* @param <T> 实体类泛型
* @return 解析后的数据集
*/
public static <T> List<T> readExcel(File file, Class<T> head) {
return EasyExcel.read(file)
.head(head)
.sheet()
.doReadSync();
}
/**
* 读取 Excel 输入流一次性读取所有数据
*
* @param inputStream Excel 输入流 MultipartFile getInputStream()
* @param head 实体类字节码
* @param <T> 实体类泛型
* @return 解析后的数据集
*/
public static <T> List<T> readExcel(InputStream inputStream, Class<T> head) {
return EasyExcel.read(inputStream)
.head(head)
.sheet()
.doReadSync();
}
/**
* 分批读取 Excel适用于大数据量避免内存溢出
*
* @param inputStream Excel 输入流
* @param head 实体类字节码
* @param batchSize 每批处理的数据量
* @param consumer 数据处理函数如批量保存到数据库
* @param <T> 实体类泛型
*/
public static <T> void readExcelByBatch(InputStream inputStream, Class<T> head, int batchSize, Consumer<List<T>> consumer) {
EasyExcel.read(inputStream)
.head(head)
.sheet()
.registerReadListener(new AnalysisEventListener<T>() {
private List<T> batchList; // 临时存储批数据
@Override
public void invoke(T data, AnalysisContext context) {
if (batchList == null) {
batchList = new java.util.ArrayList<>(batchSize);
}
batchList.add(data);
// 达到批处理量时执行消费逻辑
if (batchList.size() >= batchSize) {
consumer.accept(batchList);
batchList.clear(); // 清空集合,释放内存
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 处理剩余不足一批的数据
if (batchList != null && !batchList.isEmpty()) {
consumer.accept(batchList);
}
}
})
.doRead();
}
/**
* 生成 Excel 并写入到输出流通用样式
*
* @param outputStream 输出流 HttpServletResponse getOutputStream()
* @param data 数据集
* @param head 实体类字节码
* @param sheetName 工作表名称
* @param <T> 实体类泛型
*/
public static <T> void writeExcel(OutputStream outputStream, List<T> data, Class<T> head, String sheetName) {
// 构建通用样式策略(表头居中加粗,内容居中)
HorizontalCellStyleStrategy styleStrategy = getDefaultStyleStrategy();
ExcelWriterSheetBuilder writerBuilder = EasyExcel.write(outputStream, head)
.sheet(sheetName)
.registerWriteHandler(styleStrategy);
writerBuilder.doWrite(data);
}
/**
* 生成 Excel 并通过 HttpServletResponse 下载前端直接触发下载
*
* @param response HttpServletResponse
* @param data 数据集
* @param head 实体类字节码
* @param sheetName 工作表名称
* @param fileName 下载的文件名不带后缀
* @param <T> 实体类泛型
* @throws IOException IO异常
*/
public static <T> void downloadExcel(HttpServletResponse response, List<T> data, Class<T> head,
String sheetName, String fileName) throws IOException {
// 设置响应头,触发前端下载
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("UTF-8");
// 文件名编码,避免中文乱码
String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=UTF-8''" + encodedFileName + ".xlsx");
// 写入数据到响应流
writeExcel(response.getOutputStream(), data, head, sheetName);
}
/**
* 填充 Excel 模板适用于带固定格式的模板文件
*
* @param templateInputStream 模板文件输入流
* @param outputStream 输出流如响应流或文件流
* @param dataMap 填充数据key为模板中的占位符value为填充值
* @param sheetName 工作表名称
*/
public static void fillTemplate(InputStream templateInputStream, OutputStream outputStream,
Map<String, Object> dataMap, String sheetName) {
EasyExcel.write(outputStream)
.withTemplate(templateInputStream)
.sheet(sheetName)
.doFill(dataMap);
}
/**
* 获取默认单元格样式策略表头加粗居中内容居中
*/
private static HorizontalCellStyleStrategy getDefaultStyleStrategy() {
// 表头样式
WriteCellStyle headStyle = new WriteCellStyle();
WriteFont headFont = new WriteFont();
headFont.setBold(true); // 加粗
headFont.setFontHeightInPoints((short) 11);
headStyle.setWriteFont(headFont);
headStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); // 水平居中
headStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
// 内容样式
WriteCellStyle contentStyle = new WriteCellStyle();
WriteFont contentFont = new WriteFont();
contentFont.setFontHeightInPoints((short) 11);
contentStyle.setWriteFont(contentFont);
contentStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
contentStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 返回样式策略
return new HorizontalCellStyleStrategy(headStyle, contentStyle);
}
/**
* 关闭流工具类内部使用
*/
private static void closeStream(Closeable... closeables) {
if (closeables != null) {
for (Closeable closeable : closeables) {
if (Objects.nonNull(closeable)) {
try {
closeable.close();
} catch (IOException e) {
// 日志记录(建议替换为实际项目的日志框架)
e.printStackTrace();
}
}
}
}
}
}