背景
笔者当前从事制造业相关行业软件工作,因工作需要,在MES系统中需要向SAP拉取订单、物料、工序等数据。
笔者接触的SAP提供了跨系统通信的Po中间件(实际上是WebService SOAP1.0)。
通常情况下,我们只要使用wsdl生成工具,生成本地的调用客户端即可。常用的客户端工具是apace-cxf。
IDEA旗舰版本中,邮件项目,有个WebService相关的菜单,输入wsdl地址即可。社区版一般安装一个maven插件,如下
<build> <plugins> <plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>3.4.5</version> <executions> <execution> <id>generate-sources-w2j</id> <phase>generate-sources</phase> <configuration> <sourceRoot>src/main/java</sourceRoot> <defaultOptions> <extraargs> <extraarg>-impl</extraarg> <extraarg>-verbose</extraarg> <extraarg>-validate</extraarg> <!--<extraarg>-client</extraarg>--> </extraargs> </defaultOptions> <wsdlOptions> <wsdlOption> <wsdl>http://www1.host.com/dir/wsdl?p=ic/2f1826f53a9b398a83000fdd7a05814e</wsdl> <extendedSoapHeaders>true</extendedSoapHeaders> <autoNameResolution>true</autoNameResolution> </wsdlOption> <!-- MES向SAP 按时间读取物料主数据接口--> <wsdlOption> <wsdl>http://www1.host.com/dir/wsdl?p=ic/fb71dee0a5c538d99d305c6f28eebd53</wsdl> <extendedSoapHeaders>true</extendedSoapHeaders> <autoNameResolution>true</autoNameResolution> </wsdlOption> <!-- MES向SAP 生产报工同步接口 --> <wsdlOption> <wsdl>http://www1.host.com/dir/wsdl?p=ic/46d3848617fa3dd7bc806f248d51340f</wsdl> <extendedSoapHeaders>true</extendedSoapHeaders> <autoNameResolution>true</autoNameResolution> </wsdlOption> <!-- MES向SAP 按物料编号读取物料主数据接口 --> <wsdlOption> <wsdl>http://www1.host.com/dir/wsdl?p=ic/48c28c49f4fc337d9fdfc3d5feee4e66</wsdl> <extendedSoapHeaders>true</extendedSoapHeaders> <autoNameResolution>true</autoNameResolution> </wsdlOption> <!--派工单下达传输--> <wsdlOption> <wsdl>http://www1.host.com/dir/wsdl?p=ic/6dcd80497ea937c8b484635b554710f4</wsdl> <extendedSoapHeaders>true</extendedSoapHeaders> <autoNameResolution>true</autoNameResolution> </wsdlOption> <!--工单开工标识--> <wsdlOption> <wsdl>http://www1.host.com/dir/wsdl?p=ic/4c602e2c4d673d3ba71a205d708b9c02</wsdl> <extendedSoapHeaders>true</extendedSoapHeaders> <autoNameResolution>true</autoNameResolution> </wsdlOption> <!-- MES向SAP 工单信息读取 --> <wsdlOption> <wsdl>http://www1.host.com/dir/wsdl?p=ic/40dd063793613e2caec3d96510577b37</wsdl> <extendedSoapHeaders>true</extendedSoapHeaders> <autoNameResolution>true</autoNameResolution> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin> </plugins> </plugins>
然后在右侧点击wsdl2java即可生成本地客户端调用代码
这是一是常规情况,SAP的特殊支持就是在通信协议层面做了Http Basic认证,即在请求头要添加
Authorization: Basic base64字符串
以下是物料按时间拉取的一个标准请求报文及相应报文,使用soapui发包,通过wireshark抓取
POST /XISOAPAdapter/MessageServlet?senderParty=&senderService=BS_MES_DEV&receiverParty=&receiverService=
&interface=SI_MaterialMasterData_In&interfaceNamespace=http://host.com/MES/MaterialMasterData/Sender HTTP/1.1 Accept-Encoding: gzip,deflate Content-Type: text/xml;charset=UTF-8 SOAPAction: "http://sap.com/xi/WebService/soap1.1" Content-Length: 450 Host: www1.host.com Connection: Keep-Alive User-Agent: Apache-HttpClient/4.5.5 (Java/15) Authorization: Basic VmlzaXRvcjpxd2VyMTIzNA== <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:sap-com:document:sap:rfc:functions"> <soapenv:Header/> <soapenv:Body> <urn:ZMES_SAP_003> <!--You may enter the following 4 items in any order--> <!--Optional:--> <BEDAT>20211210</BEDAT> <!--Optional:--> <EDDAT>20211212</EDDAT> </urn:ZMES_SAP_003> </soapenv:Body> </soapenv:Envelope>HTTP/1.1 200 OK server: SAP NetWeaver Application Server 7.49 / AS Java 7.50 date: Thu, 23 Dec 2021 07:41:51 GMT set-cookie: MYSAPSSO2=AjExMDAgAA5wb3J0YWw6dmlzaXRvcogAB2RlZmF1bHQBAAdWSVNJVE9SAgADMDAwAwADUE9EBAAMMjAyMTEyMjMwNz
QxBQAEAAAACAoAB1ZJU0lUT1L%2FAQYwggECBgkqhkiG9w0BBwKggfQwgfECAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHATGB0TCBzgIBAT
AiMB0xDDAKBgNVBAMTA1BPRDENMAsGA1UECxMESjJFRQIBADAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG
9w0BCQUxDxcNMjExMjIzMDc0MTUxWjAjBgkqhkiG9w0BCQQxFgQUdWxoAzhEYiSIc27jSe8FsKCEbjswCQYHKoZIzjgEAwQwMC4CFQDLMD
BWN7xZHY!5EWvCn3aesvvO6wIVAJWRZf5SLYj6KJlD!DaUx%2F!D3X!H;path=/;domain=.host.com;HttpOnly content-type: text/xml; charset=utf-8 content-id: <soap-cb1e8be463c311ec92be0000002094d2@sap.com> content-disposition: attachment;filename="soap-cb1e8be463c311ec92be0000002094d2@sap.com.xml" content-description: SOAP content-encoding: gzip content-length: 557 set-cookie: saplb_*=(J2EE2135220)2135250; Version=1; Path=/ set-cookie: JSESSIONID=lvNdixDYPSn8vdeDR9UxlrxfOT3mfQHSlCAA_SAPZmasLjjtl7ew9y4UdoHLQTn2; Version=1; Path=/ set-cookie: JSESSIONMARKID=9EvTHA-TE05LwidImrSEHzSGbAroysc13JPdKUIAA; Version=1; Path=/ <SOAP:Envelope xmlns:SOAP='http://schemas.xmlsoap.org/soap/envelope/'><SOAP:Header/><SOAP:Body>
<ns0:ZMES_SAP_003.Response xmlns:ns0='urn:sap-com:document:sap:rfc:functions'><MESSAGE>查询成功</MESSAGE>
<STA>S</STA><IT_MARA><item><MATNR>A06010475</MATNR><MAKTX>卡扣 φ6.3-φ7 白</MAKTX><MTART>Z001</MTART>
<MEINS>ST</MEINS><MATKL>3001</MATKL><GROES/><BISMT/><PRDHA/><MFRNR>0000200021</MFRNR><MFRPN/>
<ZEXTRA1/><ZEXTRA2>C</ZEXTRA2><ZEXTRA3>18</ZEXTRA3><ZEXTRA4>总装领料</ZEXTRA4><ZEXTRA5>0</ZEXTRA5>
<ZEXTRA6/><ZEXTRA7/><ZEXTRA8>180</ZEXTRA8><ZEXTRA9/><ZEXTRA10/><ZEXTRA13/></item></IT_MARA><IT_MARC>
<item><MATNR>A06010475</MATNR><WERKS>1201</WERKS><EKGRP/><BSTMI>0</BSTMI><BESKZ/><SOBSL/><RGEKM/>
<DZEIT>0</DZEIT><PLIFZ>0</PLIFZ><EISBE>0</EISBE><MAABC/><FEVOR/><BSTRF>0</BSTRF></item><item>
<MATNR>A06010475</MATNR><WERKS>1101</WERKS><EKGRP>101</EKGRP><BSTMI>0</BSTMI><BESKZ>F</BESKZ>
<SOBSL/><RGEKM/><DZEIT>0</DZEIT><PLIFZ>5</PLIFZ><EISBE>0</EISBE><MAABC/><FEVOR/><BSTRF>12000.000</BSTRF>
</item><item><MATNR>A06010475</MATNR><WERKS>1001</WERKS><EKGRP>101</EKGRP><BSTMI>1000.000</BSTMI>
<BESKZ>F</BESKZ><SOBSL/><RGEKM/><DZEIT>0</DZEIT><PLIFZ>30</PLIFZ><EISBE>0</EISBE><MAABC/><FEVOR/>
<BSTRF>1000.000</BSTRF></item></IT_MARC></ns0:ZMES_SAP_003.Response></SOAP:Body></SOAP:Envelope>
常规情况下apache cxf生成的客户端是不能带自定义请求头的,payload可以是自定义。当然网上有注册一个bean,
代理cxf本地请求客户端,带入身份验证,笔者认为笔记麻烦,没去测试。
解决方案
这篇文章九不科普太多了,直接上解决方案
SOAPClient.java
import cn.hutool.core.annotation.AnnotationUtil; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; import com.xxx.mes.common.exception.SAPCommunicationException; import com.xxx.mes.webservice.XPathExpression; import lombok.extern.slf4j.Slf4j; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Node; import org.dom4j.io.SAXReader; import org.dom4j.xpath.DefaultXPath; import org.springframework.http.HttpStatus; import javax.xml.bind.annotation.XmlRootElement; import java.io.*; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.Base64; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import static com.xxx.mes.common.util.XmlUtil.JaxbBinder.fromXml; /*** * SOAP客户端<br/> * 可以发送报文,解析报文映射成实体类 * */ @Slf4j public final class SOAPClient { private static final SAXReader saxReader = new SAXReader(); private static final Map<Class<?>,String> annotatedClassCache = new LinkedHashMap<Class<?>,String>(); /*** * 从基于soap的webservice报文中提取响应结果 * @param xml 返回的原始报文 * @param expression xpath评估表达式 * @param targetClass 待返回的结果 * @param <T> * @return 如果解析成功将返回一个<code>T</code>类的响应实体 * @throws DocumentException */ public static <T> T extractResponse(String xml, XPathExpression expression, Class<T> targetClass) throws Exception { Document doc = saxReader.read(new ByteArrayInputStream(xml.getBytes())); DefaultXPath xpath = new DefaultXPath(expression.getExpression()); xpath.setNamespaceURIs(Collections.singletonMap(expression.getNamespaceURI(), expression.getTargetNamespace())); Node node = xpath.selectSingleNode(doc); final T response = fromXml(targetClass, node.asXML()); return response; } public static String getServiceUrl(String serviceName) { return String.format("http://www1.host.com/XISOAPAdapter/MessageServlet?senderParty=&senderService=BS_MES_DEV" + "&receiverParty=&receiverService=&interface=SI_%s_In&interfaceNamespace=http://host.com/MES/%s/Sender" , new Object[]{serviceName, serviceName}); } /*** * 通过soap请求载荷构造soap请求报文 * @param payload * @param <T> * @return xml-based soap request payload * @throws JsonProcessingException */ public static <T> String buildSOAPRequest(T payload) throws JsonProcessingException { final Class<?> targetClass = payload.getClass(); String elementName = annotatedClassCache.get(targetClass); if(elementName == null){ elementName = AnnotationUtil.getAnnotation(targetClass, XmlRootElement.class).name(); annotatedClassCache.put(targetClass,elementName); } XmlMapper xmlMapper = (XmlMapper) new XmlMapper() .setAnnotationIntrospector(new JaxbAnnotationIntrospector(TypeFactory.defaultInstance())); //字段为null,自动忽略,不再序列化 xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); StringBuilder builder = new StringBuilder(); builder.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:urn=\"urn:sap-com:document:sap:rfc:functions\">\n" + " <soapenv:Header/>\n" + " <soapenv:Body>"); builder.append("<urn:").append(elementName).append(">"); String xml = xmlMapper.writeValueAsString(payload); builder.append(xml); builder.append("</urn:").append(elementName).append(">"). append(" </soapenv:Body>"). append("</soapenv:Envelope>"); log.info("xml报文:{}", builder); return builder.toString().replace("<" + elementName + ">", "").replace("</" + elementName + ">", ""); } /*** * 向SAP服务器提供的Webservice发起调用请求 * @param httpUrl 请求地址 * @param soapBody 使用{@link #buildSOAPRequest(Object)}构造的请求报文 * @return 返回xml格式的响应报文 * @throws IOException */ public static String send(String httpUrl, String soapBody) throws IOException { String resultData = ""; URL geturl = null; try { // 构造一个URL对象 geturl = new URL(httpUrl); } catch (MalformedURLException e) { throw new SAPCommunicationException("url地址格式无效:%s", new Object[]{httpUrl}); } try { // 使用HttpURLConnection打开连接 HttpURLConnection urlConn = (HttpURLConnection) geturl.openConnection(); // 设置请求的超时时间 urlConn.setReadTimeout(50000); urlConn.setConnectTimeout(50000); // Windows验证 用户密码 String datap = "Visitor:qwer1234"; String authorization = Base64.getEncoder().encodeToString(datap.getBytes()); urlConn.setRequestProperty("Authorization", "Basic " + authorization); // 设置请求的头 urlConn.setRequestProperty("Connection", "keep-alive"); // 配置本次连接的Content-type,配置为application/x-www-form-urlencoded的 urlConn.setRequestProperty("Content-Type", "text/xml;charset=UTF-8"); urlConn.setRequestProperty("SOAPAction", "http://sap.com/xi/WebService/soap1.1"); // 设置请求的头 urlConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0"); // 因为这个是post请求,设立需要设置为true urlConn.setDoOutput(true); urlConn.setDoInput(true); // 设置以POST方式 urlConn.setRequestMethod("POST"); // Post 请求不能使用缓存 urlConn.setUseCaches(false); // 获取输出流 // BufferedReader os = new BufferedReader(new // OutputStream(urlConn.getOutputStream())) OutputStream os = urlConn.getOutputStream(); // byte[] content = data.getBytes("utf-8"); os.write(soapBody.getBytes()); os.flush(); os.close(); int statusCode = urlConn.getResponseCode(); if (statusCode == HttpStatus.OK.value()) { // 获取响应的输入流对象 InputStream is = urlConn.getInputStream(); // 创建字节输出流对象 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 定义读取的长度 int len; int irecord = 1; // 定义缓冲区 byte buffer[] = new byte[1024]; // 按照缓冲区的大小,循环读取 while ((len = is.read(buffer)) != -1) { // 根据读取的长度写入到os对象中 baos.write(buffer, 0, len); irecord += 1; } // 释放资源 is.close(); baos.close(); // 返回字符串 resultData = new String(baos.toByteArray()); irecord -= 1; return resultData; } else { urlConn.disconnect(); throw new SAPCommunicationException("接口报文返回异常:http状态码,期望值200,实际:%d", new Object[]{statusCode}); } } catch (Exception e) { log.error("SAP通信异常",e); throw e; } }
XPathExpression.java
import lombok.Data; /** * 中间参数类,用于解析xml的xpath表达式<br/> * 数据样本: * <pre> * <SOAP:Envelope * xmlns:SOAP='http://schemas.xmlsoap.org/soap/envelope/'> * <SOAP:Header/> * <SOAP:Body> * <ns0:ZMES_SAP_003.Response * xmlns:ns0='urn:sap-com:document:sap:rfc:functions'> * <MESSAGE>查询成功</MESSAGE> * <STA>S</STA> * <IT_MARA> * <item> * <MATNR>A06010475</MATNR> * <MAKTX>卡扣 φ6.3-φ7 白</MAKTX> * <MTART>Z001</MTART> * <MEINS>ST</MEINS> * <MATKL>3001</MATKL> * <GROES/> * <BISMT/> * <PRDHA/> * <MFRNR>0000200021</MFRNR> * <MFRPN/> * <ZEXTRA1/> * <ZEXTRA2>C</ZEXTRA2> * <ZEXTRA3>18</ZEXTRA3> * <ZEXTRA4>总装领料</ZEXTRA4> * <ZEXTRA5>0</ZEXTRA5> * <ZEXTRA6/> * <ZEXTRA7/> * <ZEXTRA8>180</ZEXTRA8> * <ZEXTRA9/> * <ZEXTRA10/> * <ZEXTRA13/> * </item> * </IT_MARA> * <IT_MARC> * <item> * <MATNR>A06010475</MATNR> * <WERKS>1201</WERKS> * <EKGRP/> * <BSTMI>0</BSTMI> * <BESKZ/> * <SOBSL/> * <RGEKM/> * <DZEIT>0</DZEIT> * <PLIFZ>0</PLIFZ> * <EISBE>0</EISBE> * <MAABC/> * <FEVOR/> * <BSTRF>0</BSTRF> * </item> * <item> * <MATNR>A06010475</MATNR> * <WERKS>1101</WERKS> * <EKGRP>101</EKGRP> * <BSTMI>0</BSTMI> * <BESKZ>F</BESKZ> * <SOBSL/> * <RGEKM/> * <DZEIT>0</DZEIT> * <PLIFZ>5</PLIFZ> * <EISBE>0</EISBE> * <MAABC/> * <FEVOR/> * <BSTRF>12000.000</BSTRF> * </item> * <item> * <MATNR>A06010475</MATNR> * <WERKS>1001</WERKS> * <EKGRP>101</EKGRP> * <BSTMI>1000.000</BSTMI> * <BESKZ>F</BESKZ> * <SOBSL/> * <RGEKM/> * <DZEIT>0</DZEIT> * <PLIFZ>30</PLIFZ> * <EISBE>0</EISBE> * <MAABC/> * <FEVOR/> * <BSTRF>1000.000</BSTRF> * </item> * </IT_MARC> * </ns0:ZMES_SAP_003.Response> * </SOAP:Body> * </SOAP:Envelope> * </pre> * * @author: passedbylove * @date: Created by 2021/12/28 11:04 * @version: 1.0.0 */ @Data public class XPathExpression { /*** * xpath提取数据节点的表达式 * eg.<br/> * //ns0:ZMES_SAP_003.Response */ private String expression; /*** * 命名空间的前缀 * eg.<br/> * ns0 */ private String namespaceURI; /*** * 命名空间 * eg.<br/> * "urn:sap-com:document:sap:rfc:functions" */ private String targetNamespace; public XPathExpression() { } public XPathExpression(String expression, String namespaceURI, String targetNamespace) { this.expression = expression; this.namespaceURI = namespaceURI; this.targetNamespace = targetNamespace; } }
SAPCommunicationException.java
import lombok.NoArgsConstructor; /** * 用于注明是SAP系统通信过程中产生的异常,区别于其他异常,比如调用SAP接口过程中可能产生 * <code>UnknownHostException</</code>或者<code>IOException</code</code>等;此处归一化为<code>SAPCommunicationException</code> * 方便排错 * @author: daiqiankun * @date: Created by 2021/12/28 11:11 * @version: 1.0.0 */ @NoArgsConstructor public class SAPCommunicationException extends RuntimeException { public SAPCommunicationException(String message) { super(message); } public SAPCommunicationException(String format,Object[] args) { super(String.format(format,args)); } public SAPCommunicationException(String message, Throwable ex) { super(message, ex); } public SAPCommunicationException(String message, Object[] args,Throwable ex) { super(String.format(message,args), ex); } }
JaxbBinder.java
/** * @datetime 2021/12/27 15:29 */ public static class JaxbBinder { /*** * 缓存一下JAXBContext,减少反射开销 */ static Map<Class<?>, JAXBContext> contextCache = new LinkedHashMap<>(); //多线程安全的Context. private JAXBContext jaxbContext; public JaxbBinder() {} /** * @param types 所有需要序列化的Root对象的类型. */ public JaxbBinder(Class<?>... types) { try { jaxbContext = JAXBContext.newInstance(types); } catch (JAXBException e) { throw new RuntimeException(e); } } /** * Java Object->Xml. */ public String toXml(Object root, String encoding) { try { StringWriter writer = new StringWriter(); createMarshaller(encoding).marshal(root, writer); return writer.toString(); } catch (JAXBException e) { throw new RuntimeException(e); } } /** * Java Object->Xml, 特别支持对Root Element是Collection的情形. */ @SuppressWarnings("unchecked") public String toXml(Collection root, String rootName, String encoding) { try { CollectionWrapper wrapper = new CollectionWrapper(); wrapper.collection = root; JAXBElement<CollectionWrapper> wrapperElement = new JAXBElement<CollectionWrapper>(new QName(rootName), CollectionWrapper.class, wrapper); StringWriter writer = new StringWriter(); createMarshaller(encoding).marshal(wrapperElement, writer); return writer.toString(); } catch (JAXBException e) { throw new RuntimeException(e); } } /** * Xml->Java Object. */ @SuppressWarnings("unchecked") public <T> T fromXml(String xml) { try { StringReader reader = new StringReader(xml); return (T) createUnmarshaller().unmarshal(reader); } catch (JAXBException e) { throw new RuntimeException(e); } } /** * 将XML转为指定的POJO * * @param clazz * @param xmlStr * @return * @throws Exception */ public static <T> T fromXml(Class<?> clazz, String xmlStr) throws Exception { T xmlObject = null; Reader reader = null; JAXBContext context = null; context = contextCache.get(clazz); if (Objects.isNull(context)) { context = JAXBContext.newInstance(clazz); contextCache.put(clazz, context); } // XML 转为对象的接口 Unmarshaller unmarshaller = context.createUnmarshaller(); reader = new StringReader(xmlStr); //以文件流的方式传入这个string xmlObject = (T)unmarshaller.unmarshal(reader); if (null != reader) { reader.close(); } return xmlObject; } /** * 创建Marshaller, 设定encoding(可为Null). */ public Marshaller createMarshaller(String encoding) { try { Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); if (!StringUtils.isEmpty(encoding)) { marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding); } return marshaller; } catch (JAXBException e) { throw new RuntimeException(e); } } /** * 创建UnMarshaller. */ public Unmarshaller createUnmarshaller() { try { return jaxbContext.createUnmarshaller(); } catch (JAXBException e) { throw new RuntimeException(e); } } /** * 封装Root Element 是 Collection的情况. */ public static class CollectionWrapper { @SuppressWarnings("unchecked") @XmlAnyElement protected Collection collection; } @SuppressWarnings("unchecked") public <T> T fromXML(String fileName) { return (T)fromXML(new File(fileName)); } @SuppressWarnings("unchecked") public <T> T fromXML(File file) { try { Unmarshaller unmarshaller = createUnmarshaller(); return (T) unmarshaller.unmarshal(file); } catch (JAXBException e) { throw new RuntimeException(e); } } @SuppressWarnings("unchecked") public <T> T fromXML(InputStream stream) { try { Unmarshaller unmarshaller = createUnmarshaller(); return (T) unmarshaller.unmarshal(stream); } catch (JAXBException e) { throw new RuntimeException(e); } } }
调用方法
ZMESSAP003 zmessap003 = new ZMESSAP003(); zmessap003.setBEDAT("19901101"); zmessap003.setEDDAT("19901130"); final XmlRootElement annotation = AnnotationUtil.getAnnotation(ZMESSAP003.class, XmlRootElement.class); final String data = buildSOAPRequest(zmessap003, annotation.name()); final String xml = SOAPClient.send("http://www1.host.com/XISOAPAdapter/MessageServlet?senderParty=&senderService=BS_MES_DEV&receiverParty=&receiverService=&interface=SI_MaterialMasterData_In&interfaceNamespace=http://xxx.com/MES/MaterialMasterData/Sender&sap-user=Visitor&sap-password=qwer1234", data); System.out.println(data); XPathExpression expression = new XPathExpression(); expression.setExpression("//ns0:ZMES_SAP_003.Response"); expression.setNamespaceURI("ns0"); expression.setTargetNamespace("urn:sap-com:document:sap:rfc:functions"); final ZMESSAP003Response response = SOAPClient.extractResponse(xml, expression, ZMESSAP003Response.class);
其中ZMESSAP003 是cxf生成的本地客户端代码,本文不是最终代码,仅供各位参考。
需要用到的pom依赖
hutool
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency>
本博客文章绝大多数为原创,少量为转载,代码经过测试验证,如果有疑问直接留言或者私信我。
创作文章不容易,转载文章必须注明文章出处;如果这篇文章对您有帮助,点击右侧打赏,支持一下吧。
创作文章不容易,转载文章必须注明文章出处;如果这篇文章对您有帮助,点击右侧打赏,支持一下吧。