使用阿里开源技术导入导出execl -- EasyExcel

之前导入导出是用POI完成的,导入大量数据的时候会导致内存溢出。导入十四万条数据大搞用了不到二十分钟然后还很容易内存溢出,大佬就推荐使用EasyExcel来实现导入导出。

经过测试使用EasyExcel读十四万条的数据大概需要四十秒左右,写的话没用大量数据测试过,没导出大量数据的需求。

直接看文档的解释:

    /**
     * 文件上传
     * <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";
    }

上面这是文档给的demo,下面来撸代码

/**
 * 监听器
 */
@Component
@Scope("prototype")
public class OrdersListener extends AnalysisEventListener<OrdersExcelVo> {

    @Autowired
    OrdersServiceImpl ordersService;

    List<Orders> list = new ArrayList<>();

    /**
     *每读取一行数据会调用的内容
     * @param ordersImportVo
     * @param analysisContext
     */
    @Override
    public void invoke(OrdersExcelVo ordersImportVo, AnalysisContext analysisContext) {
        //每读取一行数据就传换成数据库需要的类型,添加到列表
        list.add(OrdersConvert.convertToOrders(ordersImportVo));
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        System.out.println("表头:"+headMap);
    }

    /**
     * 读取完整个文档后会调用的内容
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        //设置默认允许更新
        ordersService.importOrders(list,true);
        //清空list
        list.clear();
    }
}

下面我们来解析一下代码:

  • 在文档给的demo中EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener(uploadDAO)).sheet().doRead();这行代码中又三个参数:
    • 第一个参数表示文件的输入流
    • 第二个参数指定用那个class去读
    • 第三个参数为监听器
    • 然后直接.sheet().doRead()就行
  • 监听器demo
    • 监听器就是对读到的数据进行操作的地方
    • 先指定多例模式
    • 监听器中的三个方法都是从文档中复制下来的,注释写的很详细
    • 如果嫌invoke方法和数据库交互太频繁可以指定一个计数器,每读到十行数据和数据库进行交互一次
      • if(i % 10 == 0)-- 和数据库交互
    • 需要注意的是读完excel调用doAfterAllAnalysed方法后需要清空一下list,否则下次读list中还会有上次读的数据

以上这些就是读excel的代码

还是直接看文档

   /**
     * 文件下载(失败了会返回一个有部分数据的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");
        EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
    }

然后撸代码:

    public void aMonthPerformance(HttpServletResponse response,AMonthPerformance aMonthPerformance){
        
        List<AMonthPerformance> list = homePageService.aMonthPerformance(aMonthPerformance);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName= null;
        try {
            fileName = URLEncoder.encode(String.valueOf(System.currentTimeMillis()) + "部门业绩","UTF-8").replaceAll("\\+","%20");
            response.setHeader("Content-disposition","attachment;filename*=utf-8''"+fileName+".xlsx");
            EasyExcel.write(response.getOutputStream(),AMonthPerformance.class).sheet("模板").doWrite(list);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

实际写代码的时候直接把文档上的demo复制下来,稍微修改一下就可以了

其中示例代码中的第三行中的 list 是我去数据库中查到的要写入的数据,其中 fileName中我为了文件名不重复用的时间戳 + 部门业绩来当作文件名,其他的用的文档demo中的实例没改

还是来看EasyExcel.write(response.getOutputStream(),AMonthPerformance.class).sheet("模板").doWrite(list);这行代码,他又两个参数

  • 第一个参数为HttpServletResponse对象的输出流,用于将数据发送给客户端
  • 第二个参数为写入数据的类型,即数据对象的类型。EasyExcel 将使用这个类型来解析数据并生成相应的 Excel 文件。

要生成的excel表格为这种格式:

那我们就继续看文档 写Excel | Easy Excel

    /**
     * 日期
     */
    @ColumnWidth(15)
    @JsonFormat(pattern = "yyyy-MM")
    @DateTimeFormat("MM月dd日")
    @ExcelProperty({"xx组业绩详情日报", "日期"})
    private String dataDate;

以上定义数据为其中一个实例,上面有最终效果

实例属性中的注解解释:

  • @ColumnWidth(15)宽度指定15(15是什么单位我也不知道。。。格式是我自己调的)
  • @JsonFormat(pattern = "yyyy-MM") 解析时间
  • @ExcelProperty({"xx组业绩详情日报", "日期"}) 标题
  • 其他的顺序啥的文档里都有,没用到就不展示了

可以指定写入的列,因为我定义属性的时候是按照顺序定义的就没写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ming__GoGo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值