背景
在异构系统中,不同的平台数据通信的方式多种多样,当前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); } }
本博客文章绝大多数为原创,少量为转载,代码经过测试验证,如果有疑问直接留言或者私信我。
创作文章不容易,转载文章必须注明文章出处;如果这篇文章对您有帮助,点击右侧打赏,支持一下吧。
创作文章不容易,转载文章必须注明文章出处;如果这篇文章对您有帮助,点击右侧打赏,支持一下吧。