WebService SOAP WSDL 接入指南

打印 上一主题 下一主题

主题 1944|帖子 1944|积分 5832

目录
一、背景概述
二、客户端文档
1、接口服务界说
2、响应格式界说
三、客户端文档使用流程
1、补充服务端地址配置
2、生成服务端代码
3、优化初始代码并实现接口
4、服务发布
4.1、添加依赖
4.2、完善CxfConfig,以实现自动发布服务
4.3、补充日志监控
5、测试
5.1、访问服务端文档
5.2、测试数据接入
5.2.1、通过curl命令调试本地测试
5.2.2、SoapUI调试
6、wsdl文档关键配置简述
6.1、服务端地址
6.2、命名空间
6.3、portName
6.4、入参
6.5、响应体界说
四、踩坑历程
1、请求乐成但拿不到响应信息xml
2、生产情况请求服务端地址404
3、甲方ERP体系需要我们自动推送响应信息,并且需要鉴权
五、附录


一、背景概述

基于WebService SOAP实现用于第三方ERP推送数据的接口。该接口要支持第三方体系通过Http协议的请求将发货单数据推送到我们的物流体系,因此我们需要开发一个相应webservice服务端和客户端来吸收发货单数据以及推送响应信息。
二、客户端文档

第三方提供的,用于界说公共参数,包括命名空间、portName、portType、服务接口名称、接口传参等信息。
1、接口服务界说

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <wsdl:definitions name="SI_LOAD_DEOR_OUTBOUND" targetNamespace="http://qhyhgf.com.cn/sd/Invoice"
  3.     xmlns:p1="http://qhyhgf.com.cn/sd/Invoice"
  4.     xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
  5.     xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
  6.     xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  7.     <wsdl:documentation/>
  8.     <wsp:UsingPolicy wsdl:required="true"/>
  9.     <wsp:Policy wsu:Id="OP_SI_LOAD_DEOR_OUTBOUND"/>
  10.     <wsdl:types>
  11.         <xsd:schema targetNamespace="http://qhyhgf.com.cn/sd/Invoice"
  12.             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  13.             xmlns="http://qhyhgf.com.cn/sd/Invoice">
  14.             <xsd:element name="MT_LOAD_DEOR" type="DT_LOAD_DEOR"/>
  15.             <xsd:complexType name="DT_LOAD_DEOR">
  16.                 <xsd:sequence>
  17.                     <xsd:element name="ITEM" maxOccurs="unbounded">
  18.                         <xsd:complexType>
  19.                             <xsd:sequence>
  20.                                 <xsd:element name="VBELN" type="xsd:string">
  21.                                     <xsd:annotation>
  22.                                         <xsd:documentation>发货单号</xsd:documentation>
  23.                                     </xsd:annotation>
  24.                                 </xsd:element>
  25.                                 <xsd:element name="POSNR" type="xsd:string">
  26.                                     <xsd:annotation>
  27.                                         <xsd:documentation>发货单行项目</xsd:documentation>
  28.                                     </xsd:annotation>
  29.                                 </xsd:element>
  30.                                 <xsd:element name="WADAT_IST" type="xsd:string">
  31.                                     <xsd:annotation>
  32.                                         <xsd:documentation>提货时间</xsd:documentation>
  33.                                     </xsd:annotation>
  34.                                 </xsd:element>
  35.                                 <xsd:element name="ZCYDW" type="xsd:string">
  36.                                     <xsd:annotation>
  37.                                         <xsd:documentation>承运企业</xsd:documentation>
  38.                                     </xsd:annotation>
  39.                                 </xsd:element>
  40.                                 <xsd:element name="PARTNER" type="xsd:string">
  41.                                     <xsd:annotation>
  42.                                         <xsd:documentation>结算单位</xsd:documentation>
  43.                                     </xsd:annotation>
  44.                                 </xsd:element>
  45.                                 <xsd:element name="ZCH" type="xsd:string">
  46.                                     <xsd:annotation>
  47.                                         <xsd:documentation>车牌号</xsd:documentation>
  48.                                     </xsd:annotation>
  49.                                 </xsd:element>
  50.                                 <xsd:element name="MATNR" type="xsd:string">
  51.                                     <xsd:annotation>
  52.                                         <xsd:documentation>物料号</xsd:documentation>
  53.                                     </xsd:annotation>
  54.                                 </xsd:element>
  55.                                 <xsd:element name="ARKTX" type="xsd:string">
  56.                                     <xsd:annotation>
  57.                                         <xsd:documentation>物料描述</xsd:documentation>
  58.                                     </xsd:annotation>
  59.                                 </xsd:element>
  60.                                 <xsd:element name="KWMENG" type="xsd:string">
  61.                                     <xsd:annotation>
  62.                                         <xsd:documentation>运输货物重量</xsd:documentation>
  63.                                     </xsd:annotation>
  64.                                 </xsd:element>
  65.                                 <xsd:element name="CHARG" type="xsd:string">
  66.                                     <xsd:annotation>
  67.                                         <xsd:documentation>货物批次号</xsd:documentation>
  68.                                     </xsd:annotation>
  69.                                 </xsd:element>
  70.                                 <xsd:element name="ZSJXM" type="xsd:string">
  71.                                     <xsd:annotation>
  72.                                         <xsd:documentation>司机姓名</xsd:documentation>
  73.                                     </xsd:annotation>
  74.                                 </xsd:element>
  75.                                 <xsd:element name="ZLXDH" type="xsd:string">
  76.                                     <xsd:annotation>
  77.                                         <xsd:documentation>司机手机号码</xsd:documentation>
  78.                                     </xsd:annotation>
  79.                                 </xsd:element>
  80.                                 <xsd:element name="ZSJSFZ" type="xsd:string">
  81.                                     <xsd:annotation>
  82.                                         <xsd:documentation>司机身份证号码</xsd:documentation>
  83.                                     </xsd:annotation>
  84.                                 </xsd:element>
  85.                                 <xsd:element name="ZBZ" type="xsd:string">
  86.                                     <xsd:annotation>
  87.                                         <xsd:documentation>备注</xsd:documentation>
  88.                                     </xsd:annotation>
  89.                                 </xsd:element>
  90.                                 <xsd:element name="VRKME" type="xsd:string">
  91.                                     <xsd:annotation>
  92.                                         <xsd:documentation>产品计量单位</xsd:documentation>
  93.                                     </xsd:annotation>
  94.                                 </xsd:element>
  95.                                 <xsd:element name="VSBED" type="xsd:string">
  96.                                     <xsd:annotation>
  97.                                         <xsd:documentation>提货方式</xsd:documentation>
  98.                                     </xsd:annotation>
  99.                                 </xsd:element>
  100.                                 <xsd:element name="ZDJCJR" type="xsd:string">
  101.                                     <xsd:annotation>
  102.                                         <xsd:documentation>单据创建人</xsd:documentation>
  103.                                     </xsd:annotation>
  104.                                 </xsd:element>
  105.                             </xsd:sequence>
  106.                         </xsd:complexType>
  107.                     </xsd:element>
  108.                 </xsd:sequence>
  109.             </xsd:complexType>
  110.         </xsd:schema>
  111.     </wsdl:types>
  112.     <wsdl:message name="MT_LOAD_DEOR">
  113.         <wsdl:documentation/>
  114.         <wsdl:part name="MT_LOAD_DEOR" element="p1:MT_LOAD_DEOR"/>
  115.     </wsdl:message>
  116.     <wsdl:portType name="SI_LOAD_DEOR_OUTBOUND">
  117.         <wsdl:documentation/>
  118.         <wsdl:operation name="SI_LOAD_DEOR_OUTBOUND">
  119.             <wsdl:documentation/>
  120.             <wsp:Policy>
  121.                 <wsp:PolicyReference URI="#OP_SI_LOAD_DEOR_OUTBOUND"/>
  122.             </wsp:Policy>
  123.             <wsdl:input message="p1:MT_LOAD_DEOR"/>
  124.         </wsdl:operation>
  125.     </wsdl:portType>
  126.     <wsdl:binding name="SI_LOAD_DEOR_OUTBOUNDBinding" type="p1:SI_LOAD_DEOR_OUTBOUND">
  127.         <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"
  128.             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/>
  129.             <wsdl:operation name="SI_LOAD_DEOR_OUTBOUND">
  130.                 <soap:operation soapAction="http://sap.com/xi/WebService/soap1.1"
  131.                     xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/>
  132.                     <wsdl:input>
  133.                         <soap:body use="literal"
  134.                             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/>
  135.                         </wsdl:input>
  136.                     </wsdl:operation>
  137.                 </wsdl:binding>
  138.             </wsdl:definitions>
