• json进阶---jackson底层之JsonParser理解使用(springboot多结构参数的映射方法的实现思路)


    1.引子

    如果你经常从事后端开发,那么一定会遇到各种各样的json数据,并非所有的数据都可以直接按照springboot的映射的默认规则进行映射。

    以我的需求为例接受的一个参数可以是

    {
      "event":"SendLinkMsg",
      "to_wxid": "wxid_rxhdmvaefp1922",
      "msg": {"xml" : "dwadadwadadwa","id" : "wxid_rxhdmvaefp1922"}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    也可能是

    {
      "event":"SendTextMsg",
      "to_wxid": "wxid_rxhdmvaefp1922",
      "msg": "草神真可爱,软软的,嘿嘿嘿"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    毫无疑问这是两种完全不同的结构,如果直接进行映射的话势必存在一个数据无法映射的情况。

    这里我们就会经常使用@JsonDeserializer手动处理参数,而其中的JsonParser则是我们不能不了解的。
    在这里插入图片描述

    那这里我就简单说一下JsonParser的使用方法和简单的运行原理!

    2.JsonParser的简单使用和理解

    1.使用JsonFactory创建JsonParser

    故名思意,jsonFactory就是用于处理json的工厂,它可以把你所指定的json处理成标记的字段,它提供了解析器,让操作者高效率手动处理json成为可能。

    String a = "{\n" +
                    "  \"event\":\"SendLinkMsg\",\n" +
                    "  \"to_wxid\": \"wxid_rxhdmvaefp1922\",\n" +
                    "  \"msg\": {\"xml\" : \"dwadadwadadwa\",\"id\" : \"22131\"}";
    JsonFactory jsonFactory = new JsonFactory();
    JsonParser parser = jsonFactory.createParser(a)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    当然也可以通过 createParser()方法传入 Reader, InputStream, URL, byte[] 或 char[] 来解析不同来源的json
    在这里插入图片描述

    这里我们就成功拿到了jsonfactory生成的json解析器。

    2.JsonParser的使用:

    解析器根据json规则把传入的json切分成带有标记的字段。

    在这里插入图片描述
    字段类型包括

        NOT_AVAILABLE((String)null, -1),
        START_OBJECT("{", 1),   //公共属性开始
        END_OBJECT("}", 2),     //公共属性结束
        START_ARRAY("[", 3),    //数组开始
        END_ARRAY("]", 4),      //数组结束
        FIELD_NAME((String)null, 5), //字段名
        VALUE_EMBEDDED_OBJECT((String)null, 12), 
        VALUE_STRING((String)null, 6),     //字符串值
        VALUE_NUMBER_INT((String)null, 7), //整数值
        VALUE_NUMBER_FLOAT((String)null, 8),//浮点值
        VALUE_TRUE("true", 9), //布尔值 正确
        VALUE_FALSE("false", 10), //布尔值 错误
        VALUE_NULL("null", 11); //空值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    当我们处理json的时候,根据token标记,当token指针指到结尾的时候,JsonParser就会关闭,我们可以通过parser.isClosed()判断json是否解析到末尾。

    parser给了我们很多操作读取字段的方法

    currentToken(),nextToken()
    
    • 1

    用于返回当前token指针对应字段的类型;向右移动指针并且返回移动后的值

    getCurrentName,getValueAsString()
    
    • 1

    获取当前指针对应字段的名字和值的类型。还有其他方法我就不一一阐述了

    需要注意的是,当指针指向字段名的时候使用getValueAsString()并不能返回字段名对应的字段值

    而指针指向值的时候使用getCurrentName却能获取对应的字段名

    当然,我们也可以根据json规则,在字段名类型后面的字段必定是值类型
    在这里插入图片描述
    正确示例

        public static void main(String[] args) {
            String a = "{\n" +
                    "  \"event\":\"SendLinkMsg\",\n" +
                    "  \"to_wxid\": \"wxid_rxhdmvaefp1922\",\n" +
                    "  \"msg\": {\"xml\" : \"dwadadwadadwa\",\"id\" : \"22131\"}\n" +
                    "}";
            JsonFactory jsonFactory = new JsonFactory();
            try (JsonParser parser = jsonFactory.createParser(a)) {
                System.out.println(parser.currentToken());
                while(!parser.isClosed()){
                    JsonToken jsonToken = parser.nextToken();
                    if(JsonToken.FIELD_NAME.equals(jsonToken)){
                        String fieldName = parser.getCurrentName();
                        parser.nextToken();
    
                        System.out.println(fieldName+","+parser.getValueAsString());
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    3:多结构json映射解决思路:

    回到最开始的问题,java是不能返回多种参数的,但是我们可以稍微变通下

    我们可以把参数封装到一个实体类里,在实体类里多加一个字符串的属性
    在这里插入图片描述

    如果不是字符串的话就正常映射,如果是字符串的话把他打包,装到实体类的一个str属性里

    那么字符串json和对象json区别很简单:

    正常json是有字段名和json值的

    把对应的json值封装即可
    在这里插入图片描述

    而单单读取字符串其实不是json数据的,仅仅会读取到一个value值,把值封装返回即可

        public Msg deserialize(JsonParser parser, DeserializationContext deserializationContext) throws IOException {
            StringBuilder str = new StringBuilder();
            String xml = null;
            String name = null;
            String path = null;
            Integer type = null;
                while(!parser.isClosed()){
                    if (parser.getValueAsString()!=null){
                        System.out.println(parser.getValueAsString());
                        str.append(parser.getValueAsString());
                    }
                    JsonToken jsonToken = parser.nextToken();
                    if(JsonToken.FIELD_NAME.equals(jsonToken)){
                        String fieldName = parser.getCurrentName();
                        parser.nextToken();
                        if ("xml".equals(fieldName)){
                            xml = parser.getValueAsString();
                        } else if("name".equals(fieldName)){
                            name = parser.getValueAsString();
                        } else if ("path".equals(fieldName)){
                            path = parser.getValueAsString();
                        } else if ("type".equals(fieldName)){
                            type = parser.getIntValue();
                        }else {
                            str.append(parser.getValueAsString());
                        }
                    }
                }
            Msg msg = new Msg(str.toString(),path,name,xml,type);
                return  msg;
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    1.处理字符串
    在这里插入图片描述
    2.处理对象
    在这里插入图片描述

    至此需求解决,当然代码不够凝练,如果各位大佬有什么更好的思路可以一起分享交流。

  • 相关阅读:
    网课答案查询单页源码+免费题库api接口
    如何在 initial / task 等 begin_end 中等待某一个信号
    哪款蓝牙耳机音质好?2022年学生党蓝牙耳机推荐
    微前端四:qiankun在开发中遇到的问题
    【web-攻击用户】(9.1.2)XSS示例、攻击有效载荷、攻击的传送机制
    LeetCode 0144. 二叉树的前序遍历:二叉树必会题
    Koa 源码剖析
    word 如何编写4x4矩阵
    【洛谷P2258】子矩阵【DFS+DP】
    安卓播放解码后的byte字节视频
  • 原文地址:https://blog.csdn.net/faker1234546/article/details/127752847