背景介绍
本文分享一个我遇到一个工作量巨大的任务时的解题思路与方法。
前一阵子接了个任务,是根据一个车控信号表格去写接口,本以为是个极其轻松的工作,做到后面我发现我还是太年轻了。
遇到的问题:
- 1.车控信号数量巨多;
- 2.信号分为上下行信号,对应的是读写接口,所对应的代码也不同;
- 3.除了信号表还要去check另一个文件,检查prop ID是否定义;
- 4.最后还要给应用层一个接口文档。
做到后面真的头皮发麻,写了十多个接口后,我觉得不能这样写了,抛开身心疲惫不谈,还容易出错。
解题
冷静下来分析一手,我做的事情总结下就是机械化的操作与格式化的编码。
等等...机械化、格式化!!
我一下子就想到了写个脚本去干这些事,我是程序员啊,得用代码解放生产力啊。OK,有了思路就直接撸起袖子开干。
读取数据
第一步就是得读取信号表格里面得数据,我一百度还真有这样的库,EasyExcel ,是阿里的一个三方库,可以读取表格数据转成对象。挺好用的,推荐大家start一下,万一以后用的上。
创建bean数据类:
public class VehicleExcelData {
@ExcelProperty("Functional classification")
private String functionalClassification;
@ExcelProperty("Fuction Describe")
private String functionDescribe;
@ExcelProperty("Detail")
private String detail;
//private String detailedExplanation;
@ExcelProperty("Project")
private String project;
//private String scope;
//private String featureID;
@ExcelProperty("Vehicle property ID")
private String vehiclePropertyId;
@ExcelProperty("Area ID")
private String areaID;
@ExcelProperty("DataType")
private String dataType;
//省略其他属性
}
读取数据:
//读取excel
//buildSheet为表中对应的sheet名
EasyExcel.read(excelPath, VehicleExcelData.class,readListener).sheet(buildSheet).doRead();
private ReadListener<VehicleExcelData> readListener = new ReadListener<>() {
@Override
public void invoke(VehicleExcelData data, AnalysisContext context) {
if (data.isAvailable() && data.getIsCheck() != null && data.getIsCheck().equals("true") ) {
checkIsInTypesHal(data, typeHalDataArrayList);
vehicleExcelDataList.add(data);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
//生成sdk代码
new SDKBuildHelper(vehicleExcelDataList, buildSheet).build();
//生成types hal
//new TypeHalBuildHelper(vehicleExcelDataList).build();
//生成接口doc
InterfaceDocWriter.writeInterfaceDoc(vehicleExcelDataList, buildSheet);
}
};
在doAfterAllAnalysed方法里就可以拿到所有读取到的数据对象。
另外一个需要读取的源文件并非是excel表格,这时候只能去一行一行读取文件内容,按照规则去匹配字符,找到需要的数据创建对象。需要根据具体的文件,制定相应的匹配规则,例如:
private static String getType(ArrayList<TypeHalData> list, String str, TypeHalData bean) {
//VehiclePropertyGroup:VENDOR
if (str.isEmpty()) {
return null;
}
String content = str.trim();
if (content.contains(":")) {
String[] dataArray = content.split(":");
String type = dataArray[0];
String value = dataArray[1];
if (type.contains(VEHICLE_STRUCT_TYPE_GROUP)) {
bean.setGroup(value);
return "| VehiclePropertyGroup." + value;
} else if (type.contains(VEHICLE_STRUCT_TYPE_PROPERTY_TYPE)) {
bean.setType(value);
return "| VehiclePropertyType." + value;
} else if (type.contains(VEHICLE_STRUCT_TYPE_AREA)) {
bean.setArea(value);
list.add(bean.clone());
return "| VehicleArea." + value + "\n end";
}
}
return null;
}
模板代码编写
接下来就是如何生成代码了。这个不难,实现方式很多,我使用的是JavaPoet。 以前写kapt时使用到过KotlinPoet,甚至还有DartPoet。我还用过它来生成框架的模板代码,例如MVVM的ViewModel、Repository、Activity...... 这个库就是用来生成代码的,Poet这一系列的库也推荐大家看一下,万一用的上了。
因为我生成的代码比较多,这里就放一部分代码给大家看看(没必要看懂我写的啥hhh)。
public JavaFile buildServiceImpl() throws Exception {
//创建类
TypeSpec.Builder classBuilder = TypeSpec.classBuilder("ServiceImpl");
//生成方法
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("callback");
for (VehicleExcelData data : vehicleExcelDataList) {
if (data.getAccessMode().equals("WRITE")) continue;
String str1 = "case " + serviceManagerName + "." + data.getIdStr() + ":\n";
methodBuilder.addCode(str1);
String str2 = data.getProStr() + " = (" + data.getVehicleDataType() + ")value.getValue()";
methodBuilder.addStatement(str2);
String str3 = "mPacket.set" + data.getProStr().substring(1) + "(" + data.getProStr() + ")";
methodBuilder.addStatement(str3);
String str4 = "LogUtil.debug(TAG," + "\"" + data.getIdStr() + ":\" + " + data.getProStr() + ")";
methodBuilder.addStatement(str4);
// methodBuilder.addStatement("LogUtil.debug(TAG, \"ID_SETTINGS_CHARGING_LIMIT:\" + mSettingsChargingLimit)");
methodBuilder.addStatement("break");
}
for (VehicleExcelData data : vehicleExcelDataList) {
if (data.getAccessMode().equals("WRITE")) continue;
String str5 = "private " + data.getVehicleDataType() + " " + data.getProStr() + "";
methodBuilder.addStatement(str5);
}
// set and get
for (VehicleExcelData data : vehicleExcelDataList) {
data.getAccessModeType(onReadWrite -> {
classBuilder.addMethod(serviceGetBuilder(data).build());
classBuilder.addMethod(serviceSetBuilder(data).build());
}, onRead -> {
classBuilder.addMethod(serviceGetBuilder(data).build());
}, onWrite -> {
classBuilder.addMethod(serviceSetBuilder(data).build());
}
);
}
classBuilder.addMethod(methodBuilder.build());
return JavaFile.builder(buildSheet, classBuilder.build()).build();
}
//写入文件
buildServiceImpl().writeTo(new File(path));
到了这里就可以依葫芦画瓢的完成接口文档生成的工作,使用EasyExcel生成表格文档。 使用EasyExcel生成表格文档 当数据转成了对象,就可以被我们随意拿捏了。
总结
完成这一套脚本后,我的工作就简单太多了,只需要一键生成代码,再把代码粘贴到相应文件就完成了。如果说还需要优化的话 ,可以考虑在原来的接口文件中埋点添加注释之类的,下次加接口的时候直接读取上次的埋点,自动的把生成的代码放到对应的文件以及对应的行号。
灵活运用工具真的是可以事半功倍,全靠自己能不能活跃思维想到解题办法。