复制代码
2、响应格式界说

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <wsdl:definitions name="SI_LOAD_DEOR_OUTBOUND_REBACK" targetNamespace="http://qhyhgf.com.cn/sd/Invoice"
  3.     xmlns:p1="http://qhyhgf.com.cn/sd/Invoice"
  4.     xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
  5.     xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
  6.     xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  7.     <wsdl:documentation/>
  8.     <wsp:UsingPolicy wsdl:required="true"/>
  9.     <wsp:Policy wsu:Id="OP_SI_LOAD_DEOR_OUTBOUND_REBACK"/>
  10.     <wsdl:types>
  11.         <xsd:schema targetNamespace="http://qhyhgf.com.cn/sd/Invoice"
  12.             xmlns="http://qhyhgf.com.cn/sd/Invoice"
  13.             xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  14.             <xsd:element name="MT_LOAD_DEOR_REBACK" type="DT_LOAD_DEOR_REBACK"/>
  15.             <xsd:complexType name="DT_LOAD_DEOR_REBACK">
  16.                 <xsd:annotation>
  17.                     <xsd:appinfo source="http://sap.com/xi/VersionID">33e74ebc0b5b11e6b0e100000044d356</xsd:appinfo>
  18.                 </xsd:annotation>
  19.                 <xsd:sequence>
  20.                     <xsd:element name="ITEM" maxOccurs="unbounded">
  21.                         <xsd:annotation>
  22.                             <xsd:appinfo source="http://sap.com/xi/TextID">2637a7160b5b11e6bf1e00ff9ec07684</xsd:appinfo>
  23.                         </xsd:annotation>
  24.                         <xsd:complexType>
  25.                             <xsd:sequence>
  26.                                 <xsd:element name="VBELN" type="xsd:string">
  27.                                     <xsd:annotation>
  28.                                         <xsd:appinfo source="http://sap.com/xi/TextID">27758e2f079111e693f700ff9ec07684</xsd:appinfo>
  29.                                         <xsd:documentation>发货单号</xsd:documentation>
  30.                                     </xsd:annotation>
  31.                                 </xsd:element>
  32.                                 <xsd:element name="ZJCBS" type="xsd:string">
  33.                                     <xsd:annotation>
  34.                                         <xsd:appinfo source="http://sap.com/xi/TextID">27758e30079111e6b00800ff9ec07684</xsd:appinfo>
  35.                                         <xsd:documentation>接收方成功标识</xsd:documentation>
  36.                                     </xsd:annotation>
  37.                                 </xsd:element>
  38.                                 <xsd:element name="ZJSXX" type="xsd:string" minOccurs="0">
  39.                                     <xsd:annotation>
  40.                                         <xsd:appinfo source="http://sap.com/xi/TextID">27758e31079111e6842c00ff9ec07684</xsd:appinfo>
  41.                                         <xsd:documentation>接收方信息</xsd:documentation>
  42.                                     </xsd:annotation>
  43.                                 </xsd:element>
  44.                             </xsd:sequence>
  45.                         </xsd:complexType>
  46.                     </xsd:element>
  47.                 </xsd:sequence>
  48.             </xsd:complexType>
  49.         </xsd:schema>
  50.     </wsdl:types>
  51.     <wsdl:message name="MT_LOAD_DEOR_REBACK">
  52.         <wsdl:documentation/>
  53.         <wsdl:part name="MT_LOAD_DEOR_REBACK" element="p1:MT_LOAD_DEOR_REBACK"/>
  54.     </wsdl:message>
  55.     <wsdl:portType name="SI_LOAD_DEOR_OUTBOUND_REBACK">
  56.         <wsdl:documentation/>
  57.         <wsdl:operation name="SI_LOAD_DEOR_OUTBOUND_REBACK">
  58.             <wsdl:documentation/>
  59.             <wsp:Policy>
  60.                 <wsp:PolicyReference URI="#OP_SI_LOAD_DEOR_OUTBOUND_REBACK"/>
  61.             </wsp:Policy>
  62.             <wsdl:input message="p1:MT_LOAD_DEOR_REBACK"/>
  63.         </wsdl:operation>
  64.     </wsdl:portType>
  65.     <wsdl:binding name="SI_LOAD_DEOR_OUTBOUND_REBACKBinding" type="p1:SI_LOAD_DEOR_OUTBOUND_REBACK">
  66.         <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"
  67.             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/>
  68.             <wsdl:operation name="SI_LOAD_DEOR_OUTBOUND_REBACK">
  69.                 <soap:operation soapAction="http://sap.com/xi/WebService/soap1.1"
  70.                     xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/>
  71.                     <wsdl:input>
  72.                         <soap:body use="literal"
  73.                             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/>
  74.                         </wsdl:input>
  75.                     </wsdl:operation>
  76.                 </wsdl:binding>
  77.                 <wsdl:service name="SI_LOAD_DEOR_OUTBOUND_REBACKService">
  78.                     <wsdl:port name="HTTP_Port" binding="p1:SI_LOAD_DEOR_OUTBOUND_REBACKBinding">
  79.                         <soap:address location="http://ip:port/XISOAPAdapter/MessageServlet?senderParty=&amp;senderService=BC_LOAD_SYSTEM&amp;receiverParty=&amp;receiverService=&amp;interface=SI_LOAD_DEOR_OUTBOUND_REBACK&amp;interfaceNamespace=http%3A%2F%2Fqhyhgf.com.cn%2Fsd%2FInvoice"
  80.                             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/>
  81.                         </wsdl:port>
  82.                         <wsdl:port name="HTTPS_Port" binding="p1:SI_LOAD_DEOR_OUTBOUND_REBACKBinding">
  83.                             <soap:address location="https://ip:port/XISOAPAdapter/MessageServlet?senderParty=&amp;senderService=BC_LOAD_SYSTEM&amp;receiverParty=&amp;receiverService=&amp;interface=SI_LOAD_DEOR_OUTBOUND_REBACK&amp;interfaceNamespace=http%3A%2F%2Fqhyhgf.com.cn%2Fsd%2FInvoice"
  84.                                 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/>
  85.                             </wsdl:port>
  86.                         </wsdl:service>
  87.                     </wsdl:definitions>
复制代码
三、客户端文档使用流程

1、补充服务端地址配置

需要先补充服务端服务地址配置。其中 <wsdl:service name="SI_LOAD_DEOR_OUTBOUND"> 与 <wsdl:port binding="tns:SI_LOAD_DEOR_OUTBOUNDSoapBinding" name="SI_LOAD_DEOR_OUTBOUNDBinding"> 要与客户端内的配置保持同等,location地址可以自行界说,我目前界说为:http://127.0.0.1:8081/rest/erp/ZJLogisticsWebServices。
  1. <wsdl:service name="SI_LOAD_DEOR_OUTBOUND">
  2.         <wsdl:port binding="tns:SI_LOAD_DEOR_OUTBOUNDSoapBinding" name="SI_LOAD_DEOR_OUTBOUNDBinding">
  3.             <soap:address location="http://127.0.0.1:8081/rest/erp/ZJLogisticsWebServices"/>
  4.         </wsdl:port>
  5.     </wsdl:service>
复制代码
2、生成服务端代码

使用 wsimport 命令(jdk1.8会自带,浅提一嘴,wsimport 在Java 9中就已经被标记为废弃,在Java 11中则不再包罗在尺度的JDK中)。
  1. wsimport -keep -s D:\projectMenu\mg-logistics-back\mg-logistics\src\main\java -p com.example.server D:\testData\SI_LOAD_DEOR_OUTBOUND2.wsdl
复制代码
实行报错:
  1. [ERROR] 元素 "soap:address" 的前缀 "soap" 未绑定。 file:/D:/testData/镁业/SI_LOAD_DEOR_OUTBOUNDService.wsdl的第 140 行 [ERROR] 元素 "soap:address" 的前缀 "soap" 未绑定。 无法读取 WSDL 文档: file:/D:/testData/镁业/SI_LOAD_DEOR_OUTBOUNDService.wsdl, 原因为 1) 找不到文档; 2) 无法读取文档; 3) 文档的根元素不是 <wsdl:definitions>。 [WARNING] 忽略端口 "SI_LOAD_DEOR_OUTBOUNDBinding": 未指定 SOAP 地址。请尝试运行带 -extension 开关的 wsimport。 file:/D:/testData/镁业/SI_LOAD_DEOR_OUTBOUNDService.wsdl的第 139 行 [WARNING] 服务 "SI_LOAD_DEOR_OUTBOUND" 不包含任何可用端口。请尝试运行带 -extension 开关的 wsimport。 file:/D:/testData/镁业/SI_LOAD_DEOR_OUTBOUNDService.wsdl的第 138 行
