基於Java+Selenium的WebUI自動化測試框架(十一)-----讀取Excel文件(POI)(1)


  上一篇說了利用JXL的jar包來讀取Excel的代碼。在Java中,還可以用另外一種jar包來讀取Excel的內容,那就是Apache的POI。

  這里和之前一樣,需要導入POI的jar包,建議導入這三個:poi-4.0.0.jar,poi-ooxml-4.0.0.jar,poi-ooxml-schemas-4.0.0.jar,

  下載地址:https://mvnrepository.com/search?q=POI

  我們先從最小的概念開始,讀取一個Cell,即Excel中一個“格子”的內容。

private static String getValue(Cell cell) {
        if (null == cell) {
            return "";            
        } else if (cell.getCellTypeEnum() == CellType.BOOLEAN) {
            // 返回布爾類型的值
            return String.valueOf(cell.getBooleanCellValue());
        } else if (cell.getCellTypeEnum() == CellType.NUMERIC) {
            // 返回數值類型的值
            return String.valueOf(cell.getNumericCellValue());
        } else {
            // 返回字符串類型的值
            return String.valueOf(cell.getStringCellValue());
        }
    }

    這里會根據每個格子里的數據類型不同,來獲取不同的值。(這里設置了三種,布爾型,數字型,字符串型)

      然后,根據我們來把整個行的內容存入一個List中。

    private static List<Object> getRow(Row xssfRow) {
        List<Object> cells = new ArrayList<Object>();
        if (xssfRow != null) {
            for (short cellNum = 0; cellNum < xssfRow.getLastCellNum(); cellNum++) {
                Cell xssfCell = xssfRow.getCell(cellNum);
                cells.add(getValue(xssfCell));
            }
        }
        return cells;
    }

  這里的是從行的第1列開始讀,因此,我們在設計Excel表格的時候,需要注意一下。

  不過,在這里我想說的是,我們除了需要讀取Excel的內容外,我們還希望“按需讀取”。什么意思呢?就是說,我們之前是按照Excel的固有格式或者數據結構來讀取內容的,比如我去指定開始/結束行,開始/結束列。

這樣的話,我就必須要知道我要讀取的范圍是什么。但是,一般來說,我們使用Excel的習慣不是這樣的。我們習慣於把某列或某行的數據提取或者過濾出來。舉個簡單的例子來說:假如一個Excel中有A,B,C三列,我們只想要A,C列的數據而忽略B列,這樣的話如果用之前的方法,就會很不方便。另外,如果我們需要一次讀取N個Excel文件中的A列和C列,也需要對代碼進行重新審視。

  為了能夠“按需讀取”,我們首先需要設計一下這個“需”。在這里,我們引入一個概念,就是構造器(當然,這個也算是一種簡單的javaBean),下面就逐步來分析,怎么實現這些功能。

  按照之前我們對頁面元素的定義,我們在這里對Excel里面的內容也進行以下定義,即假如我使用Excel存儲頁面元素的內容,我應該是以什么樣的格式去寫。一般來說我想以以下的方式:

  

  在這里,pageName是頁面名稱,positionName就是我們給想點擊的頁面元素起的名字,type是尋找方式,sec是等待時間,path是尋找元素的具體路徑的值。

  在這個Excel中,第一行的列名為我們定義的頁面元素屬性名稱,從第二行的內容開始,我們需要填寫每個頁面元素實際的屬性值。

  那么在這里我們先做一個記錄頁面元素屬性值的構造器,或者叫Bean

package webui.bean;

public class positionBean {
    //此處定義的是Excel里面列的名字,必須要一模一樣,才能正常讀取相應的數據!
    String pageName;
    String positionName;
    String path;
    int sec;
    String type;
    public String getPageName() {
        return pageName;
    }
    public void setPageName(String pageName) {
        this.pageName = pageName;
    }
    public String getPositionName() {
        return positionName;
    }
    public void setPositionName(String positionName) {
        this.positionName = positionName;
    }
    public String getPath() {
        return path;
    }
    public void setPath(String path) {
        this.path = path;
    }
    public int getSec() {
        return sec;
    }
    public void setSec(int sec) {
        this.sec = sec;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    } 
}

  我們根據頁面元素記錄的屬性,編寫了這個構造器后,我們怎么讓Excel按照這個構造器的內容來讀取數據呢?我們這里需要用到Java中類反射的概念。先看下面一段代碼:

