自从用了 EasyExcel,导入导出 Excel 更简单了!

news2024/12/23 14:22:07

EasyExcel

在做excel导入导出的时候,发现项目中封装的工具类及其难用,于是去gitHub上找了一些相关的框架,最终选定了EasyExcel。之前早有听闻该框架,但是一直没有去了解,这次借此学习一波,提高以后的工作效率。

实际使用中,发现是真的很easy,大部分api通过名称就能知道大致意思,这点做的很nice。参考文档,大部分场景的需求基本都能够满足。

GitHub上的官方说明

快速开始

maven仓库地址

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

导入

如下图excel表格:

建立导入对应实体类

@Data
public class ReqCustomerDailyImport {
    /**
     * 客户名称
     */
    @ExcelProperty(index = 0)
    private String customerName;

    /**
     * MIS编码
     */
    @ExcelProperty(index = 1)
    private String misCode;

    /**
     * 月度滚动额
     */
    @ExcelProperty(index = 3)
    private BigDecimal monthlyQuota;

    /**
     * 最新应收账款余额
     */
    @ExcelProperty(index = 4)
    private BigDecimal accountReceivableQuota;

    /**
     * 本月利率(年化)
     */
    @ExcelProperty(index = 5)
    private BigDecimal dailyInterestRate;
}

Controller代码

@PostMapping("/import")
public void importCustomerDaily(@RequestParam MultipartFile file) throws IOException {
    InputStream inputStream = file.getInputStream();
    List<ReqCustomerDailyImport> reqCustomerDailyImports = EasyExcel.read(inputStream)
            .head(ReqCustomerDailyImport.class)
            // 设置sheet,默认读取第一个
            .sheet()
            // 设置标题所在行数
            .headRowNumber(2)
            .doReadSync();
}

运行结果

可以看出只需要在实体对象使用@ExcelProperty注解,读取时指定该class,即可读取,并且自动过滤了空行,对于excel的读取及其简单。

不过此时发现一个问题,这样我如果要校验字段该怎么办?要将字段类型转换成另外一个类型呢?

不必担心,我们可以想到的问题,作者肯定也考虑到了,下面来一个Demo。

代码如下


List<ReqCustomerDailyImport> reqCustomerDailyImports = EasyExcel.read(inputStream)
            // 这个转换是成全局的, 所有java为string,excel为string的都会用这个转换器。
            // 如果就想单个字段使用请使用@ExcelProperty 指定converter
            .registerConverter(new StringConverter())
            // 注册监听器,可以在这里校验字段
            .registerReadListener(new CustomerDailyImportListener())
            .head(ReqCustomerDailyImport.class)
            .sheet()
            .headRowNumber(2)
            .doReadSync();
}

监听器

public class CustomerDailyImportListener extends AnalysisEventListener {

    List misCodes = Lists.newArrayList();

    /**
     * 每解析一行,回调该方法
     * @param data
     * @param context
     */
    @Override
    public void invoke(Object data, AnalysisContext context) {
        String misCode = ((ReqCustomerDailyImport) data).getMisCode();
        if (StringUtils.isEmpty(misCode)) {
            throw new RuntimeException(String.format("第%s行MIS编码为空,请核实", context.readRowHolder().getRowIndex() + 1));
        }
        if (misCodes.contains(misCodes)) {
            throw new RuntimeException(String.format("第%s行MIS编码已重复,请核实", context.readRowHolder().getRowIndex() + 1));
        } else {
            misCodes.add(misCode);
        }
    }

    /**
     * 出现异常回调
     * @param exception
     * @param context
     * @throws Exception
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        // ExcelDataConvertException:当数据转换异常的时候,会抛出该异常,此处可以得知第几行,第几列的数据
        if (exception instanceof ExcelDataConvertException) {
            Integer columnIndex = ((ExcelDataConvertException) exception).getColumnIndex() + 1;
            Integer rowIndex = ((ExcelDataConvertException) exception).getRowIndex() + 1;
            String message = "第" + rowIndex + "行,第" + columnIndex + "列" + "数据格式有误,请核实";
            throw new RuntimeException(message);
        } else if (exception instanceof RuntimeException) {
            throw exception;
        } else {
            super.onException(exception, context);
        }
    }

    /**
     * 解析完全部回调
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        misCodes.clear();
    }
}

转换器


public class StringConverter implements Converter<String> {

    @Override
    public Class supportJavaTypeKey() {
        return String.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 将excel对象转成Java对象,这里读的时候会调用
     *
     * @param cellData            NotNull
     * @param contentProperty     Nullable
     * @param globalConfiguration NotNull
     * @return
     */
    @Override
    public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
                                    GlobalConfiguration globalConfiguration) {
        return "自定义:" + cellData.getStringValue();
    }

    /**
     * 将Java对象转成String对象,写出的时候调用
     *
     * @param value
     * @param contentProperty
     * @param globalConfiguration
     * @return
     */
    @Override
    public CellData convertToExcelData(String value, ExcelContentProperty contentProperty,
                                       GlobalConfiguration globalConfiguration) {
        return new CellData(value);
    }

