EasyExcel实现文件读取、导出、上传、下载操作

 一、EasyExcel简介

​     Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便

二、使用方法

 1.引入依赖

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

2.读取excel

(1)默认方式读取

通过EasyExcel.read()方式进行,参数依次为文件路径、要读取成指定文件的类、读取文件类的监听器,sheet中默认读取第一个sheet,也可以自己制定,读取文件时从第二行开始,可以按批次读取,也可以自定义读取

@Test
public void easyExcelRead(){
    String path = "D:\\city_district.xlsx";
    EasyExcel.read(path, TeleCity.class, new TeleCityListener(teleCityService)).sheet("city市区表").doRead();
}

监听器TeleCityListener,这里是继承了AnalysisEventListener,需要指定读取的类,因为没有被spring管理,所以这里需要new TeleCityListener(teleCityService),传入的teleCityService需要注入,方式来创建实例,通过构造器方式传入注入的dao或者service来赋值,调用相应的方法,插入数据库,也可以使用默认构造器,不会对数据库进行操作

@Slf4j
public class TeleCityListener extends AnalysisEventListener<TeleCity> {
    /**
     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private TeleCityService teleCityService;
    
    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     *
     * @param teleCityService
     */
    public TeleCityListener(TeleCityService teleCityService) {
        this.teleCityService = teleCityService;
    }

    public TeleCityListener(){}
    /**
     * 每隔100条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    List<TeleCity> list = new ArrayList<TeleCity>();
    
    /**
     * 这个每一条数据解析都会来调用
     *
     * @param teleCity
     *            one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param analysisContext
     */
    @Override
    public void invoke(TeleCity teleCity, AnalysisContext analysisContext) {
        log.info("解析到一条数据:{}", JSON.toJSONString(teleCity));
        list.add(teleCity);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (list.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            list.clear();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
        log.info("{}条数据,开始存储数据库!", list.size());
        teleCityService.insertTeleCityList(list);
        log.info("存储数据库成功!");
    }
}

(2)使用自定义的通用监听器读取文件

通过泛型和继承AnalysisEventListener来自定义通用的一个读取监听器,只读取数据,读到的数据全都封装在list里面,通过getList()即可得到返回的数据,想要处理哪种格式就传入相应的类即可

@Slf4j
public class GeneralListener<T> extends AnalysisEventListener<T> {

    private List<T> list= Lists.newArrayList();

    @Override
    public void invoke(T data, AnalysisContext context) {
        Assert.notNull(data,"导入数据不能为null");
        log.info("start read list of data :{}",JSON.toJSONString(data));
        list.add(data);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        log.info("read data complete!");
    }

    public List<T> getList() {
        return list;
    }
}

创建一个实例,读取完毕后,调用getlist()方法

@Test
public void generalExcelRead(){
    String path = "D:\\city_district.xlsx";
    //建立一个通用读取监听器,读取数据到这个里面,通过getList方式获取读取的数据
    GeneralListener<TeleCity> teleListener=new GeneralListener<>();
    //EasyExcel进行读取
    try{
        EasyExcel.read(path,TeleCity.class,teleListener).sheet("city市区表").doRead();
    }catch (Exception e){
        log.error("读取数据失败!",e);
    }
    log.info("读取到的数据大小为:{}", JSON.toJSONString(teleListener.getList().size()));
    //进行数据库插入操作
    teleCityService.insertTeleCityList(teleListener.getList());
}

3.导出文件为Excel

使用EasyExcel.write()即可,里面参数为文件路径,要转出的文件内容,和sheet名称以及要导出的数据

@Test
public void generateExcelWrite(){
    List<TeleCity> list=teleCityService.getList();
    List<TeleCityExcelDTO> exportList=JSON.parseArray(JSON.toJSONString(list),TeleCityExcelDTO.class);
    log.info("开始写入数据!");
    String path = "D:\\demo.xlsx";
    try {
        EasyExcel.write(path, TeleCityExcelDTO.class).sheet("模板").doWrite(exportList);
    }catch (Exception e){
        log.error("写入数据失败!",e);
    }
    log.error("写入数据成功!大小为{}", JSON.toJSONString(list.size()));
}

定义导出的数据文件格式:通过注释来指定哪些列不需要导出,导出列位置和名称以及相应的高度、宽度等

@Data
public class TeleCityExcelDTO implements Serializable {
    /**
     * 忽略不读取和写入
     */
    @ExcelIgnore
    private static final long serialVersionUID = 8372588291576645501L;
    /**
     * 强制读取第三个 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配
     */
    @ExcelProperty(index = 0,value = "id")
    @ColumnWidth(10)
    private Long id;

