EasyExcel相关

1. easyexcel--100M

EasyExcel是一个基于Java的使用简单、节省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。

节省内存的原因:在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析

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

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

github地址:https://github.com/alibaba/easyexcel

官方文档:https://www.yuque.com/easyexcel/doc

2. easyexcel写操作

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

实现步骤

  1. 引入依赖
xml 复制代码
<dependency>
            <groupId>repMaven.com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.0.5</version>
        </dependency>
  1. 封装相应的对象,创建与表格对应的实体类

    java 复制代码
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class ExcelDemo {
        @ExcelProperty(value = "姓名")//标记excel的表头内容
        public String name;
        @ExcelProperty(value = "年龄")
        public Integer age;
        @ExcelProperty(value = "性别")
        public String sex;
        @ExcelIgnore//写入excel表格时忽略该属性
        public String address;
    }
    1. @ExcelProperty:标记excel的表头内容
    2. @ExcelIgnore:在写入excel表格时忽略该属性
  2. 通过easyexcel完成写入操作

    java 复制代码
    public class WriteExcel {
        public static void main(String[] args) {
            //fileName:表示excel写入的路径以及名称
            String fileName="D:\\idea\\easyexcel_demo1\\writer.xlsx";
            //这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板,然后文件流会自动关闭
            //如果这里使用03,则 传入 excelType 参数即可
            List<ExcelDemo> list=new ArrayList<>();
            list.add(new ExcelDemo("章三",18,"男","郑州"));
            list.add(new ExcelDemo("李斯",19,"男","郑州"));
            list.add(new ExcelDemo("汪芜",20,"女","郑州"));
            list.add(new ExcelDemo("码字",25,"男","郑州"));
            EasyExcel.write(fileName,ExcelDemo.class).sheet("第一次完成写操作").doWrite(list);
        }
    }
    1. 准备文件路径
    2. 写出文件

3. easyexcel写操作------web模式【导出】

导出:需要将数据库里面的文件以附件的形式下载到本地电脑,需要参数为response对象,返回值类型为void

  • 实例
java 复制代码
@Controller
public class ExcelController {
    @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");

        List<ExcelDemo> list=new ArrayList<>();
        list.add(new ExcelDemo("章三",18,"男","郑州"));
        list.add(new ExcelDemo("李斯",19,"男","郑州"));
        list.add(new ExcelDemo("汪芜",20,"女","郑州"));
        list.add(new ExcelDemo("码字",25,"男","郑州"));
        EasyExcel.write(response.getOutputStream(), ExcelDemo.class).sheet("模板").doWrite(list);
    }
}

也可以在controllre层仅进行调用操作,将逻辑交由service去做,即:

  • controller
java 复制代码
    @ApiOperation("导出")
    @GetMapping("/download")
    public void exportData(HttpServletResponse response){
        dictService.exportData(response);
    }
  • service
