easypoi技术应用
截止第五节,已经能实现数据源是excel,读取excel数据实现数据驱动,但是实际测试过程中,往往接口信息和案例信息是分开的,并不是写在一个excel的sheet页内,而且读取excel是只能按单元格读取,再进行一个存放二维数组的过程。
这时候结合java面向对象的思想,想要得到每个接口、每个案例的各类信息,把接口和案例也抽象成一个实体类,在直接操作这个实体类的数据,这里就用到了easypoi技术
新建pojo包,新建接口、案例实体类
pojo包专门用来存放实体类
每个实体类包括4部分:私有属性(excel的列表头)、有参构造函数、空参构造函数、get和set方法
举个例子:excel模板如下,2个sheet页,一个存放接口信息,一个存放案例信息,案例信息通过apiId字段和接口关联
新建2个实体类:ApiInfo和CaseInfo
public class ApiInfo {
//easypoi提供的excel注解实现excel列名和实体类属性的映射
@Excel(name = "接口编号")
//excel非空导入校验,需要配合2个依赖才生效
@NotNull
private String apiId;
@Excel(name = "接口名称")
private String apiName;
@Excel(name = "接口地址")
private String apiUrl;
@Excel(name = "接口提交方式")
private String apiMethod;
@Excel(name = "参数类型")
private String apiType;
//有参构造快捷键:Alt+shift+S+O ;
public ApiInfo(String apiId, String apiName, String apiUrl, String apiMethod, String apiType) {
super();
this.apiId = apiId;
this.apiName = apiName;
this.apiUrl = apiUrl;
this.apiMethod = apiMethod;
this.apiType = apiType;
}
// Alt+shift+S+C 生成无参构造方法
public ApiInfo() {
super();
}
// Alt+shift+S+R:生成setxxx()和getXXX()方法
/**
* @return the apiId
*/
public String getApiId() {
return apiId;
}
/**
* @param apiId the apiId to set
*/
public void setApiId(String apiId) {
this.apiId = apiId;
}
/**
* @return the apiName
*/
public String getApiName() {
return apiName;
}
/**
* @param apiName the apiName to set
*/
public void setApiName(String apiName) {
this.apiName = apiName;
}
public String getApiUrl() {
return apiUrl;
}
public void setApiUrl(String apiUrl) {
this.apiUrl = apiUrl;
}
public String getApiMethod() {
return apiMethod;
}
public void setApiMethod(String apiMethod) {
this.apiMethod = apiMethod;
}
public String getApiType() {
return apiType;
}
public void setApiType(String apiType) {
this.apiType = apiType;
}
// 重写toString方法
@Override
public String toString() {
return "ApiInfo [apiId=" + apiId + ", apiName=" + apiName + ", apiUrl=" + apiUrl + ", apiMethod=" + apiMethod
+ ", apiType=" + apiType + "]";
}
}
CaseInfo类写法同ApiInfo,不重复贴代码了
引入esaypoi依赖
esaypoi就是对poi的二次封装,所以先引入依赖,同时要删掉之前的poi依赖,因为esaypoi本身已包含了
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.0.0</version>
</dependency>
引入excel导入校验依赖
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
改造ExcelUtils
之前的写法是写一个read方法,指定sheet页,一行一单元格的去读取,现在需要改造ExcelUtils,使得能够灵活的读取到excel里的每个sheet页的每一行内容,并转成对应的实体类对象:比如接口信息sheet里的每一行代表每一个接口,就是一个接口信息实体类;案例信息类sheet里的每一行代表每一个案例,就是一个案例信息实体类
public class ExcelUtils {
public static void main(String[] args) throws Exception {
//测试excel每行内容是否创键api和case对象成功
List<ApiInfo> list1 = getElement(0,1,ApiInfo.class);
List<CaseInfo> list2 = getElement(1,1,CaseInfo.class);
}
public static void getApiInfo() throws Exception {
FileInputStream fis = new FileInputStream("src\\test\\resources\\excel名.xlsx");
// 导入配置:导入参数设置类
ImportParams params = new ImportParams();
// 把excel第1个sheet页的每行api变成apiinfo对象
params.setStartSheetIndex(0);
// 导入验证,需要2个依赖
params.setNeedVerify(true);
// 3个参数:fis从哪个文件读取;字节码文件要映射成哪个实体类;导入配置:从第几个sheet导入、表头有几行等
List<ApiInfo> importExcel = ExcelImportUtil.importExcel(fis, ApiInfo.class, params);
for(ApiInfo e : importExcel) {
System.out.println(e);
}
}
public static void getCaseInfo() throws Exception {
FileInputStream fis = new FileInputStream("src\\test\\resources\\excel名.xlsx");
ImportParams params = new ImportParams();
// 把excel第2个sheet页的每行case变成caseinfo对象
params.setStartSheetIndex(1);
params.setNeedVerify(true);
List<CaseInfo> importExcel = ExcelImportUtil.importExcel(fis, CaseInfo.class, params);
for(CaseInfo e : importExcel) {
System.out.println(e);
}
}
}
代码优化:上述的接口和案例信息,写法基本一致,把可能不一致的地方(实体类、sheet起始页等)抽取成入参,形成一个共性方法
public static void main(String[] args) throws Exception {
// 测试下共性方法是否生效
getElement(0,1,ApiInfo.class);
getElement(1,1,CaseInfo.class);
}
public static <T> List<T> getElement(int startindex, int sheetcount, Class<T> clazz) throws Exception {
FileInputStream fis = new FileInputStream("src\\test\\resources\\excel名.xlsx");
// 导入配置:导入参数设置类
ImportParams params = new ImportParams();
params.setStartSheetIndex(startindex);
// 连续几个sheet页,当前示例excel模板对应的都是1
params.setSheetNum(sheetcount);
params.setNeedVerify(true);
//3个参数:fis从哪个文件读取;字节码文件要映射成哪个实体类;导入配置:从第几个sheet导入、表头有几行等
List<T> list = ExcelImportUtil.importExcel(fis, clazz, params);
for(T e : list) {
System.out.println(e);
}
return list;
}
上述代码有2个java相关的重要点:反射和泛型的结合应用
反射:.class,java在运行时动态的获取一个类,并且可以创建对象调用方法。
泛型:<T>,一个动态值,不是固定值,根据需要的类型变换
反射
//3种定义方式
Class clazz1 = 类名.class;
Class clazz2 = 实例名.getClass();
Class clazz3 = Class.forName("全类名");
//举个例子,接口信息类
Class clazz1 = ApiInfo.class;
//1、创建对象
//newInstance()调用空参构造,空参构造是唯一
Object object = clazz1.newInstance();
//2、获取构造方法
Constructor[] constructors = clazz1.getConstructors();
//3、获取普通方法
Method[] methods = clazz1.getMethods();
//4、获取成员变量,但成员变量定义的是private私有访问权限,这样是获取不到的
Field[] fields = clazz1.getFields();
//5、暴力反射,可获取到私有变量
Field[] declaredFields = clazz1.getDeclaredFields();
泛型
// 当泛型定义在类上时(static <T>),创建对象时指定泛型类型(Class<T> clazz),返回值( List<T>)
public static <T> List<T> getElement(int startindex, int sheetcount, Class<T> clazz)