背景

在异构系统中,不同的平台数据通信的方式多种多样,当前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);
    }
}

 

posted on 2022-02-17 17:28  你不知道的浪漫  阅读(669)  评论(0编辑  收藏  举报