使用这个工具可以快速地完成excel表格和实体类对象以及Map地转化
可以在maven中引入依赖或者直接在下面的地址下载jar包
github地址是 https://github.com/oraen/excelutil
也可以在https://download.csdn.net/download/pass_JMC/15295871中下载使用说明文档
ExcelUtil使用教程
目录
一 总体介绍
ExcelUtil是一个超轻量级的Excl工具,使用它你只需要一个函数就可以把excel文档对象转化为你自定义的实体类对象或者Map对象,
ExcelUtil是对Apache的Excel工具apache poi的进一步封装,所以你也可以直接使用apache poi的其他一些复杂的功能(比如具体设
置excel文档的样式等)
Excel表格对象和实体类/Map的转换关系示例:
二 核心功能入门
这部分讲解ExcelUtil的入门教程以及核心功能的使用
2.1 引入jar包
如果使用maven管理项目,可以直接引入依赖
<dependency>
<groupId>com.oraen.oxygen</groupId>
<artifactId>excelutil</artifactId>
<version>APPLE-1.1.1</version>
</dependency>
如果你拒绝使用maven,也可以访问
下载jar包(注:X.0.Y的版本只供开发人员测试, 一般无法直接使用)
2.2 创建Workbook对象
首先第一步我们得先把Excel文件(硬盘,或者其他媒介中的IO流)读取出来,生成Workbook对象.,这一步骤我们可以使用Workbook工
厂生成代表Excel文件的Workbook对象
1:从硬盘中获取 Workbook wb = WorkbookFactory.create(new File(“全路径名”));
2:从IO流中获取 Workbook wb =
WorkbookFactroy2. createWorkbook(InputStream 输入流, String文件名);
(注:文件名并不重要,只是要根据后缀名XLSX/XLS判断Excel类型生成对应Workbook对象)
3:通过其他方式获取Workbook对象(查阅API文档)
2.3 解析Workbook对象获取数据
接下来,就是关键了,我们通过ExcelUtil提供的静态方法获取Workbook对象的数据,通过工具提供的api可以获取到文档对应的Map列表
或者是自定义的实体类列表(List)
2.3.1 获取Map列表
为了使我们设计的工具易于在web项目中使用,ExcelUtil解析workbook后生成的的列表实际类型是阿里巴巴的JSONObject类型的对象(即com.alibaba.fastjson.JSONObject类型)的ArrayList列表,
JSONObject实际上是Map<String, Object>的实现类,可以使用List<Map<JSONObject >> 来接收,实际上JSONObject内部存储的键和值存储的都是String类型的数据,对于不知道JSONObject的,
直接把他当作Map使用就好了.
(注:由于java泛型语法的限制,并不能直接使用List<Map<String, Object>>来接收对象)
API函数:List<JSONObject> ExcelUtil.getEntities(Workbook wb);
传入对应的Workbook对象即可返回对应的List<JSONObject>对象,
示例:
Workbook wb = WorkbookFactory.create(new File(“全路径名”));
List<JSONObject> list = ExcelUtil.getEntities(wb);
这样我们便获取到了我们想要的数据,以第一部分总体介绍的例子来说,如果执行
System.out.println(list.toString()); 我们将得到如下结果
[
{"名字":"王小诚","身体情况":"不健康","备注":"伟","身高":"1.65","年龄":"23"},
{"名字":"罗小伟","身体情况":"","备注":"额","身高":"1.56","年龄":"17"},
{"名字":"钟小令","身体情况":"","备注":"","身高":"1.78","年龄":""},
{"名字":"杨小龙","身体情况":"还行","备注":"文","身高":"1.02","年龄":"21"},
{"名字":"","身体情况":"","备注":"呃呃呃","身高":"1.43","年龄":""}
]
只需要两行,我们就能拿到Excel文档的数据了. 然后我们就可以对数据做一些业务操作啦
2.3.2 获取实体类对象列表
Java毕竟是一门面向对象的编程语言,把Excel文档读成实体类对象列表才是大多数人想要的功能. 配合JAP,Mybatisplus等框架把文档录入数据库甚至只需要两行代码. 因为身处China,我们日常生活中要处理的Excel文档往往是中文,而如果我们使用中文做对象的字段名,就可能会导致职业生涯的危机甚至生命危险,所以我们往往需要一个映射关系信息,将文档的字段映射到对象的字段. 最开始我打算使用配置文件(然而并不是XML文件而是JSON文件)来设置,但是实际使用后发现有点麻烦,后面我把他做成了注解形式,果然变得简单方便,现在说一下操作步骤..
第一步:准备好要转换的Excel文档 例如
第二步:编写我们实体类(完全可以和数据库实体类重叠)例如
第三步:为实体类增加@SheetEntity注解, 为实体类的字段增加@SheetField注解
注解说明
@SheetEntity 标识这是一个可以和Excel文档对应起来的对象,必须加
@SheetField 标记Excel文档中对应的字段,按需求增加,注解的属性如下
属性名 | 作用 | 默认值 | 必须指定 |
value | Excel文档中对应的字段名 |
| 是 |
necessity | 是否允许为空值 | false | 否 |
lack | 若为空值时的填充值 需necessity为false才有效 | 空字符串 | 否 |
norm | 值遵循的regexp规则,用于操作器(后面讲)核对字符合法性 | .*(匹配全部字符串) | 否 |
unique | 该字段的值是否唯一,用于操作器(后面讲)核对字符合法性 | false | 否 |
第四步:放心大胆地使用API
API函数:List<Ent > ExcelUtil.getEntities(Workbook wb, Ent ent);
传入目标Workbook对象和要转换的实体类Class对象
Workbook wb = WorkbookFactory.create(new File(“全路径名”));
List<Entt> list = ExcelUtil.getEntities(wb, Ent.class);
现在我们可以尝试看一下list中的内容(使用工具内置的对象显示工具)
System.out.println(DataFormatUtil.str(list))
输出结果
{ "age":"23", "name":"王小诚", "height":"1.65", "qk":"不健康", "alias":"null" }
{ "age":"17", "name":"罗小伟", "height":"1.56", "qk":"良好", "alias":"null" }
{ "age":"55", "name":"钟小令", "height":"1.78", "qk":"良好", "alias":"null" }
{ "age":"21", "name":"杨小龙", "height":"1.02", "qk":"还行", "alias":"null" }
{ "age":"55", "name":"", "height":"1.43", "qk":"良好", "alias":"null" }
解释:
由于age字段设置了默认值是55,钟小令和最后一个无名人士的年龄为空,所以自动赋值了55,
由于alias没有增加对应注解,并不会从文档中获取对应数据,所以都是null,
由于没有字段的value为备注,所以文档中的备注并没有注入对象
如果有一个字段的value文档中不存在,会报错并且返回null
如果我们给age或者name的necessity的值设为true,由于文档中有空白,会报错
文档的头会无视所有回车空格等空白字符
文档的值会无视两边的空白字符
2.4 利用数据生成Workbook对象
既然可以解析Workbook文档对象获取数据,当然也能用已有的数据反向生成Workbook对象了,现在我们对这部分的内容进行讲解,
2.4.1 API介绍
使用的方法非常简单,API主要是一系列的
Workbook getWorkbook(…)函数的重构函数组成,主要参数如下
1:List<T> list(带Class参数): T必须带有文档注解,生成文档带有的数据
2:List<JSONObject> list:与上面参数互斥,生成文档带有的数据
3:final boolean counter: 是否在生成的文档中增加一列序号,并且其值由1开始递增
4:List<String> heads:文档头,一般用于控制文档头的位置关系和显示列,文档的头会按照heads的顺序排序,若counter设置为true,计数列始终会在最前面, heads中没有的字段也不会被写入Excel文档
所有API如下
函数名 | 备注 |
getWorkbook(List<String> heads, List<T> list, Class clazz, boolean counter) | 推荐使用 |
getWorkbook(List<String> heads, List<T> list, Class<T> clazz) | Counter默认false |
getWorkbook(List<String> heads, List<JSONObject> list, boolean counter) | 推荐使用 |
getWorkbook(List<String> heads, List<JSONObject> list) | Counter默认false |
getWorkbook(List<JSONObject> list, final boolean counter) | 不能保证字段顺序 |
getWorkbook(List<JSONObject> list) | 不能保证字段顺序 |
getWorkbook(List<T> list, Class<T> clazz, final boolean counter) | 不能保证字段顺序 |
getWorkbook(List<T> list, Class<T> clazz) | 不能保证字段顺序 |
getTemplate(List<String> head) | 不能保证字段顺序 |
getTemplate(List<String> head, boolean counter) | 不能保证字段顺序 |
2.4.2 实战
由于生成文档和获取数据实际上是个相反的过程,聪明的人很容易就能理解,为了偷懒,对于API的介绍有点简单,为了让大家有更加清晰地认识,我决定加班实际操作一下
1:我们继续使用上文地Ent类,这里省略他的get/set方法
2:创建Ent类实例,并且赋值
Ent e1 = new Ent();
e1.setAge(50);
e1.setHeight(5.6f);
e1.setName("小笨");
e1.setQk("太笨了");
Ent e2 = new Ent();
e2.setName("大牛");
3:生成对应地List和head,我们这里只需要身高,年龄,名字数据
List<Ent> l = new ArrayList<Ent>();
l.add(e1);
l.add(e2);
List<String> head = new ArrayList<String>();
head.add("身高");
head.add("年龄");
head.add("名字");
4:通过数据创建带序号的Workbook对象, 并且把他写入硬盘
Workbook wb = ExcelUtil.getWorkbook(head, l, Ent.class, true);
wb.write(new FileOutputStream(new File("D:\\work\\excelutil\\测试excel\\生成.xlsx")));
5:运行过后,就能看到生成的文件了,如图第一个
6:打开,数据显示正常
说明:考虑到实际业务场景,如果对象一个成员的值为空时,在文档中以空白显示(注意 如果是基础数据类型, 仍然会用默认值填充,如果不希望这样,可以使用包装类)而不会是lack属性表示的默认值,由于我们传入了counter为true,excel表格中添加了序号一列
三 Excelutil高级功能
读了前面两个部分,我们基本能够使用Excelutil的核心功能了,你完全可以只使用这些功能来加速你的开发,但是如果你想要更进一步地加速你的开发甚至简化你的代码,你通过这个部分的学习,了解和学会使用ExcelUtil背后封装的工具,基于职责链模式的数据处理工具以及一系列高效率异常对象Exception的使用
3.1 数据处理工具
ExcelUtil提供了一系列静态数据处理工具用于简化开发,这些工具也是ExcelUtil的重要依赖
3.1.1 通用工具CommonUtil
这个是最底层的通用数据处理工具,而且比较简单 只有两个方法
1 Class<?> getContentType(List<?> col):获取对应列表中的组件的实际数据类型,如果列表中不存在元素,则抛出AccessingEmptyException异常
2 <T> T create(Class<T> clazz):生成对应类型的一个对象(调用其无参构造函数)并且返回,如果构造失败会抛出UnspecificException异常,通常只要满足一下情况便不会失败
1:类型不能是不能实例化的抽象类或者接口
2:类中必须含有public修饰符的无参构造函数
3:调用空构函数时发生了异常但是没有捕获解决
3.1.2 基本数据工具BaseUtil
这个工具封装了一些数据核对方法和对Excel文档和实体数据列表等最基本的操作函数
1:void set(Sheet sheet, int row, int line, String value):为sheet对象的对应单元格赋对应值
2:String get(Sheet sheet, int row, int line): 获取sheet对象对应单元格的值
3:String get(Cell cell): 获取Cell(单元格)对象的值
4:String pure(Cell cell):获取Cell对象去除文字中间空格后的值
5:Map<String, Integer> getItem(Sheet sheet):获取Sheet对象头的Map,key就是字段的字符串,value就是对应字段的索引(从0开始),
6:<T> List<String> getHead(Class<T> clazz):获取对应类型的头
7:List<String> getHead(Sheet sheet):获取对应sheet对象的头
8:<T> void check(Class<T> clazz) :核对对应的类有没有标上SheetEntity注解
9:void check(Object obj):核对对应的对象的类有没有标上SheetEntity注解
10:<T> void check(Sheet sheet, Class<T> clazz) 核对对应的类是否能正确转换成sheet
说明:check在核对失败后都会抛出对应的异常CustomException
3.1.3:数据转换工具DataConvertUtil
这个工具提供数据的转换方法
1:JSONObject transform(Object object) 将一个对象转为Map
2:List<JSONObject> transform(List<?> list) 将一组对象转为Map
3:<T> T transform(JSONObject map, Class<T> clazz) 将Map转化为指定对象
4:<T> List<T> transform(List<JSONObject> list, Class<T> clazz) 将List<Map>转化
3.1.4:数据格式化工具DataFormatUtil
这个工具一般很少使用,大部分功能是为了数据输出使用,常用于调试
1:String visualization(Number number) 返回数据得字符串
2:String visualization(String str) 返回字符串得输出模式”XXX”
3:String visualization(Map<String, ? extends Object> map) 返回Map得输出格式
4:String visualization(Collection<Object> col) 返回集合得输出格式
5:String str(Object o) 返回对象的数据格式
3.2 职责链数据工具Responsibility
在实际业务中,我们从Excel获取数据后,通常要对获取的数据进行检查和修改等操作,所以我们会经常操作获取到的List<Object>或者List<JSONObject>对象
如果业务稍微复杂一点,代码就会显示得臃肿难以维护,我也是在实际业务中遇到这个问题,所以在工具中加了一套基于职责链模式处理数据得工具,增加代码的可维护性
职责链设计思想
每个WorkNode<T>的实现类都可以调用execute(T target, Object... params)方法对数据进行处理,AssemblyLine实际上就是WorkNode的列表类型,调用work(T target, Object... params)
可以依次执行容器内WorkNode元素的执行方法,也可以调用其
addNode(WorkNode<T> workNode)方法增加里面的WorkNode.
3.2.1 工具内置WorkNode
工具里面内置了一些通用的WorkNode实现类,工具内部也是用了他们作为组件来开发,现在先来介绍一下他们
1:UniqueChecker 核对数据集合中是否有相同的元素,如果有重复的元素就抛出 RepetitiveDataException异常在抛出的异常对象
中会包含有重复的记录存储在其成员Set中,其execute方法格式为
Collection<?> execute(Collection<?> target) throws RepetitiveDataException
2:UniqueVerifier 核对传入的实体类集合,判断他们标注有unique属性的字段是否有重复的行,如果有重复,就抛出BreakUniqueException异常,
并且异常对象中带有各个有重复数据的字段以及对应重复的数据,在把Workbook对象解析为实体类数据时,并不会调用该作业,所以如果你想要核
查上传的实体类对象的不可重复字段是否存在重复的数据,就可以用到该这个类,其execute方法格式为
List<?> execute(List<?> target,) throws BreakUniqueException
3:ValueInitializer 核对传入的值和字段,如果这个字段不允许为空但是这个值是空值,抛出BreakNecessityException异常,如果字段允许为空
值(包括纯空格),则按照他们设定的默认值并且返回(如果有).我们在使用Workbook对象生成实体类集合时,在工具内部实际上就是调用
ValueInitializer过滤数据来保证获取的实体类的不可为空的字段判别以及赋默认值的功能.,其execute方法格式为
String execute(String target,Field field) throws BreakNecessityException
4:NormVerifier 核对传入的实体类集合,判断他们标注有norm属性的字段的值是否符合norm对应的规范,如果不符合,就抛出BreakNormException异常对象,
Excelutil在创建实体类的时候并不会自动调用该工具来核对,如果有需要,需要自己调用 其execute方法格式为
Collection<?> execute(Collection<?> target, Object... params) throws BreakNormException
注意,内置的所有WorkNode都使用单例模式来创建对象,其构造函数都是私有的,不可以直接new一个新对象,要获取对象时候需要调用他们各自的静态方法getInstance方法即可
3.2.2 自定义WorkNode
我们也可以定义自己的WorkNode来实现自己的业务功能,并且创建自己的AssemblyLine来管理作业,我们可以创建自己的类,实现WorkNode<T>接口,
T传入你想要处理的数据类型,并且重写T execute(T target, Object... params) throws Exception;方法,target是你想要处理的目标数据,params则是对
应的参数,如果用不到,完全可以不传实参,返回的就是处理后的数据(引用类型可以在处理完数据后返回target, 基本数据类型直接返回改变后的值
即可).在创建了自己的一个或者多个WorkNode实现类后,我们可以直接调用他的execute处理数据,当业务复杂时候,我们可以创建AssemblyLine
对象,通过其addNode和work方法来管理WorkNode和执行作业链,执行顺序也会跟随addNode的顺序,所以,对于复杂的业务,本质上我们需要两步
1:写自己的类实现WorkNode接口,重写其execute方法
2:创建AssemblyLine管理和调用他们
3.3 ExcelUtil的异常体系介绍
ExcelUtil的异常体系其实比较简单(简陋)
CustomException: 附带了抛出异常时候可能会用到的数据信息的异常类,里面的信息存储在一个Map里面,可以通过getDetail方法获取
UnexpectedException:一般是不可能发生的错误,如果发生了,强烈建议联系开发者
UnspecificException:集成了一些比较简陋的错误,一般是显而易见的错误,比如代码问题
AccessingEmptyException: 估计是访问了不该访问的数据
四 项目规划以及联系我(们)
4.1 版本号说明
我们的版本号格式为 时代号-主版本号.次版本号.微版本号,时代版本号是以为首字母顺序为顺序的单词,APPLE首字母是A,说明是第一个时代号,其他的版本号都是整数,下面简单介绍一下这些版本号
微版本号:一般用于当项目有一些小bug的时候做了一些小修改时.只有微版本号不同时工具的API及其对外的功能会一模一样,所以在其他版本号相同时推荐尽量使用较高的微版本号
次版本号:次版本号的增加一般会添加一些新的API,并且不会减少已有的API和修改已有的API功能,所以高版本会兼容低版本,你的代码不变的情况下低版本号变更为高版本号是
不会有任何影响的,通常情况下次版本号为0的是开发者留给自己调试和防止一些意外情况下的,不能使用. 单数次版本号是仅仅根据初步测试后发布的,可能会包含一些bug,双数
版本号是经过多次使用修改后较为成熟的版本,其微版本号一般也相应比较少,所以一般稳重的建议使用双数版本,当时写次文档时候最高仅仅是APPLE-1.1.1,没有双数版本,而
且通常情况下1和2, 3和4, 5和6… 的API是一样的, 有可能1.2.X还没出的情况下1.3.X就出了.
主版本号:主版本的增加一般伴随着较大的变动,大部分情况下依然是高版本向下兼容的,但是可能会有一些API可能会被宣布为弃用,并且增加对应的代替API,有较小的可能会
出现已有的API对外功能发生一些很小的细节变动的情况,所以如果老项目不想用到一些新的功能的话不是很推荐更新主版本号
时代号:只能说项目的名字不变,但是API可能会发生翻天覆地的变化,甚至和之前完全没有什么联系
4.2 后续版本的目标
未来ExcelUtil还会陆陆续续增加一些新的功能,按照目前的规划,在1.3.X版本会增加把Workbook转化成key映射为实体类字段的Map(之前的key是Excel文档中的字段).还会有
其他的一些正在探索的更新.
4.3 联系作者
作者只是个迷茫而略显落魄的大学生,如果你发现了什么bug,或者有什么建议,想要加入开发ExcelUtil,寻找合作,甚至只是想简单地交朋友,都可以通过邮箱联系到作者,
作者地邮箱是1543493541@qq.com, 项目托管在githbub上. 也欢迎大家提交自己的修改,Github的地址是https://github.com/oraen/excelutil.git,