一种基于Java注解和反射机制的Excel文件读写操作方法

2020-04-27 06:48朱虎平艾迪
九江职业技术学院学报 2020年1期
关键词:数组底层实例

朱虎平,艾迪

(九江职业技术学院,江西九江 332007)

0 引言

随着信息化办公的不断普及,大量日常生产和管理过程中产生的数据都会通过各种应用软件来管理,这极大地提高了工作效率。但在应用软件需要从外部批量导入或向外部批量导出数据时,若采用人工方式进行逐条操作,则工作烦琐、效率低下又容易出错,而如果能借助Excel办公软件,凭借其强大的数据处理能力,则能获得事半功倍的效果。

在Java应用软件中,要对Excel文件进行操作,常用的开源工具有JexcelAPI〔1〕(简称jxl)类库。长期以来,各类文献及应用软件,针对Jxl的Excel文件读写操作都是以Jxl的API接口为实现方法,直接根据应用软件的业务规则定制编写Excel读写的模块,从而实现Java应用软件与外部Excel文件进行数据批量导入导出的操作。这种紧耦合的集成方法只能够实现对固定业务的需求,而对于不同业务间的需求变化只能通过代码重构才能实现。由于业务规则与Excel读写操作掺杂在一起,形成了一定的相互依赖,致使软件代码可维护性和扩展性变得更加困难,并且难以及时适应新的需求变化。

因此,在数据已成为各种应用软件的核心情况下,基于jxl工具类库,研究并实现一种针对Java应用软件与Excel文件进行数据交互的松耦合编程方法,就显得尤为有价值和意义了。

1 基于jxl工具类库的Excel文件读写操作的传统实现步骤

Jxl是一款优秀的开源Java API, 通过它Java研发人员可以较为方便、快捷地读取和新建Excel文件。简单常用的方法和接口有Workbook、Sheet、Cell、Label、WritableWorkbook、WritableSheet、WritableCell等。读写具体步骤如下。

1.1 从Excel中读取指定Sheet工作表的方法

第一步:InputStream is = new FileInputStream(ExcelFile);

第二步:Workbook readBook = Workbook.getWorkbook(is);

第三步:Sheet readSheet = readBook.getSheet(index);

第四步:Cell cell = readSheet.getCell(row,col);

第五步:String content = cell.getContents();

第六步:is.close()、readBook.close()。

1.2 在Excel文件中创建指定Sheet工作表及写入数据的方法

第一步:OutputStram os = new FileOutputStream(ExcelFile);

第二步:WritableWorkbook writeBook=Workbook.createWorkbook(os);

第三步:WritableSheet writeSheet = writeBook.createSheet (“SheetName”, index);

第四步:Label label = new Label(row, col,“Label cell”);

第五步:writeSheet.addCell(label);

第六步:writeBook.write();

第七步:os.close()、writeBook.close()。

图1 Jxl API读取Excel文件操作

图2 Jxl API写入Excel文件操作

以上两种基于Jxl API直接读取和创建Excel文件的操作方法,长期以来,一直是各类文献及Java应用软件根据业务规则定制实现Excel文件读写操作的最终解决方案。该方案虽然有效解决了Java应用软件与Excel文件间的数据交互问题,但却是通过在应用软件中直接控制Excel文件中每一个Cell单元格读写操作实现的。这种Excel文件底层具体读写过程与应用软件高度耦合的编程方式,是计算机软件工程思想所不推崇的解决方案。

2 基于Java注解与反射机制的改进型Excel文件读写操作方法设计

基于上述传统方案的优缺点,本文在Jxl API直接读取和创建Excel文件的基础上,结合Java注解和Java反射机制〔2〕,利用面向对象编程技术,提出了一种全新的将Java应用软件业务规则与Excel文件底层读写操作分离的松耦合编程思想,并成功实现了Java应用软件与Excel文件底层读写操作分离的松耦合编程设计。

