背景
如果提供一个平台化的页面供用户操作,如果用户想在页面上操作入参,需要将复杂的对象扁平化展示,以便用户操作。
用户想在页面上操作数据流中的参数,是需要拿到结构化参数中的字段,为了便于用户操作,需要支持扁平化的操作
参数扁平化
原始数据:
{
"address":[
{
"area":"白帝小区",
"city":"洛阳",
"phone":"13617172122",
"province":"河南"
},
{
"area":"邯郸小区",
"city":"邯郸",
"phone":"19917172122",
"province":"河北"
},
{
"area":"德州小区",
"city":"德州",
"phone":"18817172122",
"province":"山东"
}
],
"balance":10.11,
"birthday":{
"day":"30",
"mon":"11",
"year":"2020"
},
"name":"小白",
"uid":1001
}
结构化schema:
{
"address":[
{
"area":"String",
"city":"String",
"phone":"String",
"province":"String"
}
],
"balance":"BigDecimal",
"birthday":{
"day":"String",
"mon":"String",
"year":"String"
},
"name":"String",
"uid":"Integer"
}
扁平化schema:
{
"address":"LIST",
"address.0":"MAP",
"address.0.area":"String",
"address.0.city":"String",
"address.0.phone":"String",
"address.0.province":"String",
"balance":"BigDecimal",
"birthday":"MAP",
"birthday.day":"String",
"birthday.mon":"String",
"birthday.year":"String",
"name":"String",
"uid":"Integer"
}
如上图所示。我们可以拿到扁平化的schema结构后,那么在页面上可以输入address.0.area
,就可以获取到Map中的对于的value值(作为Context上下文,执行脚本)。
代码实现
数据准备
public interface SourceParam {
/**
* 获取参数元数据
*/
Map<String, Object> getParamMeta();
}
public class MockSourceParam implements SourceParam {
@Override
public Map<String, Object> getParamMeta() {
//原数据
UserInfo userInfo = new UserInfo();
userInfo.setUid(1001L);
userInfo.setName("小白");
userInfo.setBalance(10.11);
Birthday birthday = new Birthday();
birthday.setYear("2020");
birthday.setMon("11");
birthday.setDay("30");
userInfo.setBirthday(birthday);
List<Address> addressList = Lists.newArrayList();
addressList.add(Address.builder().province("河南").city("洛阳").area("白帝小区").phone("13617172122").build());
addressList.add(Address.builder().province("河北").city("邯郸").area("邯郸小区").phone("19917172122").build());
addressList.add(Address.builder().province("山东").city("德州").area("德州小区").phone("18817172122").build());
userInfo.setAddress(addressList);
System.out.println(JSON.toJSONString(userInfo));
return JSON.parseObject(JSON.toJSONString(userInfo), Map.class);
}
@Data
public static class UserInfo {
private Long uid;
private String name;
private Birthday birthday;
private double balance;
private List<Address> address;
}
@Data
public static class Birthday {
private String year;
private String mon;
private String day;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Address {
private String province;
private String city;
private String area;
private String phone;
}
}
工具方案:
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.Map.Entry;
public class ParamHelper {
/**
* json的嵌套格式化
*/
public static Map<String, Object> jsonSchema(Map<String, Object> data) {
Map<String, Object> result = Maps.newHashMap();
if (MapUtils.isEmpty(data)) {
return result;
}
data.forEach((k, v) -> {
result.put(k, v.getClass().getSimpleName());
//如果Map
if (v instanceof Map) {
result.put(k, jsonSchema((Map<String, Object>) v));
return;
}
if (v instanceof Collection) {
Collection t = (Collection) v;
Iterator iterator = t.iterator();
Collection c1 = new ArrayList<>();
if (iterator.hasNext()) {
Object o = iterator.next();
if (o instanceof Map) {
c1.add(jsonSchema((Map<String, Object>) o));
} else {
c1.add(o.getClass().getSimpleName());
}
}
result.put(k, c1);
}
});
return result;
}
/**
* 写入扁平化的数据
*/
public static Map<String, Object> putFold(Map<String, Object> data) {
Map<String, Object> result = Maps.newHashMap();
if (MapUtils.isEmpty(data)) {
return result;
}
data.forEach((k, v) -> {
String[] splitKey = k.split("\\.");
int index = 0;
Map<String, Object> indexMap = result;
while (index < splitKey.length - 1) {
String subKey = splitKey[index];
indexMap = foldGetFromMap(indexMap, subKey);
index++;
}
indexMap.put(splitKey[index], v);
});
return convertDataArray(result);
}
public static Map<String, Object> jsonSchemaForUnfold(Map<String, Object> data) {
Map<String, String> unfoldData = jsonSchemaForUnfold("", data);
Map<String, Object> res = Maps.newHashMap();
for (Entry<String, String> entry : unfoldData.entrySet()) {
String key = entry.getKey();
String fieldType = entry.getValue();
res.put(key, fieldType);
}
return res;
}
public static Map<String, String> jsonSchemaForUnfold(String prefix, Map<String, Object> data) {
Map<String, String> result = Maps.newHashMap();
if (MapUtils.isEmpty(data)) {
return result;
}
data.forEach((k, v) -> {
String unfoldKey;
if (StringUtils.isNotBlank(prefix)) {
unfoldKey = prefix + "." + k;
} else {
unfoldKey = k;
}
if (v instanceof Map) {
result.put(unfoldKey, "MAP");
result.putAll(jsonSchemaForUnfold(unfoldKey, (Map<String, Object>) v));
return;
}
if (v instanceof Collection) {
result.put(unfoldKey, "LIST");
result.putAll(jsonSchemaForUnfold(unfoldKey, convertToMap((Collection) v)));
return;
}
result.put(unfoldKey, v.getClass().getSimpleName());
});
return result;
}
private static Map<String, Object> convertToMap(Collection<?> collection) {
Map<String, Object> result = Maps.newHashMap();
if (CollectionUtils.isEmpty(collection)) {
return result;
}
Iterator<?> iterator = collection.iterator();
result.put(String.valueOf(0), iterator.next());
return result;
}
private static Map<String, Object> foldGetFromMap(Map<String, Object> map, String key) {
Object subNode = map.get(key);
if (Objects.nonNull(subNode) && subNode instanceof Map) {
return (Map<String, Object>) subNode;
}
Map<String, Object> result = Maps.newHashMap();
map.put(key, result);
return result;
}
private static Map<String, Object> convertDataArray(Map<String, Object> map) {
Map<String, Object> result = Maps.newHashMap();
if (MapUtils.isEmpty(map)) {
return map;
}
for (Entry<String, Object> entry : map.entrySet()) {
String k = entry.getKey();
Object v = entry.getValue();
if (!(v instanceof Map)) {
result.put(k, v);
continue;
}
Map<String, Object> valueMap = convertDataArray((Map<String, Object>) v);
if (valueMap.keySet().stream().allMatch(StringUtils::isNumeric)) {
result.put(k, valueMap.values());
continue;
}
result.put(k, valueMap);
}
return result;
}
}
工具类实现:
public class Test {
public static void main(String[] args) {
SourceParam mockSourceParam = new MockSourceParam();
Map<String, Object> paramMeta = mockSourceParam.getParamMeta();
//获取到json串schema结构
System.out.println(JSON.toJSON(ParamHelper.jsonSchema(paramMeta)));
//获取到扁平的json的schema结构
System.out.println(JSON.toJSON(ParamHelper.jsonSchemaForUnfold(paramMeta)));
//存储扁平化的数据
Map<String, Object> hashMap = new HashMap<>();
hashMap.put("userInfo.uid", 1);
hashMap.put("userInfo.name", "tom");
Map<String, Object> stringObjectMap = putFold(hashMap);
System.out.println(JSON.toJSON(stringObjectMap));
}
}