EasyExcel的基本使用及在项目中的应用

Posted 活跃的咸鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EasyExcel的基本使用及在项目中的应用相关的知识,希望对你有一定的参考价值。

这里只是对EasyExcel的基本使用介绍,如果有需要可以根据自己的业务要求去官网查看更多的使用方法

官方网站(访问速度较慢):

https://github.com/alibaba/easyexcel

快速开始(访问速度快文档清晰):

https://www.yuque.com/easyexcel/doc/easyexcel

一、Excel导入导出

Excel导入导出的重要性

在针对运营商(移动、联通、电信、铁塔)的信息类的系统中,由于相关的从业人员习惯于Excel的办公思维。导致在做该类系统中时,Excel的导入导出功能,几乎成了每个有列表展示的页面上必备功能。因此,有必要对Excel导入导出功能进行了解。

Excel导入导出的应用场景

1、数据导入:减轻录入工作量

2、数据导出:统计信息归档

3、数据传输:异构系统之间数据传输

二、EasyExce的介绍

EasyExcel出现的背景

Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。
但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。

EasyExcel的介绍

EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。

EasyExcel的工作模式

EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)。

三、EasyExce的简单写

1、创建一个普通的maven项目名为:alibaba-easyexcel

2、pom中引入xml相关依赖

<dependencies>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>easyexcel</artifactId>
        <version>2.1.7</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.5</version>
    </dependency>

    <dependency>
        <groupId>org.apache.xmlbeans</groupId>
        <artifactId>xmlbeans</artifactId>
        <version>3.1.0</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>

</dependencies>

3、创建实体类

@Data
public class ExcelStudentDto {
    //指定列名
    @ExcelProperty(value = "学生姓名")
    private String name;
    @ExcelProperty(value = "学生生日")
    private Date birthday;
    @ExcelProperty(value = "学生薪水")
    private Double salary;
}

4、创建测试类

public class ExcelWriteTest {

    @Test
    public void TestSimpleWrite(){
        // 文件名 .xlsx扩展版后缀节省空间 xls老版本
        String fileName = "D:\\\\Excel\\\\simpleWrite.xlsx";
        // 这里 需要指定写用哪个class去写(就是封装的数据对象),
        // 然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03版后缀为xls 则 传入excelType参数即可
        EasyExcel.write(fileName, ExcelStudentDto.class)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet("模板")
                .doWrite(data());
        System.out.println("写入成功");
    }

    private List<ExcelStudentDto> data(){
        List<ExcelStudentDto> list = new ArrayList<>();
        //写入10条记入
        for (int i = 0; i < 11; i++) {
            ExcelStudentDto data = new ExcelStudentDto();
            data.setName("字符串"+i);
            data.setBirthday(new Date());
            data.setSalary(1001.1);
            list.add(data);
        }
        return list;
    }
}

5、测试结果

03版的excel写入

@Test
public void simpleWriteXls() {
    String fileName = "d:/excel/simpleWrite.xls";
    // 如果这里想使用03 则 传入excelType参数即可
    EasyExcel.write(fileName, ExcelStudentDTO.class)
    .excelType(ExcelTypeEnum.XLS)
    .sheet("模板").doWrite(data());
}

注意:

xls 版本的Excel最多一次可写0 …65535行
xlsx 版本的Excel最多一次可写0…1048575行

四、EasyExce的简单读

1、创建监听器

public class ExcelStudentDtoListener extends AnalysisEventListener<ExcelStudentDto> {

    //每条数据解析都会调用这个方法
    @Override
    public void invoke(ExcelStudentDto excelStudentDto, AnalysisContext analysisContext) {
        System.out.println("解析到一条记入:"+excelStudentDto);
    }

    //所有的数据解析完成了会调用
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        System.out.println("所有记入解析完成");
    }
}

2、测试

public class ExcelReadTest {
    @Test
    public void TestSimpleRead(){
        // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
        String fileName = "D:\\\\Excel\\\\simpleWrite.xlsx";
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(fileName, ExcelStudentDto.class, new ExcelStudentDtoListener()).sheet().doRead();
    }
}

3.测试结果

五、EasyExce的项目中的应用

需求分析

点击导出excel按钮 将数据字典从数据库导出到excel文件中,点击导入excel按钮 将excel文件导入到数据库中。

数据字典介绍

数据字典负责管理系统常用的分类数据或者一些固定数据,例如:省市区三级联动数据、民族数据、行业数据、学历数据等,数据字典帮助我们方便的获取和适用这些通用数据。

数据字典设计