注解也叫元数据,是JDK1.5版本开始引入的一个特性,其为用户提供了@Retention、@Target、@Inherited等元注解和@interface自定义注解方法,可对代码中的package、types(类、接口、枚举)、类型成员(构造方法、方法、成员变量)、方法参数等进行注解〔3〕。通过@interface自定义注解方法,用户编写代码时可依据业务规则灵活自定义注解,并利用@Retention、@Target、@Inherited等元注解对自定义注解进行注解;再根据自定义注解与Java反射机制有机结合,可实现在程序动态运行时通过元数据动态处理〔4〕,为注解所在class实时反射注入class实例。

Java反射机制是Java被视为动态语言的一个关键性质,该机制允许Java程序在运行时透过Reflection APIs取得任何一个在运行时加载、探知、使用编译期间完全未知的classes的内部信息〔5〕,可在程序运行时动态生成class对象实体,并可于运行时改变其fields内容或唤起methods。

2.1 改进型Excel文件读写操作中的注解与反射机制设计步骤

2.1.1 用@interface自定义注解MyAnnotation

2.1.2 创建JavaBean类

① 属性字段声明:字符串类型,且命名与Excel文件中的待读取/待写入列一一对应;

② 属性字段注解:用自定义注解MyAnnotation对属性进行注解,注解赋值与Excel文件中待读取/待写入列的列名相同。

图3 JavaBean类

图4 自定义MyAnnotation注解

2.2 改进型Excel文件读写操作中的底层Jxl读写封装

2.2.1 读取Excel文件中指定Sheet工作表内容的操作

创建Excel文件读取类ExcelReadHandle,通过构造方法参数传入JavaBean.class、待读取的Excel文件以及Sheet工作表编号。该类采用注解和反射机制封装Excel文件的底层读取操作,将从Excel文件Sheet工作表中读取到的选定列数据封装成JavaBean对象,并以List对象数组的形式返回给应用程序。

(1)采用注解机制获取Excel文件指定Sheet工作表中待读取列的列名及列号。

1)读取Excel文件,获得指定Sheet工作表所有列的列名,并将其逐一存入字符串数组titles[]中;

2)采用注解机制,运态获取JavaBean.class中各属性的MyAnnotation注解,并将每个属性的MyAnnotation注解值定义为Key、属性对应的setter方法名定义为Value,然后逐一存入Map(Key,Value)类型的map对象,再将map对象添加到List类型的list数组中;

3)遍历titles[]和list数组,将titles[]中的列名与list中map对象的注解值Key进行匹配,相等时的列名即为Excel文件Sheet工作表中待读取的列,并将该列名在titles[]中对应的下标号index和map对象中对应的setter方法名存入List数组cols[{index,setter}]中。

(2)采用反射机制,动态生成JavaBean.class实例对象obj,然后逐行读取Excel文件中指定Sheet工作表的列字段信息,并赋值给实例对象obj的相应属性。

1)读取Excel文件,逐行获得指定Sheet工作表的列字段信息,并将每一行的列字段信息保存到字符串数组contents[]中;

2)利用反射机制,动态生成JavaBean.class实例对象obj,并添加到List数组中;

3)逐一读取数组cols[{index,setter}]中下标值index和setter方法名,然后根据index获取contents[]中的值content,并采用反射机制JavaBean.getMethod(setter,String.class).invoke(obj,content)进行动态赋值,即将读取到的Excel文件Sheet工作表内容逐一赋值给JavaBean对象的相应属性;

4)循环执行步骤1)2)3),直到Excel文件中指定的Sheet工作表所有行都读取完毕,最后向应用程序返回List对象数组,即,List对象数组为应用程序读取到的Excel文件内容。

图5 ExcelReadHandle类读取Excel文件时序图

2.2.2 写入Excel文件中指定Sheet工作表的操作

创建Excel文件写入类ExcelWriteHandle,通过构造方法参数传入JavaBean.class、待写入的List对象数组、待写入的Excel文件和Sheet工作表编号。该类采用注解和反射机制封装Excel文件的底层写入操作,将应用程序List数组中的JavaBean对象属性值写入Excel文件的指定Sheet工作表中。

