Java - Read Excel to Compose JavaBean by Java Reflection

之前曾經發過一篇關於觀察者模式的範例,裡面所讀取的檔案為txt檔,所定義的資料格式

雖然簡單,但是編輯方式並不方便。因此在這邊將以讀取Excel檔的方式,並且自動組成

JavaBean,透過Excel檔內的第一列設定JavaBean的成員變數名稱,並且搭配程式產生的

HashMap,為成員變數對應它的setter method,如此一來再透過Java Reflection就可以自動組

出相關的JavaBean Object。

txt檔資料格式如下:

資工系,男,21,小彬
經濟系,女,19,小花
建築系,男,23,小勇
國貿系,男,21,小金
中文系,女,20,小琪
歷史系,男,18,小強
財金系,女,24,小雯
畜產系,男,23,小維
哲學系,男,25,小茂
外文系,女,20,小琳

xls檔資料格式如下:

承該篇文章,主要多定義了

public List<Participant> LoadParticipantListByXls(File f)

public Map<String, String> getSetterMethod(Class<?> c)

先來說說getSetterMethod的目的,主要是組出JavaBean下成員變數對應setter method的資料

格式,相關程式如下:

public Map<String, String> getSetterMethod(Class<?> c){
    Map<String, String> col2method = new HashMap<String, String>();
    Method[] methods = c.getDeclaredMethods();
    List<String> fields = new ArrayList<String>();
    List<String> fieldsLower = new ArrayList<String>();
    for(Field n : c.getDeclaredFields()){
        fields.add(n.getName());
        fieldsLower.add(n.getName().toLowerCase());
    }
    String colname = "";
    for (Method method : methods){
        if (Modifier.isPublic(method.getModifiers())
            && method.getParameterTypes().length == 1) {
            if (method.getName().matches("^set[A-Z].*")
               && method.getReturnType().equals(void.class)){
               colname = method.getName().toLowerCase().substring(3,
                                method.getName().length());
               for(int i = 0 ; i < fieldsLower.size() ; i++){
                   if(fieldsLower.get(i).equals(colname)){
                       col2method.put(fields.get(i), method.getName());
                   }
               }
            }
        }
    } 
    return col2method;
}

因為我們只針對setter method,因此主要是先判斷是否為public宣告的及set開頭的,同時

為void,如此一來截取出set後的字串,並且與現有的成員變數比對,如果吻合的話,則

put進col2method map內。

再來是LoadParticipantListByXls,跟原先的LoadParticipantList一樣,會回傳一list

相關程式碼如下:
public List<Participant> LoadParticipantListByXls(File f){
    List<Participant> plist = new ArrayList<Participant>();
    Map<String, String> col2method = new HashMap<String, String>();
    Map<Integer, String> col2field = new HashMap<Integer, String>();
    Workbook xlsBook = null;
    Participant bean = null;
    Method m = null;
    try{
        col2method = this.getSetterMethod(Participant.class);
        xlsBook = Workbook.getWorkbook(f);
        Sheet sheet = xlsBook.getSheet(0);
        for(int i = 0 ; i < sheet.getRows() ; i++){
            if(i > 0)bean = new Participant();
                for(int j = 0 ; j < sheet.getColumns() ; j++){
                    if(i == 0)
                        col2field.put(j, sheet.getCell(j, i).
                                            getContents().toLowerCase());
                    else{
                        String val = sheet.getCell(j, i).getContents();
                        if(NumberUtils.isNumber(val)){
                            m = Participant.class.getDeclaredMethod(
                                   col2method.get(col2field.get(j)), int.class);
                            m.invoke(bean, Integer.parseInt(val));
                        }else{
                            m = Participant.class.getDeclaredMethod(
                                   col2method.get(col2field.get(j)), String.class);
                            m.invoke(bean, val);
                        }
                    } 
                }
  if(i > 0){
      plist.add(bean);
      //System.out.println(bean);
  } 
 }   
    } catch(Exception e){
        e.printStackTrace();
    } finally{
        xlsBook.close();
    }
    return plist;
}

在此使用jxl library來讀取Excel檔的資料,除了col2method以外,也定義了col2field來得知

目前的column index為哪個field,如此一來才能夠知道該column的欄位值要做哪個setter。

最後,原程式範例要改寫的地方為

public List<Participant> LoadParticipantList(File f){
List<Participant> plist = new ArrayList<Participant>();

if(f.getName().lastIndexOf(".xls") > 0){
return LoadParticipantListByXls(f);
}
......

}

主要是多加上了這一段,如此一來如果load的檔案為.xls格式的資料,則呼叫

LoadParticipantListByXls來組list。

留言