当前位置: 首页 > news >正文

仓储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 系统发出状态更新请求也是类似以上的访问步骤;

软件流程图:

在这里插入图片描述

代码实现思路

  1. 接收奇门主动请求接口收到的XML类型的参数,将XML转换为奇门定义的对象,然后将奇门对象转换为我们自己系统的对象。
  2. 判断请求的奇门接口名称走不同的业务实现方法,接口返回数据请参照淘宝奇门接口API文档
  3. 各实现方法返回Map格式数据,转换为xml格式返回。

关键点(个人观点)

  1. xml转为对象
  2. 对象转为xml
  3. 封装统一的接口响应
  4. 对应各个接口的实现和数据返回

奇门对接关键代码


@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 之间的系统标准化对接&#xff0c;通过构建 ERP、WMS 系统之间标准通信协议来实现不同系统之间的打通&#xff1b;对商家…...

RFID软件:简介、功能和应用范围

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

Android 逆向之安全防护基本策略

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

基站机房:保障通信网络稳定,如何解决安全隐患?

基站机房作为无线通信网络的关键组成部分&#xff0c;承载着大量的网络设备和通信设施&#xff0c;对于运营商和通信服务提供商来说具有重要意义。 无论是大型运营商还是通信服务提供商&#xff0c;动环监控系统都将成为他们成功运营和管理通信网络的关键工具。 客户案例 案例…...

sqlmap -os-shell 使用方法

一、burp suite抓包。 如上图所示&#xff0c;红框处很明显是一个传参点&#xff0c;我们就在这个页面抓包。 抓到包之后将内容保存到桌面的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&#xff0c;Go 语言借用多路复用的概念&#xff0c;提供了 select 关键字&#xff0c;用 于多路监听多个通道。当监听的通道没有状态是可读或可写的&#xff0c;select 是阻塞的&#…...

黄金回收小程序开发功能有哪些?

一、用户端&#xff1a; 1、实时查询&#xff1a;通过对接三方接口实现实时金价动态查看&#xff1b; 2、多种类珠宝实时回收&#xff1a;小程序支持多品类珠宝的实时回收包含黄金饰品、金条、铂金、K金、白银等&#xff0c;同步实现价格实时更新&#xff1b; …...

nginx的详解与应用

前言 说明 要义 nginx 有一个master 进程和多个worker 进程。主进程的主要目的是读取和评估配置&#xff0c;以及维护工作进程。工作进程对请求进行实际处理。nginx 采用基于事件的模型和依赖于操作系统的机制在工作进程之间有效地分发请求。工作进程的数量在配置文件中定义…...

SpringBoot激活profiles的几种方式

多环境是最常见的配置隔离方式之一&#xff0c;可以根据不同的运行环境提供不同的配置信息来应对不同的业务场景&#xff0c;在SpringBoot内支持了多种配置隔离的方式&#xff0c;可以激活单个或者多个配置文件。 激活的profiles要在项目内创建对应的配置文件&#xff0c;格式…...

【Java】Java核心要点总结:58

文章目录 1. java中 怎么确保一个集合不能被修改2. 队列和栈是什么 有什么区别3. Java8开始的ConcurrentHashMap为什么舍弃了分段锁4. ConcurrentHashMap 和 Hashtable有什么区别5. ReadWriteLock和StampeLock 1. java中 怎么确保一个集合不能被修改 Java 中可以使用 Collectio…...

前端面试题---作用域链和原型链

一.JavaScript 中的作用域链是如何工作的? JavaScript 中的作用域链&#xff08;Scope chain&#xff09;是一种用于查找变量和函数的机制&#xff0c;它是由嵌套的作用域环境组成的链式结构。 当在 JavaScript 中访问一个变量或函数时&#xff0c;解析器会首先在当前作用域…...

零售品牌私域流量池如何运营?火山引擎数智平台提供全套产品组合

虽然距离6月18日还有两周时间&#xff0c;但各大平台的第一波618战绩&#xff08;预售尾款&#xff09;已经相继出炉。 5月31日晚8点&#xff0c;京东率先公布618开门红10分钟销售战报&#xff1a;10分钟内&#xff0c;成交额破亿品牌数同比增长23%&#xff0c;超六成的新商家…...

rk3568 SD卡启动

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

English Learning - L3 作业打卡 Lesson5 Day34 2023.6.7 周三

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

【运筹优化】最短路算法之A星算法 + Java代码实现

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

[6]PCB设计实验|认识常用元器件|电阻器|18:30~19:00

目录 一、电阻器主要用途 1. 稳定和调节电路中的电流和电压 2. 作为分流、分压和负载使用 二、常见电阻器 1. 贴片电阻 2. 热敏电阻 3. 限流电阻 4. 可调电阻 5. 排阻(网络电阻) 三、几种常用电阻器的结构特点 四、电阻的参数 1. 额定功率 电阻器功率的表示 ​2…...

Webots R2021a教程

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

C++ 输出格式控制

C 输出格式控制 需包含头文件&#xff1a; 浮点数精度、域宽、填充 操作符功能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 左值持久&#xff1b;右值短暂 3.3 变量是左值 3.4 标准库move函数 1.…...

NodeJS MongoDB⑦

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

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...