上一篇说了利用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吧。

基于Java+Selenium的WebUI自动化测试框架(十一)-----读取Excel文件(POI)(1)的更多相关文章

  1. 基于Java+Selenium的WebUI自动化测试框架(一)---页面元素定位器

    对于自动化测试,尤其是UI的自动化测试.是很多做黑盒功能测试的同学,入门自动化测试一个最为直观的或者说最容易理解的途径之一. 对于手工测试和自动化测试的优劣,网上有很多论述,在这里不作展开讨论.但是, ...

  2. 基于Java+Selenium的WebUI自动化测试框架(十四)-----使用TestNG的Sample

    到目前为止,我们所写的东西,都是集中在如何使用Selenium和Java来定位和读取元素.那么,到底如何具体开展测试,如何实现参数化,如何实现判定呢?下面,我们来看看Java应用程序的测试框架吧. 当 ...

  3. 基于Java+Selenium的WebUI自动化测试框架(八)-----读取元素(XML文件)

    我们继续回到自动化测试框架的主线上来,在前面的文章中,我们定义一个页面元素的主要参数有:路径,找寻方式,等待时间,名称,这个四个参数.另外,我们还需要考虑一个问题,就是网站的页面. 举个例子来说,如果 ...

  4. 基于Java+Selenium的WebUI自动化测试框架(六)---浏览器初始化

    本篇我们来讨论,如何写一个浏览器初始化的类.在写之前,先思考一下,我们需要一个什么样的初始化? 先来看看使用原生的Java + selenium是怎么做的.(以firefox为例) System.se ...

  5. 基于Java+Selenium的WebUI自动化测试框架(十)-----读取Excel文件(JXL)

    之前,我们使用了读取XML文件的方式来实现页面元素的读取,并做成了基础页面类.下面,我们来进行一些扩展,通过Excel来读取页面元素. Excel的使用,大多数人应该都不陌生.那么Java读取Exce ...

  6. 基于Java+Selenium的WebUI自动化测试框架(九)-----基础页面类(BasePage)

    上篇我们写了java读取xml文件的类,实现了可以从xml文件读取元素的方式.那么,接下来我们需要考虑一个问题.我们拿了这些元素之后怎么去操作呢? 先来看看我们手工测试的时候是怎么进行的. 双击浏览器 ...

  7. 基于Java+Selenium的WebUI自动化测试框架(十二)-----读取Excel文件(POI)(2)

    上一篇我们讲了怎么利用Java的反射机制,将Excel的读取到的数据,赋值给我们构造函数中定义的变量. 接下来就简单了,我们将实际实现这个读取的简单过程.来看下面一段代码. private stati ...

  8. 基于Java+Selenium的WebUI自动化测试框架(十三)-----基础页面类BasePage(Excel)

    前面,我们讲了如何使用POI进行Excel的“按需读取”.根据前面我们写的BasePageX,我们可以很轻松的写出来基于这个“按需读取”的BasePage. package webui.xUtils; ...

  9. 基于Java+Selenium的WebUI自动化测试框架(五)------页面操作实现类

    在编写完Log类和监听类之后,终于要回到正轨上来了.我们继续开始写UIExcutor的实现类. PS:如果你想让你的报告更加美观一些.推荐使用reportNG这个jar包. 在项目中导入reportn ...

随机推荐

  1. [LeetCode] 337. House Robber III 打家劫舍 III

    The thief has found himself a new place for his thievery again. There is only one entrance to this a ...

  2. [LeetCode] 502. IPO 上市

    Suppose LeetCode will start its IPO soon. In order to sell a good price of its shares to Venture Cap ...

  3. java的Array和List相互转换

    1.Array转List,通过java.util.Arrays.asList(T... a)参数是可变泛型参数 注意,Arrays.asList返回的类型是不可变长度的集合,底层是final修饰的泛型 ...

  4. 在ensp上的ARP及Proxy ARP

    啥是ARP?啥又是Proxy ARP? ARP是用来将 IP 地址解析为 MAC 地址的协议. ARP 表项可以分为动态和静态两种类型.动态 ARP ,是利用 ARP 广播报文,动态执行并自动进行 I ...

  5. vcf和bed的位置信息区别

    vcf和bed的位置信息区别 vcf和gff一般是从1-base开始计数,也就是文件里所代表的的位置是染色体的真实位置 bed文件一般所代表的位置是从0开始计数的,是一个半闭合区间,也就是(0,200 ...

  6. windows10 ubuntu子系统运行docker出现的问题

    前一篇笔记记录了安装的过程及错误处理办法,但是在正式使用docker时,却又出现新的问题: “docker: Cannot connect to the Docker daemon at unix:/ ...

  7. 06 Mybatis 使用xml配置映射模式+动态SQL---使用案例

    1.项目结构 2.数据库表User对应的实体类 package domain; import java.io.Serializable; import java.util.Date; /** * 数据 ...

  8. Java开发笔记(一百一十五)使用Socket开展文件传输

    前面介绍了怎样通过Socket在客户端与服务端之间传输文本,当然Socket也支持在客户端与服务端之间传输文件,因为文件本身就是通过I/O流实现读写操作的,所以在套接字的输入输出流中传输文件真是再合适 ...

  9. c++ 基础学习(二)—— IO 对象

    1. IO 类 c++ 语言不能直接处理输入输出,而是通过一族定义在标准库中的类型来处理 IO,这些类型支持设备读取数据,向设备写入数据的 IO 的数据操作. istream 输入流类型,提供输入操作 ...

  10. quartz2.3.0(六)job任务异常处理方式

    Job1类 package org.quartz.examples.example6; import org.quartz.DisallowConcurrentExecution; import or ...