1.概述

EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。 github地址:GitHub - alibaba/easyexcel: 快速、简洁、解决大文件内存溢出的java处理Excel工具

通过java代码完成对Excel的读写操作,所谓的读写理解为上传和下载

官网:关于Easyexcel | Easy Excel (alibaba.com) 

2. easyexcel写操作

所谓的写操作就是把java中的类对象写入到excel表格中。

 实现步骤:

1.引入相关依赖

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

2.封装响应的对象

package com.wzh.excel;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class DemoData {
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private String ignore;
}

3.通过easyexcel完成写操作

package com.wzh.excel;

import com.alibaba.excel.EasyExcel;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @ProjectName: computer
 * @Package: com.wzh.excel
 * @ClassName: TestWriterDemo
 * @Author: 王振华
 * @Description:
 * @Date: 2022/10/24 20:37
 * @Version: 1.0
 */
public class TestWriterDemo {
    public static void main(String[] args) {
        //fileName:表示excel文件所在路径以及名称
        String fileName = "D:\\java_idea_2020\\dev\\自己代码\\computer\\easyexcel.xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入excelType参数即可

        //模拟要写入excel的数据
        List<DemoData> list = new ArrayList<>();
        list.add(new DemoData("aaa",new Date(),3.1,"aaaaaa"));
        list.add(new DemoData("bbb",new Date(),3.1,"bbbbbb"));

        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(list);
    }
}

3.easyexcel写操作--web模式

写Excel | Easy Excel (alibaba.com)

package com.wzh.controller;

import com.alibaba.excel.EasyExcel;
import com.wzh.excel.DemoData;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


@Controller
public class ExcelController {
    /**
     * 文件下载(失败了会返回一个有部分数据的Excel)
     * <p>
     * 1. 创建excel对应的实体对象 参照{@link DownloadData}
     * <p>
     * 2. 设置返回的 参数
     * <p>
     * 3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
     */
    @GetMapping("download")
    public void download(HttpServletResponse response) throws IOException {
        // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        //模拟要写入excel的数据
        List<DemoData> list = new ArrayList<>();
        list.add(new DemoData("aaa",new Date(),3.1,"aaaaaa"));
        list.add(new DemoData("bbb",new Date(),3.1,"bbbbbb"));

        EasyExcel.write(response.getOutputStream(), DemoData.class).sheet("模板").doWrite(list);
    }
}

 这个是我之前的一个工具类:

package com.wzh.utils;

import com.alibaba.excel.EasyExcel;

import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;


import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ProjectName: computer
 * @packageName: com.wzh.utils
 * @author: xmhz45
 * @create: 2022/7/6 19:31
 */
public class ExcelUtil {

    public void print(String filename, List objects, HttpServletResponse response) {
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            //防止中文乱码
            //String fileName = URLEncoder.encode("测试","utf-8");
            response.setHeader("Content-Disposition","attachment;filename=UTF-8''"+fileName+".xlsx");
            ServletOutputStream outputStream = response.getOutputStream();
            //工作簿对象
            ExcelWriterBuilder writerWork = EasyExcel.write(outputStream,objects.get(0).getClass());
            //工作表对象
            ExcelWriterSheetBuilder sheet = writerWork.sheet(filename);
            sheet.doWrite(objects);
            outputStream.flush();
            outputStream.close();

        } 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());
            e.printStackTrace();

        }
    }

}

4.easyexcel完成读操作

读Excel | Easy Excel (alibaba.com)

 1.需要一个监听器

package com.wzh.excel;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;



import java.util.List;

// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener implements ReadListener<DemoData> {

    /**
     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    /**
     * 缓存的数据
     */
    private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    /**
     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private DemoDAO demoDAO;

    public DemoDataListener() {
        // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
        demoDAO = new DemoDAO();
    }

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     *
     * @param demoDAO
     */
    public DemoDataListener(DemoDAO demoDAO) {
        this.demoDAO = demoDAO;
    }

    /**
     * 这个每一条数据解析都会来调用   excel数据 07版没有限制
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(DemoData data, AnalysisContext context) {
        log.info("解析到一条数据:{}", JSON.toJSONString(data));
        cachedDataList.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        //如果excel数据够100条执行if语句  不够的话执行doAfterAllAnalysed方法
        if (cachedDataList.size() >= BATCH_COUNT) {
            System.out.println("100条保存");
            saveData();
            // 存储完成清理 list
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context   最后需要执行的代码
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        System.out.println("不足100条最后调用");
        log.info("所有数据解析完成!");
    }

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

2.dao层  之后只需要操作这个  存入数据库即可

package com.wzh.excel;

import java.util.List;

/**
 * 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。
 **/
