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

news2025/5/26 3:26:44

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/334964.html

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

相关文章

【Selenium学习】Selenium 八大定位法

1.1 ID定位HTML Tag 的 id 属性值是唯一的&#xff0c;故不存在根据 id 定位多个元素的情况。下面以在百度首页搜索框输入文本“python”为例。搜索框的 id 属性值为“kw”&#xff0c;如图1.1所示&#xff1a;代码如下&#xff0c;“find_element_by_id”方法已废弃&#xff0…

基于nodejs+vue的健身房课程预约平台

本系统主要实现了首页、个人中心、用户管理、教练管理、会员卡管理、购买会员管理、课程类型管理、课程信息管理、课程购买管理、场地信息管理、场地预约管理、系统管理,用户&#xff1a;首页、个人中心、购买会员管理、课程购买管理、场地预约管理,教练&#xff1a;首页、个人…

睿创转债,声迅转债上市价格预测

睿创转债基本信息转债名称&#xff1a;睿创转债&#xff0c;评级&#xff1a;AA&#xff0c;发行规模&#xff1a;15.6469亿元。正股名称&#xff1a;睿创微纳&#xff0c;今日收盘价&#xff1a;47.45元&#xff0c;转股价格&#xff1a;40.09元。当前转股价值 转债面值 / 转…

树生成工具泛型接口 TreeNode

1、定义泛型接口 // 实现接口需要传入两个参数&#xff0c;第一个T 为节点中的id&#xff0c;第二个R 为节点&#xff0c;TreeNode。 public interface TreeNode<T, R extends TreeNode<T, R>> {/*** 获取节点id** return 树节点id*/T id();/*** 获取该节点的父节…

读书笔记//《数据分析:企业的贤内助》

数据分析师是个杂家——作者陈哲。 为什么写这本书&#xff1f; 懂得再多知识却不会用&#xff0c;原因是缺少通往思路、方法和技能的两条路径——项目流程和项目应用&#xff08;案例&#xff09; —————————— 数据分析师的晋升空间 &#xff08;见第2章&#xff0…

NLP模型检查英语语法错误

当NLP模型产生了语法错误&#xff0c;怎么办&#xff1f;比如&#xff0c;He wants that you send him an email.没关系&#xff0c;现在可以像小时候的英语老师&#xff0c;改作文一样简单。只要装上一个专门纠正语法错误的库就可以&#xff0c;还是毫秒钟就可揪出来的那种。这…

【shell】awk、sed、sort是什么?怎么用?

目录 一、AWK 干什么用的&#xff1f; 使用起来有什么条件&#xff1f; 怎么使用&#xff1f; 二、sed 功能&#xff1f; sed怎样读取数据&#xff1f; 怎样调用sed &#xff1f; 三、sort 功能是什么&#xff1f; 命令有哪些&#xff1f; 本文只讲解了一些简略的知…

“千年之恋”注册页面制作

“千年之恋”注册页面制作一、实验名称&#xff1a;二、实验日期&#xff1a;三、实验目的&#xff1a;四、实验内容&#xff1a;五、实验步骤&#xff1a;六、实验结果&#xff1a;七、源程序&#xff1a;八、心得体会&#xff1a;一、实验名称&#xff1a; “千年之恋”注册…

算法导论—SAT、NP、NPC、NP-Hard问题

算法导论—SAT、NP、NP-Hard、NPC问题SAT 问题基本定义问题复杂性P、NP、NP-Hard、NP-Complete&#xff08;NPC&#xff09;证明NP-Hard关系图NP问题的概念约化的定义NPC问题NP-Hard问题SAT 问题基本定义 SAT 问题 (Boolean satisfiability problem, 布尔可满足性问题,SAT): 给…

C++之完美转发、移动语义(forward、move函数)

完美转发1. 在函数模板中&#xff0c;可以将自己的参数“完美”地转发给其它函数。所谓完美&#xff0c;即不仅能准确地转发参数的值&#xff0c;还能保证被转发参数的左、右值属性不变。2. C11标准引入了右值引用和移动语义&#xff0c;所以&#xff0c;能否实现完美转发&…

