java 自定义json解析注解 复杂json解析

news2024/11/28 14:43:46

java 自定义json解析注解 复杂json解析 工具类

目录

  • java 自定义json解析注解 复杂json解析 工具类
    • 1.背景
    • 2、需求-各式各样的json
      • 一、一星难度json【json对象中不分层】
      • 二、二星难度json【json对象中出现层级】
      • 三、三星难度json【json对象中存在数组】
      • 四、四星难度json【json对象中数组中存在层级】
      • 五、五星难度json【json对象中包含数组、且选择是存在底层级跳转到高层级的】
      • 六、利用自定义注解和配置类解析
        • 1.自定义注解类
        • 2.自定义注解对应解析工具类
        • 如果业务中json的key出现了 > 这种特殊符合(并且前后带空格的)可以替换。如下:
      • 七、实战 某个业务场景的一段json

1.背景

为什么要写这个自定义注解,因为需求需要处理一批比较复杂的json(如果只有一个,直接手动写代码解析就好),众所周知批量且类似的工作,最好抽象出来。这也符合编程的风格,不重复造轮子,但是需要造轮子。【前面铺垫比较长,如果需求比较复杂的json可以直接划到最下面,粘贴自定义注解类 和 自定义注解解析工具类】

2、需求-各式各样的json

一、一星难度json【json对象中不分层】

需要的字段也恰好是对应上的
json

{
"name": "wuyuanshun",
"sex":"男"
}[
{
"name": "wuyuanshun",
"sex":"男"
},
{
"name": "liuyuanshun",
"sex":"男"
}
]

java对象

@Data
public class Bean {
    private String name;
    private String sex;

}

解析方法

public class JsonUtil {
    public static final ObjectMapper mapper = new ObjectMapper();
    
	public static <T> T fromJson(String json, Class<T> clazz) {
        requireNonNull(json);
        requireNonNull(clazz);

        try {
            return mapper.readValue(json, clazz);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
	/**
     * json数组转java对象
     * @param json
     * @param valueType
     * @param <T>
     * @return
     * @author: wuyuanshn
     */
    public static <T> List<T> jsonArrayToObjectList(String json, Class<T> valueType)  {
        try {
            //解析
            JSONArray redisJsonArray = JSONArray.parseArray(json);
            List<T> redisList = new ArrayList<>(redisJsonArray.size());
            //封装
            for (int i = 0; i < redisJsonArray.size(); i++) {
                T item = mapper.readValue(redisJsonArray.getString(i), valueType);
                redisList.add(item);
            }
            //返回
            return redisList;
        } catch (Exception e) {
            return null;
        }
    }

	public static void main(String[] args) {
        String json="xxx";
        Bean bean = fromJson(json, Bean.class);
        System.out.println(bean);

        String jsonList="[xxx,xxx]";
 		List<Bean> beanList = jsonArrayToObjectList(jsonList, Bean.class);
        System.out.println(beanList);

    }
}

二、二星难度json【json对象中出现层级】

难度加大一些,比如,出现了层级
json

{
"name": "wuyuanshun",
"sex":"男",
 "like":{
	"title":"羽毛球",
	"level":1,
	"time":1672402865000
}
}

简单解析的话,我们可以再新建一个Like对象,如:

@Data
public class Like {
    private String title;
    private Integer level;
    private Long time;
}

然后再bean里加上Like对象即可:

java对象

public class Bean {
    private String name;
    private String sex;
    private Like like;
}

不过需求真的会那么简单,我就不需要写这个文章了。像闯关一下,让我们提升难度,
比如我需要的对象是要同一层级的(如下),要存在一起(比如存数据库表)。当然我们也可以建Like对象再通过代码导入到同一层级。不过我们可以让他简单一些(正题开始了):
对应解析java对象

@Date
public class Bean {
	@JsonAnalysisProperty("name")
    private String name;
    @JsonAnalysisProperty("sex")
    private String sex;
    @JsonAnalysisProperty("like > title")
    private String likeTitle;
    @JsonAnalysisProperty("like > level")
    private Integer likeLevel;
    @JsonAnalysisProperty("like > time")
    private Long likeTime;
}

对应解析的bean【自定义注解@JsonAnalysisProperty在文章最下面 目录六】

  • name 单层级直接获取
  • like > title 多层级 用 > 隔断取下一层级内容 【注意 > 前后有空格】

*测试方法【之后每个测试用测方法】

public static void main(String[] args) {
       //json
        String json = "{xxxxxxxxxxx}";
        //自定义对象
        Bean bean = new Bean();
        JsonAnalysisPropertyConfig.setObjectByJsonAnalysis(bean,json);
        System.out.println(bean);
    }
}

三、三星难度json【json对象中存在数组】

需求取出姓名、性别、爱好名称(like > title)、语文分数。

{
    "name":"wuyuanshun",
    "sex":"男",
    "like":{
        "title":"羽毛球",
        "level":1,
        "time":1672402865000
    },
    "examination_results":[
        {
            "subject":"数学",
            "date":"2023-01-29",
            "score":98.5
        },
         {
            "subject":"语文",
            "date":"2023-01-29",
            "score":98.5
        },
        {
            "subject":"英语",
            "date":"2023-01-29",
            "score":98.5
        }
    ]
}

对应解析java对象

@Date
public class Bean {
	@JsonAnalysisProperty("name")
    private String name;
    @JsonAnalysisProperty("sex")
    private String sex;
    @JsonAnalysisProperty("like > title")
    private String likeTitle;
    @JsonAnalysisProperty("like > level")
    private Integer likeLevel;
    @JsonAnalysisProperty("examination_results >> \"subject\":\"语文\" > score")
    private Double chineseScore;
}

>> 代表之后是数组中的内容,直到"key": "value"这种选择器结束。如果数组到选择器key:value中还有层级,原来的层级( > )需要换成 (>>),如四星难度json。【注意 >> 前后有空格】

