赞
踩
EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。
EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>easyexcel</artifactId>
- <version>2.1.1</version>
- </dependency>
这里的ExcelProperty表示在Excle表格中第一行,表头的列名称
- @Data
- public class Stu {
- //设置表头名称
- @ExcelProperty("学生编号")
- private int sno;
- //设置表头名称
- @ExcelProperty("学生姓名")
- private String sname;
- }
- package com.atguigu.excel;
-
- import com.alibaba.excel.EasyExcel;
-
- import java.util.ArrayList;
- import java.util.List;
-
- public class TestWrite {
- public static void main(String[] args) {
- //设置文件名称和路径
- String fileName="D:\\桌面内容迁移\\测试创建excel.xlsx";
- EasyExcel.write(fileName, User.class)
- .sheet("写操作")
- .doWrite(data());
- }
- //循环设置要添加的数据,最终封装到list集合中
- private static List<User> data() {
- List<User> list = new ArrayList<User>();
- for (int i = 0; i < 10; i++) {
- User user = new User();
- user.setId(i+1);
- user.setName("张三");
- list.add(user);
- }
- return list;
- }
- }
- package com.atguigu.excel;
-
- import com.alibaba.excel.context.AnalysisContext;
- import com.alibaba.excel.event.AnalysisEventListener;
- import com.alibaba.excel.metadata.CellData;
- import com.alibaba.excel.util.ConverterUtils;
-
- import java.util.Map;
-
- public class ExcelListener extends AnalysisEventListener<User> {
- //一行一行去读取excel内容并封装到User中
- //默认从第二行读取数据,因为第一行一般都是表头
- @Override
- public void invoke(User user, AnalysisContext context) {
- System.out.println(user.toString());
- }
- //读取表头内容
- @Override
- public void invokeHead(Map<Integer, CellData> headMap, AnalysisContext context) {
- //System.out.println("表头:"+headMap);
- }
- @Override
- public void doAfterAllAnalysed(AnalysisContext context) {
-
- }
- }
- package com.atguigu.excel;
-
- import com.alibaba.excel.EasyExcel;
-
- public class TestRead {
- public static void main(String[] args) {
- String fileName="D:\\桌面内容迁移\\测试创建excel.xlsx";
- EasyExcel.read(fileName, User.class,new ExcelListener())
- .sheet()
- .doRead();
- }
- }
先写两个实体类,第一个是数据库对应的实体类(EasyExcel中要求实体类属性个数与表中表头列的名称个数一致,我们一般实体类还会自己添加一些其他属性,比如说多表联查还需要嵌入一个属性是另一个表的实体类,那么这就不符合EasyExcel的规范,所以要写一个实体类属性与表格完全一致的实体类),第二个是你业务中需要的实体类(可能添加了一些其他的属性值,一般我们开发中都是用的这个,不需要添加)
这里第一个是我重新写的实体类,第二个是原本的实体类,被我自己加了属性,大家可以进行对比
- package com.atguigu.ggkt.vo.vod;
-
- import com.alibaba.excel.annotation.ExcelProperty;
- import lombok.Data;
-
- /**
- * <p>
- * Dict
- * </p>
- *
- * @author qy
- */
- @Data
- public class SubjectEeVo {
-
- @ExcelProperty(value = "id" ,index = 0)
- private Long id;
-
- @ExcelProperty(value = "课程分类名称" ,index = 1)
- private String title;
-
- @ExcelProperty(value = "上级id" ,index = 2)
- private Long parentId;
-
- @ExcelProperty(value = "排序" ,index = 3)
- private Integer sort;
-
-
- }
-
- package com.atguigu.ggkt.model.vod;
-
- import com.atguigu.ggkt.model.base.BaseEntity;
- import com.baomidou.mybatisplus.annotation.*;
- import com.fasterxml.jackson.annotation.JsonFormat;
- import com.fasterxml.jackson.annotation.JsonIgnore;
- import io.swagger.annotations.ApiModel;
- import io.swagger.annotations.ApiModelProperty;
- import lombok.Data;
-
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Map;
-
- @Data
- @ApiModel(description = "Subject")
- @TableName("subject")
- public class Subject {
-
- private static final long serialVersionUID = 1L;
- @ApiModelProperty(value = "id")
- private Long id;
-
- @ApiModelProperty(value = "创建时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- @TableField("create_time")
- private Date createTime;
-
- @ApiModelProperty(value = "更新时间")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- @TableField("update_time")
- private Date updateTime;
-
- @ApiModelProperty(value = "逻辑删除(1:已删除,0:未删除)")
- @JsonIgnore
- @TableLogic
- @TableField("is_deleted")
- private Integer isDeleted;
-
- @ApiModelProperty(value = "其他参数")
- @TableField(exist = false)
- private Map<String,Object> param = new HashMap<>();
-
- @ApiModelProperty(value = "类别名称")
- @TableField("title")
- private String title;
-
- @ApiModelProperty(value = "父ID")
- @TableField("parent_id")
- private Long parentId;
-
- @ApiModelProperty(value = "排序字段")
- @TableField("sort")
- private Integer sort;
-
- @ApiModelProperty(value = "是否包含子节点")
- @TableField(exist = false)
- private boolean hasChildren;
-
- }
- package com.atguigu.ggkt.vod.service;
-
-
- import com.atguigu.ggkt.model.vod.Subject;
- import com.baomidou.mybatisplus.extension.service.IService;
- import org.springframework.web.multipart.MultipartFile;
-
- import javax.servlet.http.HttpServletResponse;
-
- /**
- * <p>
- * 课程科目 服务类
- * </p>
- *
- * @author atguigu
- * @since 2023-04-19
- */
- public interface SubjectService extends IService<Subject> {
-
- void exportData(HttpServletResponse response);
-
- void importDictData(MultipartFile file);
- }
- package com.atguigu.ggkt.vod.service.impl;
-
- import com.alibaba.excel.EasyExcel;
- import com.atguigu.ggkt.model.vod.Subject;
- import com.atguigu.ggkt.vo.vod.SubjectEeVo;
- import com.atguigu.ggkt.vod.listener.SubjectListener;
- import com.atguigu.ggkt.vod.mapper.SubjectMapper;
- import com.atguigu.ggkt.vod.service.SubjectService;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import org.springframework.beans.BeanUtils;
- import org.springframework.stereotype.Service;
- import org.springframework.web.multipart.MultipartFile;
-
- import javax.annotation.Resource;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
- import java.net.URLEncoder;
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- * <p>
- * 课程科目 服务实现类
- * </p>
- *
- * @author atguigu
- * @since 2023-04-19
- */
- @Service
- public class SubjectServiceImpl extends ServiceImpl<SubjectMapper, Subject> implements SubjectService {
- @Resource
- SubjectService subjectService;
- @Resource
- SubjectListener subjectListener;
- //课程分类导出功能
- @Override
- public void exportData(HttpServletResponse response) {
- try{
- //设置从数据库下载值的信息
- 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");
- List<Subject> subjects = subjectService.list();
- List<SubjectEeVo> subjectEeVos = new ArrayList<>(subjects.size());
- for(Subject dict : subjects) {
- SubjectEeVo dictVo = new SubjectEeVo();
- // dictVo.setId(dict.getId());
- // dictVo.setParentId(dict.getParentId());
- // 以上的赋值写法较为复杂,Java提供一个方法让一个对象的属性赋值给另一个对象
- BeanUtils.copyProperties(dict,dictVo);
- subjectEeVos.add(dictVo);
- }
- EasyExcel.write(response.getOutputStream(), SubjectEeVo.class)
- .sheet("课程分类")
- .doWrite(subjectEeVos);
- }catch (Exception e){
- e.printStackTrace();
- }
- }
-
- @Override
- public void importDictData(MultipartFile file) {
- try {
- EasyExcel.read(file.getInputStream(),SubjectEeVo.class,subjectListener)
- .sheet().doRead();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
没有使用swagger的记得把@ApiOperation注解删掉
- package com.atguigu.ggkt.vod.controller;
-
-
- import com.atguigu.ggkt.model.vod.Subject;
- import com.atguigu.ggkt.result.Result;
- import com.atguigu.ggkt.vod.service.SubjectService;
- import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
- import io.swagger.annotations.ApiOperation;
- import org.springframework.web.bind.annotation.*;
- import org.springframework.web.multipart.MultipartFile;
-
- import javax.annotation.Resource;
- import javax.servlet.http.HttpServletResponse;
- import java.util.List;
-
- /**
- * <p>
- * 课程科目 前端控制器
- * </p>
- *
- * @author atguigu
- * @since 2023-04-19
- */
- @RestController
- @RequestMapping("/admin/vod/subject")
- @CrossOrigin(origins = "*")
- public class SubjectController {
- @Resource
- SubjectService subjectService;
-
- @ApiOperation("课程分类导出")
- @GetMapping("/exportData")
- public void exportData(HttpServletResponse response){
- subjectService.exportData(response);
- }
- @ApiOperation(value = "导入")
- @PostMapping("importData")
- public Result importData(MultipartFile file) {
- subjectService.importDictData(file);
- return Result.ok(null);
- }
- }
-
- <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>
- exportData() {
- window.open("http://localhost:8301/admin/vod/subject/exportData")
- }
按钮
<el-button type="text" @click="importData"><i class="fa fa-plus"/> 导入</el-button>
点击对应的弹出层
- <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="'http://localhost:8333/admin/vod/subject/importData'"
- 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>
data中添加弹出层的属性
- data() {
- return {
- dialogImportVisible: false,
- list:[] //数据字典列表数组
- }
- }
添加导入方法
- importData() {
- this.dialogImportVisible = true
- },
- onUploadSuccess(response, file) {
- this.$message.info('上传成功')
- this.dialogImportVisible = false
- this.getSubList(0)
- },
这里的this.getSubList(0)只是导入数据后调用重新加载页面数据的一个方法,可以自行编写
准备好我们要导入到数据库的表格
然后打开树形菜单,可以发现表格中的数据已经被渲染上去了
对service中的sersheet方法和doWrite、doRead方法有疑问的这里解答一下,sersheet是excel表格中底端的那个名称,doRead通过监听器每次读取一行,这也是EasyExcel的优点,一次一行,读完这行再下一行不会全部读取出来,举个极端例子。比如说你内存仅剩100kb了,你表格有500kb,那是不是一下子就蹦了?那读一行完加载到内存中,再下一行就可以很好的解决了这种问题,doWrite就是写入的操作了
以上就是 EasyExcel的读写操作并且与Element-ui进行整合实现导入导出功能
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。