复制代码
报错原因是 缺少 soap:address 命名空间声明,需要在头部补充声明:
  1. xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
复制代码
重新实行无报错,生成的初始代码如下,其中MtLoadDeorReback、DTLOADDEOR、DTITEM是客户端文档中界说的一些实体类。
SILOADDEOROUTBOUND为服务接口,SILOADDEOROUTBOUND_Service是接口实现类,类名都可以按照Java规范自行修改。

3、优化初始代码并实现接口

类名、冗余方法界说等都可以自行修改和删除。
SILOADDEOROUTBOUND_Service 需实现接口 SILOADDEOROUTBOUND,并清除默认继续的Service类。
  1. /**
  2. * This class was generated by the JAX-WS RI.
  3. * JAX-WS RI 2.2.9-b130926.1035
  4. * Generated source version: 2.2
  5. *
  6. */
  7. @WebService(name = "SI_LOAD_DEOR_OUTBOUND", targetNamespace = "http://qhyhgf.com.cn/sd/Invoice")
  8. @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
  9. @XmlSeeAlso({
  10.     ObjectFactory.class
  11. })
  12. public interface SILOADDEOROUTBOUND {
  13.     /**
  14.      *
  15.      * @param mtLOADDEOR
  16.      * @return
  17.      *     returns com.example.server.MtLoadDeorReback
  18.      */
  19.     @WebMethod(operationName = "SI_LOAD_DEOR_OUTBOUND", action = "http://sap.com/xi/WebService/soap1.1")
  20.     @WebResult(name = "SI_LOAD_DEOR_OUTBOUNDResponse", targetNamespace = "http://qhyhgf.com.cn/sd/Invoice", partName = "SI_LOAD_DEOR_OUTBOUNDResponse")
  21.     public MtLoadDeorReback siLOADDEOROUTBOUND(
  22.         @WebParam(name = "MT_LOAD_DEOR", targetNamespace = "http://qhyhgf.com.cn/sd/Invoice", partName = "MT_LOAD_DEOR")
  23.         DTLOADDEOR mtLOADDEOR);
  24. }
复制代码
  1. /**
  2. * This class was generated by the JAX-WS RI.
  3. * JAX-WS RI 2.2.9-b130926.1035
  4. * Generated source version: 2.2
  5. *
  6. */
  7. @WebServiceClient(name = "SI_LOAD_DEOR_OUTBOUND", targetNamespace = "http://qhyhgf.com.cn/sd/Invoice", wsdlLocation = "file:/D:/testData/server.wsdl")
  8. public class SILOADDEOROUTBOUND_Service
  9.     extends Service
  10. {
  11.     private final static URL SILOADDEOROUTBOUND_WSDL_LOCATION;
  12.     private final static WebServiceException SILOADDEOROUTBOUND_EXCEPTION;
  13.     private final static QName SILOADDEOROUTBOUND_QNAME = new QName("http://qhyhgf.com.cn/sd/Invoice", "SI_LOAD_DEOR_OUTBOUND");
  14.     static {
  15.         URL url = null;
  16.         WebServiceException e = null;
  17.         try {
  18.             url = new URL("file:/D:/testData/server.wsdl");
  19.         } catch (MalformedURLException ex) {
  20.             e = new WebServiceException(ex);
  21.         }
  22.         SILOADDEOROUTBOUND_WSDL_LOCATION = url;
  23.         SILOADDEOROUTBOUND_EXCEPTION = e;
  24.     }
  25.     public SILOADDEOROUTBOUND_Service() {
  26.         super(__getWsdlLocation(), SILOADDEOROUTBOUND_QNAME);
  27.     }
  28.     public SILOADDEOROUTBOUND_Service(WebServiceFeature... features) {
  29.         super(__getWsdlLocation(), SILOADDEOROUTBOUND_QNAME, features);
  30.     }
  31.     public SILOADDEOROUTBOUND_Service(URL wsdlLocation) {
  32.         super(wsdlLocation, SILOADDEOROUTBOUND_QNAME);
  33.     }
  34.     public SILOADDEOROUTBOUND_Service(URL wsdlLocation, WebServiceFeature... features) {
  35.         super(wsdlLocation, SILOADDEOROUTBOUND_QNAME, features);
  36.     }
  37.     public SILOADDEOROUTBOUND_Service(URL wsdlLocation, QName serviceName) {
  38.         super(wsdlLocation, serviceName);
  39.     }
  40.     public SILOADDEOROUTBOUND_Service(URL wsdlLocation, QName serviceName, WebServiceFeature... features) {
  41.         super(wsdlLocation, serviceName, features);
  42.     }
  43.     /**
  44.      *
  45.      * @return
  46.      *     returns SILOADDEOROUTBOUND
  47.      */
  48.     @WebEndpoint(name = "SI_LOAD_DEOR_OUTBOUNDBinding")
  49.     public SILOADDEOROUTBOUND getSILOADDEOROUTBOUNDBinding() {
  50.         return super.getPort(new QName("http://qhyhgf.com.cn/sd/Invoice", "SI_LOAD_DEOR_OUTBOUNDBinding"), SILOADDEOROUTBOUND.class);
  51.     }
  52.     /**
  53.      *
  54.      * @param features
  55.      *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> parameter will have their default values.
  56.      * @return
  57.      *     returns SILOADDEOROUTBOUND
  58.      */
  59.     @WebEndpoint(name = "SI_LOAD_DEOR_OUTBOUNDBinding")
  60.     public SILOADDEOROUTBOUND getSILOADDEOROUTBOUNDBinding(WebServiceFeature... features) {
  61.         return super.getPort(new QName("http://qhyhgf.com.cn/sd/Invoice", "SI_LOAD_DEOR_OUTBOUNDBinding"), SILOADDEOROUTBOUND.class, features);
  62.     }
  63.     private static URL __getWsdlLocation() {
  64.         if (SILOADDEOROUTBOUND_EXCEPTION!= null) {
  65.             throw SILOADDEOROUTBOUND_EXCEPTION;
  66.         }
  67.         return SILOADDEOROUTBOUND_WSDL_LOCATION;
  68.     }
  69. }
复制代码
修改后:
  1. @WebService(name = "SI_LOAD_DEOR_OUTBOUND",
  2.         targetNamespace = "http://qhyhgf.com.cn/sd/Invoice")
  3. @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
  4. @XmlSeeAlso({
  5.         ServerFactory.class
  6. })
  7. public interface SILoadDeorOutboundService {
  8.     /**
  9.      * 推送数据
  10.      *
  11.      * @param mtLoadDeor
  12.      */
  13.     @WebMethod(operationName = "SI_LOAD_DEOR_OUTBOUND", action = "http://sap.com/xi/WebService/soap1.1")
  14.     @WebResult(name = "MT_LOAD_DEOR_REBACK")
  15.     MTLoadDeorReback siLoadDeorOutbound(
  16.             @WebParam(name = "MT_LOAD_DEOR", partName = "MT_LOAD_DEOR")
  17.             MtLoadDeor mtLoadDeor);
  18. }
