EasyExcel太方便易用了,强烈推荐!

背景

系统中经常要导出大量的数据,格式基本上都是Excel,然而每次导表都是对系统内存的一次挑战。

在Java领域,生成或解析Excel的框架比较有名的当属Apache的poi和jxl了。但使用它们,会面临着严重的内存损耗问题。如果系统的并发量还不行,一旦导出大量数据,便会出现JVM频繁full gc,甚至导致OOM。

EasyExcel是阿里巴巴开源的一个Excel处理框架,使用简单、节省内存。节省内存的原理也很简单,在解析Excel时没有将文件数据全部加载到内存当中,而是从磁盘文件中一行行读取。

今天这篇文章就带大家来了解一下EasyExcel的使用,个人使用后的感慨是:太简单易用了。

项目构建及依赖

首先创建一个Maven项目,在pom文件中添加如下依赖:

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

当引入该依赖之后,会发现在项目的依赖文件中同时多出了poi的类库。也就是说,EasyExcel是基于poi来进行实现的,间接地引入了如下依赖:

<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.17</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.17</version>
</dependency>

所以,当你的项目中已经引入了poi的依赖,要考虑一下版本的兼容问题。

创建实体类

EasyExcel易用性的体现之一就是可以通过在实体类中使用注解的形式,来与Excel中的表头进行绑定。

现在直接上实体类:

@Data
public class UserData {@ExcelProperty(index = 0, value = "姓名")private String username;@ExcelProperty(index = 1, value = "年龄")private int age;@DateTimeFormat("yyyy-MM-dd")@ExcelProperty(index = 2, value = "生日")private Date birthday;
}

在上面的实体类中@Data为Lombok的注解,当然你可以自行生成getter/setter方法,其他的注解均为EasyExcel提供的:

  • @ExcelProperty:用于设置Excel表头,其中index用户表头的编号,从0开始;value为表头对应的内容。

  • @DateTimeFormat:用于日期的格式化。

完成上述功能准备工作之后,我们先来生成一个Excel。

生成Excel

下面直接展示生成Excel的示例代码:

