朱文君 黃國權
摘 ?要: 隨著Java語言越來越多地被選擇用于B/S結構系統的開發語言,利用POI解析技術操作Excel文件越來越廣泛。在POI組件下,采用Java反射機制及自定義注解原理,設計實現了數據庫與Excel文件的數據交互。此方法不僅能保證數據導入的完整性,而且能免去數據導出后重新編輯的復雜性,從而提高POI實現Excel數據導入/導出的靈活性、重用性和易擴展性。
關鍵詞: POI; Excel; 反射機制; 自定義注解; 數據導入導出
中圖分類號:TP312 ? ? ? ? ?文獻標志碼:A ? ? 文章編號:1006-8228(2015)01-38-02
Realization of import and export of data in Excel files by POI based on Java reflection
Zhu Wenjun, Huang Guoquan
(College of Medical Information Engineering, Guangdong Pharmaceutical University, Guangzhou, Guangdong 510006, China)
Abstract: With more and more systems on B/S structure being developed by Java, operating Excel by POI is used more widely. Under POI component, applying Java reflection and custom annotation, data interaction between database and Excel files is designed and realized. This method can not only ensure the integrity of data import, but also avoid the complexity of the data export. Flexibility, re-usability and ductility of using POI in importing and exporting Excel files are improved.
Key words: POI; Excel; reflection; custom annotation; data import and export
0 引言
在Web應用系統中,用戶常會要求將數據庫中的數據導出到Excel表格中,或將Excel表格中的數據導入到數據庫中[1]。然而,傳統的Excel數據導入導出技術,對于不同的對象,都需要重新配置固定的表頭并且頻繁更改關鍵代碼算法,導致程序員操作過于繁瑣。本文介紹一種基于Java反射機制原理,只需要配置自定義注解,而無需更改關鍵代碼算法的Excel導入導出技術。
1 Java反射機制簡介
Java反射機制是指Java語言在運行時擁有的一項自審的能力,對自身進行檢查,并能直接操作程序的內部屬性[2]。即在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性。通過采用該機制來實現對自己行為的描述和檢測,并能根據自身行為的狀態和結果,為下一步的動作做準備[3]。
也就是說,Java反射機制提供了一種在運行中獲得類信息并構建類的Class對象和生成類的實例的機制。同時,使程序代碼能夠訪問裝載到JVM中的類的內部信息,主要包括:已裝載類的字段、方法和構造函數的信息,并允許編寫處理類的代碼[4]。
2 輔助類
2.1 ExcelAnnotation.java
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelAnnotation {
String title();
int order();
}
ExcelAnnotation注釋采用自定義注解技術,可在實體model類上的字段get()方法上注釋,同時設定屬性所對應的title(標題)、order(順序)。通過設定@Retention(RetentionPolicy.RUNTIME),該注釋會在Class字節碼文件中存在,在運行時可通過反射機制獲取該注釋的屬性。沒有注釋的實體model類的字段將不受影響,有注釋的實體model類的字段將會根據title的值輸出標題,并且根據order的值進行排序。從而在不需要預定義模板的情況下,實現Excel表格的表頭的動態輸出,提高了功能模塊的靈活性。
2.2 ExcelHeader.java
public class ExcelHeader implements Comparable
private String title;
private int order;
private String methodName;
……
public int compareTo(ExcelHeader eh) {
return order>eh.order?1:(order public ExcelHeader(String title, int order, String methodName) { super(); this.title = title; …… } } ExcelHeader類用來存儲Excel標題的對象,通過該類在反射機制中可以動態獲取標題和方法的對應關系。同時,該類實現Comparable接口,重寫了public int compareTo()方法。通過調用Collections.sort()方法,可根據order的值進行標題的排序,從而實現Excel表格的表頭的靈活配置。 3 主類 3.1 Excel數據導出 傳統的Excel數據導出技術,只能根據數據持久層或業務邏輯層中已經由程序員寫好的sql查詢語句導出規定的數據,不能滿足用戶的自定義需求。引用Java反射機制后,通過BeanUtils.getProperty()方法,根據加載類對象和字段名便可以動態獲得對應的屬性值,因此,不需要更改關鍵代碼的算法,減少了程序員的操作,同時也提高了功能模塊的重用性。 以下為Excel數據導出的關鍵代碼: private List List //通過反射機制,能訪問model對象表示的類的所有方法 Method[] methods=model.getDeclaredMethods(); for (Method m:methods) { String mn=m.getName(); if (mn.startsWith("get") ) { //通過反射機制,判斷注釋存在于方法上,篩選出指定的數據集 if (m.isAnnotationPresent(ExcelAnnotation.class)) { ExcelAnnotation ea=m.getAnnotation(ExcelAnnotation.class); headers.add(new ExcelHeader(ea.title(),ea.order(), mn)); } } } return headers; } getHeaderList()方法首先通過反射機制,獲取實體model類的所有方法,然后通過自定義注解技術獲取存在于方法上的注釋,并且把注釋的內容添加到headers對象中,從而動態的綁定標題和方法的對應關系。 private Workbook exportExcel(List objs, Class model) { …… List Collections.sort(headers); //輸出表頭 for (int i=0; i cell1.setCellValue(headers.get(i).getTitle()); } //輸出對象信息 for (int i=0; i …… obj=objs.get(i); for (int j=0; j Cell cell2=r.createCell(j); setDefaultCellStyle(cell2, cellStyle); //通過反射機制,調用加載類對象和字段名獲取對應的屬性值 cell2.setCellValue(BeanUtils.getProperty(obj, getMethodName(headers.get(j)))); …… } exportExcel()方法通過調用getHeaderList()取得headers對象中標題和方法的對應關系。通過反射機制,調用加載類對象和字段名獲取對應的屬性值,從而動態的綁定表頭和屬性值的映射關系。最后,通過Workbook對象傳值調用POI生成Excel表格方法,便實現將數據庫中的數據導出到Excel表格中。 3.2 Excel數據導入 傳統的Excel數據導入技術,需要程序員在數據持久層或業務邏輯層中手動組合sql插入語句。數據處理效率過低,并且容易導致數據處理出錯。引用Java反射機制后,通過BeanUtils.copyProperty()方法,把字段名和對應的屬性值復制到加載類對象中,調用數據持久層的存儲操作即可。同樣,不需要更改關鍵代碼的算法,體現了功能模塊的重用性。 以下為Excel數據導入的關鍵代碼: private Map Class model) { List (model); for (Cell c:titleRow) { String title=c.getStringCellValue(); for (ExcelHeader eh : headers) { if (eh.getTitle().equals(title.trim())) { maps.put(c.getColumnIndex(), eh.getMethodName() .replace("get", "set")); …… return maps; } getHeaderMap()方法首先獲取Excel表格中的表頭,然后通過與實體model類中注釋的標題作對比,若一致,則把標題的順序和對應的方法名添加到maps對象中。 public List int read, int tail) { …… List objs=new ArrayList Map if (maps==null || maps.size()<=0) throw new RuntimeException("要讀取的Excel表格的格式不正確, 請檢查標題欄順序!"); for (int i=read+1; i<=sheet.getLastRowNum()-tail; i++) { row=sheet.getRow(i); //通過反射機制,只能調用無參數的構造方法,篩選出指定的數據集 Object obj=model.newInstance(); for (Cell c:row) { int ci=c.getColumnIndex(); //對方法名進行改造,形成字段名 String mn=maps.get(ci).substring(3); mn=mn.substring(0, 1).toLowerCase()+mn.substring(1); Map Object>(); //通過反射機制,把字段名和對應的屬性值復制到加載類對象中 BeanUtils.copyProperty(obj, mn, this.getCellValue(c)); } …… } readExcel()方法通過調用getHeaderMap()取得Excel表格中的標題和對應實體model的方法名的對應關系。通過反射機制,把字段名和Excel表格中對應的屬性值復制到obj對象中,形成實體model類的復制類。最后,通過objs集合傳值調用數據持久層的存儲操作,實現將Excel表格中的數據導入到數據庫中。 4 結束語 反射是Java語言中一個非常突出的動態相關機制。在使用Java語言開發出靈活、高重用及易于擴展的系統的過程中,反射機制起到越來越關鍵的作用[5]。本文通過對基于Java反射機制的POI實現Excel數據導入導出的研究,減少了程序員的手工操作,帶來了極大的方便。該方法在實際中得到應用,取得了較好的效果。 本文創新點:第一,在Web應用系統中,只需要本文中所提及的三個封裝類,即ExcelAnnotation注釋、ExcelHeader類及ExcelUtil類便可以實現其功能,體現了功能模塊的松耦合性;第二,只需為實體類配置ExcelAnnotation注釋,在不需要預定義模板的情況下,實現Excel表格的表頭的動態輸出,體現了功能模塊的靈活性;第三,在實體類沒有外鍵關聯的情況下,不需要更改關鍵代碼的算法,體現了功能模塊的重用性。當實體類存在外鍵關聯時,只需調用數據持久層的查詢操作修改屬性值即可,體現了功能模塊的易擴展性。 參考文獻: [1] 戴維.POI實現Excel的數據導入導出的研究[J].科技信息,2013.1: 107 [2] Bruce Eckel.Thinking in Java[M].4.American:Prentice Hall PTR, 2006. [3] 王善發,吳道榮.Java語言的反射機制[J].保山學院學報,2011.5:32 [4] 王開,譚翼,周蘭江.Java中反射機制淺析及應用[J].計算機教育, 2007.1:255 [5] 尹松強,傅鸝.Java反射機制探究[J].軟件導刊,2008.7(11):85