复制代码
  1. /**
  2. * This class was generated by the JAX-WS RI.
  3. * JAX-WS RI 2.2.9-b130926.1035
  4. * Generated source version: 2.2
  5. */
  6. @Slf4j
  7. @WebService(
  8.         serviceName = "SI_LOAD_DEOR_OUTBOUNDService", // 必须与 WSDL 中的服务名称相同
  9.         portName = "SI_LOAD_DEOR_OUTBOUNDBinding",
  10.         endpointInterface = "com.zhejuedata.webService.service.webservice.server.SILoadDeorOutboundService" // SEI 接口的全限定名
  11. )
  12. @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE, style = SOAPBinding.Style.DOCUMENT)
  13. @Service
  14. public class SILoadDeorOutboundServiceImpl implements SILoadDeorOutboundService {
  15.     @Resource
  16.     private OmniRedisTemplate omniRedisTemplate;
  17.     @Override
  18.     @Transactional(rollbackFor = Exception.class)
  19.     public MTLoadDeorReback siLoadDeorOutbound(MtLoadDeor mtLoadDeor) {
  20.         String key = "ERP_DATA_PUSH_" + DateUtils.dateTimeNow("yyyy-MM-dd HH:mm");
  21.         Boolean hasClock = omniRedisTemplate.opsForValue().setIfAbsent(key, 1, Duration.ofSeconds(30));
  22.         if (Boolean.TRUE.equals(hasClock)) {
  23.             MTLoadDeorReback mtLoadDeorReback = saveDispatchListData(mtLoadDeor);
  24.             log.info("成功接收数据:{}", JSONObject.toJSONString(mtLoadDeor));
  25.             // 回调,推送响应信息
  26.             try {
  27.                 log.info("开始回调接口推送响应数据: {}", JSONObject.toJSONString(mtLoadDeorReback));
  28.                 sendCallback(mtLoadDeorReback);
  29.             } catch (Exception e) {
  30.                 // 错误处理
  31.                 log.error("回调ERP接口,推送响应信息失败", e);
  32.             }
  33.             omniRedisTemplate.delete(key);
  34.             return mtLoadDeorReback;
  35.         } else {
  36.             List<String> dispatchListCodes = mtLoadDeor.getItem().stream().map(Item::getDispatchListCode)
  37.                     .collect(Collectors.toList());
  38.             log.info("未抢到锁,即未成功接收数据。待重发数据:{}", dispatchListCodes);
  39.             omniRedisTemplate.delete(key);
  40.             return MTLoadDeorReback.fail(dispatchListCodes);
  41.         }
  42.     }
  43.     private void sendCallback(MTLoadDeorReback response) {
  44.         try {
  45.             // 创建一个JAXB上下文用于序列化响应对象
  46.             Class<?>[] classes = new Class<?>[]{
  47.                     MTLoadDeorReback.class,
  48.                     ResponseItem.class,
  49.                     ClientFactory.class,
  50.             };
  51.             JAXBContext jaxbContext = JAXBContext.newInstance(classes);
  52.             Marshaller marshaller = jaxbContext.createMarshaller();
  53.             marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
  54.             // 使用ClientFactory创建JAXBElement
  55.             ClientFactory clientFactory = new ClientFactory();
  56.             JAXBElement<MTLoadDeorReback> jaxbElement = clientFactory.createMTLoadDeorReback(response);
  57.             // 创建SOAP连接并发送请求
  58.             SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
  59.             SOAPConnection soapConnection = soapConnectionFactory.createConnection();
  60.             MessageFactory messageFactory = MessageFactory.newInstance();
  61.             SOAPMessage soapMessage = messageFactory.createMessage();
  62.             SOAPPart soapPart = soapMessage.getSOAPPart();
  63.             SOAPEnvelope envelope = soapPart.getEnvelope();
  64.             SOAPBody soapBody = envelope.getBody();
  65.             // 直接将JAXBElement序列化到SOAP Body中
  66.             marshaller.marshal(jaxbElement, soapBody);
  67.             // 设置SOAP Action头
  68.             MimeHeaders headers = soapMessage.getMimeHeaders();
  69.             headers.addHeader("SOAPAction", "http://sap.com/xi/WebService/soap1.1");
  70. //            headers.addHeader("Authorization", "Basic WlBJQVBQTFVTRVI6emFxMXhzdzI=");
  71.             headers.addHeader("Authorization", "Basic " + Base64Encoder.encode("ZPIAPPLUSER:zaq1xsw2"));
  72.             // 回调推送
  73.             URL endpoint = new URL(WebServiceConf.wsCallBackUrl);
  74.             log.info("回调接口地址: {}", WebServiceConf.wsCallBackUrl);
  75.             SOAPMessage soapResponse = soapConnection.call(soapMessage, endpoint);
  76.             // 获取SOAP Body
  77.             SOAPBody body = soapResponse.getSOAPBody();
  78.             // 检查是否有SOAP Fault
  79.             if (body.hasFault()) {
  80.                 SOAPFault fault = body.getFault();
  81.                 log.error("回调失败!!!");
  82.                 log.error("SOAP Fault: {}", fault.getFaultString());
  83.             } else {
  84.                 log.info("回调成功...");
  85.             }
  86.             // 关闭连接
  87.             soapConnection.close();
  88.         } catch (Exception e) {
  89.             log.error("调用回调方法异常...url:{}", WebServiceConf.wsCallBackUrl, e);
  90.             throw new RuntimeException(e);
  91.         }
  92.     }
  93.     @NotNull
  94.     private MTLoadDeorReback saveDispatchListData(MtLoadDeor mtLoadDeor) {
  95.         List<Item> itemList = mtLoadDeor.getItem();
  96.         log.info("此次访问未接受到任何数据。mtLoadDeor:{}", JSONArray.toJSONString(mtLoadDeor));
  97.         if (CollectionUtils.isEmpty(itemList)) {
  98.             return MTLoadDeorReback.success(new ArrayList<>());
  99.         }
  100.         log.info("推送时间【{}】 此次推送数据: mtLoadDeor.itemList:{}", DateUtils.getTime(), JSONArray.toJSONString(itemList));
  101.         List<String> dispatchListCodes = itemList.stream().map(Item::getDispatchListCode).collect(Collectors.toList());
  102.         // 去除前后空格、回车等内容
  103.         itemList = itemList.stream().peek(Item::trimAllStrings).collect(Collectors.toList());
  104.         try {
  105.             // todo: 具体业务实现
  106.             
  107.             return MTLoadDeorReback.success(dispatchListCodes);
  108.         } catch (Exception e) {
  109.             log.error("此次推送出现异常", e);
  110.             dispatchListCodes = itemList.stream().map(Item::getDispatchListCode).collect(Collectors.toList());
  111.             log.error("数据集体回滚, 发货单号:{}", JSONArray.toJSONString(dispatchListCodes));
  112.             return MTLoadDeorReback.fail(dispatchListCodes);
  113.         }
  114.     }
  115. }
复制代码
在这时我们的业务根本实现完毕。
4、服务发布

我这里选择的是集成CXF框架,自动发布Web服务的方式。具体实现如下:
4.1、添加依赖

  1. <dependency>
  2.     <groupId>org.apache.cxf</groupId>
  3.     <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
  4. </dependency>
  5. <dependency>
  6.     <groupId>org.apache.cxf</groupId>
  7.     <artifactId>cxf-rt-transports-http</artifactId>
  8. </dependency>
  9. <!-- 统一管理cxf版本,以确保项目中所有CXF相关依赖都使用一致的版本 -->
  10. <dependencyManagement>
  11.     <dependencies>
  12.         <dependency>
  13.             <groupId>org.apache.cxf</groupId>
  14.             <artifactId>cxf-bom</artifactId>
  15.             <version>3.5.5</version>
  16.             <type>pom</type>
  17.             <scope>import</scope>
  18.         </dependency>
  19.     </dependencies>
  20. </dependencyManagement>
复制代码
4.2、完善CxfConfig,以实现自动发布服务

/rest/erp 为统一服务前缀,ZJLogisticsWebServices为实际服务地址配置好后,服务端访问地址即为:http://127.0.0.1:8081/rest/erp/ZJLogisticsWebServices
  1. @Configuration
  2. @Slf4j
  3. public class CxfConfig {
  4.     @Bean(name = Bus.DEFAULT_BUS_ID)
  5.     public SpringBus springBus() {
  6.         SpringBus bus = new SpringBus();
  7.         // 启用日志记录
  8.         bus.getInInterceptors().add(new WebserviceLoggingInInterceptor());
  9.         bus.getOutInterceptors().add(new WebserviceLoggingOutInterceptor());
  10.         return bus;
  11.     }
  12.     /**
  13.      * webservice下的请求将由CXFServlet处理
  14.      */
  15.     @Bean
  16.     public ServletRegistrationBean<CXFServlet> cxfServlet() {
  17.         return new ServletRegistrationBean<>(new CXFServlet(), "/rest/erp/*");
  18.     }
  19.     @Bean
  20.     public Endpoint siLoadDeorOutboundEndpoint() {
  21.         EndpointImpl endpoint = new EndpointImpl(springBus(), new SILoadDeorOutboundServiceImpl());
  22.         // 设置服务名称和端口名称
  23.         endpoint.setServiceName(new QName(WebServiceConf.wsNamespace, WebServiceConf.wsInterfaceName));
  24.         endpoint.setEndpointName(new QName(WebServiceConf.wsNamespace, WebServiceConf.wsPortName));
  25.         endpoint.publish("/ZJLogisticsWebServices");
  26.         // 注册动态地址拦截器替换WSDL 的地址
  27.         endpoint.getInInterceptors().add(new DynamicSoapAddressInterceptor());
  28.         return endpoint;
  29.     }
  30.     @Bean
  31.     public Endpoint callbackReceiverEndpoint() {
  32.         EndpointImpl endpoint = new EndpointImpl(springBus(), new CallbackReceiverServicesImpl());
  33.         // 设置服务名称和端口名称
  34.         endpoint.setServiceName(new QName(WebServiceConf.wsNamespace, WebServiceConf.wsCallBackInterfaceName));
  35.         endpoint.setEndpointName(new QName(WebServiceConf.wsNamespace, WebServiceConf.wsCallBackPortName));
  36.         endpoint.publish("/XISOAPAdapter/MessageServlet");
  37.         return endpoint;
  38.     }
  39. }