可以看出注册了一个监听器:CustomerDailyImportListener,还注册了一个转换器:StringConverter。流程为:框架读取一行数据,先执行转换器,当一行数据转换完成,执行监听器的回调方法,如果转换的过程中,出现转换异常,也会回调监听器中的onException方法。因此,可以在监听器中校验数据,在转换器中转换数据类型或者格式。

运行结果

修改一下表格,测试校验是否生效

再次导入,查看运行结果

导入相关常用API

注解

  • ExcelProperty 指定当前字段对应excel中的那一列。可以根据名字或者Index去匹配。当然也可以不写,默认第一个字段就是index=0,以此类推。千万注意,要么全部不写,要么全部用index,要么全部用名字去匹配。千万别三个混着用,除非你非常了解源代码中三个混着用怎么去排序的。

  • ExcelIgnore 默认所有字段都会和excel去匹配,加了这个注解会忽略该字段。

  • DateTimeFormat 日期转换,用String去接收excel日期格式的数据会调用这个注解。里面的value参照java.text.SimpleDateFormat。

  • NumberFormat 数字转换,用String去接收excel数字格式的数据会调用这个注解。里面的value参照java.text.DecimalFormat。

EasyExcel相关参数

  • readListener 监听器,在读取数据的过程中会不断的调用监听器。

  • converter 转换器,默认加载了很多转换器。也可以自定义,如果使用的是registerConverter,那么该转换器是全局的,如果要对单个字段生效,可以在ExcelProperty注解的converter指定转换器。

  • headRowNumber 需要读的表格有几行头数据。默认有一行头,也就是认为第二行开始起为数据。

  • head 与clazz二选一。读取文件头对应的列表,会根据列表匹配数据,建议使用class。

  • autoTrim 字符串、表头等数据自动trim。

  • sheetNo 需要读取Sheet的编码,建议使用这个来指定读取哪个Sheet。

  • sheetName 根据名字去匹配Sheet,excel 2003不支持根据名字去匹配。

导出

建立导出对应实体类


@Data
public class ReqCustomerDailyImport {
    /**
     * 客户名称
     */
    @ExcelProperty(index = 0)
    private String customerName;

    /**
     * MIS编码
     */
    @ExcelProperty(index = 1)
    private String misCode;

    /**
     * 月度滚动额
     */
    @ExcelProperty(index = 3)
    private BigDecimal monthlyQuota;

    /**
     * 最新应收账款余额
     */
    @ExcelProperty(index = 4)
    private BigDecimal accountReceivableQuota;

    /**
     * 本月利率(年化)
     */
    @ExcelProperty(index = 5)
    private BigDecimal dailyInterestRate;
}

Controller代码

@PostMapping("/import")
public void importCustomerDaily(@RequestParam MultipartFile file) throws IOException {
    InputStream inputStream = file.getInputStream();
    List<ReqCustomerDailyImport> reqCustomerDailyImports = EasyExcel.read(inputStream)
            .head(ReqCustomerDailyImport.class)
            // 设置sheet,默认读取第一个
            .sheet()
            // 设置标题所在行数
            .headRowNumber(2)
            .doReadSync();
}

导出效果

导出相关常用API

注解

  • ExcelProperty 指定写到第几列,默认根据成员变量排序。value指定写入的名称,默认成员变量的名字。

  • ExcelIgnore 默认所有字段都会写入excel,这个注解会忽略这个字段。

  • DateTimeFormat 日期转换,将Date写到excel会调用这个注解。里面的value参照java.text.SimpleDateFormat。

  • NumberFormat 数字转换,用Number写excel会调用这个注解。里面的value参照java.text.DecimalFormat。

EasyExcel相关参数

  • needHead 监听器是否导出头。

  • useDefaultStyle 写的时候是否是使用默认头。

  • head 与clazz二选一。写入文件的头列表,建议使用class。

  • autoTrim 字符串、表头等数据自动trim。

  • sheetNo 需要写入的编码。默认0。

  • sheetName 需要些的Sheet名称,默认同sheetNo。

总结

可以看出不管是excel的读取还是写入,都是一个注解加上一行代码完成,可以让我们少些很多解析的代码,极大减少了重复的工作量。当然这两个例子使用了最简单的方式,EasyExcel还支持更多场景,例如读,可以读多个sheet,也可以解析一行数据或者多行数据做一次入库操作;写的话,支持复杂头,指定列写入,重复多次写入,多个sheet写入,根据模板写入等等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/584379.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

服了呀,00后怎么这么卷....

现在的小年轻真的卷得过分了。前段时间我们公司来了个00年的&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天&#xff0c;原来这位小老弟家里条…

FDA辅料数据库-在线查询网址

在药物的制剂研发过程中&#xff0c;辅料是不可或缺的。然而&#xff0c;在使用辅料时需要明确其安全使用量&#xff0c;这并非易事。因此&#xff0c;美国FDA 辅料数据库&#xff08;IID&#xff09;成为了一个重要的参考标准&#xff0c;对于制剂开发提供了帮助。 如果研发人…

《汇编语言》- 读书笔记 - 第7章- 更灵活的定位内存地址的方法

《汇编语言》- 读书笔记 - 第7章- 更灵活的定位内存地址的方法 7.1 and 和 or 指令7.2 关于 ASCII 码7.3 以字符形式给出的数据程序 7.1 7.4 大小写转换的问题7.5 [bxidata] &#xff08;变量 固定偏移量&#xff09;问题 7.1 7.6 用[bxidata]的方式进行数组的处理7.7 SI 和 D…

软件测试测试环境搭建很难?一天学会这份测试环境搭建教程

如何搭建测试环境&#xff1f;这既是一道高频面试题&#xff0c;又是困扰很多小伙伴的难题。因为你在网上找到的大多数教程&#xff0c;乃至在一些培训机构的课程&#xff0c;都不会有详细的说明。 你能找到的大多数项目&#xff0c;是在本机电脑环境搭建环境&#xff0c;或是…

Linux服务器上如何安装OpenCV的库?

Linux上安装OpenCV其实挺简单的。对于Python来说&#xff0c;可以直接使用pip进行安装&#xff0c;如&#xff1a; pip3 install opencv-python 当然&#xff0c;如果你是想在C或者Java内作为外部包使用&#xff0c;你可以考虑编译安装。 安装依赖 首先是依赖安装问题&#…

LED屏控制卡

LED屏控制卡&#xff08;LED Screen Control Card&#xff09;是一种用于控制和管理LED显示屏的关键设备。它通常是一个硬件设备&#xff0c;具有处理器、存储器、接口和软件功能&#xff0c;用于接收、解码和显示图像、视频和其他多媒体内容。 以下是LED屏控制卡的一些重要特点…

JVM (基础概念、类加载过程、垃圾回收算法)

目录 一、JVM 是什么 二、JVM 运行流程 三、Java运行时数据区 1、程序计数器&#xff08;线程私有&#xff09; 2、栈区&#xff08;线程私有&#xff09; 3、堆 4、方法区 四、OOM内存溢出和内存泄漏 1、OOM内存溢出 2、内存泄漏 五、类加载过程 1、加载 2、连接…

PMP课堂模拟题目及解析(第14期)

131. 项目经理正在制定干系人参与计划&#xff0c;并识别到一位权力等级较高但在项目中兴趣较低的干系人&#xff0c;项目经理应该如何对待该干系人&#xff1f; A. 重点管理 B. 随时告知 C. 监督 D. 令其满意 132. 项目经理识别到项目干系人具有明显不同的需求和期望。…

不合格机器人工程专业讲师笔记-230529-

工作八年&#xff0c;最大的遗憾&#xff0c;就是对不起学生&#xff0c;对不起同事&#xff0c;对不起领导&#xff0c;各项工作都没有做好。 但是由于个人水平低&#xff0c;能力差&#xff0c;唯一能做的就是在忏悔中不断总结&#xff0c;避免一次又一次失败。 一万句&…

别让测试岗位的坑太大,10年老鸟亲身经历告诉你如何避开陷阱