  • examination_results >> “subject”:“语文” 找到examination_results数组中key:value为"subject":"语文“的json对象
  • > score 继续在json对象层级里找到score的值98.5

四、四星难度json【json对象中数组中存在层级】


{
    "purchase_crowd":{
        "interact_data":[
            {
                "index_value":{
                    "index_display":"有互动人数",
                    "value":{
                       "value":44,
                       "unit":"number"
                   },
                },
                "show_list":[
                    {
                        "display":"首购人数占比",
                        "value":{
                            "value":0.5909090909090909
                        }
                    }
                ]
            },
            {
                "index_value":{
                    "index_display":"无互动人数"
                },
                "show_list":[
                    {
                        "display":"xxx占比",
                        "value":{
                            "value":0.02
                        }
                    },
                    {
                        "display":"首购人数占比",
                        "value":{
                            "value":0.4444444444444444
                        }
                    }
                ]
            }
        ]
    }
}

对应解析java对象

@Date
public class Bean {
	 @JsonAnalysisProperty(defaultValue = "0",value = "purchase_crowd > interact_data >> index_value >> \"index_display\":\"有互动人数\" > value > value") @ApiModelProperty("有互动人数") private String purchaseCrowdInteractDataPeopleNumberInteracting;
  
}
  • defaultValue = “0” 是如果json解析中没找到这个字段添加的默认值。
  • interact_data >> index_value >> “index_display”:“有互动人数” 这一段都是在数组中选择某一个key:value,来定位自己要找的json对象。找到key:value后,默认在当前层级继续向下选择
  • value > value 找到值44。

五、五星难度json【json对象中包含数组、且选择是存在底层级跳转到高层级的】

json同上
如 需求是取index_display 为 "有互动人数"的数组中的 ‘收购人数占比’ value数值、和取index_display 为 "无互动人数"的数组中的‘收购人数占比’value数值

对应解析java对象

@Date
public class Bean {
	
     @JsonAnalysisProperty(defaultValue = "0",value = "purchase_crowd > interact_data >> * index_value >> \"index_display\":\"有互动人数\" > show_list >> \"display\":\"首购人数占比\" > value > value") @ApiModelProperty("有互动人数-首购人数占比") private String purchaseCrowdInteractDataPeopleNumberFirstPurchaseRatio;

     @JsonAnalysisProperty(defaultValue = "0",value = "purchase_crowd > interact_data >> * index_value >> \"index_display\":\"无互动人数\" > show_list >> \"display\":\"首购人数占比\" > value > value") @ApiModelProperty("无互动人数-首购人数占比") private String purchaseCrowdNotInteractDataPeopleNumberFirstPurchaseRatio;
}

自定义注解的逻辑就是像指针一样根据注解中的路由去寻找字段

符号 “ * ” 代表记录指针位置层级,等找到对应的key:value时,返回之前保存的层级。【注意 * 前后有空格】