@Component
public class DemoDAO {
    public void save(List<DemoData> list) {
        // 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
    }
}

3.测试

package com.wzh.excel;

import com.alibaba.excel.EasyExcel;

import java.io.File;


public class TestReadDemo {
    public static void main(String[] args) {
        //要读的文件路劲及文件名
        String fileName = "D:\\java_idea_2020\\dev\\自己代码\\computer\\easyexcel.xlsx";
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet
        //DemoData.class:实体类
        //new DemoDataListener() 监听器
        EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
    }
}

5.easyexcel读操作--web 

ssm框架:

1.依赖--文件上传的依赖

    <!--文件上传的依赖-->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.4</version>
    </dependency>

2.文件上传解析器

<!--
     id的名称必须叫multipartResolver
     -->
    <!--文件解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--这里的单位为字节10M*1024K*1024-->
        <property name="maxUploadSize" value="10485760"/>
    </bean>
    /**
     * 文件上传
     * <p>
     * 1. 创建excel对应的实体对象 参照{@link UploadData}
     * <p>
     * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
     * <p>
     * 3. 直接读即可
     */
    @PostMapping("upload")
    @ResponseBody
    public String upload(MultipartFile file) throws IOException {
        EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener(uploadDAO)).sheet().doRead();
        return "success";
    }
package com.wzh.controller;

import com.alibaba.excel.EasyExcel;
import com.wzh.excel.DemoDAO;
import com.wzh.excel.DemoData;
import com.wzh.excel.DemoDataListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


@Controller
public class ExcelController {
    /**
     * 文件下载(失败了会返回一个有部分数据的Excel)
     * <p>
     * 1. 创建excel对应的实体对象 参照{@link DownloadData}
     * <p>
     * 2. 设置返回的 参数
     * <p>
     * 3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
     */
    @GetMapping("download")
    public void download(HttpServletResponse response) throws IOException {
        // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        //模拟要写入excel的数据
        List<DemoData> list = new ArrayList<>();
        list.add(new DemoData("aaa",new Date(),3.1,"aaaaaa"));
        list.add(new DemoData("bbb",new Date(),3.1,"bbbbbb"));

        EasyExcel.write(response.getOutputStream(), DemoData.class).sheet("模板").doWrite(list);
    }

    @Autowired
    private DemoDAO demoDAO;
    /**
     * 文件上传
     * <p>
     * 1. 创建excel对应的实体对象 参照{@link UploadData}
     * <p>
     * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
     * <p>
     * 3. 直接读即可
     */
    @PostMapping("upload")
    @ResponseBody
    public String upload(MultipartFile file) throws IOException {
        EasyExcel.read(file.getInputStream(), DemoData.class, new DemoDataListener(demoDAO)).sheet().doRead();
        return "success";
    }
}

测试用postman传参文件:

 测试的时候会出现一个问题DemoDao没有注入成功,那是因为没有被包扫描到。

springboot:

一个普通类如何被spring所管理,spring boot整合EasyExcel_calf小小牛的博客-CSDN博客

前端需要注意的是  要设置类型  blob

//导出
            printC(){

                if(this.multipleSelection.length!=0){
                    var that = this;
                    axios.post("/outlibrarytransfer/printC?filename=平调入库", this.multipleSelection
                        ,{responseType: 'blob'}).then(function (res){
                        var blob = new Blob([res.data])
                        var downloadElement = document.createElement('a');
                        var href = window.URL.createObjectURL(blob); //创建下载的链接
                        downloadElement.href = href;
                        downloadElement.download = '平调入库.xlsx'; //下载后文件名
                        document.body.appendChild(downloadElement);
                        downloadElement.click(); //点击下载
                        document.body.removeChild(downloadElement); //下载完成移除元素
                        window.URL.revokeObjectURL(href); //释放掉blob对象
                        console.log(res);
                        that.initTable();

                    });
                }else{
                    this.$message.error("请选择要到导出的数据!");
                }
            },

2.poi导出excel

(8条消息) postman 导出excel_天狼1222的博客-CSDN博客_postman 导出excel

(8条消息) poi excel操作汇总_天狼1222的博客-CSDN博客

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