    @ExcelProperty(index = 1,value = "城市名称")
    @ColumnWidth(20)
    private String cityName;

    @ExcelProperty(index = 2,value = "组织编码")
    @ColumnWidth(20)
    private String orgCode;

    @ExcelProperty(index = 3,value = "物流编码")
    @ColumnWidth(20)
    private String logisticCode;

    @ExcelProperty(index = 4,value = "省份Id")
    @ColumnWidth(10)
    private Long provinceId;

    @ExcelProperty(index = 5,value = "创建时间")
    @ColumnWidth(20)
    private String createTime;

    @ExcelProperty(index = 6,value = "更新时间")
    @ColumnWidth(20)
    private String updateTime;
}

4.Download下载文件

类似于上面导出文件,需要自定义导出文件内容格式。实际是将导出的文件写入response中,需要指定编码格式和输出流格式等。这里特别注意是需要使用Get方式请求的,将下载的数据在当前界面作为附件方式下载,不会打开新的界面

 @GetMapping("/test17")
    public void testExportExcel(HttpServletResponse response) {
        //导出数据
        List<TeleCity> list = teleCityService.getList();
        List<TeleCityExcelDTO> exportList = JSON.parseArray(JSON.toJSONString(list), TeleCityExcelDTO.class);
        // 设置为导出件格式为excel
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String filePrefix="测试文件";
        try {
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode(filePrefix, "UTF-8").replaceAll("\\+", "%20");
            //Content-disposition 的 attachment参数将文件作为附件下载
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), TeleCityExcelDTO.class).sheet("模板").doWrite(exportList);
        } catch (Exception e) {
            log.error("下载文件失败!", e);
            throw new BizException(ResponseCode.EXPORT_FILE_FAILURE);
        }
        log.info("下载数据大小为:{}", exportList.size());
    }

5.Upload上传文件

类似于前面的读取excel文件,这里是通过前端选取文件,读入到输入流里面,然后通过监听器读取指定格式。注意接收文件的类型为:MultipartFile

@RequestMapping("/test18")
public Response testUpLoadExcel(MultipartFile file){
    log.info("文件名称:{}",file.getName());
    //构建上传文件的数据格式
    GeneralListener<TeleCityExcelDTO> generalListener=new GeneralListener<>();
    try {
        EasyExcel.read(file.getInputStream(), TeleCityExcelDTO.class, generalListener).sheet().doRead();
    } catch (IOException e) {
        log.error("上传文件失败!", e);
        throw new BizException(ResponseCode.UP_LOAD_FILE_FAILURE);
    }
    return new Response("0","读取数据成功!",generalListener.getList().size());
}

前端样式,注意读取文件的类型为:multipart/form-data,前端

<form action="/test/test18", method="post", enctype="multipart/form-data">
    <input type="file" name="file"/>
    <input type="submit">
</form>

要使用EasyExcel实现导出xls文件,你需要按照以下步骤进行操作: 1. 首先,你需要在你的项目中添加EasyExcel的依赖。你可以在pom.xml文件中添加以下内容: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.10</version> </dependency> ``` 2. 创建一个Java类,用于实现导出功能。在该类中,你可以使用EasyExcel提供的API来实现导出操作。下面是一个简单的示例代码: ```java import com.alibaba.excel.EasyExcel; import com.alibaba.excel.write.builder.ExcelWriterBuilder; import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; import java.util.ArrayList; import java.util.List; public class ExcelExporter { public static void main(String[] args) { // 创建数据列表 List<User> userList = new ArrayList<>(); userList.add(new User("张三", 20)); userList.add(new User("李四", 25)); userList.add(new User("王五", 30)); // 指定导出文件路径和文件名 String fileName = "user_list.xls"; // 使用EasyExcel进行导出 EasyExcel.write(fileName, User.class) .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) .sheet("用户列表") .doWrite(userList); } static class User { private String name; private Integer age; public User(String name, Integer age) { this.name = name; this.age = age; } // 省略getter和setter方法 } } ``` 在上面的示例中,我们创建了一个名为`ExcelExporter`的类,其中包含了一个名为`User`的内部类作为导出数据的模型。我们使用`EasyExcel.write()`方法来指定导出文件的路径和文件名,使用`.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())`来设置列宽自适应,并使用`.sheet()`方法指定导出的sheet名称。最后,使用`.doWrite()`方法执行导出操作。 3. 运行该类,你将在指定的路径下找到生成的xls文件。 请注意,上述示例代码仅供参考,你可以根据自己的需求进行修改和扩展。此外,还可以使用EasyExcel提供的其他功能,如读取xls文件、自定义样式等。你可以参考EasyExcel的官方文档以获得更多详细信息。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值