复制代码
4.3、补充日志监控

在总线配置中补充日志拦截器
  1. @Bean(name = Bus.DEFAULT_BUS_ID)
  2. public SpringBus springBus() {
  3.     SpringBus bus = new SpringBus();
  4.     // 启用日志记录
  5.     bus.getInInterceptors().add(new WebserviceLoggingInInterceptor());
  6.     bus.getOutInterceptors().add(new WebserviceLoggingOutInterceptor());
  7.     return bus;
  8. }
复制代码
  1. import org.apache.cxf.message.Message;
  2. import org.apache.cxf.phase.AbstractPhaseInterceptor;
  3. import org.apache.cxf.phase.Phase;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. public class WebserviceLoggingInInterceptor extends AbstractPhaseInterceptor<Message> {
  7.     private static final Logger LOG = LoggerFactory.getLogger(WebserviceLoggingInInterceptor.class);
  8.     public WebserviceLoggingInInterceptor() {
  9.         super(Phase.RECEIVE);
  10.     }
  11.     @Override
  12.     public void handleMessage(Message message) {
  13.         // 记录输入消息内容
  14.         String input = message.getContent(String.class);
  15.         if (input != null) {
  16.             LOG.info("Incoming Message: {}", input);
  17.         }
  18.     }
  19. }
复制代码
  1. import org.apache.cxf.message.Message;
  2. import org.apache.cxf.phase.AbstractPhaseInterceptor;
  3. import org.apache.cxf.phase.Phase;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. public class WebserviceLoggingOutInterceptor extends AbstractPhaseInterceptor<Message> {
  7.     private static final Logger LOG = LoggerFactory.getLogger(WebserviceLoggingOutInterceptor.class);
  8.     public WebserviceLoggingOutInterceptor() {
  9.         super(Phase.PRE_PROTOCOL);
  10.     }
  11.     @Override
  12.     public void handleMessage(Message message) {
  13.         // 记录输出消息内容
  14.         String output = message.getContent(String.class);
  15.         if (output != null) {
  16.             LOG.info("Outgoing Message: {}", output);
  17.         }
  18.     }
  19. }
复制代码
在logback.xml配置cxf监控级别
  1. <!-- 设置 CXF 日志-->
  2. <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  3.     <encoder>
  4.         <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n</pattern>
  5.     </encoder>
  6. </appender>
  7. <!-- 日志级别 -->
  8. <logger name="org.apache.cxf" level="INFO"/>
  9. <root level="info">
  10.     <appender-ref ref="STDOUT"/>
  11. </root>
复制代码
5、测试

到 3.4 为止,我的服务端根本搭建完毕,可以开测啦!
5.1、访问服务端文档

启动后假如无报错,那么你将可以通过 3.1 中配置的服务端地址来访问你的服务端文档,这个服务端文档就是用来提供给三方客户端用来解析和推送数据的。即搭建完毕后你只需要提供一个服务端地址就ok了。
这里我配置的地址是 http://127.0.0.1:8081/rest/erp/ZJLogisticsWebServices 以是我可以在浏览器访问
http://127.0.0.1:8081/rest/erp/ZJLogisticsWebServices?wsdl来预览我的服务端文档:
  1. <wsdl:definitions    xmlns:xsd="http://www.w3.org/2001/XMLSchema"    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"    xmlns:tns="http://qhyhgf.com.cn/sd/Invoice"    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"    xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="SI_LOAD_DEOR_OUTBOUND" targetNamespace="http://qhyhgf.com.cn/sd/Invoice">    <wsdl:types>        <xs:schema            xmlns:xs="http://www.w3.org/2001/XMLSchema"            xmlns:tns="http://qhyhgf.com.cn/sd/Invoice" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://qhyhgf.com.cn/sd/Invoice" version="1.0">            <xs:element name="MT_LOAD_DEOR" type="tns:DT_LOAD_DEOR"/>            <xs:element name="MT_LOAD_DEOR_REBACK" type="tns:mtLoadDeorReback"/>            <xs:complexType name="DT_LOAD_DEOR">                <xs:sequence>                    <xs:element maxOccurs="unbounded" name="ITEM">                        <xs:complexType>                            <xs:sequence>                                <xs:element name="VBELN" type="xs:string"/>                                <xs:element name="POSNR" type="xs:string"/>                                <xs:element name="WADAT_IST" type="xs:string"/>                                <xs:element minOccurs="0" name="ZCYDW" nillable="true" type="xs:string"/>                                <xs:element name="PARTNER" type="xs:string"/>                                <xs:element name="ZCH" type="xs:string"/>                                <xs:element name="MATNR" type="xs:string"/>                                <xs:element name="ARKTX" type="xs:string"/>                                <xs:element name="KWMENG" type="xs:string"/>                                <xs:element name="CHARG" type="xs:string"/>                                <xs:element name="ZSJXM" type="xs:string"/>                                <xs:element name="ZLXDH" type="xs:string"/>                                <xs:element name="ZSJSFZ" type="xs:string"/>                                <xs:element minOccurs="0" name="ZBZ" nillable="true" type="xs:string"/>                                <xs:element name="VRKME" type="xs:string"/>                                <xs:element name="VSBED" type="xs:string"/>                                <xs:element name="ZDJCJR" type="xs:string"/>                            </xs:sequence>                        </xs:complexType>                    </xs:element>                </xs:sequence>            </xs:complexType>            <xs:complexType name="mtLoadDeorReback">                <xs:sequence>                    <xs:element maxOccurs="unbounded" name="ITEM" type="tns:DT_ITEM"/>                </xs:sequence>            </xs:complexType>            <xs:complexType name="DT_ITEM">                <xs:sequence>                    <xs:element name="VBELN" type="xs:string"/>                    <xs:element name="ZJCBS" type="xs:string"/>                    <xs:element name="ZJSXX" type="xs:string"/>                </xs:sequence>            </xs:complexType>            <xs:element name="SI_LOAD_DEOR_OUTBOUNDResponse" nillable="true" type="tns:mtLoadDeorReback"/>        </xs:schema>    </wsdl:types>    <wsdl:message name="SI_LOAD_DEOR_OUTBOUNDResponse">        <wsdl:part element="tns:SI_LOAD_DEOR_OUTBOUNDResponse" name="SI_LOAD_DEOR_OUTBOUNDResponse"></wsdl:part>    </wsdl:message>    <wsdl:message name="SI_LOAD_DEOR_OUTBOUND">        <wsdl:part element="tns:MT_LOAD_DEOR" name="MT_LOAD_DEOR"></wsdl:part>    </wsdl:message>    <wsdl:portType name="SI_LOAD_DEOR_OUTBOUND">        <wsdl:operation name="SI_LOAD_DEOR_OUTBOUND">            <wsdl:input message="tns:SI_LOAD_DEOR_OUTBOUND" name="SI_LOAD_DEOR_OUTBOUND"></wsdl:input>            <wsdl:output message="tns:SI_LOAD_DEOR_OUTBOUNDResponse" name="SI_LOAD_DEOR_OUTBOUNDResponse"></wsdl:output>        </wsdl:operation>    </wsdl:portType>    <wsdl:binding name="SI_LOAD_DEOR_OUTBOUNDSoapBinding" type="tns:SI_LOAD_DEOR_OUTBOUND">        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>        <wsdl:operation name="SI_LOAD_DEOR_OUTBOUND">            <soap:operation soapAction="http://sap.com/xi/WebService/soap1.1" style="document"/>            <wsdl:input name="SI_LOAD_DEOR_OUTBOUND">                <soap:body use="literal"/>            </wsdl:input>            <wsdl:output name="SI_LOAD_DEOR_OUTBOUNDResponse">                <soap:body use="literal"/>            </wsdl:output>        </wsdl:operation>    </wsdl:binding>    <wsdl:service name="SI_LOAD_DEOR_OUTBOUND">
  2.         <wsdl:port binding="tns:SI_LOAD_DEOR_OUTBOUNDSoapBinding" name="SI_LOAD_DEOR_OUTBOUNDBinding">
  3.             <soap:address location="http://127.0.0.1:8081/rest/erp/ZJLogisticsWebServices"/>
  4.         </wsdl:port>
  5.     </wsdl:service></wsdl:definitions>