private static Map<String, Method> getSetMethod(Class<?> clz,List<Object> heads) {
        Map<String, Method> map = new HashMap<String, Method>();
        Method[] methods = clz.getMethods();
        for (Object head : heads) {
            for (Method method : methods) {
                if (method.getName().toLowerCase().equals("set" + head.toString().toLowerCase())
                        && method.getParameterTypes().length == 1) {
                    map.put(head.toString(), method);
                    break;
                }
            }
        }
        return map;
    }

  這段代碼稍微有些抽象,我們需要根據兩個參數(泛型Class<?>來指代我們剛才書寫的構造器,List<Object> heads來對應寫在Excel里面第一行的列名),我這里用實例來說明一下。

  Excel上有頁面元素屬性的幾列數據(參考之前的Excel圖片),構造器里是通過方法返回來取得的實際數據的。如果,我們把相應的列名和相應的方法對應起來,這樣就可以把數據對應起來了。例如:pageName對應setPageName(String pageName)這個方法。

       Method[] methods = clz.getMethods();  //這一句,實際上是獲取這個類的所有公共方法。  

  if (method.getName().toLowerCase().equals("set" + head.toString().toLowerCase())&& method.getParameterTypes().length == 1)

  //這個判定實際上也是一個過濾,也就是尋找來自於這個類當中,由編寫構造器時,生成的setter方法。(如果方法的名字與set + head的小寫字母相同,且方法的參數類型長度為1,即只有1個參數)

  {map.put(head.toString(), method);}

  //將頭名與方法對應放入HashMap中。------>可以理解為(pageName對應setPageName方法)

  這樣一來,我們就用一個HashMap把這個關系給對應起來了。

  我們在取得這個對應關系之后,我們需要用Java的反射機制,來調用具體的方法來設置pageName的值。

  首先,由於Method的invoke方法,參數必須是一個底層的Object,所以,我們設計我們這個設置值的方法必須有這幾個參數:

  Object obj------>其實這個可以是positionBean這個類一個實例,List<Object> data --------> 這個是讀取的Excel的具體數據集合,List<Object> heads -------->這個List是讀取列名的集合,Map<String,Method> methods ----->這個就是我們之前獲取的列名與方法的對應關系集合。

  來看下面一段代碼

private static void setValue(Object obj, List<Object> data,List<Object> heads, Map<String, Method> methods)throws IllegalArgumentException, IllegalAccessException,InvocationTargetException {
    //在獲取了對應關系的HashMap之后,我們要對這個Map進行遍歷。
for (Map.Entry<String, Method> entry : methods.entrySet()) { Object value = ""; int dataIndex = heads.indexOf(entry.getKey());
      //按照當前列的序號小於數據List的長度(例如數據List的長度為5,當前為0~4的情況)
if (dataIndex < data.size()) {
           //使用一個Object來取得當前項的數據。 value
= data.get(heads.indexOf(entry.getKey())); }
         //取得HashMap里對應的方法 Method method
= entry.getValue();
        //取得方法里的第一個參數的類型 Class
<?> param = method.getParameterTypes()[0];
        //如果參數類型為String
if (String.class.equals(param)) {
         //方法反射,將具體的值賦給列名所代表的obj。 method.invoke(obj, value);
          //如果參數類型為整數 }
else if (Integer.class.equals(param) || int.class.equals(param)) {
          //加入判斷是否為空字符,因為很多時候Excel里空着就是0的意思
if(value.toString()==""){ value=0; }
          //方法反射 method.invoke(obj,
new BigDecimal(value.toString()).intValue()); } else if (Long.class.equals(param) || long.class.equals(param)) { if(value.toString()==""){ value=0; } method.invoke(obj, new BigDecimal(value.toString()).longValue()); } else if (Short.class.equals(param) || short.class.equals(param)) { if(value.toString()==""){ value=0; } method.invoke(obj, new BigDecimal(value.toString()).shortValue()); } else { // Date method.invoke(obj, value); } } }

  關於反射,可能稍微比較難於理解。我再貼一段代碼,大家可以是否容易理解。

public class MethodDemo {
   public static void main(String[] args) 
      throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
      Method[] methods = SampleClass.class.getMethods();
      SampleClass sampleObject = new SampleClass();
      methods[1].invoke(sampleObject, "data");
      System.out.println(methods[0].invoke(sampleObject));
   }
}

class SampleClass {
   private String sampleField;

   public String getSampleField() {
      return sampleField;
   }

   public void setSampleField(String sampleField) {
      this.sampleField = sampleField;
   } 
}

  以上運行的結果為:

data  

  寫了這么多,好像離我們的所想要的功能越來越近了。我們把Excel的列名和構造類中的方法關聯,然后讀取數據來給他們賦值。下一章我們就具體來“按需讀取”Excel吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM