【平台化引擎-2】— 参数扁平与结构化操作

背景

如果提供一个平台化的页面供用户操作,如果用户想在页面上操作入参,需要将复杂的对象扁平化展示,以便用户操作。

页面操作流程.png

用户想在页面上操作数据流中的参数,是需要拿到结构化参数中的字段,为了便于用户操作,需要支持扁平化的操作

参数扁平化

原始数据:

{
    "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));
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 193,812评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,626评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,144评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,052评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,925评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,035评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,461评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,150评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,413评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,501评论 2 307
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,277评论 1 325
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,159评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,528评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,868评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,143评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,407评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,615评论 2 335

推荐阅读更多精彩内容