复制代码
5.2、测试数据接入

5.2.1、通过curl命令调试本地测试

测试文件内容如下,注意需将以下内容保存为xml文件。
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <soapenv:Envelope
  3.     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
  4.     xmlns:sil="http://qhyhgf.com.cn/sd/Invoice">
  5.     <soapenv:Header/>
  6.     <soapenv:Body>
  7.         <sil:MT_LOAD_DEOR>
  8.             <ITEM>
  9.                 <VBELN>0080000405</VBELN>
  10.                 <POSNR>900001</POSNR>
  11.                 <WADAT_IST>20241204</WADAT_IST>
  12.                 <ZCYDW>郭六运输公司</ZCYDW>
  13.                 <PARTNER>上海英济塑料有限公司</PARTNER>
  14.                 <ZCH>新A66601</ZCH>
  15.                 <MATNR>350</MATNR>
  16.                 <ARKTX>轻质纯碱优等品</ARKTX>
  17.                 <KWMENG>40.000</KWMENG>
  18.                 <CHARG>1602230193</CHARG>
  19.                 <ZSJXM>张五</ZSJXM>
  20.                 <ZLXDH>13138542156</ZLXDH>
  21.                 <ZSJSFZ>632128198902052117</ZSJSFZ>
  22.                 <ZBZ>大换小</ZBZ>
  23.                 <VRKME>吨</VRKME>
  24.                 <VSBED>自提</VSBED>
  25.                 <ZDJCJR>张晓瑜</ZDJCJR>
  26.             </ITEM>
  27.             <ITEM>
  28.                 <VBELN>0080000405</VBELN>
  29.                 <POSNR>900002</POSNR>
  30.                 <WADAT_IST>20241204</WADAT_IST>
  31.                 <ZCYDW>郭六运输公司</ZCYDW>
  32.                 <PARTNER>上海英济塑料有限公司</PARTNER>
  33.                 <ZCH>青C3DR3N</ZCH>
  34.                 <MATNR>350</MATNR>
  35.                 <ARKTX>轻质纯碱优等品</ARKTX>
  36.                 <KWMENG>40.000</KWMENG>
  37.                 <CHARG>1602230193</CHARG>
  38.                 <ZSJXM>李四</ZSJXM>
  39.                 <ZLXDH>13876526374</ZLXDH>
  40.                 <ZSJSFZ>673273198801221111</ZSJSFZ>
  41.                 <ZBZ>大换小</ZBZ>
  42.                 <VRKME>吨</VRKME>
  43.                 <VSBED>自提</VSBED>
  44.                 <ZDJCJR>张晓瑜</ZDJCJR>
  45.             </ITEM>
  46.             <ITEM>
  47.                 <VBELN>0080000406</VBELN>
  48.                 <POSNR>000010</POSNR>
  49.                 <WADAT_IST>20241204</WADAT_IST>
  50.                 <ZCYDW>个体</ZCYDW>
  51.                 <PARTNER>上海英济塑料有限公司</PARTNER>
  52.                 <ZCH>青H33331</ZCH>
  53.                 <MATNR>60340431</MATNR>
  54.                 <ARKTX>PP专用纯碱 轻质纯碱优等品 标准GB210.1-2004Ⅱ类(≥99.2%)</ARKTX>
  55.                 <KWMENG>10.000</KWMENG>
  56.                 <CHARG/>
  57.                 <ZSJXM>理财</ZSJXM>
  58.                 <ZLXDH>18800023332</ZLXDH>
  59.                 <ZSJSFZ>123456789009876543</ZSJSFZ>
  60.                 <ZBZ/>
  61.                 <VRKME>吨</VRKME>
  62.                 <VSBED>自提</VSBED>
  63.                 <ZDJCJR>李志山</ZDJCJR>
  64.             </ITEM>
  65.             <ITEM>
  66.                 <VBELN>0080000406</VBELN>
  67.                 <POSNR>000020</POSNR>
  68.                 <WADAT_IST>20241204</WADAT_IST>
  69.                 <ZCYDW>个体</ZCYDW>
  70.                 <PARTNER>上海英济塑料有限公司</PARTNER>
  71.                 <ZCH>青H33331</ZCH>
  72.                 <MATNR>60340431</MATNR>
  73.                 <ARKTX>PP专用纯碱 轻质纯碱优等品 标准GB210.1-2004Ⅱ类(≥99.2%)</ARKTX>
  74.                 <KWMENG>11.000</KWMENG>
  75.                 <CHARG/>
  76.                 <ZSJXM>下滑</ZSJXM>
  77.                 <ZLXDH>18800023332</ZLXDH>
  78.                 <ZSJSFZ>123456789009876555</ZSJSFZ>
  79.                 <ZBZ/>
  80.                 <VRKME>吨</VRKME>
  81.                 <VSBED>自提</VSBED>
  82.                 <ZDJCJR>李志山</ZDJCJR>
  83.             </ITEM>
  84.         </sil:MT_LOAD_DEOR>
  85.     </soapenv:Body>
  86. </soapenv:Envelope>
复制代码
打开cmd窗口,进入测试文件目录,输入以下命令,完成测试。
  1. curl -X POST http://localhost:8081/rest/erp/ZJLogisticsWebServices/services/SILoadDeorOutbound ^ -H "Content-Type: text/xml; charset=utf-8" ^ -H "SOAPAction: "http://sap.com/xi/WebService/soap1.1"" ^ --data @testERPData.xml
复制代码
5.2.2、SoapUI调试

具体使用方式可以参照工具使用指南
在左边copy测试参数,即测试文件的内容。点击绿色三角启动按钮,右边是来自我们服务端的响应信息。

响应示例:
  1. HTTP/1.1 200
  2. Vary: Origin
  3. Vary: Access-Control-Request-Method
  4. Vary: Access-Control-Request-Headers
  5. X-Content-Type-Options: nosniff
  6. X-XSS-Protection: 1; mode=block
  7. Content-Type: text/xml;charset=UTF-8
  8. Content-Length: 374
  9. Date: Tue, 10 Dec 2024 08:35:05 GMT
  10. Keep-Alive: timeout=60
  11. Connection: keep-alive
  12. <soap:Envelope
  13.     xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  14.     <soap:Body>
  15.         <ns2:SI_LOAD_DEOR_OUTBOUNDResponse
  16.             xmlns:ns2="http://qhyhgf.com.cn/sd/Invoice">
  17.             <ITEM>
  18.                 <VBELN>0080000406</VBELN>
  19.                 <ZJCBS>S</ZJCBS>
  20.                 <ZJSXX>成功</ZJSXX>
  21.             </ITEM>
  22.             <ITEM>
  23.                 <VBELN>0080000405</VBELN>
  24.                 <ZJCBS>S</ZJCBS>
  25.                 <ZJSXX>成功</ZJSXX>
  26.             </ITEM>
  27.         </ns2:SI_LOAD_DEOR_OUTBOUNDResponse>
  28.     </soap:Body>
  29. </soap:Envelope>
复制代码
6、wsdl文档关键配置简述

6.1、服务端地址

<soap:address location 标签为服务端地址,即客户端访问地址,实际使用时会通过加?wsdl来访问服务端文档。127.0.0.1:8081 为实际后端服务的ip端口,实际生产情况需要配置nginx代理。
  
  1. http://localhost:8081/rest/erp/ZJLogisticsWebServices?wsdl
复制代码
6.2、命名空间

用于唯一标识Web服务的接口和数据类型。它们资助克制名称辩论,并且为XML元素提供上下文信息。命名空间通常由URI(统一资源标识符)表现,尽管这个URI不一定要指向实际存在的资源,它只是作为一个唯一的标识符。


  • Target Namespace: http://qhyhgf.com.cn/sd/Invoice
  1. <wsdl:definitions name="SI_LOAD_DEOR_OUTBOUND"
  2.     targetNamespace="http://qhyhgf.com.cn/sd/Invoice"
  3.     xmlns:p1="http://qhyhgf.com.cn/sd/Invoice"
  4.     xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
  5.     xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
  6.     xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
