当前位置:网站首页>EasyExcel读取写入简单使用
EasyExcel读取写入简单使用
2022-07-07 07:53:00 【wnfee】
官方文档 https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read
一. 读取
1.1 定义实体类
@Data
public class EmailImportParam implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "数据添加方式 1 系统自动通过邮箱域名查找备案的公司名称 2 手动输入")
@NotNull
@ExcelProperty(index = 0)
private Integer dataType;
@ApiModelProperty(value = "备用公司名称")
@ExcelProperty(index = 1)
private String inputCompanyName;
@ApiModelProperty(value = "邮箱地址")
@NotBlank
@ExcelProperty(index = 2)
private String email;
}
- 如果不使用标题
@ExcelProperty(index = 0),标题从0开启- 如果使用标题
@ExcelProperty("数据添加方式")
1.2 不检查数据批量导入
接口实现
@Override
@SneakyThrows
public Boolean importExcel(MultipartFile file) {
EasyExcel.read(file.getInputStream(), EmailImportParam.class, new EmailDataListener(this)).sheet().doRead();
return true;
}
添加EmailDataListener
package com.tophant.pentestinfoinv.listener;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.tophant.pentestinfoinv.common.domain.query.EmailAddParam;
import com.tophant.pentestinfoinv.common.domain.query.EmailImportParam;
import com.tophant.pentestinfoinv.service.IEmailService;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @Description email excel导入监听类
* @Author WanFei
* @Date 2022/7/4 16:43
**/
@Slf4j
public class EmailDataListener implements ReadListener<EmailImportParam> {
/**
* 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 100;
private List<EmailImportParam> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
/**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
*/
private IEmailService emailService;
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*
* @param emailService
*/
public EmailDataListener(IEmailService emailService) {
this.emailService = emailService;
}
/**
* 这个每一条数据解析都会来调用
*
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(EmailImportParam data, AnalysisContext context) {
log.info("解析到一条数据:{}", JSONUtil.toJsonStr(data));
cachedDataList.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (cachedDataList.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
log.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
log.info("{}条数据,开始存储数据库!", cachedDataList.size());
List<EmailAddParam> emailAddParams = cachedDataList.stream().map(emailImportParam -> new EmailAddParam()
.setEmails(Set.of(emailImportParam.getEmail()))
.setDataType(emailImportParam.getDataType())
.setInputCompanyName(emailImportParam.getInputCompanyName()))
.collect(Collectors.toList());
emailAddParams.forEach(emailService::create);
log.info("存储数据库成功!");
}
}
1.3 检查数据一次性导入
@Override
@SneakyThrows
public Boolean importExcel(MultipartFile file) {
File newFile = MultipartFileUtil.multipartFileToFile(file);
Assert.isFalse(ObjectUtil.isNull(file) || ObjectUtil.isNull(newFile), "文件不能为空!");
// 获取文件类型
String fileType = FileUtil.getType(newFile);
log.info("上传文件的扩展名: {}", fileType);
Assert.notNull(fileType, "上传文件拓展名为空!");
Assert.isTrue(StrUtil.containsAnyIgnoreCase(fileType, "xls", "xlsx"), StrUtil.format("不允许上传文件类型: {}", fileType));
List<EmailImportParam> emailList = new ArrayList<>();
EasyExcel.read(file.getInputStream()).head(EmailImportParam.class)
.sheet()
.registerReadListener(new AnalysisEventListener<EmailImportParam>() {
@Override
public void invoke(EmailImportParam data, AnalysisContext context) {
emailList.add(data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
log.info("数据读取完毕");
}
}).doRead();
Set<String> emails = emailList.stream().map(EmailImportParam::getEmail).collect(Collectors.toSet());
InfoInvUtil.checkDomain(emails);
// 查询已存在邮箱
Set<String> repeatEmails = this.lambdaQuery()
.eq(Email::getDelFlag, false)
.in(Email::getEmail, emails)
.select(Email::getEmail)
.list()
.stream()
.map(Email::getEmail)
.collect(Collectors.toSet());
Assert.isFalse(CollUtil.isNotEmpty(repeatEmails), StrUtil.format("邮箱: {} 已存在, 请检查excel文件", CollUtil.join(repeatEmails, ", ")));
// 添加到数据库
List<EmailAddParam> emailAddParams = emailList.stream().map(emailImportParam -> new EmailAddParam()
.setEmails(Set.of(emailImportParam.getEmail()))
.setDataType(emailImportParam.getDataType())
.setInputCompanyName(emailImportParam.getInputCompanyName()))
.collect(Collectors.toList());
emailAddParams.forEach(this::create);
return true;
}
MultipartFileUtil工具类
package com.tophant.pentestinfoinv.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Objects;
/**
* File转换工具
*
* @author [email protected]
* @date 06-21-0021-2021
*/
@Slf4j
public class MultipartFileUtil {
/**
* MultipartFile转换为File
*
* @param file multipartFile
* @return File
* @throws Exception
*/
public static File multipartFileToFile(MultipartFile file) {
try {
File toFile = null;
if (file.equals("") || file.getSize() <= 0) {
file = null;
} else {
InputStream ins = null;
ins = file.getInputStream();
toFile = new File(Objects.requireNonNull(file.getOriginalFilename()));
inputStreamToFile(ins, toFile);
ins.close();
}
return toFile;
} catch (Exception e) {
log.warn("MultipartFile转化为File失败!");
return null;
}
}
/**
* 获取流文件
* @param ins
* @param file
*/
private static void inputStreamToFile(InputStream ins, File file) {
try {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
二. 写入
2.1 写入
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
EasyExcel.write(byteArrayOutputStream, EmailExcelVO.class)
// 注册自定义拦截器
.registerWriteHandler(new CustomCellWriteConfig())
.registerWriteHandler(new CustomColumnWidthConfig())
.registerWriteHandler(new CustomRowHeightConfig())
.sheet("邮箱")
.doWrite(excelVOList);
2.2 自定义拦截器
2.2.1 设置样式
package com.tophant.component.starter.excel.common.config;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.*;
import java.util.List;
/**
* @Description 设置样式
* @Author WanFei
* @Date 2022/5/13 12:13
*/
public class CustomCellWriteConfig implements CellWriteHandler {
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
CellStyle cellStyle = workbook.createCellStyle();
// 居中
cellStyle.setAlignment(HorizontalAlignment.LEFT);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
// 设置边框
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
// 自动换行
cellStyle.setWrapText(true);
// 配置生效
cell.setCellStyle(cellStyle);
}
}
2.2.2 自适应宽度
package com.tophant.component.starter.excel.common.config;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.CellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.util.CollectionUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Description 自适应宽度
* @Author WanFei
* @Date 2022/5/13 13:59
*/
public class CustomColumnWidthConfig extends AbstractColumnWidthStyleStrategy {
private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<>();
@Override
protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {
boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
if (needSetWidth) {
Map<Integer, Integer> maxColumnWidthMap = CACHE.computeIfAbsent(writeSheetHolder.getSheetNo(), k -> new HashMap<>());
Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
if (columnWidth >= 0) {
if (columnWidth > 254) {
columnWidth = 254;
}
Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
Sheet sheet = writeSheetHolder.getSheet();
sheet.setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
}
}
}
}
/**
* 计算长度
* @param cellDataList
* @param cell
* @param isHead
* @return
*/
private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {
if (isHead) {
return cell.getStringCellValue().getBytes().length;
} else {
CellData<?> cellData = cellDataList.get(0);
CellDataTypeEnum type = cellData.getType();
if (type == null) {
return -1;
} else {
switch (type) {
case STRING:
// 换行符(数据需要提前解析好)
int index = cellData.getStringValue().indexOf("\n");
return index != -1 ?
cellData.getStringValue().substring(0, index).getBytes().length + 1 : cellData.getStringValue().getBytes().length + 1;
case BOOLEAN:
return cellData.getBooleanValue().toString().getBytes().length;
case NUMBER:
return cellData.getNumberValue().toString().getBytes().length;
default:
return -1;
}
}
}
}
}
2.2.3 自适应行高
package com.tophant.component.starter.excel.common.config;
import com.alibaba.excel.write.style.row.AbstractRowHeightStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import java.util.Iterator;
/**
* @Description 自适应行高
* @Author WanFei
* @Date 2022/5/13 14:03
*/
public class CustomRowHeightConfig extends AbstractRowHeightStyleStrategy {
/**
* 默认高度
*/
private static final Integer DEFAULT_HEIGHT = 300;
@Override
protected void setHeadColumnHeight(Row row, int relativeRowIndex) {
}
@Override
protected void setContentColumnHeight(Row row, int relativeRowIndex) {
Iterator<Cell> cellIterator = row.cellIterator();
if (!cellIterator.hasNext()) {
return;
}
// 默认为 1行高度
Integer maxHeight = 1;
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
switch (cell.getCellType()) {
case STRING:
if (cell.getStringCellValue().contains("\n")) {
int length = cell.getStringCellValue().split("\n").length;
maxHeight = Math.max(maxHeight, length);
}
break;
default:
break;
}
}
row.setHeight((short) (maxHeight * DEFAULT_HEIGHT));
}
}
边栏推荐
- Appx代碼簽名指南
- [original] what is the core of programmer team management?
- Use of JSON extractor originals in JMeter
- Enterprise practice | construction of banking operation and maintenance index system under complex business relations
- China's first electronic audio category "Yamano electronic audio" digital collection is on sale!
- Differences between MCU and MPU
- SQLyog数据库怎么取消自动保存更改
- Es classes and objects, prototypes
- fiddler-AutoResponder
- Applet sliding, clicking and switching simple UI
猜你喜欢

SolidWorks工程图中添加中心线和中心符号线的办法

Bean operation domain and life cycle

ORM model -- creation and query of data records

Leetcode exercise - 113 Path sum II

Arcgis操作: 批量修改属性表

AI moves from perception to intelligent cognition

能源路由器入门必读:面向能源互联网的架构和功能

喜马拉雅网页版每次暂停后弹窗推荐下载客户端解决办法

Word自动生成目录的方法

柏拉图和他的三个弟子的故事:如何寻找幸福?如何寻找理想伴侣?
随机推荐
【acwing】786. 第k个数
ES类和对象、原型
Word自动生成目录的方法
Introduction to uboot
Basic chapter: take you through notes
IPv4套接字地址结构
arcgis操作:dwg数据转为shp数据
Download Text, pictures and ab packages used by unitywebrequest Foundation
Appx代碼簽名指南
Garbage disposal method based on the separation of smart city and storage and living digital home mode
ISP、IAP、ICP、JTAG、SWD的编程特点
Google Colab装载Google Drive(Google Colab中使用Google Drive)
Win10 installation vs2015
MCU is the most popular science (ten thousand words summary, worth collecting)
Interface test
ORM -- database addition, deletion, modification and query operation logic
ES6中的函数进阶学习
The physical meaning of imaginary number J
LLVM之父Chris Lattner:為什麼我們要重建AI基礎設施軟件
The landing practice of ByteDance kitex in SEMA e-commerce scene