欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

快速学习阿里巴巴EasyExcel

程序员文章站 2022-06-13 19:10:14
...

1.Excel导入导出的应用场景

  1. 数据导入:减轻录入的工作量
  2. 数据导出:统计信息归档
  3. 数据传输:异构系统之间数据传输

2.EasyExcel简介

2.1.EasyExcel特点

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

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

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

2.2.2 代码演示

2.2.3开发环境IDEA+SringBoot
2.2.4.Maven依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.6</version>
        </dependency>
        <!--xls-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.0-alpha1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>

</project>

2.2.5.实体entity
@Data
@ContentRowHeight(20)
@HeadRowHeight(20)
@ColumnWidth(15)
public class DemoData {
    /**
    * 设置excel表头名称
    */
    @ExcelProperty(value = "学生编号",index = 0)
    private Integer sno;

    @ExcelProperty(value = "学生姓名",index = 1)
    private String sname;

    @DateTimeFormat("yyyy-MM-dd")
    @ExcelProperty(value = "日期",index = 2 )
    private Date loanBeginDate;
}
2.2.6.service类
public interface DemoService {
    //导入
    boolean save(List<DemoData> list);
    //导出
    List<DemoData> data(String typeIndex);
}
@Service
public class DemoServiceImpl implements DemoService{
    @Override
    public boolean save(List<DemoData> list) {
        return false;
    }

    @Override
    public List<DemoData> data(String typeIndex) {
        List<DemoData> list = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            DemoData data = new DemoData();
            data.setSno(i);
            data.setSname("宝宝"+i);
            data.setLoanBeginDate(new Date());
            list.add(data);

        }
        return list;
    }
}
2.2.7.controller类
@RestController
@RequestMapping("test/")
public class EasyExcelRead {

    @Resource
    private DemoService demoService;

    /*
     * 导入
     */
    @PostMapping("/upload")
    public String upload(MultipartFile file) throws IOException {
        EasyExcel.read(file.getInputStream(), DemoData.class, new DemoDataListener(demoService)).sheet().doRead();
        return "success";
    }
    /*
     * 导出
     */
    @GetMapping("download")
    public void download(HttpServletResponse response, String typeIndex) throws IOException {
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里需要设置不关闭流
            String fileName = URLEncoder.encode("导出模板", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), DemoData.class).autoCloseStream(Boolean.FALSE).sheet("模板").doWrite(demoService.data(typeIndex));
        } catch (Exception e) {
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, String> map = new HashMap<String, String>();
            map.put("status", "failure");
            map.put("message", "下载文件失败" + e.getMessage());
            response.getWriter().println(JSON.toJSONString(map));
        }
    }
}
2.2.8.listener监听类
public class DemoDataListener extends AnalysisEventListener<DemoData> {
    private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
    /**
     * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 3000;
    List<DemoData> list = new ArrayList<DemoData>();
    /**
     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private DemoService demoService;
    public DemoDataListener(DemoService demoService) {
        this.demoService = demoService;
    }

    @Override
    public void invoke(DemoData data, AnalysisContext context) {
        LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
        list.add(data);
        if (list.size() >= BATCH_COUNT) {
            saveData();
            list.clear();
        }
    }
    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
        LOGGER.info("所有数据解析完成!");
    }
    /**
     * 加上存储数据库
     */
    private void saveData() {
        LOGGER.info("{}条数据,开始存储数据库!", list.size());
        //demoService.save(list);
        list.stream().forEach(demoData -> System.out.println(demoData.getSname()));

        LOGGER.info("存储数据库成功!");
    }

}

easyexcel 读excel 的时候可以用 AnalysisEventListener 监听器 invoke() 对读文件的数据监听处理,每处理一行会调用invoke方法

2.3.启动项目,访问导入接口 127.0.0.1:8080/test/upload

表格数据

快速学习阿里巴巴EasyExcel

访问接口

快速学习阿里巴巴EasyExcel

后台打印

快速学习阿里巴巴EasyExcel

2.4 导出数据

本应该从DB拿数据在此省略步骤直接从代码中生成数据

public List<DemoData> data(String typeIndex) {
        List<DemoData> list = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            DemoData data = new DemoData();
            data.setSno(i);
            data.setSname("张三"+i);
            data.setLoanBeginDate(new Date());
            list.add(data);

        }
        return list;
    }

访问接口 直接使用浏览器访问127.0.0.1:8080/test/download

快速学习阿里巴巴EasyExcel

至此使用Excel的导入导出简单地使用完成,如需更深入地了解请访问官方文档