复制代码
6.3、portName

portName 是WSDL(Web Services Description Language)文档中的一个重要概念。它用于界说一个特定的服务端点(endpoint),该端点是客户端与服务交互的具体位置。portName 通常由两部分组成:服务名称和端口名称,它们共同标识了一个唯一的操作集合。
portName 在WSDL中是由<port>元素指定的,它是<service>元素的一部分。每个<service>可以包罗多个<port>,每个<port>对应于一种访问服务的方式(即绑定)。portName 是这个端口的唯一标识符,并且它资助区分同一个服务的不同端点。
比方,在我的服务端文档中可以看到如下界说:
  1.   <wsdl:service name="SI_LOAD_DEOR_OUTBOUND">
  2.         <wsdl:port binding="tns:SI_LOAD_DEOR_OUTBOUNDSoapBinding" name="SI_LOAD_DEOR_OUTBOUNDBinding">
  3.             <soap:address location="http://127.0.0.1:8081/rest/erp/ZJLogisticsWebServices"/>
  4.         </wsdl:port>
  5.     </wsdl:service>
复制代码
在这个例子中:


  • name="SI_LOAD_DEOR_OUTBOUND" 界说了服务的名称。
  • name="SI_LOAD_DEOR_OUTBOUNDBinding" 界说了端口的名称。
  • binding="tns:SI_LOAD_DEOR_OUTBOUNDSoapBinding" 指定了这个端口使用哪种绑定(协媾和数据格式)。
  • <soap:address location="http://127.0.0.1:8081/rest/erp/ZJLogisticsWebServices"/> 提供了访问该端点的实际URL。
在Java代码中的界说,通过@WebService注解来指定serviceName和portName。如:
  1. @WebService(name = "SI_LOAD_DEOR_OUTBOUND",
  2.         targetNamespace = "http://qhyhgf.com.cn/sd/Invoice")
  3. @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
  4. @XmlSeeAlso({
  5.         ServerFactory.class
  6. })
  7. public interface SILoadDeorOutboundService {
  8. }
复制代码
  1. @Slf4j
  2. @WebService(
  3.         serviceName = "SI_LOAD_DEOR_OUTBOUNDService", // 必须与 WSDL 中的服务名称相同
  4.         portName = "SI_LOAD_DEOR_OUTBOUNDBinding",
  5.         endpointInterface = "com.zhejuedata.logistics.service.webservice.server.SILoadDeorOutboundService" // SEI 接口的全限定名
  6. )
  7. @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE, style = SOAPBinding.Style.DOCUMENT)
  8. @Service
  9. public class SILoadDeorOutboundServiceImpl implements SILoadDeorOutboundService {
  10. }
复制代码
  1.     @Bean
  2.     public Endpoint siLoadDeorOutboundEndpoint() {
  3.         EndpointImpl endpoint = new EndpointImpl(springBus(), new SILoadDeorOutboundServiceImpl());
  4.         // 设置服务名称和端口名称
  5.         endpoint.setServiceName(new QName(WebServiceConf.wsNamespace, WebServiceConf.wsInterfaceName));
  6.         endpoint.setEndpointName(new QName(WebServiceConf.wsNamespace, WebServiceConf.wsPortName));
  7.         endpoint.publish("/ZJLogisticsWebServices");
  8.         return endpoint;
  9.     }
复制代码
  1. public class WebServiceConf {
  2.     public final static String wsServerUrl = OmniConf.getString("ws.server.url", "/rest/erp/ZJLogisticsWebServices");
  3.     public final static String wsNamespace = OmniConf.getString("ws.namespace", "http://qhyhgf.com.cn/sd/Invoice");
  4.     public final static String wsPortName = OmniConf.getString("ws.port.name", "SI_LOAD_DEOR_OUTBOUNDBinding");
  5.     public final static String wsInterfaceName = OmniConf.getString("ws.interface.name", "SI_LOAD_DEOR_OUTBOUND");
  6. }
复制代码
6.4、入参

服务接口的入参界说。


  • MT_LOAD_DEOR: 包罗要推送的数据。

    • name:MT_LOAD_DEOR
    • 类型:DT_LOAD_DEOR
    • 命名空间:http://qhyhgf.com.cn/sd/Invoice

  1. <wsdl:types>
  2.         <xsd:schema targetNamespace="http://qhyhgf.com.cn/sd/Invoice"
  3.             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  4.             xmlns="http://qhyhgf.com.cn/sd/Invoice">
  5.             <xsd:element name="MT_LOAD_DEOR" type="DT_LOAD_DEOR"/>
  6.             <xsd:complexType name="DT_LOAD_DEOR">
  7.                 <xsd:sequence>
  8.                     <xsd:element name="ITEM" maxOccurs="unbounded">
  9.                         <xsd:complexType>
  10.                             <xsd:sequence>
  11.                                 <xsd:element name="VBELN" type="xsd:string">
  12.                                     <xsd:annotation>
  13.                                         <xsd:documentation>发货单号</xsd:documentation>
  14.                                     </xsd:annotation>
  15.                                 </xsd:element>
  16.                                 <xsd:element name="POSNR" type="xsd:string">
  17.                                     <xsd:annotation>
  18.                                         <xsd:documentation>发货单行项目</xsd:documentation>
  19.                                     </xsd:annotation>
  20.                                 </xsd:element>
  21.                                 <xsd:element name="WADAT_IST" type="xsd:string">
  22.                                     <xsd:annotation>
  23.                                         <xsd:documentation>提货时间</xsd:documentation>
  24.                                     </xsd:annotation>
  25.                                 </xsd:element>
  26.                                 <xsd:element name="ZCYDW" type="xsd:string">
  27.                                     <xsd:annotation>
  28.                                         <xsd:documentation>承运企业</xsd:documentation>
  29.                                     </xsd:annotation>
  30.                                 </xsd:element>
  31.                                 <xsd:element name="PARTNER" type="xsd:string">
  32.                                     <xsd:annotation>
  33.                                         <xsd:documentation>结算单位</xsd:documentation>
  34.                                     </xsd:annotation>
  35.                                 </xsd:element>
  36.                                 <xsd:element name="ZCH" type="xsd:string">
  37.                                     <xsd:annotation>
  38.                                         <xsd:documentation>车牌号</xsd:documentation>
  39.                                     </xsd:annotation>
  40.                                 </xsd:element>
  41.                                 <xsd:element name="MATNR" type="xsd:string">
  42.                                     <xsd:annotation>
  43.                                         <xsd:documentation>物料号</xsd:documentation>
  44.                                     </xsd:annotation>
  45.                                 </xsd:element>
  46.                                 <xsd:element name="ARKTX" type="xsd:string">
  47.                                     <xsd:annotation>
  48.                                         <xsd:documentation>物料描述</xsd:documentation>
  49.                                     </xsd:annotation>
  50.                                 </xsd:element>
  51.                                 <xsd:element name="KWMENG" type="xsd:string">
  52.                                     <xsd:annotation>
  53.                                         <xsd:documentation>运输货物重量</xsd:documentation>
  54.                                     </xsd:annotation>
  55.                                 </xsd:element>
  56.                                 <xsd:element name="CHARG" type="xsd:string">
  57.                                     <xsd:annotation>
  58.                                         <xsd:documentation>货物批次号</xsd:documentation>
  59.                                     </xsd:annotation>
  60.                                 </xsd:element>
  61.                                 <xsd:element name="ZSJXM" type="xsd:string">
  62.                                     <xsd:annotation>
  63.                                         <xsd:documentation>司机姓名</xsd:documentation>
  64.                                     </xsd:annotation>
  65.                                 </xsd:element>
  66.                                 <xsd:element name="ZLXDH" type="xsd:string">
  67.                                     <xsd:annotation>
  68.                                         <xsd:documentation>司机手机号码</xsd:documentation>
  69.                                     </xsd:annotation>
  70.                                 </xsd:element>
  71.                                 <xsd:element name="ZSJSFZ" type="xsd:string">
  72.                                     <xsd:annotation>
  73.                                         <xsd:documentation>司机身份证号码</xsd:documentation>
  74.                                     </xsd:annotation>
  75.                                 </xsd:element>
  76.                                 <xsd:element name="ZBZ" type="xsd:string">
  77.                                     <xsd:annotation>
  78.                                         <xsd:documentation>备注</xsd:documentation>
  79.                                     </xsd:annotation>
  80.                                 </xsd:element>
  81.                                 <xsd:element name="VRKME" type="xsd:string">
  82.                                     <xsd:annotation>
  83.                                         <xsd:documentation>产品计量单位</xsd:documentation>
  84.                                     </xsd:annotation>
  85.                                 </xsd:element>
  86.                                 <xsd:element name="VSBED" type="xsd:string">
  87.                                     <xsd:annotation>
  88.                                         <xsd:documentation>提货方式</xsd:documentation>
  89.                                     </xsd:annotation>
  90.                                 </xsd:element>
  91.                                 <xsd:element name="ZDJCJR" type="xsd:string">
  92.                                     <xsd:annotation>
  93.                                         <xsd:documentation>单据创建人</xsd:documentation>
  94.                                     </xsd:annotation>
  95.                                 </xsd:element>
  96.                             </xsd:sequence>
  97.                         </xsd:complexType>
  98.                     </xsd:element>
  99.                 </xsd:sequence>
  100.             </xsd:complexType>
  101.         </xsd:schema>
  102.     </wsdl:types>
  103.     <wsdl:message name="MT_LOAD_DEOR">
  104.         <wsdl:documentation/>
  105.         <wsdl:part name="MT_LOAD_DEOR" element="p1:MT_LOAD_DEOR"/>
  106.     </wsdl:message>
  107.     <wsdl:portType name="SI_LOAD_DEOR_OUTBOUND">
  108.         <wsdl:documentation/>
  109.         <wsdl:operation name="SI_LOAD_DEOR_OUTBOUND">
  110.             <wsdl:documentation/>
  111.             <wsp:Policy>
  112.                 <wsp:PolicyReference URI="#OP_SI_LOAD_DEOR_OUTBOUND"/>
  113.             </wsp:Policy>
  114.             <wsdl:input message="p1:MT_LOAD_DEOR"/>
  115.         </wsdl:operation>
  116.     </wsdl:portType>