public class EasyExcelDemo {public static void main(String[] args) {// 实现excel写操作//1.设置写入文件夹地址和excel文件名称String fileName = "/Users/zzs/temp/excel/write.xlsx";//调用easyExcel里面的方法实现写操作//2个参数,第一个参数是文件名称,第二个参数是实体类EasyExcel.write(fileName, UserData.class).sheet("学生信息表").doWrite(getData());}//创建方法返回list集合public static List<UserData> getData() {List<UserData> list = new ArrayList<>();UserData userData1 = new UserData();userData1.setUsername("张三");userData1.setAge(22);userData1.setBirthday(formatDate("2000-10-11"));list.add(userData1);UserData userData2 = new UserData();userData2.setUsername("李四");userData2.setAge(23);userData2.setBirthday(formatDate("1999-5-3"));list.add(userData2);return list;}public static Date formatDate(String birthday) {SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd");try {return sdf.parse(birthday);} catch (ParseException e) {e.printStackTrace();}return null;}
}

除了准备数据的代码,核心代码只有main方法中调用的EasyExcel.write方法,就是如此的简单。EasyExcel的write方法会根据传入的数据和实体类UserData进行绑定,生成Excel文件。

我们来看一下Excel的效果:

d2c60e637fa8ebbfd5595ca75e3d519b.png
write-excel

生成效果还不错,而且使用起来是不是非常简单?

解析Excel

再来看看解析Excel的操作,直接用上面生成的Excel文件。

首先创建一个监听器ExcelListener,集成EasyExcel提供AnalysisEventListener类:

public class ExcelListener extends AnalysisEventListener<UserData> {/*** 一行一行的读取excel内容*/@Overridepublic void invoke(UserData data, AnalysisContext analysisContext) {System.out.println("****" + data);}/*** 读取表头内容*/@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {System.out.println("表头" + headMap);}/*** 读取完成操作*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {System.out.println("读取Excel完毕");}
}

在该监听器中,通过重写AnalysisEventListener的方法来获得解析的数据、表头信息,以及解析完毕之后执行的操作信息。

同样写Excel一样,通过EasyExcel类的静态方法来执行读操作:

public class EasyExcelReadDemo {public static void main(String[] args) {// 实现excel写操作//1.设置写入文件夹地址和excel文件名称String fileName = "/Users/zzs/temp/excel/write.xlsx";//调用easyExcel里面的方法实现写操作//2个参数,第一个参数是文件名称,第二个参数是实体类EasyExcel.read(fileName, UserData.class, new ExcelListener()).sheet().doRead();}
}

执行上述方法,打印信息如下:

表头{0=姓名, 1=年龄, 2=生日}
****UserData(username=张三, age=22, birthday=Wed Oct 11 00:00:00 CST 2000)
****UserData(username=李四, age=23, birthday=Mon May 03 00:00:00 CST 1999)
读取Excel完毕

最先是打印了表头信息,这里也可以看到表头的排序是从0开始的。然后,读取并打印了对应的Excel内容,两条数据;最后,执行读取完的方法中的日志打印。

看完了上面的整个操作,解析Excel是不是变得非常简单了?再也不为解析Excel犯愁了。

其他相关特殊用法

上面提到的@DateTimeFormat注解可转换日期格式,还有其他类似功能的注解和自定义转换器。

自定义转换器

通过自定义转换器,比如将1、0转换成男、女的实例:

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;public class SexConverter implements Converter<Integer> {@Overridepublic Class<Integer> supportJavaTypeKey() {return Integer.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}@Overridepublic Integer convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {return "男".equals(cellData.getStringValue()) ? 1 : 0;}@Overridepublic CellData<String> convertToExcelData(Integer integer, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {return new CellData<>(integer.equals(1) ? "男" : "女");}
}

性别属性注入SexConverter转换器:

@ExcelProperty(value = "性别", converter = SexConverter.class)
private Integer sex;

再次生成Excel,性别字段内容便显示为:男、女字样。

保留两位小数

比如体重需要保留两位小数,可通过@NumberFormat 注解实现:

@ExcelProperty(value = "体重KG")
@NumberFormat("0.##") // 会以字符串形式生成单元格,要计算的列不推荐
private BigDecimal weight;

另外一种方法是使用@ContentStyle注解:

@ContentStyle(dataFormat = 2)
private BigDecimal weight2;

这样也能达到保留两位小数的效果。

当然,也可以使用实现Converter接口的方式实现(同性别实现)。

排除指定Excel列

在很多场景下,Excel的列与实体类可能并不完全一致,这时就需要排除一些实体类的字段。

方式一:类上加注解 @ExcelIgnoreUnannotated,过滤属性没有@ExcelProperty注解的字段

@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor  // 一定要有无参构造方法
@ExcelIgnoreUnannotated
public class UserData {.....
}

方式二:指定字段加@ExcelIgnore注解

@ExcelIgnore // 该字段不生成excel
private String remark;

方式三:代码指定过滤字段,通过excludeColumnFiledNames方法:

EasyExcel.write(fileName, UserData.class).sheet("学生信息表").excludeColumnFiledNames(Arrays.asList("remark")).doWrite(getData());

这种方法的好处是:同一Excel可以在调用方法时排除不同的数据列。

小结

本文介绍了EasyExcel的使用,整体而言操作简单、使用方便,提供了不少注解,方便与实体对象之间的关系绑定。而且官网也提供了相关的性能数据,更多的API使用大家还可以继续探索。

无论从性能或易用性上来说,都值得你尝试。特别是临时写一个Excel的解析或生成的工具,再也不用惆怅一行行的解析了,赶紧收藏用起来吧。

70c8218282b2a1055d1e91e3d3cdb540.gif

往期推荐

7dca4f63ee9102480c7a457f7044d4f8.png

实战:10 种实现延迟任务的方法,附代码!


d1454482462f64b9d3e54b99db032575.png

最简单的6种防止数据重复提交的方法!(干货)


7dc63ecb53dfceef30185b947c804910.png

Spring Cloud OpenFeign 的 5 个优化小技巧!


28058439873e178baef7d519d6bc1829.gif

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

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

相关文章

Java Date hashCode()方法与示例

日期类hashCode()方法 (Date Class hashCode() method) hashCode() method is available in java.util package. hashCode()方法在java.util包中可用。 hashCode() method is used to retrieve hash code of this Date object. hashCode()方法用于检索此Date对象的哈希码。 has…

eclispe快捷键

快捷键无效解决办法&#xff1a; 1、考虑是否被其他应用占用&#xff0c;如QQ&#xff0c;QQ音乐&#xff0c;千千动听等 2、在eclispe查看是否被修改&#xff1a;Window->Preferences->General->Keys 快捷键&#xff1a; 1、复制当前行到下一行&#xff1a;CtrlAlt↓…

【端午】送3本书!

白天在公司搬砖&#xff0c;晚上到家赶紧给小伙伴们安排一波福利&#xff0c;这次送的书是 H 大新出的《深入理解Java核心技术&#xff1a;写给Java工程师的干货笔记&#xff08;基础篇&#xff09;》。书中介绍了普通Java工程师必须要学习的相关知识点&#xff0c;包括面向对象…

java bitset_Java BitSet length()方法与示例

java bitsetBitSet类的length()方法 (BitSet Class length() method) length() method is available in java.util package. length()方法在java.util包中可用。 length() method is used to return the length of this BitSet otherwise it returns 0 when this BitSet is &qu…

SpriteBuilder物理对象的父子关系

注意:打开物理使能(Physics-enabled)的节点忽略他们的父节点关系. 这意味着,一个物理使能的子节点不会随着其父节点移动. 物理引擎对于节点父子关系这个概念毫不知情,因此单独的对待所有物理使能的节点,意味着这些节点与其他节点相互独立. 我强烈建议你在设计所有复杂物理对象的…

面试突击51:为什么单例一定要加 volatile?

.作者 | 磊哥来源 | Java面试真题解析&#xff08;ID&#xff1a;aimianshi666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;单例模式的实现方法有很多种&#xff0c;如饿汉模式、懒汉模式、静态内部类和枚举等&#xff0c;当面试官问到“为什…

kotlin 扩展类的功能_Kotlin程序| 扩展功能功能

kotlin 扩展类的功能扩展功能 (Extension function) Kotlin provides the ability to add more functionality to the existing class without inheriting them. Kotlin可以在不继承现有类的情况下为其添加更多功能。 This is done via a special declaration called "Ext…

聊聊保证线程安全的10个小技巧

前言对于从事后端开发的同学来说&#xff0c;线程安全问题是我们每天都需要考虑的问题。线程安全问题通俗的讲&#xff1a;主要是在多线程的环境下&#xff0c;不同线程同时读和写公共资源&#xff08;临界资源&#xff09;&#xff0c;导致的数据异常问题。比如&#xff1a;变…

Raid控制器

转载于:https://blog.51cto.com/xuepengdou/1699799

并行计算机架构_计算机科学组织| 并行处理

并行计算机架构并行处理 (Parallel Processing) Parallel processing is processing of the data concurrently. We process the data concurrently to fulfill the demands of the increasingly high performance so that to achieve better throughput instead of processing…

15个必知的Mysql索引失效场景,别再踩坑了!

背景 无论你是技术大佬&#xff0c;还是刚入行的小白&#xff0c;时不时都会踩到Mysql数据库不走索引的坑。常见的现象就是&#xff1a;明明在字段上添加了索引&#xff0c;但却并未生效。前些天就遇到一个稍微特殊的场景&#xff0c;同一条SQL语句&#xff0c;在某些参数下生效…

网站高可用数据

网站高可用数据1、CAP原理&#xff1a;数据一致性&#xff0c;数据可用性&#xff0c;分区耐受性&#xff0c;无法同时满足2、数据备份a、冷备份b、热备份1、同步热备份2、异步热备份3、失效转移a、失效确认b、访问转移c、数据恢复转载于:https://blog.51cto.com/hanchengen/17…

运维工程师常见软件故障_软件故障 软件工程师

运维工程师常见软件故障软件故障 (Software Failure) A failure that shows up when the user recognizes that the software has come to bring to an end to deliver the anticipated result with respect to the specification input values. The user may need to identify…

干掉 Swagger UI,这款神器更好用、更高效!

事情是这样的&#xff1a;今天我们公司的后端说他接口写完了&#xff0c;并分享了一个接口文档给我。用的就是 Swagger UI 自动生成的那种接口文档&#xff0c;就像这种&#xff1a;这种 Swagger UI文档我每次看着就头大&#xff0c;毛病多多查看多级模型时要一级级点开在接口数…

Android UI ActionBar功能-ActionBarProvider的使用

分享功能是很多App都有一个功能&#xff0c;ActionBarProvider可以实现分享功能&#xff1a; 3.0以前的版 本和3.0以后的版 本的区别&#xff1a; public class MainActivity extends Activity {private ShareActionProvider provider;Overrideprotected void onCreate(Bundle …

ruby 类方法与实例方法_Ruby Set相交? 实例方法

ruby 类方法与实例方法Ruby Set相交&#xff1f; 方法 (Ruby Set intersect? Method) intersect?(Set) method is a method which is predefined in Rubys library. You may call this method as an exact opposite of Set.disjoint?() method. With the help of this metho…

面渣逆袭:MyBatis连环20问,这谁顶得住?

大家好&#xff0c;今天我们的主角是MyBatis&#xff0c;作为当前国内最流行的ORM框架&#xff0c;是我们这些crud选手最趁手的工具&#xff0c;赶紧来看看面试都会问哪些问题吧。基础1.说说什么是MyBatis?MyBatis logo先吹一下&#xff1a;Mybatis 是一个半 ORM&#xff08;对…

Wi-Fi 协议和数率?

IEEE 802.11Wi-Fi 协议摘要 协议 频率 信号 最大数据速率 传统 802.11 2.4GHz FHSS 或 DSSS 2Mbps 802.11A 5GHz OFDM 54Mbps 802.11B 2.4GHz 人力资源DSSS 11Mbps 802.11G 2.4GHz OFDM 54Mbps 802.11n 2.4 或 5GHz OFDM 600Mbps(理论值) 802.11AC 5…

as_hash ruby_Ruby中带有示例的Hash.keep_if方法

as_hash rubyHash.keep_if方法 (Hash.keep_if Method) In this article, we will study about Hash.keep_if Method. The working of this method can be predicted with the help of its name but it is not as simple as it seems. Well, we will understand this method wit…

高并发下如何防重?

前言最近测试给我提了一个bug&#xff0c;说我之前提供的一个批量复制商品的接口&#xff0c;产生了重复的商品数据。追查原因之后发现&#xff0c;这个事情没想象中简单&#xff0c;可以说一波多折。1. 需求产品有个需求&#xff1a;用户选择一些品牌&#xff0c;点击确定按钮…