• springboot解析带控制字符\"的json字符串


    背景

    在异构系统中,不同的平台数据通信的方式多种多样,当前web系统流行restful接口通信方法。

    restful接口通信的灵魂无非是json。本文适用于c#中使用newtonsoft 生成的json向java开放的restful接口通信。

    以及SAP向java的restful接口进行通信。

    比较接收到的json如下

    {
        "json": "{\"HEADER\":{\"AUFNR\":\"100002312156\",\"PLNBEZ\":\"20481438\",\"GAMNG\":\"100.000\",\"GMEIN\":\"PC\",\"GSTRP\":\"20211227\",\"GLTRP\":\"20211229\",\"WERKS\":\"1001\",\"ZKUNNR\":\"\",\"ZNAME1\":\"\",\"STATUS\":\"1\",\"ZLS\":\"l2211240013\",\"FEVOR\":\"101\"},\"OPERATES\":[{\"AUFNR\":\"100002312156\",\"VORNR\":\"0010\",\"ARBPL\":\"ctkx02\",\"LTXA1\":\"开线\",\"SORTL\":\"0010\",\"BMSCH\":\"1.000\",\"VGW01\":\"1.460\",\"VGE01\":\"S\",\"VGW02\":\"\",\"VGE02\":\"\",\"VGW03\":\"\",\"VGE03\":\"\",\"VGW04\":\"\",\"VGE04\":\"\",\"VGW05\":\"\"}],\"COMPONENTS\":[{\"AUFNR\":\"100002312156\",\"MATNR\":\"a01011551\",\"BDMNG\":\"784.000\",\"ENMNG\":\"520.000\",\"MEINS\":\"M\",\"LGORT\":\"4001\",\"VORNR\":\"0010\",\"RGEKZ\":\"\",\"WERKS\":\"1001\",\"POSNR\":\"0001\",\"RSNUM\":\"0012552966\",\"LOEKZ\":\"\",\"DUMPS\":\"\",\"MENGE\":\"0.280\",\"ZMEINS\":\"M\"},{\"AUFNR\":\"100002312156\",\"MATNR\":\"a01011551\",\"BDMNG\":\"2800.000\",\"ENMNG\":\"1000.000\",\"MEINS\":\"PC\",\"LGORT\":\"4001\",\"VORNR\":\"0010\",\"RGEKZ\":\"\",\"WERKS\":\"1001\",\"POSNR\":\"0002\",\"RSNUM\":\"0012552966\",\"LOEKZ\":\"\",\"DUMPS\":\"\",\"MENGE\":\"1.280\",\"ZMEINS\":\"M\"}]}"
    }

    服务端的实体如下

    package com.www.dto;
    
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
    import com.www.common.component.json.SAPOrderReceiveDTODeserializer;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    import org.apache.commons.lang3.builder.ToStringBuilder;
    
    import javax.validation.Valid;
    import javax.validation.constraints.NotEmpty;
    import javax.validation.constraints.NotNull;
    import java.util.Set;
    
    
    @Data
    @EqualsAndHashCode(callSuper = false)
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    @ApiModel("SAP订单接收接口入参")
    public class SAPOrderReceiveDTO {
    
            /***
             * 订单头
             */
            @Valid
            @ApiModelProperty(value = "订单号 参见SAPMoHeaderDTO类型")
            @NotNull(message = "订单头必填")
            @JsonProperty(value = "HEADER")
            private SAPMoHeaderDTO header;
    
            /***
             * 订单工艺
             */
            @Valid
            @ApiModelProperty(value = "订单工序 参见SAPMoOperateDTO类型")
            @NotEmpty(message = "订单工序必填")
            @JsonProperty(value = "OPERATES")
            private Set<SAPMoOperateDTO> operateList;
            /***
             * 订单组件
             */
            @Valid
            @ApiModelProperty(value = "订单组件 参见SAPMoComponentDTO类型")
            @NotEmpty(message = "订单组件必填")
            @JsonProperty(value = "COMPONENTS")
            private Set<SAPMoComponentDTO> componentList;
    }

    解决方法

    笔者日常使用springboot进行web项目开发,json解析框架是springboot默认的Jackson,本文以Jackson解析带控制字符的json为例。

    理论上fastjson是支持这种非标json的,不过不在本文讨论范围内,笔者不太喜欢fastjson,恕不回答fastjson相关的解决方案。

    实体改造

    package com.www.dto;
    
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
    import com.www.common.component.json.SAPOrderReceiveDTODeserializer;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    import org.apache.commons.lang3.builder.ToStringBuilder;
    
    import javax.validation.Valid;
    import javax.validation.constraints.NotEmpty;
    import javax.validation.constraints.NotNull;
    import java.util.Set;
    
    
    @Data
    @EqualsAndHashCode(callSuper = false)
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    @ApiModel("SAP订单接收接口入参")
    public class SAPOrderReceiveDTO {
    
        @Valid
        @JsonDeserialize(using = SAPOrderReceiveDTODeserializer.class)
        @JsonProperty(value = "json")
        @NotNull(message = "无效的json数据")
        private JsonNode json;
    
        @Data
        public static final class JsonNode
        {
            /***
             * 订单头
             */
            @Valid
            @ApiModelProperty(value = "订单号 参见SAPMoHeaderDTO类型")
            @NotNull(message = "订单头必填")
            @JsonProperty(value = "HEADER")
            private SAPMoHeaderDTO header;
    
            /***
             * 订单工艺
             */
            @Valid
            @ApiModelProperty(value = "订单工序 参见SAPMoOperateDTO类型")
            @NotEmpty(message = "订单工序必填")
            @JsonProperty(value = "OPERATES")
            private Set<SAPMoOperateDTO> operateList;
            /***
             * 订单组件
             */
            @Valid
            @ApiModelProperty(value = "订单组件 参见SAPMoComponentDTO类型")
            @NotEmpty(message = "订单组件必填")
            @JsonProperty(value = "COMPONENTS")
            private Set<SAPMoComponentDTO> componentList;
        }
    
    }

    新增自定义反序列化类

    package com.www.common.component.json;
    
    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.core.TreeNode;
    import com.fasterxml.jackson.databind.*;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    import com.fasterxml.jackson.databind.node.TextNode;
    import com.www.dto.SAPOrderReceiveDTO;
    import org.springframework.util.StringUtils;
    
    import java.io.IOException;
    
    public class SAPOrderReceiveDTODeserializer extends JsonDeserializer<SAPOrderReceiveDTO.JsonNode> {
        JacksonMapperEnhance objectMapper = new JacksonMapperEnhance();
    
        @Override
        public SAPOrderReceiveDTO.JsonNode deserialize(final JsonParser jp, final DeserializationContext ctx) throws IOException, JsonProcessingException {
            final TreeNode node = jp.getCodec().readTree(jp);
    
            String json = null;
            if ((node instanceof TextNode)) {
                json = ((TextNode) node).textValue();
            }
            if(node instanceof ObjectNode)
            {
                json = (((ObjectNode)node).get("json")).textValue();
            }
    
            if(StringUtils.isEmpty(json))
                return null;
    
    
            objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
    
            //反序列化:空字符串的对象直接转换成null对象
            objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT,true);
    
            // 忽略字段大小写
            objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
    
            final SAPOrderReceiveDTO.JsonNode jsonNode = objectMapper.readValue(toHalfWidth(json), SAPOrderReceiveDTO.JsonNode.class);
    
            return jsonNode;
        }
    
        /**
         * 转半角的函数(DBC case)<br/><br/>
         * 全角空格为12288,半角空格为32
         * 其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248
         *
         * @param input 任意字符串
         * @return 半角字符串
         */
        public String toHalfWidth(String input) {
            char[] c = input.toCharArray();
            for (int i = 0; i < c.length; i++) {
                if (c[i] == 12288) {
                    //全角空格为12288,半角空格为32
                    c[i] = (char) 32;
                    continue;
                }
                if (c[i] > 65280 && c[i] < 65375)
                    //其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248
                    c[i] = (char) (c[i] - 65248);
            }
            return new String(c);
        }
    }
  • 相关阅读:
    Java I/O(二 使用)
    Java 基本I/O的学习总结(一 是什么)
    设计模式(一)
    浏览器输入一个网址(发生的过程)
    final关键字的4种用法
    JavaScript(4)——闭包与this对象以及window对象
    JavaScript(3)—— 正则表达式
    JavaScript(2)——对象属性、原型与原型链
    JavaScript(1)——变量、函数声明及作用域
    构建分布式配置中心阿波罗(Apollo)
  • 原文地址:https://www.cnblogs.com/passedbylove/p/15905622.html
Copyright © 2020-2023  润新知