(1)从JavaBean.class属性注解获取待写入Excel文件中指定Sheet工作表列名及属性对应的getter方法名。采用注解机制,运态获取JavaBean.class中各属性的MyAnnotation注解,并将每个属性的MyAnnotation注解值定义为Key、属性对应的getter方法名定义为Value,然后逐一存入Map(Key,Value)类型的map对象,再将map对象添加到List类型的list数组中;其中,属性的注解值Key即为待写入的Excel文件中指定Sheet工作表的列名。

(2)遍历list数组,将list中map对象的注解值Key,写入Excel文件中,生成Excel文件中指定Sheet工作表的列名。

(3)读取List中的实例对象obj,然后遍历list数组获取map对象中的getter方法名,对每一个getter方法名,都采用反射机制JavaBean.getMethod(getter).invoke(obj)获得实例对象obj中的属性值content,并将content值写入Excel文件的指定Sheet工作表中。

(4)重复执行步骤(3),直到List中所有实例对象全部获取完毕,即完成了将应用程序List对象数组的全部属性值写入Excel文件的操作。

图6 ExcelWriteHandle类写入Excel文件时序图

3 基于Java注解与反射机制的改进型Excel文件读写操作的实现步骤

3.1 读取Excel文件中指定Sheet工作表的操作

第一步:用@interface自定义注解MyAnnotation;

第二步:根据Excel文件中指定Sheet工作表的待读取列,创建与Sheet列名相对应的JavaBean类,并用Sheet中待读取列名对JavaBean属性进行MyAnnotation注解;

第三步:调用public ExcelReadHandle(Class clazz,File file)构造方法,创建Excel文件的读取操作的实例对象,然后通过该实例对象中的public List handle(int sheetIndex)方法,既可读取Excel文件中指定的Sheet工作表内容。

3.2 写入Excel文件中指定Sheet工作表的操作

第一步:用@interface自定义注解MyAnnotation;

第二步:根据Excel文件中指定Sheet工作表的待写入列,创建与Sheet列名相对应的JavaBean类,并用Sheet中待写入列名对JavaBean属性进行MyAnnotation注解;

第三步:调用public ExcelWriteHandle(Class clazz, File file)构造方法,创建Excel文件的写入操作的实例对象,然后通过该实例对象中的public void handle(List list, int sheetIndex)方法,将应用软件中List对象数组的全部属性值写入Excel的指定Sheet工作表中。

通过以上读写操作步骤,可以发现基于Java注解与反射机制的改进型Excel文件读写操作方法,对于Excel文件的读写操作,只需根据应用软件业务规则创建注解、JavaBean类,然后分别调用ExcelReadHandle或ExcelWriteHandle,即可实现读写操作。该方法完全不用关心底层的Jxl API工作方式,成功实现了应用软件中Excel导入导出操作与Jxl API具体读写过程的高度解耦。

图7 基于Java注解与反射机制的改进型Excel文件读写操作步骤

4 结束语

基于Java注解与反射机制的改进型Excel文件读写操作方法,使得应用软件在读取Excel文件时完全不用了解底层Jxl API的工作方式,实现了应用软件中Excel导入导出操作与Jxl API具体读写操作的高度解耦。该方法操作方便、简单易用,针对当今大量应用系统都需要从外部Excel文件中批量导入或导出数据的实现方式,无疑将是一项具有积极意义的技术革新,也必将给软件研发和维护人员在Excel读取方面带来极大的方便。

猜你喜欢
数组底层实例
航天企业提升采购能力的底层逻辑
JAVA稀疏矩阵算法
JAVA玩转数学之二维数组排序
更高效用好 Excel的数组公式
寻找勾股数组的历程
完形填空Ⅱ
完形填空Ⅰ
回到现实底层与悲悯情怀
中国底层电影研究探略
略论“底层”