  • interact_data >> * index_value >> “index_display”:“无互动人数” 中的 * 号记录了找到key:value后从 interact_data到 index_value这层开始选择可以继续选择【index_value、show_list】,及通过之前的选择选中了下图中绿色区域。
  • > show_list >> “display”:“首购人数占比” 继续从show_list数组中找到对应的key:value(黄色区域)
  • > value > value 继续从‘首购人数占比’层级往下寻找 到0.4444…。
    在这里插入图片描述

六、利用自定义注解和配置类解析

 public static void main(String[] args) {
       //json
        String json = "{xxxxxxxxxxx}";
        //自定义对象
        Bean bean = new Bean();
        JsonAnalysisPropertyConfig.setObjectByJsonAnalysis(bean,json);
        System.out.println(bean);
    }
}

1.自定义注解类


package com.wuyuanshun.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @program: wys-service
 * @description: 自定义json解析注解
 * @author: wuyuanshn
 * @create: 2022-12-26 17:12
 **/

@Target({java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JsonAnalysisProperty {
    /**
     * 正常层级选择
     */
    String SPLIT_DEFAULT = " > ";
    /**
     * 下层级是数组内元素
     */
    String SPLIT_DEFAULT_ARRAY = " >> ";

    /**
     * 数组内 选择返回的层级 默认是最后(最深层)的节点
     */
    String SELECT_ARRAY_DEFAULT_ARRAY = "* ";

    /**
     * 核心字段
     *
     * @return
     */

    String value();

    /**
     * 类型 默认0
     * 1 多层级【后续可以改为枚举类型】
     *
     * @return
     */
    int type() default 0;

    /**
     * 分隔符
     *
     * @return
     */
    String split() default SPLIT_DEFAULT;

    /**
     * 数组内 选择返回的层级 默认是最后(最深层)的节点
     *
     * @return
     */
    String selectArrayOne() default SELECT_ARRAY_DEFAULT_ARRAY;

    /**
     * 标记为数组
     *
     * @return
     */
    String splitArray() default SPLIT_DEFAULT_ARRAY;

    /**
     * 是否忽略
     *
     * @return
     */
    boolean ignore() default false;


    /**
     * 默认值
     *
     * @return
     */

    String defaultValue() default "";
}

2.自定义注解对应解析工具类

package com.wuyuanshun.annotation;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @program: wys-service
 * @description: 自定义json解析注解 工具类
 * @author: wuyuanshn
 * @create: 2022-12-26 18:38
 **/
@Slf4j
public class JsonAnalysisPropertyConfig {

    public static final ObjectMapper mapper = new ObjectMapper();
    static Pattern GROUP_INDEX_PATTERN = Pattern.compile("\"([\\u4E00-\\u9FA5A-Za-z0-9_]+)\"[ ]*:[ ]*\"([\\u4E00-\\u9FA5A-Za-z0-9_%&',,+!@#^*《》【】\\-()。;=?$\\x22]+)\"");

    /**
     * 根据注解解析 对象中的所有
     *
     * @param t
     * @param json
     * @param <T>
     */
    public static <T> void setObjectByJsonAnalysis(T t, String json) {
        List<Field> fieldList = getFieldList(t.getClass());
        for (Field field : fieldList) {
            setAnalysisProperty(field, t, json);
        }
    }



    /**
     * 解析对象
     *
     * @return
     */
    public static List<Field> getFieldList(Class<?> clazz) {
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);

        return fieldList;
    }

    /**
     * 根据注解解析 对象中的单个字段
     *
     * @param field
     * @param t
     * @param json
     * @param <T>
     */
    public static <T> void setAnalysisProperty(Field field, T t, String json) {
        try {
            JsonAnalysisProperty annotation = field.getAnnotation(JsonAnalysisProperty.class);
            if (annotation == null || StringUtils.isEmpty(json)) {
                return;
            }
            //一、 验证参数
            //忽略
            boolean ignore = annotation.ignore();
            String split = annotation.split();
            String splitArray = annotation.splitArray();
            String selectArrayOne = annotation.selectArrayOne();
            String defaultValue = annotation.defaultValue();
            if (ignore) {
                return;
            }
            field.setAccessible(true);
            //字段内容
            Object fieldValue = field.get(t);
            //有默认值 先这设置默认值 防止后续报错 设置不上(字段没有内容的情况下 再设置默认值)
            if (!StringUtils.isEmpty(defaultValue) && StringUtils.isEmpty(fieldValue)) {
                setField(field, t, defaultValue);
            }

            //默认-核心字段
            String codeValue = annotation.value();
            if (StringUtils.isEmpty(codeValue)) {
                return;
            }
            //二、 处理数据
            JsonNode jsonNode = mapper.readTree(json);
            String[] codeValueList = codeValue.split(split);
            for (int i = 0; i < codeValueList.length; i++) {
                String codeValueItem = codeValueList[i];
                if (StringUtils.isEmpty(codeValueItem)) {
                    continue;
                }
                //剔除多余空格
                codeValueItem = codeValueItem.trim();

                //判断是否是数组 是则处理数组 选择节点
                JsonNode jsonNodeItem = analysisSplitArrayMax(jsonNode, codeValueItem, splitArray, selectArrayOne);
                //是选择数组 跳过
                if (jsonNodeItem != null) {
                    jsonNode = jsonNodeItem;
                    continue;
                }

                jsonNode = jsonNode.get(codeValueItem);
            }
            String text = jsonNode.asText();
            //设置值
//            field.set(t, text);
            setField(field, t, text);
            //如果为空 且有默认值 设置默认值
            if (StringUtils.isEmpty(text) && !StringUtils.isEmpty(defaultValue) && StringUtils.isEmpty(fieldValue)) {
                setField(field, t, defaultValue);
            }

        } catch (Exception e) {
            String error = null;
            try {
                StackTraceElement[] stackTrace = e.getStackTrace();
                StackTraceElement stackTraceElement = stackTrace[0];
                error = e + "\r\n " + stackTraceElement;
            } catch (Exception exception) {
                log.error("JsonAnalysisPropertyConfig setAnalysisProperty exception error {}", e, exception);
            }
            log.error("JsonAnalysisPropertyConfig setAnalysisProperty field {}  error {}", field, error);
        }
    }

    /**
     * 设置字段值 不同类型
     *
     * @param field
     * @param t
     * @param value
     * @param <T>
     */
    public static <T> void setField(Field field, T t, String value) {
        try {
            Object obj = value;
            Class<?> type = field.getType();
            if (type.equals(String.class)) {
//                field.set(t, obj);
            } else if (type.equals(Long.class)) {
                obj = Long.parseLong(value);
            } else if (type.equals(Integer.class)) {
                obj = Integer.parseInt(value);
            } else if (type.equals(Boolean.class)) {
                obj = Boolean.parseBoolean(value);
            } else if (type.equals(BigDecimal.class)) {
                obj = new BigDecimal(value);
            } else if (type.equals(Double.class)) {
                obj = Double.parseDouble(value);
            } else if (type.equals(Float.class)) {
                obj = Float.parseFloat(value);
            }
//            else if (type.equals(Date.class)) {
//                obj = DateUtils.getDate(value);
//            }
            //其他类型可以在这里添加
            field.set(t, obj);
        } catch (Exception e) {
            log.error("JsonAnalysisPropertyConfig setField 赋值字段失败 field {}; t {}; value {}", field, t, value, e);
        }
    }


    /**
     * 判断是否是数组,如果是 接着处理
     *
     * @param jsonNode
     * @param codeValueItem
     * @param splitArray
     */
    public static JsonNode analysisSplitArray1(JsonNode jsonNode, String codeValueItem, String splitArray) {
        //判断是否是数组
        if (codeValueItem.startsWith(splitArray)) {
            String key;
            String value;
            //查看是否需要选择json数组中的某一个
            Matcher matcher = GROUP_INDEX_PATTERN.matcher(codeValueItem);
            if (matcher.find()) {
                key = matcher.group(1);
                value = matcher.group(2);
            } else {
                return null;
            }
            Iterator<JsonNode> elements = jsonNode.elements();
            //遍历找出对应的数组item
            while (elements.hasNext()) {
                JsonNode next = elements.next();
                String getValue = next.get(key).asText();
                if (!StringUtils.isEmpty(getValue) && getValue.equals(value)) {
                    return next;
                }
            }
        }
        return null;
    }

    /**
     * 判断是否是数组,如果是 接着处理
     *
     * @param jsonNode
     * @param codeValueItem
     * @param splitArray
     */
    public static JsonNode analysisSplitArray2(JsonNode jsonNode, String codeValueItem, String splitArray) {
        //判断是否是数组
        if (codeValueItem.contains(splitArray)) {
            String[] keyList = null;

            keyList = codeValueItem.split(splitArray);
            //一、平级选择
            String codeNext = keyList[0];
            jsonNode = jsonNode.get(codeNext);
            //二、数组选择
            Iterator<JsonNode> elements = jsonNode.elements();
            String key;
            String value;
            //查看是否需要选择json数组中的某一个
            Matcher matcher = GROUP_INDEX_PATTERN.matcher(codeValueItem);
            if (matcher.find()) {
                key = matcher.group(1);
                value = matcher.group(2);
            } else {
                //匹配不到筛选key value 但是包含数组 按第一哥个返回(认为数组中只有一个JsonNode 或者取第一个【顺序保证的前提下】)
                if (elements.hasNext()) {
                    return elements.next();
                }
                //取不到数据 认为不是数组
                return null;
            }
            //遍历找出对应的数组item
            while (elements.hasNext()) {
                JsonNode next = elements.next();
                //判断是否需要深层选择
                if (keyList.length > 2) {
                    for (int i = 0; i < keyList.length; i++) {
                        //跳过最后一个 认为最后一个是key value
                        //跳过第一个 第一个事平级选择
                        if (i == 0 || i == keyList.length - 1) {
                            continue;
                        }
                        next = next.get(keyList[i]);
                    }
                }

                String getValue = next.get(key).asText();
                if (!StringUtils.isEmpty(getValue) && getValue.equals(value)) {
                    return next;
                }
            }
        }
        return null;
    }

    /**
     * 判断是否是数组,如果是 接着处理
     *
     * @param jsonNode
     * @param codeValueItem
     * @param splitArray
     * @param selectArrayOne
     */
    public static JsonNode analysisSplitArrayMax(JsonNode jsonNode, String codeValueItem, String splitArray, String selectArrayOne) {
        //判断是否是数组
        if (codeValueItem.contains(splitArray)) {
            String[] keyList = null;

            keyList = codeValueItem.split(splitArray);
            //一、层级选择
            String codeNext = keyList[0];
            jsonNode = jsonNode.get(codeNext);
            //二、数组选择
            Iterator<JsonNode> elements = jsonNode.elements();
            String key;
            String value;
            //查看是否需要选择json数组中的某一个
            Matcher matcher = GROUP_INDEX_PATTERN.matcher(codeValueItem);
            if (matcher.find()) {
                key = matcher.group(1);
                value = matcher.group(2);
            } else {
                //匹配不到筛选key value 但是包含数组 按第一哥个返回(认为数组中只有一个JsonNode 或者取第一个【顺序保证的前提下】)
                if (elements.hasNext()) {
                    return elements.next();
                }
                //取不到数据 认为不是数组
                return null;
            }
            //遍历找出对应的数组item
            while (elements.hasNext()) {
                JsonNode next = elements.next();
                JsonNode returnNext = null;
                //判断是否需要深层选择
                if (keyList.length > 2) {
                    for (int i = 0; i < keyList.length; i++) {
                        //跳过最后一个 认为最后一个是key value
                        //跳过第一个 第一个事平级选择
                        if (i == 0 || i == keyList.length - 1) {
                            continue;
                        }
                        String keyItem = keyList[i];
                        if (keyItem.startsWith(selectArrayOne)) {
                            keyItem = keyItem.replace(selectArrayOne, "");
                            returnNext = next;
                        }
                        next = next.get(keyItem);
                    }
                }

                String getValue = next.get(key).asText();
                if (!StringUtils.isEmpty(getValue) && getValue.equals(value)) {
                    //是否选择返回层级
                    if (returnNext != null) {
                        return returnNext;
                    }
                    return next;
                }
            }
        }
        return null;
    }


    public static void main(String[] args) {
        String a = "aasddd@@\"key_\" :\"value值(asdd,。a)\"";
        Matcher matcher = GROUP_INDEX_PATTERN.matcher(a);
        if (matcher.find()) {
            String key = matcher.group(1);
            String value = matcher.group(2);
            System.out.println("key = " + key);
            System.out.println("value = " + value);
         /*   key = key_
            value = value值(asdd,。a)*/
        }


        String json = "{\n" +
                "\"name\": \"wuyuanshun\",\n" +
                "\"sex\":\"男\",\n" +
                "\"like\":{\n" +
                "\t\"title\":\"羽毛球\",\n" +
                "\t\"level\":1,\n" +
                "\t\"time\":1672402865000\n" +
                "},\n" +
                " \"examination_results\":[\n" +
                "    {\n" +
                "\t\"subject\":\"语文\",\n" +
                "\t\"date\":\"2023-01-29\",\n" +
                "\t\"score\":98.5\n" +
                "    }, {\n" +
                "\t\"subject\":\"数学\",\n" +
                "\t\"date\":\"2023-01-29\",\n" +
                "\t\"score\":98.5\n" +
                "    }, {\n" +
                "\t\"subject\":\"英语\",\n" +
                "\t\"date\":\"2023-01-29\",\n" +
                "\t\"score\":98.5\n" +
                "    }\n" +
                "]\n" +
                "}";
        Bean bean = new Bean();
        setObjectByJsonAnalysis(bean,json);
        System.out.println(bean);
    }
}

如果业务中json的key出现了 > 这种特殊符合(并且前后带空格的)可以替换。如下:


 @JsonAnalysisProperty(defaultValue = "0",value = "purchase_crowd > interact_data >> * index_value >> \"index_display\":\"有互动人数\" > show_list >> \"display\":\"首购人数占比\" > value > value")
  @ApiModelProperty("成交人群分析-有互动人数-首购人数占比") 
  private String purchaseCrowdInteractDataPeopleNumberFirstPurchaseRatio;
//替换为
@JsonAnalysisProperty(split = " 》 ", splitArray = " 》》 ",  selectArrayOne= "** ", defaultValue = "0",value = "purchase_crowd 》 interact_data 》》 ** index_value 》》 \"index_display\":\"有互动人数\" > show_list 》》 \"display\":\"首购人数占比\" 》 value 》 value")
     @ApiModelProperty("成交人群分析-有互动人数-首购人数占比") 
     private String purchaseCrowdInteractDataPeopleNumberFirstPurchaseRatio;

七、实战 某个业务场景的一段json


 {
   "purchase_crowd":{
       
       "interact_data":[
           {
               "index_value":{
                   "index_display":"有互动人数",
                   "index_name":"",
                   "value":{
                       "value":44,
                       "unit":"number"
                   },
                   "change_value":{
                       "value":0.4943820224719101,
                       "unit":"ratio"
                   }
               },
               "show_list":[
                   {
                       "display":"粉丝占比",
                       "name":"",
                       "value":{
                           "value":0.8636363636363636,
                           "unit":"ratio"
                       }
                   },
                   {
                       "display":"首购人数占比",
                       "name":"",
                       "value":{
                           "value":0.5909090909090909,
                           "unit":"ratio"
                       }
                   }
               ]
           },
           {
               "index_value":{
                   "index_display":"无互动人数",
                   "index_name":"",
                   "value":{
                       "value":45,
                       "unit":"number"
                   },
                   "change_value":{
                       "value":0.5056179775280899,
                       "unit":"ratio"
                   },
                 
               },
               "show_list":[
                   {
                       "display":"粉丝占比",
                       "name":"",
                       "value":{
                           "value":0.6888888888888889,
                           "unit":"ratio"
                       }
                   },
                   {
                       "display":"首购人数占比",
                       "name":"",
                       "value":{
                           "value":0.4444444444444444,
                           "unit":"ratio"
                       }
                   }
               ]
           }
       ]
   }
}

对应解析java对象

    @JsonAnalysisProperty(defaultValue = "0", value = "purchase_crowd > interact_data >> index_value >> \"index_display\":\"有互动人数\" > value > value")
    @ApiModelProperty("成交人群分析-有互动人数")
    private String purchaseCrowdInteractDataPeopleNumberInteracting;
    @JsonAnalysisProperty(defaultValue = "0", value = "purchase_crowd > interact_data >> index_value >> \"index_display\":\"有互动人数\" > change_value > value")
    @ApiModelProperty("成交人群分析-有互动人数占比")
    private String purchaseCrowdInteractDataPeopleNumberRatio;
    @JsonAnalysisProperty(defaultValue = "0", value = "purchase_crowd > interact_data >> * index_value >> \"index_display\":\"有互动人数\" > show_list >> \"display\":\"粉丝占比\" > value > value")
    @ApiModelProperty("成交人群分析-有互动人数-粉丝占比")
    private String purchaseCrowdInteractDataPeopleNumberFansDataRatio;
    @JsonAnalysisProperty(defaultValue = "0", value = "purchase_crowd > interact_data >> * index_value >> \"index_display\":\"有互动人数\" > show_list >> \"display\":\"首购人数占比\" > value > value")
    @ApiModelProperty("成交人群分析-有互动人数-首购人数占比")
    private String purchaseCrowdInteractDataPeopleNumberFirstPurchaseRatio;


    @JsonAnalysisProperty(defaultValue = "0", value = "purchase_crowd > interact_data >> index_value >> \"index_display\":\"无互动人数\" > value > value")
    @ApiModelProperty("成交人群分析-无互动人数")
    private String purchaseCrowdNotInteractDataPeopleNumber;
    @JsonAnalysisProperty(defaultValue = "0", value = "purchase_crowd > interact_data >> index_value >> \"index_display\":\"无互动人数\" > change_value > value")
    @ApiModelProperty("成交人群分析-无互动人数占比")
    private String purchaseCrowdNotInteractDataPeopleNumberRatio;
    @JsonAnalysisProperty(defaultValue = "0", value = "purchase_crowd > interact_data >> * index_value >> \"index_display\":\"无互动人数\" > show_list >> \"display\":\"粉丝占比\" > value > value")
    @ApiModelProperty("成交人群分析-无互动人数-粉丝占比")
    private String purchaseCrowdNotInteractDataPeopleNumberFansDataRatio;
    @JsonAnalysisProperty(defaultValue = "0", value = "purchase_crowd > interact_data >> * index_value >> \"index_display\":\"无互动人数\" > show_list >> \"display\":\"首购人数占比\" > value > value")
    @ApiModelProperty("成交人群分析-无互动人数-首购人数占比")
    private String purchaseCrowdNotInteractDataPeopleNumberFirstPurchaseRatio;


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/331438.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【c++之于c的优化 - 下】

前言 一、inline 概念 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方展开&#xff0c;没有函数调用建立栈帧的开销&#xff0c;内联函数提升程序运行的效率。 如果在上述函数前增加inline关键字将其改成内联函数&#xff0c;在编译期间编译…

契约锁与200多家软件厂商实现集成应用,实现更多业务电子签需求

在中大型组织的数字化建设中&#xff0c;电子签章需求紧紧围绕业务展开&#xff0c;实现电子签章与管理软件集成应用已经成为普遍需求。 契约锁数字可信产品拥有200多家管理软件厂商集成对接经验&#xff0c;覆盖ERP、OA、专项业务系统、移动APP应用、低代码平台、BPM流程、小程…

Vue - 使用Lodash实现防抖和节流

GitHub Demo 地址 在线预览 Lodash 官网 参考&#xff1a; Vue 防抖节流 详细介绍 vue 优雅的实现防抖和节流 防抖、节流的介绍 js防抖和节流的实现原理及应用场景 js防抖节流应用场景及写法 JS中的防抖 什么的防抖和节流&#xff1f; 函数节流&#xff08;throttle&#x…

论文翻译:2022_Phase-Aware Deep Speech Enhancement: It’s All About The Frame Length

摘要 虽然相位感知语音处理近年来受到越来越多的关注&#xff0c;但大多数帧长约为32 ms的窄带STFT方法显示出相位对整体性能的影响相当有限。与此同时&#xff0c;现代基于深度神经网络(DNN)的方法&#xff0c;如Conv-TasNet&#xff0c;隐式修改幅度和相位&#xff0c;在非常…

CUDA虚拟内存管理

CUDA中的虚拟内存管理 文章目录CUDA中的虚拟内存管理1. Introduction2. Query for support3. Allocating Physical Memory3.1. Shareable Memory Allocations3.2. Memory Type3.2.1. Compressible Memory4. Reserving a Virtual Address Range5. Virtual Aliasing Support6. Ma…

自动化测试实战篇(6)jmeter实现脚本录制,抓取接口信息

Jmeter中脚本录制&#xff0c;是一个非常方便找到接口内容的一种工具&#xff0c;不用想fiddler抓包定位接口信息速度不够快 设置代理服务器 这里以谷歌浏览器为例子 打开您的计算机的代理设置 把代理服务器打开这里就以127.0.0.1和8080端口为例子&#xff0c;这个需要记住…

ChatGPT背后的经济账

ChatGPT能否取代Google、百度这样的传统搜索引擎&#xff1f;为什么中国不能很快做出ChatGPT&#xff1f;当前&#xff0c;对这些问题的探讨大多囿于大型语言模型&#xff08;LLM&#xff09;的技术可行性&#xff0c;忽略或者非常粗糙地估计了实现这些目标背后的经济成本&…

((蓝桥杯 刷题全集)【备战(蓝桥杯)算法竞赛-第4天(搜索与图论-下 专题)】( 从头开始重新做题,记录备战竞赛路上的每一道题 )距离蓝桥杯还有63天

&#x1f3c6;&#x1f3c6;&#x1f3c6;&#x1f3c6;&#x1f3c6;&#x1f3c6;&#x1f3c6; 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&a…

差分隐私学习笔记

2021网络空间安全西湖学术论坛线上报告中介绍了差分隐私过去发展&#xff0c;目前现状以及未来研究方向。博主对这个报告进行了介绍与总结。总结中提到学习差分隐私最重要的环节是&#xff1a; 了解差分隐私的基本机制&#xff1a;拉普拉斯机制、指数机制和高斯机制差分隐私的组…

【数据结构与算法】前缀树的实现

&#x1f320;作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《数据结构与算法要啸着学》 &#x1f387;座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;…

54 循环神经网络 RNN【动手学深度学习v2】

54 循环神经网络 RNN【动手学深度学习v2】 深度学习学习笔记 学习视频&#xff1a;https://www.bilibili.com/video/BV1D64y1z7CA/?spm_id_from333.880.my_history.page.click&vd_source75dce036dc8244310435eaf03de4e330 对序列化数据集的训练网络&#xff0c;通常称为RN…

第三章 Opencv图像像素操作

目录1.像素1-1.确定像素位置1-2.获取指定像素的像素值1-3.修改像素的BGR值2.用numpy模块操作像素2-1.创建图像1.创建黑白图像2.创建彩色图像3.创建随机图像2-2.拼接图像1.水平拼接hstack()方法2.垂直拼接vstack()方法1.像素 1.像素是构成数字图像的最小单位。每一幅图像都是由M…

【第29天】SQL进阶-查询优化- performance_schema系列实战四:查看最近的SQL执行信息(SQL 小虚竹)

回城传送–》《32天SQL筑基》 文章目录零、前言一、 查看最近的top sql1.1 数据准备&#xff08;如果已有数据可跳过此操作&#xff09;1.2 查询events_statements_summary_by_digest表二、查看最近执行失败的SQL2.1 开启第一个会话&#xff0c;执行错误sql2.2 开启第二个会话&…

pytest当中pytest.ini使用

目录 一、作用 二、存放位置 三、功能&#xff08;只列了简单的&#xff09; 1、 addopts 2、更改测试用例收集规则 四、运行就减少了命令了 前言&#xff1a;pytest配置文件可以改变pytest的运行方式&#xff0c;它是一个固定的文件pytest.ini文件。 一、作用 pytest.in…

Ceph分部署存储知识总结

Ceph 一.deploy-ceph部署 投入使用ceph前&#xff0c;要知道一个很现实得问题&#xff0c;ceph对低版本内核得客户端使用非常不友好&#xff0c;低内核是指小于等于3.10.0-862&#xff0c;默认的centos7.5及以下的系统都是小于此类内核&#xff0c;无法正常使用ceph的文件存储…

内网渗透(十一)之内网信息收集-内网IP扫描和发现

系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…

用YOLOv8推荐的Roboflow工具来训练自己的数据集

YOLOv8是Ultralytics公司开发的YOLO目标检测和图像分割模型的最新版本&#xff0c;相较于之前的版本&#xff0c;YOLOv8可以更快速有效地识别和定位图像中的物体&#xff0c;以及更准确地分类它们。 作为一种深度学习技术&#xff0c;YOLOv8需要大量的训练数据来实现最佳性能。…

如何旋转YUV图片数据且使用Qt显示

前言 提一下这篇文章的需求&#xff1a;将USB相机获取到的YUV数据进行旋转&#xff0c;然后转为QImage进行显示。原本程序中是有旋转的代码&#xff0c;但不知道为什么&#xff0c;旋转出来的图片会花屏。关于花屏的问题&#xff0c;后面会稍微阐述一下。所以&#xff0c;经过…

[多线程进阶] 常见锁策略

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录: 1. 常见的锁策略 1.1 乐观锁 vs 悲观锁 1.2 读写…

bootstrap 框架

文章目录bootstrap必须使用 HTML5 文档类型排版和链接默认栅格系统带有基本栅格的 HTML 代码媒体类型媒体类型逻辑运算符 用来做条件判断页面布局&#xff1a; 引入 css&#xff08;bootstrap.min.css&#xff09; 类名03-面包屑导航警告框、徽章、面包屑导航、按钮、按钮组卡…