测试岗位一直是IT行业中备受争议的一个职业&#xff0c;有人看重其重要性&#xff0c;有人则认为这是个巨坑。如果你也对测试岗位存在疑虑和担忧&#xff0c;那么这篇文章一定能帮到你&#xff01; 作者是一位在测试领域摸爬滚打了10年的老鸟&#xff0c;他深刻地理解了测试工…

行业报告 | 智能制造在中国—中国机器视觉产业链现状分析

文 | BFT机器人 导语 Introduction 智能制造装备是指具有感知、分析、推理、决策、控制功能的制造装备&#xff0c;它是先进制造技术、信息技术和智能技术的集成和深度融合&#xff0c;体现了制造业智能化、数字化和网络化的发展要求。智能制造装备的水平已成为当今衡量一个国家…

数据类岗位面试随想录

数据分析或者是偏向数据分析的数据开发岗&#xff0c;要求无非就是SQL、Python和业务相关的问题。 1 SQL问答 基本这些问题和期末考试的难度比&#xff0c;是简单的。和学校所教的比&#xff0c;基本超纲的问题只会有窗口函数。这一部分面试官一般不会问你难的问题&#xff0c…

通用支付系统设计

支付永远是一个公司的核心领域&#xff0c;因为这是一个有交易属性公司的命脉。那么&#xff0c;支付系统到底长什么样&#xff0c;又是怎么运行交互的呢?抛开带有支付牌照的金融公司的支付架构&#xff0c;下述链路和系统组成基本上符合绝大多数支付场景。其实整体可以看成是…

【人脸识别】insightface 使用记录和搭建服务注意点 从0到1

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言1.开始1.1 前置1.2 再次运行&#xff0c;人脸检测跑通 前言 人脸识别项目&#xff0c;再走一遍。之前是公司老人留下的&#xff0c;没部署过&#xff0c;没交付…

【HMS Core】Health Kit关于获取历史数据问题

【问题描述1】 应用已经开通了历史数据访问权限&#xff0c;同时用户在授权页面已经勾选了”历史数据“项&#xff0c;然后我们是调用healthkit的rest接口查询健康数据&#xff0c;那么是否用户授权之前一年的健康数据都能被查询到呢&#xff1f; 【解决方案】 当用户授予应用…

5月底了,让我看看有多少准备跳槽的····

前两天跟朋友感慨&#xff0c;今年的铜三铁四、裁员导致好多人都没拿到offer!现在已经5月底了&#xff0c;具体金九银十只剩下3个月。 对于想跳槽的职场人来说&#xff0c;绝对要从现在开始做准备了。这时候&#xff0c;很多高薪技术岗、管理岗的缺口和市场需求也出来了。 所…

字节跳动测试岗,3面都过了,HR告诉我这个原因被刷了...

说在前面 面试时最好不要虚报工资。本来字节跳动是很想去的&#xff0c;几轮面试也通过了&#xff0c;最后没offer&#xff0c;自己只想到下面几个原因&#xff1a; 虚报工资&#xff0c;比实际高30%&#xff1b; 有更好的人选&#xff0c;这个可能性不大&#xff0c;我看还在…

6个月的测试,来面试居然要18K,我一问连8K都不值

2023年4月份我入职了深圳某家创业公司&#xff0c;刚入职还是很兴奋的&#xff0c;到公司一看我傻了&#xff0c;公司除了我一个自动化测试&#xff0c;公司的测试人员就只有2个开发3个前端1个测试还有2个UI&#xff0c;在粗略了解公司的业务后才发现是一个从零开始的项目&…

笔记本电脑正常开机但是桌面变成错误代码怎么办?

笔记本电脑正常开机但是桌面变成错误代码怎么办&#xff1f;有用户将自己的笔记本电脑开机之后&#xff0c;电脑可以正常开启&#xff0c;但是系统在加载的过程中&#xff0c;突然变成了一些错误代码&#xff0c;无法正常的到达桌面上。那么这个问题怎么去进行解决呢&#xff1…

操作系统学习系列(1.启航)-操作系统基本概念

文章目录 前言操作系统基本概述中断与硬件的基本交互基本地址地址概念启动流程应用程序与操作系统的关系 Hello World启动总结 前言 本系列博文主要用于第二阶段深入了解的408专业内容考研使用。也就是说在开启本系列之前&#xff0c;最好已经对408有基本的了解。重复的基础概…