一、背景
实践中我们有如下的YAML参数模板,我们想要替换YAML文件中的这几个参数值param1
、param22
、param3111
以及param3122
param1: value1
param2:
param21: value21
param22: value22
param3:
param31:
param311:
param3111: value3111
param3112: value3112
param312:
param3121: value3121
param3122: value3122
二、实施过程
2.1 转换YAML为Map
- 引入依赖:
org.yaml
snakeyaml
1.21
- 转换YAML为Map
Yaml yaml = new Yaml();
Map map = yaml.load(valuesYaml);
2.2 定义模板参数对象
为了对模板中的参数值进行反射替换,我们需要将模板参数定义为对象,这里将模板中所有的value值作为字符串来处理,那么上述模板文件对应的对象:
# 1. 首先定义最外层的结构
@Data
public class Values {
private String param1;
private Param2Values param2;
private Param3Values param3;
}
# 2. 然后定义Param2Values
@Data
public class Param2Values {
private String param21;
private String param22;
}
# 3. 然后定义Param3Values
@Data
public class MysqlHAPersistence {
private Param31Values param31;
}
# 4. 然后定义Param31Values
@Data
public class Param31Values {
private Param311Values param311;
private Param312Values param312;
}
# 5. 然后定义Param311Values
@Data
public class Param311Values {
private Param3111Values param3111;
private Param3112Values param3112;
}
#### 类似的方式我们还需要定义好:Param312Values、Param3111Values、Param3112Values 、Param3121Values、Param3122Values 这四个对象
可以看出非常繁琐,而且一旦参数模板修改了,我们就需要修改代码
2.3 将2.1中生成的Map转换为对象存储
private Values convertValuesTemplateMap(Map map){
String param1 = (String) map.get("param1");
Map param2Map = (Map) map.get("param2");
Param2Values param2 = new Param2Values();
param2.setParam21(param2Map.get("param21"));
param2.setParam22(param2Map.get("param22"));
// 其他参数的转换过程类似
Values values = new Values();
values.setParam1(param1);
values.setParam2(param2);
return values;
}
2.4 开始替换模板中的参数值
假设我们想要设置这几个值param1: new_value1, param22: new_value22, param3112: new_value3112
private Object copyProperties(Values obj, String key, String value){
Object target = obj;
Class clz = obj.class;
// 我们通过小数点来标识模板文件中的层级关系,如:param3111表示为:param3.param31.param311.param3111
String[] paramArgs = key.split("\\.");
int i = 0;
for (String fieldName : paramArgs){
try {
PropertyDescriptor pd = new PropertyDescriptor(fieldName, clz);
if (i == chartParamArgs.length - 1){
// 找到了需要设置的参数,开始设置值
Method method = pd.getWriteMethod();
Field f = clz.getDeclaredField(fieldName);
method.invoke(target, value);
} else {
// 还没找到需要设置的参数,迭代更新clz和target参数
Field f = clz.getDeclaredField(fieldName);
i++;
clz = f.getType();
Method method = pd.getReadMethod();
target = method.invoke(target);
}
} catch (Exception e){
log.error(String.format("get Field failed for fieldName: %s, ErrorMsg: %s", fieldName, e.getMessage()));
}
}
return obj;
}
缺陷:和模板文件绑定死了,一旦模板文件修改,那么就需要改动代码,但是好在是能够实现参数值的替换