复制代码
6.5、响应体界说

详细见2、响应格式界说


  • <xsd:element name="MT_LOAD_DEOR_REBACK" type="DT_LOAD_DEOR_REBACK"/>

    • name:MT_LOAD_DEOR_REBACK
    • 类型:DT_LOAD_DEOR_REBACK
    • 命名空间:http://qhyhgf.com.cn/sd/Invoice

响应对象wsdl文档界说:
  1. <xsd:schema targetNamespace="http://qhyhgf.com.cn/sd/Invoice"
  2.             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  3.             xmlns="http://qhyhgf.com.cn/sd/Invoice">
  4.             <xsd:element name="MT_LOAD_DEOR_REBACK" type="DT_LOAD_DEOR_REBACK"/>
  5.             <xsd:complexType name="DT_LOAD_DEOR_REBACK">
  6.                 <xsd:sequence>
  7.                     <xsd:element name="ITEM" maxOccurs="unbounded">
  8.                         <xsd:complexType>
  9.                             <xsd:sequence>
  10.                                 <xsd:element name="VBELN" type="xsd:string">
  11.                                     <xsd:annotation>
  12.                                         <xsd:documentation>发货单号</xsd:documentation>
  13.                                     </xsd:annotation>
  14.                                 </xsd:element>
  15.                                 <xsd:element name="ZJCBS" type="xsd:string">
  16.                                     <xsd:annotation>
  17.                                         <xsd:documentation>接收方成功标识</xsd:documentation>
  18.                                     </xsd:annotation>
  19.                                 </xsd:element>
  20.                                 <xsd:element name="ZJSXX" type="xsd:string" minOccurs="0">
  21.                                     <xsd:annotation>
  22.                                         <xsd:documentation>接收方信息</xsd:documentation>
  23.                                     </xsd:annotation>
  24.                                 </xsd:element>
  25.                             </xsd:sequence>
  26.                         </xsd:complexType>
  27.                     </xsd:element>
  28.                 </xsd:sequence>
  29.             </xsd:complexType>
  30.         </xsd:schema>
复制代码
对应Java实体界说如下:
  1. @XmlAccessorType(XmlAccessType.FIELD)
  2. @XmlRootElement(name = "MT_LOAD_DEOR_REBACK")
  3. @Getter
  4. @Setter
  5. public class MTLoadDeorReback {
  6.     @XmlElement(name = "ITEM", required = true)
  7.     private ArrayList<ResponseItem> responseItem;
  8.     public static MTLoadDeorReback success(List<String> dispatchListCodes) {
  9.         MTLoadDeorReback response = new MTLoadDeorReback();
  10.         response.setResponseItem(new ArrayList<>(dispatchListCodes.stream()
  11.                 .map(ResponseItem::success)
  12.                 .collect(Collectors.toList())));
  13.         return response;
  14.     }
  15.     public static MTLoadDeorReback fail(List<String> dispatchListCodes) {
  16.         MTLoadDeorReback response = new MTLoadDeorReback();
  17.         response.setResponseItem(new ArrayList<>(dispatchListCodes.stream()
  18.                 .map(ResponseItem::fail)
  19.                 .collect(Collectors.toList())));
  20.         return response;
  21.     }
  22. }
复制代码
  1. @XmlAccessorType(XmlAccessType.FIELD)
  2. @XmlType(name = "DT_ITEM", propOrder = {
  3.         "dispatchListCode", "code", "msg"}
  4.         , namespace = "http://qhyhgf.com.cn/sd/Invoice")
  5. @Getter
  6. @Setter
  7. public class ResponseItem {
  8.     /**
  9.      * 发货单号
  10.      */
  11.     @XmlElement(name = "VBELN", required = true)
  12.     private String dispatchListCode;
  13.     /**
  14.      * 接收方成功标识
  15.      * S/E
  16.      */
  17.     @XmlElement(name = "ZJCBS", required = true)
  18.     private String code;
  19.     /**
  20.      * 接收方信息
  21.      * 成功/错误
  22.      */
  23.     @XmlElement(name = "ZJSXX", required = true)
  24.     private String msg;
  25.     public static ResponseItem success(String dispatchListCode) {
  26.         ResponseItem item = new ResponseItem();
  27.         item.setDispatchListCode(dispatchListCode);
  28.         item.setCode("S");
  29.         item.setMsg("成功");
  30.         return item;
  31.     }
  32.     public static ResponseItem fail(String dispatchListCode) {
  33.         ResponseItem item = new ResponseItem();
  34.         item.setDispatchListCode(dispatchListCode);
  35.         item.setCode("E");
  36.         item.setMsg("失败");
  37.         return item;
  38.     }
  39. }
复制代码
四、踩坑历程

1、请求乐成但拿不到响应信息xml

误用了@OneWay注解,这个注解只有在实际业务场景不需要思量和处置处罚响应信息的时候才会需要使用,即单向通信。方法无需返回内容时才会需要。
2、生产情况请求服务端地址404

经排查发现是因为webservice在后台服务启动后。默认以服务ip:port/rest/erp/ZJLogisticsWebServices方式提供访问,但我们生产情况的nginx做了代理会在ip:port后增长后缀/api,于是我们提供出去的服务地址就成了ip:port/api/rest/erp/ZJLogisticsWebServices,而实际服务端文档内的地址仍然为:ip:port/rest/erp/ZJLogisticsWebServices。导致第三方使用我们的服务端文档解析出来的地址时会404。
解决方案:修改nginx配置文件:
  1. location /api/ {
  2.             proxy_pass http://ip:port/;
  3.             proxy_http_version 1.1;
  4.             proxy_set_header Upgrade $http_upgrade;
  5.             proxy_set_header Connection 'upgrade';
  6.             proxy_set_header Host $host;
  7.             proxy_cache_bypass $http_upgrade;
  8.             # 设置超时时间
  9.             proxy_connect_timeout 60s;
  10.             proxy_send_timeout 60s;
  11.             proxy_read_timeout 60s;
  12.         }
复制代码
3、甲方ERP体系需要我们自动推送响应信息,并且需要鉴权

甲方仅提供了鉴权需要使用的用户名密码,访问吸收响应信息接口服务地址发现,需要以雷同代填表单方式完成用户名密码的填写。颠末一系列排查测试,发现甲方服务端实际使用的鉴权认证方式是 www-authenticate。 一种通过BASE-64加密的简单认证技术。
  1. headers.addHeader("Authorization", "Basic " + Base64Encoder.encode("用户名:密码"));
复制代码
五、附录

   彻底理解Webservice SOAP WSDL
    SoapUI使用指南
    www-authenticate与BASE-64认证技术
    Apache CXF:简化SOA集成的开源框架
     Apache CXF 开发指南

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

钜形不锈钢水箱

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表