EasyExcel大大减少了内存占用的原因是,它会一行一行的解析Excel中的数据,从磁盘读到内存,并不会一次性加载到内存中。
一、引入依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
二、创建实体
@Data
public class Stu {
//设置表头名称
@ExcelProperty("学生编号")
private int sno;
//设置表头名称
@ExcelProperty("学生姓名")
private String sname;
}
用来接收从数据库查出来的数据
三、实现写操作
public class WriteTest {
public static void main(String[] args) {
String fileName = "D:\\test\\220718\\a.xlsx";
EasyExcel.write(fileName,Stu.class).sheet("学员信息")
.doWrite(data());
}
//循环设置要添加的数据,最终封装到list集合中
private static List<Stu> data() {
List<Stu> list = new ArrayList<Stu>();
for (int i = 0; i < 10; i++) {
Stu data = new Stu();
data.setSno(i);
data.setSname("张三"+i);
list.add(data);
}
return list;
}
}
核心代码 就一行
EasyExcel.write(“文件名 or 输入流 or 文件”,"实体类的class").sheet("可以理解为表名").doWrite(数据集合)
四、实现读操作
1、改变实体类,实体类 注解上面要添加index属性
@Data
public class Stu {
//设置表头名称
@ExcelProperty(value = "学生编号",index = 0)
private int sno;
//设置表头名称
@ExcelProperty(value = "学生姓名",index = 1)
private String sname;
}
读的时候 index的值就是 要读的Excel表的第几列 列名
2、需要写一个监听器
通过监听器来指定怎么读 (就是指定具体的操作)
public class ExcelListener extends AnalysisEventListener<Stu> {
@Override
public void invoke(Stu stu, AnalysisContext analysisContext) {
System.out.println("stu = " + stu);
}
//读取excel表头信息
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
System.out.println("表头信息:"+headMap);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
关键继承 AnalysisEventListener<自己定义的实体类> 重写两个方法
在invoke方法中 可以将读到的一行数据 存到数据库中 在本文下面会有实例
五、读操作代码
public class ReadTest {
public static void main(String[] args) {
String fileName = "D:\\test\\220718\\a.xlsx";
EasyExcel.read(fileName,Stu.class,new ExcelListener()).sheet().doRead();
}
}
关键代码就一行
EasyExcel.read("文件名(路径) or 输入流",实体类的class,new 一个监听器).sheet().doRead();
如此 一个简单的Demo就完成了
下面将在前后端实现业务
========================================================================
一、实现文件导出功能(从数据库查出来 写到本地Excel)
1、首先导入依赖
2、确认VO对象(也就是Excel表头)
3、实现controller
(1)分析接口
*参数:reponse
*返回值:无
(2)实现方法
@ApiOperation(value = "导出")
@GetMapping(value = "/exportData")
public void exportData(HttpServletResponse response){
dictService.exportData(response);
}
实现service
4、实现service
//导出
@Override
public void exportData(HttpServletResponse response) {
try {
//1设置response基础参数
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("数据字典", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
//2查询所有字典数据
List<Dict> dictList = baseMapper.selectList(null);
//3数据对象转型 Dict集合=>DictEeVo集合
List<DictEeVo> dictEeVoList = new ArrayList<>();
for (Dict dict : dictList) {
DictEeVo dictEeVo = new DictEeVo();
//dictEeVo.setId(dict.getId());
BeanUtils.copyProperties(dict,dictEeVo);
dictEeVoList.add(dictEeVo);
}
//4调用方法生成文件
EasyExcel.write(response.getOutputStream(),DictEeVo.class)
.sheet("数据字典").doWrite(dictEeVoList);
} catch (IOException e) {
e.printStackTrace();
throw new YyghException(20001,"导出失败");
}
}
实现逻辑:
从数据库查询出所有的数据 存到一个集合中(dictList)
创建出来VO的集合 用来保存将来Excel中的数据
遍历dictList集合 将每一个对象都复制到 VO的集合中
将来把这个VO集合作为写入数据导出到Excel
核心代码
EasyExcel.write("文件目录 or 输出流",实体类的class).sheet("名字").doWrite();
4、对接前端
(2)添加页面元素
<div class="el-toolbar">
<div class="el-toolbar-body" style="justify-content: flex-start;">
<el-button type="text" @click="exportData">
<i class="fa fa-plus"/> 导出
</el-button>
</div>
</div>
(3)实现js
//导出
exportData(){
window.open(`${process.env.VUE_APP_BASE_API}admin/cmn/dict/exportData`)
}
二、实现文件导入功能
1、创建controller
(1)接口分析
*参数:文件
*返回值:R.ok()
(2)实现方法
@ApiOperation(value = "导入")
@PostMapping("importData")
public R importData(MultipartFile file){
dictService.importData(file);
return R.ok();
}
2、创建监听器
@Component
public class DictListener extends AnalysisEventListener<DictEeVo> {
@Autowired
private DictMapper dictMapper;
//手动注入,利用有参构造,new DictListener(dictMapper)
//private DictMapper dictMapper;
@Override
public void invoke(DictEeVo dictEeVo, AnalysisContext analysisContext) {
Dict dict = new Dict();
BeanUtils.copyProperties(dictEeVo,dict);
dict.setIsDeleted(0);
dictMapper.insert(dict);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
注意使用注解@component的话 就是让spring来管理我们这个监听器了,在service想要使用的话 一定要提前@Autowired自动注入,要不然用不了
复制Excel中的数据的话 使用BeanUtils.copyProperties(dictEeVo,dict);
不要忘了在设置一下is_deleted=0
3、实现service
//导入
@Override
public void importData(MultipartFile file) {
try {
InputStream inputStream = file.getInputStream();
EasyExcel.read(inputStream,DictEeVo.class,dictListener)
.sheet().doRead();
} catch (IOException e) {
e.printStackTrace();
throw new YyghException(20001,"导入失败");
}
}
核心代码
EasyExcel.read(输入流,实体类的)
4、对接前端
(1)确认入口
正在上传…重新上传取消
(2)实现方案
正在上传…重新上传取消
(3)添加页面元素
*入口
<div class="el-toolbar">
<div class="el-toolbar-body" style="justify-content: flex-start;">
<el-button type="text" @click="exportData">
<i class="fa fa-plus"/> 导出
</el-button>
<el-button type="text" @click="importData">
<i class="fa fa-plus"/> 导入
</el-button>
</div>
</div>
*对话框
<el-dialog title="导入" :visible.sync="dialogImportVisible" width="480px">
<el-form label-position="right" label-width="170px">
<el-form-item label="文件">
<el-upload
:multiple="false"
:on-success="onUploadSuccess"
:action="BASE_API"
class="upload-demo"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传xls文件,且不超过500kb</div>
</el-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogImportVisible = false">取消</el-button>
</div>
</el-dialog>
(4)实现js
data() {
return {
list: [],//表格数据
dialogImportVisible: false,//对话框是否显示
BASE_API:`${process.env.VUE_APP_BASE_API}admin/cmn/dict/importData`
};
},
methods: {
……
//打开上传对话框
importData(){
this.dialogImportVisible = true
},
//上传成功后操作
onUploadSuccess(response,file){
//1成功提示
this.$message({
type: "success",
message: "上传成功!"
});
//2关闭对话框
this.dialogImportVisible = false
//3刷新数据
this.getData(1)
}
}