EasyExcel使用

EasyExcel

EasyExcel是阿里巴巴开源poi插件之一,主要解决了poi框架使用复杂,sax解析模式不容易操作,数据量大起来容易OOM,解决了POI并发造成的报错。

主要解决方式:通过解压文件的方式加载,一行一行的加载,并且抛弃样式字体等不重要的数据,降低内存的占用。

EasyExcel优势

  • 注解式自定义操作
  • 输入输出简单,提供输入输出过程的接口
  • 支持一定程度的单元格合并等灵活化操作

常用注解

  • @ExcelProperty指定当前字段对应excel中的那一列。可以根据名字或者Index去匹配。当然也可以不写,默认第一个字段就是index=0,以此类推。千万注意,要么全部不写,要么全部用index,要么全部用名字去匹配。千万别三个混着用,除非你非常了解源代码中三个混着用怎么去排序的。
  • @ExcelIgnore默认所有字段都会和excel去匹配,加了这个注解会忽略该字段
  • @DateTimeFormat日期转换,用String去接收excel日期格式的数据会调用这个注解。里面的value参照java.text.SimpleDateFormat
  • @NumberFormat数字转换,用String去接收excel数字格式的数据会调用这个注解。里面的value参照java.text.DecimalFormat
  • @ExcelIgnoreUnannotated过滤属性没有@ExcelProperty注解的字段

依赖

 <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.1.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>poi-ooxml-schemas</artifactId>
                    <groupId>org.apache.poi</groupId>
                </exclusion>
            </exclusions>
</dependency>

写完后通过web直接下载


controller层

    @ResponseBody
    @GetMapping("/studentDownload")
    public String download(HttpServletResponse response){
        studentService.writeToExcel(response);
        return "download success";
    }

service层

    @Override
    public void writeToExcel(HttpServletResponse response) {
        // 使用swagger 会导致各种问题,请直接用浏览器或者用postman
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = null;
        try {
            fileName = URLEncoder.encode("学生表" + System.currentTimeMillis(), "UTF-8")
                    .replaceAll("\\+", "%20");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");


        try {
            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), Student.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet("one").build();

            int total = studentMapper.selectTotal();
            int pages = total % NUMBER_OF_WRITES_PER_TIME == 0
                    ? total / NUMBER_OF_WRITES_PER_TIME
                    : total / NUMBER_OF_WRITES_PER_TIME + 1;
            System.out.println(pages);
            for (int i = 1; i <= pages; i++) {
                // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
                List<Student> data = dataList(i);
                data.forEach(System.out::println);
                excelWriter.write(data, writeSheet);
            }
            excelWriter.finish();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

访问

在这里插入图片描述


结果

在这里插入图片描述

通过web上传

    @PostMapping("/studentUpload")
    @ResponseBody
    public String upload(MultipartFile file) throws IOException {
        System.out.println("------upload--------------");
        InputStream inputStream = file.getInputStream();
        // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(inputStream, Student.class, new StudentListener(studentService)).sheet().doRead();
        return "upload success";
    }

解析到每一条数据都会调用一次listener进行处理,需要的业务逻辑操作都写在listener内部即可


listener写法


此listener逻辑

  • 每100条数据进行一次存储数据库操作
  • 每条数据拿到后进行校验,校验不合法不放入list

/**
 * @author QN
 */
@Slf4j
public class StudentListener implements ReadListener<Student> {
    /**
     * 每隔100条存储数据库,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    /**
     * 缓存的数据
     */
    private List<Student> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    private StudentService studentService;

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

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(Student data, AnalysisContext context) {
        Gson gson = new Gson();
        log.info("解析到一条数据:{}",gson.toJson(data) );
        boolean b = studentService.registerCheck(data.getStu_no(), data.getStu_password());
        if (b){
            data.setStu_password(studentService.Digest(data.getStu_password()));
            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());
        studentService.saveBatch(cachedDataList);
        log.info("存储数据库成功!");
    }

}


结尾

更多详细操作,阅读EasyExcel官方文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值