parent_id上级id,通过id与parent_id构建上下级关系,例如:我们要获取所有学历相关的数据,那么只需查询parent_id=30000的数据

name:名称,例如:填写用户信息,我们要select标签选择民族,“汉族”就是数据字典的名称

value:值,例如:填写用户信息,我们要select标签选择民族,“1”(汉族的标识)就是数据字典的值

dict_code:编码,编码是我们自定义的,全局唯一,例如:我们要获取行业数据,我们可以通过parent_id获取,但是parent_id是不确定的,所以我们可以根据编码来获取行业数据

导出excel的实现

1、实体类

@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;

}

2、controller层

 @ApiOperation("Excel数据的导出")
    @GetMapping("/exportData")
    public void export(HttpServletResponse response){

        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("mydict", "UTF-8")
                    .replaceAll("\\\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            
            EasyExcel.write(response.getOutputStream(), DictEeVo.class)
                    .sheet("数据字典")
                    .doWrite(dictService.listDictData());

        } catch (IOException e) {
            //EXPORT_DATA_ERROR(104, "数据导出失败"),
            throw  new BusinessException(ResultCodeEnum.EXPORT_DATA_ERROR, e);
        }
    }

3、service层

@Override
    public List<DictEeVo> listDictData() {
        List<Dict> dicts = baseMapper.selectList(null);
        //创建ExcelDictDTO列表 将dict转换为ExcelDictDTO列表
        ArrayList<DictEeVo> list=new ArrayList<>(dicts.size());
        dicts.forEach(dict->{
            DictEeVo excelDictDTO = new DictEeVo();
            BeanUtils.copyProperties(dict,excelDictDTO);
            list.add(excelDictDTO);
        });
        return list;
    }

4、测试:数据成功导出

导入excel的实现

controller层

 @ApiOperation("excel数据的批量导入")
    @PostMapping("/importData")
    public Result batchImport(
            @ApiParam(value = "excel数据字典文件",required = true)
            @RequestParam("file") MultipartFile file){
        InputStream is = null;
        try {
            is = file.getInputStream();
            dictService.ImportData(is);

            return Result.ok().message("数据字典批量导入成功");
        } catch (Exception e) {
            throw new BusinessException( ResultCodeEnum.UPLOAD_ERROR,e);
        }

    }

mapper层

public interface DictMapper extends BaseMapper<Dict> {
    void insertBatch(List<DictEeVo> list);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yygh.dict.mapper.DictMapper">
    <insert id="insertBatch">
        insert into dict (
        id ,
        parent_id ,
        name ,
        value ,
        dict_code
        ) values
        <foreach collection="list" item="item" index="index" separator=",">
            (
            #{item.id} ,
            #{item.parentId} ,
            #{item.name} ,
            #{item.value} ,
            #{item.dictCode}
            )
        </foreach>
    </insert>
</mapper>

service层

 @Override
    public void ImportData(InputStream is) {
        EasyExcel.read(is, DictEeVo.class,new DictEeVoDTOListener(baseMapper)).sheet().doRead();
        log.info("excel导入成功");
    }

监听器

@Slf4j
public class DictEeVoDTOListener extends AnalysisEventListener<DictEeVo> {
    private DictMapper dictMapper;

    public DictEeVoDTOListener(DictMapper dictMapper) {
        this.dictMapper = dictMapper;
    }

    public DictEeVoDTOListener() {
    }


    //数据列表用于批量存入数据库
    List<DictEeVo> list=new ArrayList();
    //每100条数据批量存储一次
    public static final int BATCH_COUNT=100;
    @Override
    public void invoke(DictEeVo data, AnalysisContext analysisContext) {
      log.info("解析到一条数据:{}",data);
      list.add(data);
        if (list.size()>=BATCH_COUNT) {
            saveData();
            list.clear();
        }


    }

    private void saveData() {
        log.info("{}条被存储到数据库....",list.size());
        //调用mapper层的save方法把list对象批量插入到数据库
        dictMapper.insertBatch(list);
        log.info("{}条被存储到数据库成功....",list.size());
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

        //将不足BATCH_COUNT的数据时最终一次性存储到数据库
        saveData();
         log.info("解析完成");
    }
}


导入成功

页面展示

以上是关于EasyExcel的基本使用及在项目中的应用的主要内容,如果未能解决你的问题,请参考以下文章

SQLite数据库及在Android开发中的基本使用

Maven常用命令及在Eclipse中的应用

QT项目增加图片Resource文件夹及在项目代码中的使用

Vue 自定义一个插件的用法小案例及在项目中的应用

Solr的原理及在项目中的使用实例

Swagger简介及在SpringBoot项目中的使用