POI解析Excel之应用反射等技术实现动态读取

技术要点及难点分析

源码分析

测试用例

 

 

背景

Tip:因为产品提的需求我都开发完了,进行了项目提测;前天老大走过来说:你用spring-boot开发一个解析Excel的jar包.....详细对话如下:

A:世生,你用spring-boot开发一个解析Excel的jar包。

B:为什么不在原来的项目上进行开发呢?(很纳闷,这个东西不是一般用于前端上传数据的嘛,这是后端层,咋搞这个)

A:因为家庭医生这个需求有比较多的数据需要初始化,这个jar是作为一个上线的数据初始化脚本

B:嗯,好的

 

 

技术选型

   毕竟是第一次写解析Excel代码,问了度娘说是有两种方式可以做到。一是利用wso2的jxl解析二是利用apache的poi解析;我去maven repository官网搜索了这两个jar包,对比了下jml的最新版本是2.6.12竟然是2011.05月更新的,而poi的最新版本是4.0.x是2018.08更新的;个人觉得jml最新版本都是2011.05更新的,相对于apache的poi包来说更不靠谱;不断持续更新的开源项目或者开源jar包不管是bug还是兼容性相对来说是越来越好。所以最终选定用apache大佬的poi进行开发。

 

 

问题分析

  解析Excel的关键点是在于从Excel表格中读取数据到内存(解析Excel),然后可能是校验数据、通过业务逻辑分析数据、最终持久化到数据库中;其实这其中最重要的不是解析Excel,而是将解析出的数据持久化到数据库中以备有用之需。而解析Excel的这块功能只能算是一个Util类,不能与业务代码耦合一起;然后我看到很多的Excel解析相关的代码都是在解析数据中混淆业务代码逻辑,其实这些都是不可取的,这会导致解析Excel逻辑与业务逻辑相耦合也就是冗杂、代码重用率低、可扩展性低等问题。因为之前在做项目的时候遇到过一个问题:我负责的模块是一个中间模块(通讯采用Dubbo),其他系统要依赖我这个接口进行请求的转发可我调用其他系统返回的结果对象却各个都不同,我叫其他系统负责人说要统一调用接口返回的对象,但是其他系统的负责人都不是同一个人执行起来效率太低了,在历经一个星期都无果的情况下我只能撒下自己的杀手锏了;在这种极端条件下最终我不管其他数据的接口返回的对象是什么,我直接用Object接收返回类型,通过反射获取决定请求成功与否的属性值(欣慰的是当时必传属性值倒是一样的)。通过这种方法我可以少些很多的代码(当时其他系统有15+),不然的话每调用不同系统的接口我都需要进行逻辑判断或者是干脆对于调用他们不同的系统我采用不同接口进行转发,但选用这种方法却便利多了。

  以上问题分析及一个场景的描述很好理解,但是通过Object接收返回信息得这个场景事实上却有所欠佳;返回对象不同的这个问题最好的处理方案就是统一接口,我那个方案是在需求推动但别人无法及时配合的极端条件下使用的,是没办法中的办法,但这也是一个没有办法中的一个最优的处理方案,兼容性比较强。以下我就用图来分析这两种情况的比较:

  1.非动态模式:将Excel数据加载到内存与业务代码逻辑混合,数据在解析期间交叉传递。弊端:每新增一个需要解析的Excel,解析Excel代码块就需要重新开发,代码复用率底下、可扩展性也低。

  

POI解析Excel之应用反射等技术实现动态读取

 

  2.动态模式:将Excel数据加载到内存与业务代码逻辑分开;Excel数据加载到内存之后才将数据传递给业务代码逻辑处理,解析Excel与业务代码之间分开;优点:将解析Excel的这部分代码封装为一个ExcelUtil,代码复用率明显提高,而且解析与业务代码间实行解耦,可扩展性增强。

       

POI解析Excel之应用反射等技术实现动态读取

 

技术要点及难点分析

  要实现动态解析,实现解析与业务代码逻辑相解耦;那么我们不难会想起一个Java的一个关键技术-Reflection(反射原理),Python、Ruby等是动态语言而理论上Java是一门静态语言,但是Java引入了Reflection技术实现了动态性。反射原理我们都比较熟悉,就是在运行期间动态获取类的所有属性及其方法,可以对这些数据进行相关的操作。以上动态解析Excel的实现就需要用到Java这项的高级技术了,通过这项技术可以实现动态解析、解析与业务逻辑解耦等。为了实现动态解析的目的我应用了Java反射技术,但是在开发的过程我发现反射执行一行数据结束的时候如何保存呢?换句话说就是:解析的时候一行的Excel数据封装后就是一个bean,一个Excel表格就是多个bean 即“beans”;如果我们直接将反射执行后的结果保存至List中,当解析整个Excel结束后我们会发现,整个List里面的对象的值完全一样的?what?这是什么原因导致的呢?这就是类似于:Object obj=new Object(),我们每次解析都只是把 obj 放在List中,List中的每一个对象都是同一个 obj(引用不变,实例也不变),所以自然也就相同了;因为当一个类执行反射的时候其实它的运行时状态只有一个,也就是类似于只有一个实例,而传统的解析Excel是解析出一条数据就new一个对象进行封装数据,然后将bean存放至List。然而有什么方法能够解决这一类问题呢?那就是Object 的native clone()方法了,clone()这个大佬是比较牛逼的一个人物,在不创建对象的情况下将属性值复制给另一个对象,具体实现需要实现Cloneable接口并重写clone()。而解决这个问题的方式就是在每解析完一行Excel数据的时候,反射调用该对象的clone方法。动态解析具体实现应用了Apache POI、 LRUCache(LRU缓存)、Reflection(反射)、java的Clone等技术。如果以上技术没有了解过的朋友可以去自行了解,这里不加赘述。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppwjy.html