EasyPoi
EasyExcel
以上两种大家都可以根据业务情况自行选择使用,在使用之前请详细阅读文档,熟悉之后再看本章节的使用说明
注意:同一工程里面只能选择使用一种,避免冲突。
使用easyPoi无需额外引入maven包
什么场景该用那个方法
导出
1.正规excel导出 (格式简单,数据量可以,5W以内吧)
注解方式: ExcelExportUtil.exportExcel(ExportParams entity, Class pojoClass,Collection dataSet)
2.不定多少列,但是格式依然简单数据库不大
自定义方式: ExcelExportUtil.exportExcel(ExportParams entity, List entityList,Collection> dataSet) 3.数据量大超过5W,还在100W以内 注解方式 ExcelExportUtil.exportBigExcel(ExportParams entity, Class> pojoClass,IExcelExportServer server, Object queryParams)
自定义方式: ExcelExportUtil.exportBigExcel(ExportParams entity, List excelParams,IExcelExportServer server, Object queryParams)
4.样式复杂,数据量尽量别大
模板导出 ExcelExportUtil.exportExcel(TemplateExportParams params, Map
5.一次导出多个风格不一致的sheet
模板导出 ExcelExportUtil.exportExcel(Map
6.一个模板但是要导出非常多份
模板导出 ExcelExportUtil.exportExcelClone(Map
7.模板无法满足你的自定义,试试html
自己构造html,然后我给你转成excel ExcelXorHtmlUtil.htmlToExcel(String html, ExcelType type)
8.数据量过百万级了.放弃excel吧,csv导出
注解方式: CsvExportUtil.exportCsv(CsvExportParams params, Class> pojoClass, OutputStream outputStream)
自定义方式: CsvExportUtil.exportCsv(CsvExportParams params, List entityList, OutputStream outputStream)
9.word导出
模板导出: WordExportUtil.exportWord07(String url, Map
导入
如果想提高性能 ImportParams 的concurrentTask 可以帮助并发导入,仅单行,最小1000
excel有单个的那种特殊读取,readSingleCell 参数可以支持
1. 不需要检验,数据量不大(5W以内)
注解或者MAP: ExcelImportUtil.importExcel(File file, Class> pojoClass, ImportParams params)
2. 需要导入,数据量不大
注解或者MAP: ExcelImportUtil.importExcelMore(InputStream inputstream, Class> pojoClass, ImportParams params)
3. 数据量大了,或者你有特别多的导入操作,内存比较少,仅支持单行
SAX方式 ExcelImportUtil.importExcelBySax(InputStream inputstream, Class> pojoClass, ImportParams params, IReadHandler handler)
4. 数据量超过EXCEL限制,CSV读取
小数据量: CsvImportUtil.importCsv(InputStream inputstream, Class> pojoClass,CsvImportParams params)
大数据量: CsvImportUtil.importCsv(InputStream inputstream, Class> pojoClass,CsvImportParams params, IReadHandler readHandler)
如何使用
@Data
public class UserEntity implements Serializable {
@Excel(name = "用户账号", height = 20, width = 30, isImportField = "true_st")
private String userId;
@Excel(name = "用户名称", height = 20, width = 30, isImportField = "true_st")
private String username;
@Excel(name = "学生性别", replace = { "男_1", "女_2" }, suffix = "生", isImportField = "true_st")
private String sex;
@Excel(name = "入校时间", format = "yyyy-MM-dd", isImportField = "true_st", width = 20)
private Date createTime;
}
/**
* 导出用户信息
* @throws IOException
*/
@Override
public void userInfoExport() {
// 数据库查询数据记录
List<UserEntity> users = userMapper.userInfoExport();
// 导出excel,传入参数 title,sheetName
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("计算机一班学生","学生"),
UserEntity.class, users);
// excel文件路径, 建议使用Java临时目录 System.getProperty("java.io.tmpdir")
FileOutputStream fos = null;
try {
fos = new FileOutputStream("D:/home/excel/testStudentList.xls");
workbook.write(fos);
fos.close();
} catch (FileNotFoundException e) {
throw new YErrorException("导出用户信息时找不到文件!");
} catch (IOException e) {
throw new YErrorException("导出用户信息发生io错误!");
} catch (Exception e) {
throw new YErrorException("导出用户信息时出错!");
}
}
/**
* 导入用户信息
* @throws IOException
*/
@Override
public void userInfoImport() {
try {
ImportParams params = new ImportParams();
params.setHeadRows(2);
// excel文件路径, 建议使用Java临时目录 System.getProperty("java.io.tmpdir")
List<UserEntity> list = ExcelImportUtil.importExcel(
new File("D:/home/excel/testStudentList.xls"), UserEntity.class, params);
//将导入的数据存入数据库......
//打印出来看看
if (CollectionUtils.isEmpty(list)) {
return;
}
list.forEach(in-> System.out.println(in));
} catch (Exception e) {
throw new YErrorException("导入用户信息时出错!");
}
}
使用easyExcel需要引入如下依赖包
基础依赖
<dependency>
<groupId>com.ly.msspgroupId>
<artifactId>ly-ac-core-excelartifactId>
<version>${cloud.core.version}version>
dependency>
Excel准备
@Data
@ColumnWidth(25)
@HeadRowHeight(20)
@ContentRowHeight(18)
public class NoticeExcel {
@ColumnWidth(15)
@ExcelProperty("标题")
private String title;
@ExcelIgnore
@ColumnWidth(10)
@ExcelProperty("类型")
private Integer category;
@ColumnWidth(20)
@ExcelProperty("类型名称")
private String categoryName;
@ColumnWidth(10)
@ExcelProperty("发布日期")
private Date releaseTime;
@ColumnWidth(30)
@ExcelProperty("内容")
private String content;
}
package com.ly.cloud.core.excel.util;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.DateUtils;
import com.ly.cloud.core.excel.listener.DataListener;
import com.ly.cloud.core.excel.listener.ImportListener;
import com.ly.cloud.core.excel.support.ExcelException;
import com.ly.cloud.core.excel.support.ExcelImporter;
import lombok.SneakyThrows;
import org.apache.commons.codec.Charsets;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
/**
* Excel工具类
*
* @author zhumin
* @apiNote https://www.yuque.com/easyexcel/doc/easyexcel
*/
public class ExcelUtil {
/**
* 读取excel的所有sheet数据
*
* @param excel excel文件
* @return List
public static <T> List<T> read(MultipartFile excel, Class<T> clazz) {
DataListener<T> dataListener = new DataListener<>();
ExcelReaderBuilder builder = getReaderBuilder(excel, dataListener, clazz);
if (builder == null) {
return null;
}
builder.doReadAll();
return dataListener.getDataList();
}
/**
* 读取excel的指定sheet数据
*
* @param excel excel文件
* @param sheetNo sheet序号(从0开始)
* @return List
public static <T> List<T> read(MultipartFile excel, int sheetNo, Class<T> clazz) {
return read(excel, sheetNo, 1, clazz);
}
/**
* 读取excel的指定sheet数据
*
* @param excel excel文件
* @param sheetNo sheet序号(从0开始)
* @param headRowNumber 表头行数
* @return List
public static <T> List<T> read(MultipartFile excel, int sheetNo, int headRowNumber, Class<T> clazz) {
DataListener<T> dataListener = new DataListener<>();
ExcelReaderBuilder builder = getReaderBuilder(excel, dataListener, clazz);
if (builder == null) {
return null;
}
builder.sheet(sheetNo).headRowNumber(headRowNumber).doRead();
return dataListener.getDataList();
}
/**
* 读取并导入数据
*
* @param excel excel文件
* @param importer 导入逻辑类
* @param 泛型
*/
public static <T> void save(MultipartFile excel, ExcelImporter<T> importer, Class<T> clazz) {
ImportListener<T> importListener = new ImportListener<>(importer);
ExcelReaderBuilder builder = getReaderBuilder(excel, importListener, clazz);
if (builder != null) {
builder.doReadAll();
}
}
/**
* 导出excel
*
* @param response 响应类
* @param dataList 数据列表
* @param clazz class类
* @param 泛型
*/
@SneakyThrows
public static <T> void export(HttpServletResponse response, List<T> dataList, Class<T> clazz) {
export(response, DateUtils.format(new Date(), DateUtils.DATE_FORMAT_14), "导出数据", dataList, clazz);
}
/**
* 导出excel
*
* @param response 响应类
* @param fileName 文件名
* @param sheetName sheet名
* @param dataList 数据列表
* @param clazz class类
* @param 泛型
*/
@SneakyThrows
public static <T> void export(HttpServletResponse response, String fileName, String sheetName, List<T> dataList, Class<T> clazz) {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding(Charsets.UTF_8.name());
fileName = URLEncoder.encode(fileName, Charsets.UTF_8.name());
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(dataList);
}
/**
* 获取构建类
*
* @param excel excel文件
* @param readListener excel监听类
* @return ExcelReaderBuilder
*/
public static <T> ExcelReaderBuilder getReaderBuilder(MultipartFile excel, ReadListener<T> readListener, Class<T> clazz) {
String filename = excel.getOriginalFilename();
if (StringUtils.isEmpty(filename)) {
throw new ExcelException("请上传文件!");
}
if ((!StringUtils.endsWithIgnoreCase(filename, ".xls") && !StringUtils.endsWithIgnoreCase(filename, ".xlsx"))) {
throw new ExcelException("请上传正确的excel文件!");
}
InputStream inputStream;
try {
inputStream = new BufferedInputStream(excel.getInputStream());
return EasyExcel.read(inputStream, clazz, readListener);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Excel导出
一、初次尝试
@GetMapping("export-notice")
public void exportNotice(HttpServletResponse response) {
List<NoticeExcel> list = new ArrayList<>();
ExcelUtil.export(response, "通知公告导出数据", "通知公告数据表", list, NoticeExcel.class);
}
二、数据导出
@GetMapping("export-notice")
public void exportNotice(HttpServletResponse response) {
List<NoticeExcel> list = new ArrayList<>();
NoticeExcel ne1 = new NoticeExcel();
ne1.setTitle("标题1");
ne1.setCategoryName("发布通知");
ne1.setReleaseTime(DateUtil.now());
ne1.setContent("内容1");
NoticeExcel ne2 = new NoticeExcel();
ne2.setTitle("标题2");
ne2.setCategoryName("批转通知");
ne2.setReleaseTime(DateUtil.now());
ne2.setContent("内容2");
list.add(ne1);
list.add(ne2);
ExcelUtil.export(response, "通知公告导出数据", "通知公告数据表", list, NoticeExcel.class);
}
Excel读取
一、开始尝试
@PostMapping("read-notice")
public R<List<NoticeExcel>> readNotice(MultipartFile file) {
List<NoticeExcel> list = ExcelUtil.read(file, NoticeExcel.class);
return R.data(list);
}
@PostMapping("read-notice")
public R<List<NoticeExcel>> readNotice(MultipartFile file) {
List<NoticeExcel> list = ExcelUtil.read(file, NoticeExcel.class);
list.forEach(noticeExcel -> {
String category = DictCache.getKey("notice", noticeExcel.getCategoryName());
noticeExcel.setCategory(Func.toInt(category));
});
return R.data(list);
}
二、拓展用法
@PostMapping("read-notice")
public R<List<NoticeExcel>> readNotice(MultipartFile file, Integer sheetNo) {
List<NoticeExcel> list = ExcelUtil.read(file, sheetNo, NoticeExcel.class);
list.forEach(noticeExcel -> {
String category = DictCache.getKey("notice", noticeExcel.getCategoryName());
noticeExcel.setCategory(Func.toInt(category));
});
return R.data(list);
}
@PostMapping("read-notice")
public R<List<NoticeExcel>> readNotice(MultipartFile file) {
List<NoticeExcel> list = ExcelUtil.read(file, NoticeExcel.class);
list.forEach(noticeExcel -> {
String category = DictCache.getKey("notice", noticeExcel.getCategoryName());
noticeExcel.setCategory(Func.toInt(category));
});
return R.data(list);
}
Excel导入
一、普通导入
@PostMapping("write-notice")
public R<Boolean> writeNotice(MultipartFile file) {
List<Notice> noticeList = new ArrayList<>();
List<NoticeExcel> list = ExcelUtil.read(file, NoticeExcel.class);
list.forEach(noticeExcel -> {
String category = DictCache.getKey("notice", noticeExcel.getCategoryName());
noticeExcel.setCategory(Func.toInt(category));
Notice notice = BeanUtil.copy(noticeExcel, Notice.class);
noticeList.add(notice);
});
return R.data(noticeService.saveBatch(noticeList));
}
二、进阶导入
/**
* Excel监听器
*
* @author zhumin
*/
@Data
@RequiredArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class ImportListener<T> extends AnalysisEventListener<T> {
/**
* 默认每隔3000条存储数据库
*/
private int batchCount = 3000;
/**
* 缓存的数据列表
*/
private List<T> list = new ArrayList<>();
/**
* 数据导入接口类
*/
private final ExcelImporter<T> importer;
/**
* 每一条数据解析都会调用
*
* @param data 解析到的数据
* @param analysisContext
*/
@Override
public void invoke(T data, AnalysisContext analysisContext) {
// 校验数据
boolean validator = importer.validator(data);
if (validator) {
list.add(data);
}
// 达到BATCH_COUNT,则调用importer方法入库,防止数据几万条数据在内存,容易OOM
if (list.size() >= batchCount) {
// 调用importer方法
importer.save(list);
// 存储完成清理list
list.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 调用importer方法
importer.save(list);
// 存储完成清理list
list.clear();
}
}
/**
* 读取并导入数据
*
* @param excel excel文件
* @param importer 导入逻辑类
* @param 泛型
*/
public static <T> void save(MultipartFile excel, ExcelImporter<T> importer, Class<T> clazz) {
ImportListener<T> importListener = new ImportListener<>(importer);
ExcelReaderBuilder builder = getReaderBuilder(excel, importListener, clazz);
if (builder != null) {
builder.doReadAll();
}
}
/**
* 通知数据导入类
*
* @author zhumin
*/
@RequiredArgsConstructor
public class NoticeImporter implements ExcelImporter<NoticeExcel> {
private final INoticeService service;
@Override
public boolean validator(NoticeExcel data){
return true;
}
@Override
public void save(List<NoticeExcel> data) {
data.forEach(noticeExcel -> {
String category = DictCache.getKey("notice", noticeExcel.getCategoryName());
noticeExcel.setCategory(Func.toInt(category));
Notice notice = BeanUtil.copy(noticeExcel, Notice.class);
service.save(notice);
});
}
}
@PostMapping("write-notice")
public R<Boolean> writeNotice(MultipartFile file) {
NoticeImporter importer = new NoticeImporter(noticeService);
ExcelUtil.save(file, importer, NoticeExcel.class);
return R.success("操作成功");
}
结语