仓储WMS对接淘宝奇门详细说明【亲测可用】
文章目录
- 简介
- 名词解释
- 奇门对接方案
- 前期准备
- 系统调用流程
- 代码实现思路
- 关键点(个人观点)
- 奇门对接关键代码
- 可能遇到的问题
简介
- 淘宝奇门项目支持 ERP、WMS 之间的系统标准化对接,通过构建 ERP、WMS 系统之间标准通信协议来实现不同系统之间的打通;对商家来说,省去了更换系统软件所带来的额外开发成本;对 ISV(独立软件开发商) 来说,省去了与多家 ERP、WMS 系统对接难的问题,ERP 通过一次对接奇门项目,打通与所有 WMS 之间的通信,WMS 通过一次对接奇门项目,可以适配所有 ERP 软件;后期也将加入更多系统的支持,例如 CRM 与 ERP 的标准化对接,CRM 与在线订购类营销工具的标准化对接;
名词解释
奇门对接方案
无奇门的情况
- 目前商家使用的各个业务系统之间依靠 ISV 帮助实现 ERP 到 WMS 的对接,如果有多仓需求的商家还需要使用到 2 套以上的第三方仓储服务所提供的WMS 软件,ERP、WMS 各自对接,对接的总工作量为 N*N 倍,不但给 ISV的开发带来了极大的成本,对于后期维护,也将是一项艰巨的任务,如下图所示:
有奇门的情况
- 通过奇门项目后可使原有的网状对接结构变为一对一的对接方式,ERP、WMS 只需要与奇门数据总线对接一次即可完成所有系统的适配(特殊场景可能采用扩展字段的方式给与支持),如下图:
前期准备
- 首先要在淘宝开放平台上线对应的服务。
- 具体上线申请参考:应用接入流程 , 奇门仓储接入说明,奇门仓储标准白皮书
- 上线完成后,拿到对应开发语言的sdk,appkey,secret。
- 创建一个场景
- 点击进入。
- 然后就可以开始开发了。
系统调用流程
- 正向调用:前端 ERP 系统通过 TOP 接口与奇门项目应用进行交互,对于想要发送到 WMS 的请求首先发送到奇门应用,由奇门负责数据的解析、字段映射、数据翻译,再将处理后的数据通过 ERP 系统所请求的目的地发送至 WMS系统;WMS 系统收到请求后,将返回结果送回至奇门应用,由奇门应用统一返回至 ERP 系统;
- 反向调用:WMS 系统主动向 ERP 系统发出状态更新请求也是类似以上的访问步骤;
软件流程图:
代码实现思路
- 接收奇门主动请求接口收到的XML类型的参数,将XML转换为奇门定义的对象,然后将奇门对象转换为我们自己系统的对象。
- 判断请求的奇门接口名称走不同的业务实现方法,接口返回数据请参照淘宝奇门接口API文档
- 各实现方法返回Map格式数据,转换为xml格式返回。
关键点(个人观点)
- xml转为对象
- 对象转为xml
- 封装统一的接口响应
- 对应各个接口的实现和数据返回
奇门对接关键代码
@RestController
@RequestMapping("/qiMen")
@RequiredArgsConstructor
@Slf4j
public class QiMenController {private final QiMenService qiMenService;@ApiModelProperty("奇门调用WMS数据")@RequestMapping(value="/apiRealization",produces="text/xml;charset=UTF-8")public byte[] apiRealization(HttpServletRequest request, HttpServletResponse response) throws IOException {byte[] result;Map<String, Object> resultMap = new HashMap<>();// API接口名称String methodVal = request.getParameter("method");// 验签CheckResult checkResult = QiMenUtils.checkSign(request);log.info("验签:{}",checkResult.isSuccess());if(!checkResult.isSuccess()) {resultMap.put("sub_code","sign-check-failure");resultMap.put("sub_message","Illegal request");resultMap.put("flag","failure");result = QiMenUtils.multilayerMapToXml(resultMap, false).getBytes(StandardCharsets.UTF_8);return result;}try {// 解析xml参数log.info("xml参数:{}", checkResult.getRequestBody());JSONObject jsonObject = JSONUtil.xmlToJson(checkResult.getRequestBody());log.info("jsonObject:{}", jsonObject);if(Objects.nonNull(jsonObject)) {if(!StringUtils.isBlank(methodVal)) {switch (methodVal) {case "entryorder.create":// 入库单创建接口resultMap = qiMenService.entryorderCreate(jsonObject);break;case "stockout.create":// 出库单创建接口resultMap = qiMenService.stockoutCreate(jsonObject);break;default:resultMap = RCode.failure(RCode.FAILURE,"接口名称method填写有误");break;}}else {resultMap = RCode.failure(RCode.FAILURE,"接口名称method不能为空");}result = QiMenUtils.multilayerMapToXml(resultMap, false).getBytes("UTF-8");}else {result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>".getBytes("UTF-8");}} catch (BizException e) {resultMap = RCode.failure(RCode.FAILURE,e.getMessage());try {result = QiMenUtils.multilayerMapToXml(resultMap, false).getBytes("UTF-8");} catch (UnsupportedEncodingException e1) {return null;}} catch (Exception e) {log.error("操作失败:" + e + "-----" + e.getMessage());resultMap = RCode.failure(RCode.FAILURE,"操作失败");try {result = QiMenUtils.multilayerMapToXml(resultMap, false).getBytes("UTF-8");} catch (UnsupportedEncodingException e1) {return null;}}log.info("ERP调用响应结果 resultMap:{}",resultMap);return result;}@ApiModelProperty("WMS主动推送奇门数据")@PostMapping("/push/{method}")public Result pushQiMen(@PathVariable String method,@RequestBody JSONObject jsonObject) {QimenResponse response = null;switch (method) {case "entryorder.confirm":// 入库单确认response = qiMenService.entryorderConfirm(jsonObject);break;case "stockout.confirm":// 出库单确认response = qiMenService.stockoutConfirm(jsonObject);break;default:break;}return RCode.result(response);}
}
@RequiredArgsConstructor
@Slf4j
@Service
public class QiMenServiceImpl implements QiMenService {public static final String XML_KEY = "request";/*** 入库单创建** @param jsonObject* @return*/@Overridepublic Map<String, Object> entryorderCreate(JSONObject jsonObject) {// 将请求头的数据转换为当前系统对应的dto类EntryorderCreateRequest bean = jsonObject.getBean(XML_KEY, EntryorderCreateRequest.class);List<JSONObject> list = jsonObject.getByPath("request.orderLines.orderLine", List.class);if (CollUtil.isEmpty(list)) {throw new BizException("入库单详情列表为空!");}List<EntryorderCreateRequest.OrderLine> orderLines = new ArrayList<>();for (JSONObject object : list) {orderLines.add(object.toBean(EntryorderCreateRequest.OrderLine.class));}bean.setOrderLines(orderLines);QiMenReceiptOrderDTO receiptOrderDTO = QiMenConvert.entryorderCreate(bean);// 远程调用创建入库单Result result = qiMenRequestInBound.qiMenRequestInBound(receiptOrderDTO);// 包装响应结果return RCode.result(result);}/*** WMS调用接口,回传入库单信息;** @param jsonObject* @return*/@Overridepublic QimenResponse entryorderConfirm(JSONObject jsonObject) {// wms dto 转换为 EntryorderConfirmRequestQiMenInboundAckVO bean = JSONUtil.toBean(jsonObject, QiMenInboundAckVO.class);EntryorderConfirmRequest req = QiMenConvert.entryorderConfirm(bean);req.setVersion("2.0");req.setCustomerId("mockCustomerId"); // mockCustomerId 挡板测试的客户idQimenClient client = getClient();EntryorderConfirmResponse rsp = new EntryorderConfirmResponse();try {rsp = client.execute(req);} catch (ApiException e) {log.error("调用奇门异常:",e);rsp.setMessage(e.getMessage());}return rsp;}
public class QiMenUtils {private final static String secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";private final static String appkey = "xxxx";// 联调地址 http://qimen.api.taobao.com/router/qmtest// 正式地址 https://qimen.api.taobao.com/router/qimen/serviceprivate final static String url = "https://qimen.api.taobao.com/router/qimen/service";/*** wms主动发起请求奇门的接口 创建一个连接* @return*/public static QimenClient getClient() {return new DefaultQimenClient(url, appkey, secret);}/*** 验签 调用sdk中的签名验证方法* @param request* @return*/@SneakyThrowspublic static CheckResult checkSign(HttpServletRequest request) {return SpiUtils.checkSign(request, secret);}/*** (多层)map转换为xml格式字符串** @param map 需要转换为xml的map* @param isCDATA 是否加入CDATA标识符 true:加入 false:不加入* @return xml字符串* @throws UnsupportedEncodingException*/public static String multilayerMapToXml(Map<String, Object> map, boolean isCDATA) throws UnsupportedEncodingException{String parentName = "response";Document doc = DocumentHelper.createDocument();doc.addElement(parentName);String xml = recursionMapToXml(doc.getRootElement(), parentName, map, isCDATA);return formatXML(xml);}/*** multilayerMapToXml核心方法,递归调用** @param element 节点元素* @param parentName 根元素属性名* @param map 需要转换为xml的map* @param isCDATA 是否加入CDATA标识符 true:加入 false:不加入* @return xml字符串*/@SuppressWarnings("unchecked")private static String recursionMapToXml(Element element, String parentName, Map<String, Object> map, boolean isCDATA) {Element xmlElement = element.addElement(parentName);map.keySet().forEach(key -> {Object obj = map.get(key);if (obj instanceof Map) {recursionMapToXml(xmlElement, key, (Map<String, Object>)obj, isCDATA);} else {String value = obj == null ? "" : obj.toString();if (isCDATA) {xmlElement.addElement(key).addCDATA(value);} else {xmlElement.addElement(key).addText(value);}}});return xmlElement.asXML();}/*** 格式化xml,显示为容易看的XML格式** @param xml 需要格式化的xml字符串* @return*/public static String formatXML(String xml) {String requestXML = null;try {// 解析器SAXReader reader = new SAXReader();Document document = reader.read(new StringReader(xml));if (null != document) {StringWriter stringWriter = new StringWriter();// 格式化,每一级前的空格OutputFormat format = new OutputFormat("", true);// xml声明与内容是否添加空行format.setNewLineAfterDeclaration(false);// 是否设置xml声明头部format.setSuppressDeclaration(false);// 是否分行format.setNewlines(true);XMLWriter writer = new XMLWriter(stringWriter, format);writer.write(document);writer.flush();writer.close();requestXML = stringWriter.getBuffer().toString();}return requestXML;} catch (Exception e) {e.printStackTrace();return null;}}
}
可能遇到的问题
xml转换为对象
对象list转换为xml
你知道的越多,你不知道的越多。
相关文章:

仓储WMS对接淘宝奇门详细说明【亲测可用】
文章目录 简介名词解释奇门对接方案前期准备系统调用流程代码实现思路关键点(个人观点)奇门对接关键代码可能遇到的问题 简介 淘宝奇门项目支持 ERP、WMS 之间的系统标准化对接,通过构建 ERP、WMS 系统之间标准通信协议来实现不同系统之间的打通;对商家…...

RFID软件:简介、功能和应用范围
在当今快节奏的商业环境中,RFID(射频识别)技术已经成为物流、供应链和库存管理等领域中不可或缺的工具。本文将向您介绍RFID软件的基本知识,探讨其功能和广泛应用的范围。 第一部分:RFID软件简介 RFID软件是一种应用…...

Android 逆向之安全防护基本策略
对抗反编译 混淆 使用混淆主要可以减小包的大小。混淆对于安全保护来说,只是增加了阅读难度而已。混淆不会把关键代码混淆掉,比如MainActivity,Application等,可以通过分析smali和阅读jar包定位代码。 资源混淆也是换汤不换药&…...

基站机房:保障通信网络稳定,如何解决安全隐患?
基站机房作为无线通信网络的关键组成部分,承载着大量的网络设备和通信设施,对于运营商和通信服务提供商来说具有重要意义。 无论是大型运营商还是通信服务提供商,动环监控系统都将成为他们成功运营和管理通信网络的关键工具。 客户案例 案例…...

sqlmap -os-shell 使用方法
一、burp suite抓包。 如上图所示,红框处很明显是一个传参点,我们就在这个页面抓包。 抓到包之后将内容保存到桌面的1000.txt文件下。 二、sqlmap跑包。 打开sqlmap跑包。 python sqlmap.py -r C:\Users\16434\Desktop\1000.txt -dbmsmysql --os-shell…...

Go语言并发之Select多路选择操作符
1、Go语言并发之Select多路选择操作符 select 是类 UNIX 系统提供的一个多路复用系统 API,Go 语言借用多路复用的概念,提供了 select 关键字,用 于多路监听多个通道。当监听的通道没有状态是可读或可写的,select 是阻塞的&#…...

黄金回收小程序开发功能有哪些?
一、用户端: 1、实时查询:通过对接三方接口实现实时金价动态查看; 2、多种类珠宝实时回收:小程序支持多品类珠宝的实时回收包含黄金饰品、金条、铂金、K金、白银等,同步实现价格实时更新; …...
nginx的详解与应用
前言 说明 要义 nginx 有一个master 进程和多个worker 进程。主进程的主要目的是读取和评估配置,以及维护工作进程。工作进程对请求进行实际处理。nginx 采用基于事件的模型和依赖于操作系统的机制在工作进程之间有效地分发请求。工作进程的数量在配置文件中定义…...
SpringBoot激活profiles的几种方式
多环境是最常见的配置隔离方式之一,可以根据不同的运行环境提供不同的配置信息来应对不同的业务场景,在SpringBoot内支持了多种配置隔离的方式,可以激活单个或者多个配置文件。 激活的profiles要在项目内创建对应的配置文件,格式…...

【Java】Java核心要点总结:58
文章目录 1. java中 怎么确保一个集合不能被修改2. 队列和栈是什么 有什么区别3. Java8开始的ConcurrentHashMap为什么舍弃了分段锁4. ConcurrentHashMap 和 Hashtable有什么区别5. ReadWriteLock和StampeLock 1. java中 怎么确保一个集合不能被修改 Java 中可以使用 Collectio…...
前端面试题---作用域链和原型链
一.JavaScript 中的作用域链是如何工作的? JavaScript 中的作用域链(Scope chain)是一种用于查找变量和函数的机制,它是由嵌套的作用域环境组成的链式结构。 当在 JavaScript 中访问一个变量或函数时,解析器会首先在当前作用域…...
零售品牌私域流量池如何运营?火山引擎数智平台提供全套产品组合
虽然距离6月18日还有两周时间,但各大平台的第一波618战绩(预售尾款)已经相继出炉。 5月31日晚8点,京东率先公布618开门红10分钟销售战报:10分钟内,成交额破亿品牌数同比增长23%,超六成的新商家…...

rk3568 SD卡启动
rk3568 SD卡启动 SD卡启动系统,它可以让rk3568在没有硬盘或其他存储设备的情况下启动和运行操作系统。这使得rk3568变得与树梅派一样灵活切换系统,与此同时进行故障排查和修复,而不需要拆卸设备或者使用专业的烧录工具。SD卡启动还可以方便地…...

English Learning - L3 作业打卡 Lesson5 Day34 2023.6.7 周三
English Learning - L3 作业打卡 Lesson5 Day34 2023.6.7 周三 引言🍉句1: The woman reading the romantic novel could be a lawyer.成分划分弱读连读爆破语调 🍉句2: She just wants a light read to take her mind off work.成分划分弱读连读爆破语调…...

【运筹优化】最短路算法之A星算法 + Java代码实现
文章目录 一、A星算法简介二、A星算法思想三、A星算法 java代码四、测试 一、A星算法简介 A*算法是一种静态路网中求解最短路径最有效的直接搜索方法,也是解决许多搜索问题的有效算法。算法中的距离估算值与实际值越接近,最终搜索速度越快。 二、A星算…...

[6]PCB设计实验|认识常用元器件|电阻器|18:30~19:00
目录 一、电阻器主要用途 1. 稳定和调节电路中的电流和电压 2. 作为分流、分压和负载使用 二、常见电阻器 1. 贴片电阻 2. 热敏电阻 3. 限流电阻 4. 可调电阻 5. 排阻(网络电阻) 三、几种常用电阻器的结构特点 四、电阻的参数 1. 额定功率 电阻器功率的表示 2…...

Webots R2021a教程
文章目录 Windows安装设置中文打开世界添加贴图 为外部控制器配置Anaconda解决报错:CondaSSLError: Encountered an SSL error. Most likely a certificate verification issue.调用Python API Windows 安装 进入下载页面 https://github.com/cyberbotics/webots/r…...

C++ 输出格式控制
C 输出格式控制 需包含头文件: 浮点数精度、域宽、填充 操作符功能right-alignedright-alignedsetprecision(int n)设置以n表示的数值精度setw(int n)设置以n表示的域宽setfill(char c)设置以c表示的填充字符 输出格式 操作符功能oct以八进制格式输出数据dec以…...

【C++】引用和右值引用
目录 1. 引用 1.1 引用的概念 1.2 引用的特性 1.3 引用的使用场景 1.3.1 作为参数 1.3.2 作为返回值 1.4 常量引用 1.5 引用和指针的区别 2. 左值和右值 3. 右值引用 3.1 右值引用的概念 3.2 左值持久;右值短暂 3.3 变量是左值 3.4 标准库move函数 1.…...

NodeJS MongoDB⑦
文章目录 ✨文章有误请指正,如果觉得对你有用,请点三连一波,蟹蟹支持😘前言Node&MongoDB 第一步 连接数据库 第二步 创建User Mongodb模型 第三步 简单使用 Mongodb命令 第四步 规范使用 Mongodb命令 (…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...

【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...