「敏捷架构」敏捷架构:规模化敏捷开发的策略

与流行的看法相反&#xff0c;架构是敏捷软件开发工作的一个重要方面&#xff0c;就像传统的工作一样&#xff0c;并且是扩展敏捷方法以满足现代组织的现实需求的关键部分。但是&#xff0c;敏捷专家的架构方式与传统主义者的方式略有不同。本文讨论以下问题&#xff1a; 迈向敏…

Acer传奇Go电脑开机自动安装软件卡死怎么重装系统?

Acer传奇Go电脑开机自动安装软件卡死怎么重装系统&#xff1f;一些用户在网络上下载安装了一些恶意软件之后&#xff0c;导致电脑中了病毒。每次开机联网之后&#xff0c;有很多的软件就会自动开始下载&#xff0c;占满你的桌面&#xff0c;这个情况导致电脑直接卡死了&#xf…

前端知识点复盘

组件和jsx <body><div id"root"></div><script type"text/babel">const root ReactDOM.createRoot(document.getElementById("root"))class App extends React.Component {render() {return (<div> <h1>s…

MOTORTECH控制器维修燃气机点火模块MIC500

MOTORTECH发电机点火控制器模块维修注意事项: (1)由于主配电板经常发生振动,因此故障多发生在振动较强烈之处,所以要检查引起振动的原因并排除之,如躲开共振转速,增加防震垫片等。 (2)尘埃是造成接触不良的原因,对接线端子座及防尘罩等容易附着灰尘的场所要经常清扫。 1、看元…

2023级浙江大学MBA提面优秀资格最新经验分享

通过将近一年时间的奋斗&#xff0c;我的浙大MBA备考之路也算是告一段落了&#xff0c;在备考之初&#xff0c;我也在网络上看了很多“经验帖”&#xff0c;深知提前批面试对于浙大MBA录取来说这个有多重要&#xff0c;虽然我的笔试成绩还没有出来&#xff0c;但是在考完后估分…

HTTP请求返回304状态码以及研究nginx中的304

文章目录1. 引出问题2. 分析问题3. 解决问题4. 研究nginx中的3044.1 启动服务4.2 ETag说明4.3 响应头Cache-Control1. 引出问题 之前在调试接口时&#xff0c;代码总出现304问题&#xff0c;如下所示&#xff1a; 2. 分析问题 HTTP 304: Not Modified是什么意思&#xff1f; …

2022年新一代kaldi团队技术输出盘点

目录 1. 技术创新 1.1 Pruned RNN-T loss 1.2 RNN-T 的快速 GPU 解码 1.3 多码本量化索引的知识蒸馏 1.4 RNN-T 和 CTC 的低延时训练 1.5 Zipformer 1.6 Small tricks 2. 模型部署 2.1 Sherpa 2.1 Sherpa-ncnn 3. 更多的 recipe 和模型 参考资料 1. 技术创新 1.1 …

C语言程序环境剖析——探究从.c到.exe之路

程序环境1.程序的翻译环境和执行环境2. 详解编译 链接2.1 翻译环境2.2 编译的三部分预编译编译汇编2.3链接3.运行环境1.程序的翻译环境和执行环境 在ANSI C的任何一种实现中&#xff0c;都存在两个不同的环境。 翻译环境&#xff0c;在这个环境中源代码被转换成可执行的机器指…

three.js 基础认识与简单应用

一、前言 1. 什么是three.js&#xff1f;你将它理解成threejs&#xff0c;three表示3D的意思&#xff0c;js表示JavaScript的意思&#xff0c;合起来&#xff0c;three.js就是使用JavaScript来写3D程序的意思。three.js是基于WebGL的一个运行在浏览器上的开源框架&#xff0c;使…

企业级安全软件装机量可能大增

声明 本文是学习大中型政企机构网络安全建设发展趋势研究报告. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 研究背景 大中型政企机构是网络安全保护的重中之重&#xff0c;也是国内网络安全建设投入最大&#xff0c;应用新技术、新产品最多的机构…