什么是EasyExcel?
是阿里巴巴开源的excel处理框架,以使用简单,节省内存著称,
在读取数据的时候是从磁盘一行一行的读取数据,逐个解析,而不是全部加载到内存中。
支持Excel的导入与导出,支持xls和xlsm的文件格式
EasyExcel的依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.0.5</version>
</dependency>
数据导出
导出测试
使用相关API进行数据的导出
EasyExcel.write(IO流/文件名,数据类型).sheet(文件名).doWrite(数据列表)
public class TsetWrite {
public static void main(String[] args) {
//构建一个虚拟数据list集合
List list = new ArrayList();
for(int i=0;i<10;i++)
{
UserData userData = new UserData();
userData.setUid(i);
userData.setUsername("alice"+i);
list.add(userData);
}
//设置excel文件的路径和文件名
String filename = "D:\\yygh_parent\\01.xlsx";
//调用方法实现操作
EasyExcel.write(filename, UserData.class).sheet("用户信息")
.doWrite(list);
}
}
项目实现
需要一个model模块添加导出实体
@Data
public class DictEeVo {
@ExcelProperty(value = "id" ,index = 0)
private Long id;
@ExcelProperty(value = "上级id" ,index = 1)
private Long parentId;
@ExcelProperty(value = "名称" ,index = 2)
private String name;
@ExcelProperty(value = "值" ,index = 3)
private String value;
@ExcelProperty(value = "编码" ,index = 4)
private String dictCode;
}
编写对应的service方法
//导出数据字典接口
@Override
public void exportData(HttpServletResponse response) {
//设置下载信息
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
String fileName = null;
try {
fileName = URLEncoder.encode("数据字典", "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
response.setHeader("Content-disposition",
"attachment;filename="+ fileName + ".xlsx");
//查询数据库
List<Dict> dictList = baseMapper.selectList(null);
//将Dict类型数据转换成DictEeVo类型
List<DictEeVo> dictVoList = new ArrayList<>();
for(Dict dict:dictList) {
DictEeVo dictEeVo = new DictEeVo();
// dictEeVo.setId(dict.getId());
BeanUtils.copyProperties(dict,dictEeVo);
dictVoList.add(dictEeVo);
}
//调用方法进行写操作,使用流作为对象,将文件数据通过流的形式传递给用户
try {
EasyExcel.write(response.getOutputStream(), DictEeVo.class).sheet("dict")
.doWrite(dictVoList);
} catch (IOException e) {
e.printStackTrace();
}
导入数据
创建回调监听器
导入数据要分配一个拦截器AnalysisEventListener
@Slf4j
public class DictListener extends AnalysisEventListener<DictEeVo> {
@Autowired
private DictMapper dictMapper;
//一行一行的读取,读一行,写一行
@Override
public void invoke(DictEeVo dictEeVo, AnalysisContext analysisContext) {
Dict dict = new Dict();
//转换对象类
BeanUtils.copyProperties(dictEeVo, dict);
//写入数据库
dictMapper.insert(dict);
}
//导入结束后执行
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
log.info("文件导入成功");
}
}
@Slf4j
//@AllArgsConstructor //全参
@NoArgsConstructor //无参
public class ExcelDictDTOListener extends AnalysisEventListener<ExcelDictDTO> {
/**
* 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 5;
List<ExcelDictDTO> list = new ArrayList();
private DictMapper dictMapper;
//传入mapper对象
public ExcelDictDTOListener(DictMapper dictMapper) {
this.dictMapper = dictMapper;
}
/**
*遍历每一行的记录
* @param data
* @param context
*/
@Override
public void invoke(ExcelDictDTO data, AnalysisContext context) {
log.info("解析到一条记录: {}", data);
list.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
log.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
log.info("{}条数据,开始存储数据库!", list.size());
dictMapper.insertBatch(list); //批量插入
log.info("存储数据库成功!");
}
}
使用相关API进行数据的导如
EasyExcel.read(IO流/文件名,数据类型,数据类型对应的mapper映像 ).sheet().doRead(数据列表)
//导入数据
@Override
@CacheEvict(value = "dict",allEntries = true)
public void importData(MultipartFile file) {
try {
EasyExcel.read(file.getInputStream(),DictEeVo.class,
new DictListener(dictMapper)).sheet().doRead();
} catch (IOException e) {
e.printStackTrace();
}
}