java 复制代码
 @Override
    public void exportData(HttpServletResponse response) {
        try {
            //设置相关参数
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("数据字典", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");
            //获取文件
            List<Dict> list = this.baseMapper.selectList(null);
            //转换文件
            ArrayList<DictEeVo> dictEeVos = new ArrayList<>();
            for (Dict dict : list) {
                DictEeVo dictEeVo = new DictEeVo();
                //转换
                BeanUtils.copyProperties(dict, dictEeVo);
                //添加
                dictEeVos.add(dictEeVo);
            }
            //写出
              EasyExcel.write(response.getOutputStream(), DictEeVo.class).sheet("数据字典").doWrite(dictEeVos);
          } catch (Exception e) {
              e.printStackTrace();
        }
    }

测试

测试仅需允许项目,然后在前端页面写入实际的url地址即可,也可以添加按钮的点击事件进行测试

4. easyexcel读操作

  • 流程
  • 实现步骤
  1. 引入fastjson依赖

    xml 复制代码
    <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.83</version>
            </dependency>

    com.alibaba.fastjson.JSON是阿里巴巴开源的一个高性能数据交换格式库,它是基于Java语言的JSON解析和生成工具。Fastjson旨在提供一种快速、便捷的方式来序列化和反序列化Java对象到JSON字符串,以及将JSON字符串转换回Java对象。它支持大数据量的处理,并且具有优秀的性能,通常比标准的Java自带的java.util.JSONObjectorg.json.JSONObject更快。

    使用Fastjson的好处包括:

    1. 高效:通过字节码操作,使得JSON解析和生成的速度非常快。
    2. 易用:API设计简洁明了,易于理解和上手。
    3. 功能丰富:支持复杂数据结构的处理,如日期、数组、集合等。

    在Java项目中,你可以通过Maven或Gradle添加fastjson依赖来使用它,然后通过JSONObjectJSONArray或其他类来进行JSON相关的操作。

  2. 创建监听器

    java 复制代码
    package com.zmq.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<ExcelDemo> {
    
        /**
         * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
         */
        private static final int BATCH_COUNT = 100;
        /**
         * 缓存的数据
         */
        private List<ExcelDemo> 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;
        }
    
        /**
         * 这个每一条数据解析都会来调用
         *
         * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
         * @param context
         */
        //一行一行的去读取里面的数据
        @Override
        public void invoke(ExcelDemo data, AnalysisContext context) {
            log.info("解析到一条数据:{}", JSON.toJSONString(data));
            cachedDataList.add(data);
            // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
            if (cachedDataList.size() >= BATCH_COUNT) {
                saveData();
                // 存储完成清理 list
                cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            }
        }
    
        /**
         * 所有数据解析完成了 都会来调用
         *
         * @param context
         */
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            // 这里也要保存数据,确保最后遗留的数据也存储到数据库
            saveData();
            log.info("所有数据解析完成!");
        }
    
        /**
         * 加上存储数据库
         */
        private void saveData() {
            log.info("{}条数据,开始存储数据库!", cachedDataList.size());
            demoDAO.save(cachedDataList);
            log.info("存储数据库成功!");
        }
    }

    进行读操作时就会触发监听器,基本不需要改动

  3. dao

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

    dao中填写需要的操作

  4. 读取

    java 复制代码
    public class ReadExcel {
        public static void main(String[] args) {
            /**
             * 指定列的下标或者列名
             *
             * <p>1. 创建excel对应的实体对象,并使用{@link ExcelProperty}注解. 参照{@link IndexOrNameData}
             * <p>2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link IndexOrNameDataListener}
             * <p>3. 直接读即可
             */
    
            //fileName:表示excel读取的路径以及名称
            String fileName="D:\\idea\\easyexcel_demo1\\writer.xlsx";
            // 这里默认读取第一个sheet
            //new DemoDataListener():监听器
            EasyExcel.read(fileName, ExcelDemo.class, new DemoDataListener()).sheet().doRead();
        }
    }

5. easyexcel文件上传-web【导入】

导入:需要将本地文件插入到数据库,参数:multiparefile,返回值:"成功或失败"

使用excel进行导入需要解析器的配合,使用监听器对读取的文件进行操作

解析器:用来读取文件,并将数据插入到数据库

  1. 加入文件上传的依赖

    xml 复制代码
     <dependency>
                <groupId>repMaven.commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>1.4</version>
            </dependency>

    commons-fileupload是一个开源库,专为Java应用程序设计,用于处理文件上传功能。它简化了处理HTTP请求中的multipart/form-data格式,这种格式通常用于用户通过Web表单上传文件到服务器。该库提供了一组工具类和处理器,使得开发者能够解析上传的文件流,并管理文件名、大小限制等复杂操作。它的API易于使用,支持断点续传以及错误处理,广泛应用于web应用开发中的文件上传组件。

  2. 文件上传解析器------spring配置文件中

    若使用springboot框架,仅引入上述依赖即可

    xml 复制代码
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <property name="maxUploadSize" value="1000000000"/>
        </bean>
  3. controller

    java 复制代码
    @Autowired
        private DemoDAO demoDAO;
        @PostMapping("/upload")
        @ResponseBody //将返回值转化为json格式
        public String upload(MultipartFile file) throws IOException{
            EasyExcel.read(file.getInputStream(), ExcelDemo.class, new DemoDataListener(demoDAO)).sheet().doRead();
            return "success";
        }

    DemoDao层加入注入spring容器的注解:@Component

  4. 测试------使用postman完成测试

相关推荐
Yaml41 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~1 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端
hong1616881 小时前
Spring Boot中实现多数据源连接和切换的方案
java·spring boot·后端
aloha_7891 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
记录成长java2 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
睡觉谁叫~~~2 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust
程序媛小果2 小时前
基于java+SpringBoot+Vue的旅游管理系统设计与实现
java·vue.js·spring boot
小屁孩大帅-杨一凡3 小时前
java后端请求想接收多个对象入参的数据
java·开发语言
java1234_小锋3 小时前
使用 RabbitMQ 有什么好处?
java·开发语言
TangKenny3 小时前
计算网络信号
java·算法·华为