zoukankan      html  css  js  c++  java
  • 使用JSLT进行对象转换

    一.介绍与使用

    JSLT是一种完整的JSON查询和转换语言。git地址:https://github.com/schibsted/jslt

    java中使用:

    <dependency>
    <groupId>com.schibsted.spt.data</groupId>
    <artifactId>jslt</artifactId>
    <version>0.1.11</version>
    <scope>compile</scope>
    </dependency>

    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.schibsted.spt.data.jslt.Expression;
    import com.schibsted.spt.data.jslt.Parser;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import java.io.IOException;
    
    @Slf4j
    public class JsltUtil {
        /**
         * 转换json字符串(忽略异常,当异常时返回null)
         * @param jsltStr   jslt表达式
         * @param inputStr  json字符串入参
         * @return
         */
        public static String jsonAdapt(String jsltStr, String inputStr) {
            try {
                return jsonAdapt(jsltStr, inputStr, true);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("jsonAdapt error jsltStr={},inputStr={}", jsltStr, inputStr, e);
            }
            return null;
        }
    
        /**
         * 转换json字符串
         * @param jsltStr   jslt表达式
         * @param inputStr  json字符串入参
         * @param ignoreException  是否忽略异常 如果为ture,出现异常后返回null
         * @return
         */
        public static String jsonAdapt(String jsltStr, String inputStr, boolean ignoreException) throws IOException {
            if (StringUtils.isBlank(jsltStr) || StringUtils.isBlank(inputStr)) {
                log.info("jsonAdapt param illegal");
                return null;
            }
            try {
                ObjectMapper mapper = new ObjectMapper();
                JsonNode input = mapper.readTree(inputStr);
                Expression jslt = Parser.compileString(jsltStr);
                JsonNode output = jslt.apply(input);
                return output.toString();
            } catch (Exception e) {
                log.error("jsonAdapt error jsltStr={},inputStr={}", jsltStr, inputStr, e);
                if (!ignoreException) {
                    throw e;
                }
            }
            return null;
        }
    }
    

      

     

    二.常用转换场景示例

     

    1.普通对象转换

    // jslt表达式
    // crowd 根据age进行if判断输出人群
    {
        "name":.name,
        "age":.age,
        "crowd":if(.age<18"未成年" else if(.age<60"成年人" else "老年人"
    }
    // 入参:
    {
        "name":"nameTest",
        "age":10
    }
    // 结果:
    {
      "name" "nameTest",
      "age" 10,
      "crowd" "未成年"
    }

     

    2.子对象转换

    // jslt表达式
    // * : . 匹配输入对象中的所有键,除了那些已经指定的,并将它们复制到输出对象中;如果有部分字段不想全拷贝使用 :* - bar, baz, quux : .
    // 注意一点, * :  这个语法必须在最后,否则会报错    子对象中,没效果 "extendMsg3":{*:.}   这个字段直接不输出(只有当对象名和入参的一样时,才能在嵌套中再用*  ,eg:"extendMsg":{*:.} 是生效的)
    {
    "extendMsg1":.extendMsg,
    "extendMsg2":{"married2":.extendMsg.married},
    *:.
    }
    // 入参:
    {
        "name":"nameTest",
        "age":10,
        "extendMsg":{"sex":"男","married":false,"education":"小学生"}
    }
    // 结果:
    {
      "extendMsg1" : {
        "sex" "男",
        "married" false,
        "education" "小学生"
      },
      "extendMsg2" : {
        "married2" false
      },
      "name" "nameTest",
      "age" 10,
      "extendMsg" : {
        "sex" "男",
        "married" false,
        "education" "小学生"
      }
    }

     

    3.子对象平铺展开/对象缩进 转换

    // 展开
    // jslt表达式
    {
    "sex":.extendMsg.sex,
    "married":.extendMsg.married,
    * - extendMsg:.
    }
    // 入参:
    {
        "name":"nameTest",
        "age":10,
        "extendMsg":{"sex":"男","married":false,"education":"小学生"}
    }
    // 结果:
    {
      "sex" "男",
      "married" false,
      "name" "nameTest",
      "age" 10
    }
     
     
     
    // 缩进
    // jslt表达式
    {
    "name":.name,
    "age":.age,
    "extendMsg":{"sex":.sex,"married":.married,"education":.education}
    }
    // 入参:
    {
        "name":"nameTest",
        "age":10,
        "sex":"男",
        "married":false,
        "education":"小学生"
    }
    // 结果:
    {
      "name" "nameTest",
      "age" 10,
      "extendMsg" : {
        "sex" "男",
        "married" false,
        "education" "小学生"
      }
    }

     

    4.集合转换

    /** 把集合全部转换 */
    // jslt表达式
    [for(.) {*:.}]
    // 入参:
    [
        {
            "name":"nameTest",
            "age":10,
            "sex":"男",
            "married":false,
            "education":"小学生"
        },
        {
            "name":"nameTest2",
            "age":102,
            "sex":"女",
            "married":true,
            "education":"女博士"
        }
    ]
    // 结果:
    // 输出和入参相同
     
     
    /** 集合部分转换 */
    // jslt表达式
    [for(.) {"name":.name,"age":.age,"test":"testxxx"}]
    // 结果:
    [ {
      "name" "nameTest",
      "age" 10,
      "test" "testxxx"
    }, {
      "name" "nameTest2",
      "age" 102,
      "test" "testxxx"
    } ]

     

    5.复杂对象(分页为例)转换

    /** 1.复杂组合=基础+集合 转换;2.haveNextPaga 举例变量计算 */
    // jslt表达式
    {
    "pageIndex":.pageNo,
    "pageSize":.pageSize,
    "total":.total,
    "haveNextPaga":if((.total - .pageNo * .pageSize) > 0true else false,
    "data":[for(.list) {*:.}]
    }
    // 入参:
    {
        "pageNo":1,
        "pageSize":2,
        "total":100,
        "list":[
            {
                "name":"nameTest",
                "age":10,
                "sex":"男",
                "married":false,
                "education":"小学生"
            },
            {
                "name":"nameTest2",
                "age":102,
                "sex":"女",
                "married":true,
                "education":"女博士"
            }
        ]
    }
    // 结果:
    {
      "pageIndex" : 1,
      "pageSize" : 2,
      "total" : 100,
      "haveNextPaga" : true,
      "data" : [ {
        "name" : "nameTest",
        "age" : 10,
        "sex" : "男",
        "married" : false,
        "education" : "小学生"
      }, {
        "name" : "nameTest2",
        "age" : 102,
        "sex" : "女",
        "married" : true,
        "education" : "女博士"
      } ]
    }

     

    6.取集合中的某一个对象

    // jslt表达式
    {"data1":.[0].name,"data2":.[0].age}
    // 入参:
    [
        {
            "name":"nameTest",
            "age":10,
            "sex":"男",
            "married":false,
            "education":"小学生"
        },
        {
            "name":"nameTest2",
            "age":102,
            "sex":"女",
            "married":true,
            "education":"女博士"
        }
    ]
    // 结果:{
     
      "data1" "nameTest",
      "data2" 10
    }

     

    三.可视化界面生成表达式

    可进行两个事情:1.实现入下所示通过列表自动生成jslt表达式;2.通过json生成列表


    生成的jslt表达式: 

    {"a1":.a, "b1":{"c1":.c, "d1":.d}, "e1":.e, "g1":[for(.g){"a2":.ga, "b2":.gb}]}

    入参json:

    {"a":"a","c":"c","d":"d","e":"e","g":[{"ga":"ga","gb":"gb"},{"ga":"ga2","gb":"gb2"},{"ga":"ga3","gb":"gb3"}]}

    出参json:

    {"a1":"a","b1":{"c1":"c","d1":"d"},"e1":"e","g1":[{"a2":"ga","b2":"gb"},{"a2":"ga2","b2":"gb2"},{"a2":"ga3","b2":"gb3"}]}

    ObjectAdaptMappingInfoBO (配置对象)
    public class ObjectAdaptMappingInfoBO implements Serializable {
        /**
         * id
         */
        private Long id;
    
        /**
         * 对象映射id
         */
        private Long adaptId;
    
        /**
         * 原始字段
         */
        private String sourceColumn;
    
        /**
         * 目标字段
         */
        private String targetColumn;
    
        /**
         * 对象类型:1:基本类型,2:object,3:集合
         * @see ObjectAdaptTypeEnum
         */
        private Byte targetType;
    
        /**
         * 创建时间
         */
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
        private Date createTime;
    
        /**
         * 创建人
         */
        private String creator;
    
        /**
         * 更新时间
         */
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
        private Date updateTime;
    
        /**
         * 修改人
         */
        private String updator;
    
        /**
         * 是否有效 0无效 1有效
         */
        private Byte yn;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public Long getAdaptId() {
            return adaptId;
        }
    
        public void setAdaptId(Long adaptId) {
            this.adaptId = adaptId;
        }
    
        public String getSourceColumn() {
            return sourceColumn;
        }
    
        public void setSourceColumn(String sourceColumn) {
            this.sourceColumn = sourceColumn;
        }
    
        public String getTargetColumn() {
            return targetColumn;
        }
    
        public void setTargetColumn(String targetColumn) {
            this.targetColumn = targetColumn;
        }
    
        public Byte getTargetType() {
            return targetType;
        }
    
        public void setTargetType(Byte targetType) {
            this.targetType = targetType;
        }
    
        public Date getCreateTime() {
            return createTime;
        }
    
        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }
    
        public String getCreator() {
            return creator;
        }
    
        public void setCreator(String creator) {
            this.creator = creator;
        }
    
        public Date getUpdateTime() {
            return updateTime;
        }
    
        public void setUpdateTime(Date updateTime) {
            this.updateTime = updateTime;
        }
    
        public String getUpdator() {
            return updator;
        }
    
        public void setUpdator(String updator) {
            this.updator = updator;
        }
    
        public Byte getYn() {
            return yn;
        }
    
        public void setYn(Byte yn) {
            this.yn = yn;
        }
    }
    View Code
    JsltConvertUtil (转换工具类)
    @Slf4j
    public class JsltConvertUtil {
        /**
         * 通过mapping配置,生成jslt表达式
         * @param list
         * @param type
         * @param parentName
         * @return
         */
        public static String convert(List<ObjectAdaptMappingInfoBO> list, Byte type, String parentName) {
            String result = "";
    
            String collectionName = "";
            List<ObjectAdaptMappingInfoBO> selfList = getSelfList(list, type, parentName);
            if (CollectionUtils.isEmpty(selfList)) {
                return returnConvertByType(result, type, collectionName);
            }
            Set<String> existColumn = new HashSet<>();
            for (ObjectAdaptMappingInfoBO mappingInfoBO : selfList) {
                try {
                    if (mappingInfoBO == null || StringUtil.isBlank(mappingInfoBO.getTargetColumn())) {
                        continue;
                    }
                    String targetColumn = mappingInfoBO.getTargetColumn();
                    String sourceColumn = mappingInfoBO.getSourceColumn();
                    // 如果原字段没有对应值,不返回
                    if (StringUtil.isBlank(sourceColumn)) {
                        continue;
                    }
                    if (ObjectAdaptTypeEnum.COLLECTION.getCode().equals(type)) {
                        String[] split = sourceColumn.split("\.");
                        collectionName = split[0];
                        sourceColumn = split.length > 1 ? split[1] : split[0];
                    }
    
                    boolean haveChild = false;
                    if (targetColumn.contains(".")) {
                        haveChild = true;
                        String[] split = targetColumn.split("\.");
                        targetColumn = split[0];
                    }
                    // targetColumn之前已添加过,跳出
                    if (!existColumn.add(targetColumn)) {
                        continue;
                    }
    
                    // 不是第一次,字符串就不为空,添加一个分割符
                    if (result != "") {
                        result += ", ";
                    }
                    result += """ + targetColumn + "":";
                    if (!haveChild) {
                        result += "." + sourceColumn;
                    } else {
                        // 还有子层级,递归调用
                        result += convert(selfList, mappingInfoBO.getTargetType(), targetColumn);
                    }
                } catch (Exception e) {
                    log.error("JsltConvertUtil convert error list={}, type, parentName", JSON.toJSONString(list), type, parentName, e);
                }
            }
    
    
            return returnConvertByType(result, type, collectionName);
        }
    
        /**
         * 返回结果处理
         * @param result
         * @param type
         * @return
         */
        private static String returnConvertByType(String result, Byte type, String collectionName) {
            if (ObjectAdaptTypeEnum.OBJECT.getCode().equals(type)) {
                result = "{" + result + "}";
            } else if (ObjectAdaptTypeEnum.COLLECTION.getCode().equals(type)) {
                result = "[for(." + collectionName + "){" + result + "}]";
            }
    
            return result;
        }
    
        /**
         * 获取本次要处理的集合
         * @param list
         * @param type
         * @param parentName
         * @return
         */
        private static List<ObjectAdaptMappingInfoBO> getSelfList(List<ObjectAdaptMappingInfoBO> list, Byte type, String parentName) {
            if (CollectionUtils.isEmpty(list)) {
                return null;
            }
            // 如果parentName isBlank 直接返回所有
            if (StringUtil.isBlank(parentName)) {
                return list;
            }
    
            List<ObjectAdaptMappingInfoBO> selfList = new ArrayList<>();
            for (ObjectAdaptMappingInfoBO mappingInfoBO : list) {
                if (mappingInfoBO == null || mappingInfoBO.getTargetType() == null) {
                    continue;
                }
    
                String targetColumn = mappingInfoBO.getTargetColumn();
                if (mappingInfoBO.getTargetType().equals(type) && targetColumn.startsWith(parentName + ".")) {
                    ObjectAdaptMappingInfoBO mappingInfoBONew = new ObjectAdaptMappingInfoBO();
                    BeanUtils.copyProperties(mappingInfoBO, mappingInfoBONew);
                    // 把父去掉,生成新对象
                    mappingInfoBONew.setTargetColumn(targetColumn.replaceFirst(parentName + ".", ""));
                    selfList.add(mappingInfoBONew);
                }
            }
            return selfList;
        }
    
        /**
         * 将json字符串转为目标转换对象集合
         * @param str
         * @return
         */
        public static List<ObjectAdaptMappingInfoBO> jsonStrToTargetList(String str) {
            List<ObjectAdaptMappingInfoBO> list = new ArrayList<>();
            Map map = JSON.parseObject(str, Map.class);
            for (Object key : map.keySet()) {
                jsonStrConvertMappingBOList(list, (String) key, map.get(key), null);
            }
            return list;
        }
    
        /**
         * 将json字符串转为来源转换对象集合
         * @param str
         * @return
         */
        public static List<ObjectAdaptMappingInfoBO> jsonStrToSourceList(String str) {
            List<ObjectAdaptMappingInfoBO> mappingInfoBOList = jsonStrToTargetList(str);
            List<ObjectAdaptMappingInfoBO> result = new ArrayList<>();
            for (ObjectAdaptMappingInfoBO mappingInfoBO : mappingInfoBOList) {
                ObjectAdaptMappingInfoBO sourceMappingInfoBO = new ObjectAdaptMappingInfoBO();
                sourceMappingInfoBO.setSourceColumn(mappingInfoBO.getTargetColumn());
                result.add(sourceMappingInfoBO);
            }
            return result;
        }
    
        /**
         * 对象转换
         * @param list
         * @param parentName
         * @param value
         * @param type
         */
        private static void jsonStrConvertMappingBOList(List<ObjectAdaptMappingInfoBO> list, String parentName, Object value, Byte type) {
            if (value != null && JSON.class.isAssignableFrom(value.getClass())) {
                // 判断对象任然是JSON
                if (JSONObject.class.isAssignableFrom(value.getClass())) {
                    JSONObject oo = (JSONObject) value;
                    for (Map.Entry<String, Object> stringObjectEntry : oo.entrySet()) {
                        String key = stringObjectEntry.getKey();
                        Object value2 = stringObjectEntry.getValue();
                        String nextName = parentName == null ? key : parentName + "." + key;
                        if (JSONObject.class.isAssignableFrom(value2.getClass())) {
                            jsonStrConvertMappingBOList(list, nextName, value2, ObjectAdaptTypeEnum.OBJECT.getCode());
                        } else if (JSONArray.class.isAssignableFrom(value2.getClass())) {
                            jsonStrConvertMappingBOList(list, nextName, value2, ObjectAdaptTypeEnum.COLLECTION.getCode());
                        } else {
                            ObjectAdaptMappingInfoBO mappingInfoBO = new ObjectAdaptMappingInfoBO();
                            if (type == null) {
                                mappingInfoBO.setTargetType(ObjectAdaptTypeEnum.OBJECT.getCode());
                            } else {
                                mappingInfoBO.setTargetType(type);
                            }
                            mappingInfoBO.setTargetColumn(nextName);
                            addToList(list, mappingInfoBO);
                        }
                    }
                } else if (JSONArray.class.isAssignableFrom(value.getClass())) {
                    JSONArray oo = (JSONArray) value;
                    for (Object o : oo) {
                        jsonStrConvertMappingBOList(list, parentName, o, ObjectAdaptTypeEnum.COLLECTION.getCode());
                    }
                }
            } else {
                ObjectAdaptMappingInfoBO mappingInfoBO = new ObjectAdaptMappingInfoBO();
                if (type == null) {
                    mappingInfoBO.setTargetType(ObjectAdaptTypeEnum.BASIC.getCode());
                } else {
                    mappingInfoBO.setTargetType(type);
                }
                mappingInfoBO.setTargetColumn(parentName);
                addToList(list, mappingInfoBO);
    
            }
        }
    
        /**
         * 添加到集合,需要判断是否要可以添加
         * @param list
         * @param mappingInfoBO
         */
        private static void addToList(List<ObjectAdaptMappingInfoBO> list, ObjectAdaptMappingInfoBO mappingInfoBO) {
            Set<String> collect = list.stream().map(ObjectAdaptMappingInfoBO::getTargetColumn).collect(Collectors.toSet());
            if (collect.add(mappingInfoBO.getTargetColumn())) {
                list.add(mappingInfoBO);
            }
        }
    }
    View Code
    JsltConvertUtilTest (测试方法) 
    public class JsltConvertUtilTest {
        /**
         * | sourceColumn | targetColumn | type       |
         * | ------------ | ------------ | ---------- |
         * | a            | a1           | basic      |
         * | c            | b1.c1        | object     |
         * | d            | b1.d1        | object     |
         * | e            | e1           | basic      |
         * | g.ga         | g1.a2        | collection |
         * | g.gb         | g1.b2        | collection |
         *
         * 生成的jslt表达式:
         * {"a1":.a, "b1":{"c1":.c, "d1":.d}, "e1":.e, "g1":[for(.g){"a2":.ga, "b2":.gb}]}
         *
         * 原json:
         * {"a":"a","c":"c","d":"d","e":"e","g":[{"ga":"ga","gb":"gb"},{"ga":"ga2","gb":"gb2"},{"ga":"ga3","gb":"gb3"}]}
         *
         * jslt转换后json:
         * {"a1":"a","b1":{"c1":"c","d1":"d"},"e1":"e","g1":[{"a2":"ga","b2":"gb"},{"a2":"ga2","b2":"gb2"},{"a2":"ga3","b2":"gb3"}]}
         * @param args
         */
        public static void main(String[] args) {
    
            List<ObjectAdaptMappingInfoBO> list = new ArrayList<>();
    
            ObjectAdaptMappingInfoBO mappingInfoBO = new ObjectAdaptMappingInfoBO();
            mappingInfoBO.setSourceColumn("a");
            mappingInfoBO.setTargetColumn("a1");
            mappingInfoBO.setTargetType(ObjectAdaptTypeEnum.BASIC.getCode());
            list.add(mappingInfoBO);
    
            ObjectAdaptMappingInfoBO mappingInfoBO2 = new ObjectAdaptMappingInfoBO();
            mappingInfoBO2.setSourceColumn("c");
            mappingInfoBO2.setTargetColumn("b1.c1");
            mappingInfoBO2.setTargetType(ObjectAdaptTypeEnum.OBJECT.getCode());
            list.add(mappingInfoBO2);
    
            ObjectAdaptMappingInfoBO mappingInfoBO3 = new ObjectAdaptMappingInfoBO();
            mappingInfoBO3.setSourceColumn("d");
            mappingInfoBO3.setTargetColumn("b1.d1");
            mappingInfoBO3.setTargetType(ObjectAdaptTypeEnum.OBJECT.getCode());
            list.add(mappingInfoBO3);
    
            ObjectAdaptMappingInfoBO mappingInfoBO4 = new ObjectAdaptMappingInfoBO();
            mappingInfoBO4.setSourceColumn("e");
            mappingInfoBO4.setTargetColumn("e1");
            mappingInfoBO4.setTargetType(ObjectAdaptTypeEnum.OBJECT.getCode());
            list.add(mappingInfoBO4);
    
            ObjectAdaptMappingInfoBO mappingInfoBO5 = new ObjectAdaptMappingInfoBO();
            mappingInfoBO5.setSourceColumn("");
            mappingInfoBO5.setTargetColumn("f1");
            mappingInfoBO5.setTargetType(ObjectAdaptTypeEnum.OBJECT.getCode());
            list.add(mappingInfoBO5);
    
            ObjectAdaptMappingInfoBO mappingInfoBO6 = new ObjectAdaptMappingInfoBO();
            mappingInfoBO6.setSourceColumn("g.ga");
            mappingInfoBO6.setTargetColumn("g1.a2");
            mappingInfoBO6.setTargetType(ObjectAdaptTypeEnum.COLLECTION.getCode());
            list.add(mappingInfoBO6);
    
            ObjectAdaptMappingInfoBO mappingInfoBO7 = new ObjectAdaptMappingInfoBO();
            mappingInfoBO7.setSourceColumn("g.gb");
            mappingInfoBO7.setTargetColumn("g1.b2");
            mappingInfoBO7.setTargetType(ObjectAdaptTypeEnum.COLLECTION.getCode());
            list.add(mappingInfoBO7);
    
            System.out.println(JsltConvertUtil.convert(list, ObjectAdaptTypeEnum.OBJECT.getCode(), null));
    
            testStrToMapping();
        }
    
        /**
         * 测试str 转为 配置信息
         */
        private static void testStrToMapping() {
            String str = "{"a1":"a","b1":{"c1":"c","d1":"d","a3":{"t":"tt"},"a4":[1,2,3]},"e1":"e","g1":[{"b2":"gb"},{"a2":"ga2","b2":"gb2"},{"a2":"ga3","b2":"gb3"}]}";
            List<ObjectAdaptMappingInfoBO> mappingInfoBOList = JsltConvertUtil.jsonStrToTargetList(str);
            System.out.println(JSON.toJSONString(mappingInfoBOList));
        }
    }
    View Code
  • 相关阅读:
    关于springMVC的一些常用注解
    关于springMVC的一些xml配置
    关于easyUI的一些js方法
    关于easyUI一些标签的使用
    关于easyUI分页
    P3376 模板网络流
    P1343 地震逃生
    网络流最大流
    python函数知识三 函数名的使用、格式化、递归
    python函数知识二 动态参数、函数的注释、名称空间、函数的嵌套、global,nonlocal
  • 原文地址:https://www.cnblogs.com/dengding/p/14202651.html
Copyright © 2011-2022 走看看