SpringBoot调用第三方WebService接口的两种方法
作者:代号diitich
WebService简介
WebService接口的发布通常一般都是使用WSDL(web service descriptive language)文件的样式来发布的,该文档包含了请求的参数信息,返回的结果信息,我们需要根据WSDL文档的信息来编写相关的代码进行调用WebService接口。接下来我将采用常见的两种方式调用WebService接口。
场景描述
目前我需要使用java调用C#系统的一个WebService接口,传递参数为一个表号,返回的是一个Xml的数据类型,需要实现调用接口,获取到xml之后并解析为Json格式数据,并返回给前端。Java调用WebService接口,需要根据提供接口方的XSD文档编写相关代码,Xsd文档可以直接通过提供的接口地址进行查看。
WebServiceTemplate调用WebService接口实现
1.导入相关的依赖包,如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> </dependency>
2.使用WebServiceTemplate实现调用WebService接口,需要编写先关的解析类,根据提供的XSDL文档编写先关代码,XSDL文档信息如下:
POST /rootServiceFlow/EBoardService.asmx HTTP/1.1 Host: 10.200.0.74 Content-Type: text/xml; charset=utf-8 Content-Length: length SOAPAction: "http://tempuri.org/AAFlow002x" <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <AAFlow002x xmlns="http://tempuri.org/"> <LotNo>string</LotNo> </AAFlow002x> </soap:Body> </soap:Envelope>
上面的信息是包含请求所需要传递的参数,字段为LotNo。接下来XSDL的文档信息为返回的数据格式,如下:
HTTP/1.1 200 OK Content-Type: text/xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <AAFlow002xResponse xmlns="http://tempuri.org/"> <AAFlow002xResult>string</AAFlow002xResult> </AAFlow002xResponse> </soap:Body> </soap:Envelope>
需要根据以上信息编写请求类AAFlow002x,响应接收解析类AAFlow002xResponse,和ObjectFactory类,这三个类可以使用Idea的终端通过命令的方式生成对应的java类,也可以通过自己编写生成java类。通过命令的方式如下:
xjc -d /path/to/output http://example.com/sample.xsd
/path/to/output为生成类的目录,http://example.com/sample.xsd为webServce的接口地址,生成的类如下:
AAFlow002x类编写如下: import lombok.Data; import javax.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { "LotNo" }) @XmlRootElement(name = "AAFlow002x", namespace = "http://tempuri.org/") @Data public class AAFlow002x { @XmlElement(name = "LotNo", namespace = "http://tempuri.org/", required = true) protected String LotNo; }
AAFlow002xResponse类编写如下: import lombok.Data; import javax.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "AAFlow002xResponse", namespace = "http://tempuri.org/", propOrder = { "AAFlow002xResult" }) @XmlRootElement(name = "AAFlow002xResponse") @Data public class AAFlow002xResponse { @XmlElement(name = "AAFlow002xResult", namespace = "http://tempuri.org/", required = true) private String AAFlow002xResult; }
ObjectFatoty类编写如下: import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.XmlElementDecl; import javax.xml.bind.annotation.XmlRegistry; import javax.xml.namespace.QName; @XmlRegistry public class ObjectFactory { private final static QName _AAFlow002_QNAME = new QName("http://tempuri.org/", "AAFlow002x"); private final static QName _AAFlow002Response_QNAME = new QName("http://tempuri.org/", "AAFlow002xResponse"); public ObjectFactory() { } public AAFlow002x createAAFlow002x() { return new AAFlow002x(); } public AAFlow002xResponse createAAFlow002xResponse() { return new AAFlow002xResponse(); } @XmlElementDecl(namespace = "http://tempuri.org/", name = "AAFlow002x") public JAXBElement<AAFlow002x> createAAFlow002x(AAFlow002x value) { return new JAXBElement<AAFlow002x>(_AAFlow002_QNAME, AAFlow002x.class, null, value); } @XmlElementDecl(namespace = "http://tempuri.org/", name = "AAFlow002yResponse") public JAXBElement<AAFlow002xResponse> createAAFlow002yResponse(AAFlow002xResponse value) { return new JAXBElement<AAFlow002xResponse>(_AAFlow002Response_QNAME, AAFlow002xResponse.class, null, value); } }
编写使用WebServiceTemplate进行调用
@Service @Slf4j public class TestWebService { private static final String ENDPOINT_URL = "这里填写你调用的WebService接口地址"; private static final String SOAP_ACTION = "http://tempuri.org/AAFlow002x"; public String getDataTable(String LotNo) { // 创建WebServiceTemplate对象 WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); // 设置解析类,这里填写包的路径为AAFlow002xResponse类所在路径 marshaller.setContextPath("org.test.parse"); webServiceTemplate.setMarshaller(marshaller); webServiceTemplate.setUnmarshaller(marshaller); // 封装请求参数 AAFlow002x aaFlow002 = new ObjectFactory().createAAFlow002x(); aaFlow002.setLotNo("22113102"); // 创建SOAP请求回调对象,这里的SOAP_ACTION指定你调用的接口的哪个方法 SoapActionCallback soapActionCallback = new SoapActionCallback(SOAP_ACTION); // 调用WebService接口,发送请求并返回数据 JAXBElement<AAFlow002xResponse> aaFlow002xResponse = (JAXBElement<AAFlow002xResponse>) webServiceTemplate.marshalSendAndReceive(ENDPOINT_URL, aaFlow002, soapActionCallback); String result = aaFlow002xResponse.getValue().getAAFlow002xResult(); // 输出响应结果 System.out.println(aaFlow002xResponse.getValue().getAAFlow002xResult()); return result; } }
编写完成之后,Debug启动项目。出现如下图所示证明调用接口成功:
我们可以针对以上代码进行优化,写一个WebServiceConfig类,专门对WebServiceTemplate进行配置,这里就不在赘述。采用WebServiceTemplate接口调用WebService接口,虽然可以采用命令的方式生成对应的Java代码,但是其缺点是如果请求的参数和返回的参数数据结构很复杂,生成的java类代码就很复杂。
HttpClientBuilder调用WebService接口实现
@Override public JSONObject getDataFromMESSystem(String deviceNumber) { // 根据上面的XSDL文档封装请求参数 String strParameter = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" + " <soap:Body>\n" + " <AAFlow002y xmlns=\"http://tempuri.org/\">\n" + " <LotNo>" + deviceNumber + "</LotNo>\n" + " </AAFlow002y>\n" + " </soap:Body>\n" + " </soap:Envelope>"; // 获取数据,返回的是一个xml格式数据 String xmlData = doPostSoap(UrlConstant.MES_SERVICE_URL, strParameter, UrlConstant.MES_SOAP_URI); JSONObject jsonObject = null; try { // 将请求结果转换成json类型 if(StringUtils.isNotBlank(xmlData)){ jsonObject = xml2Json(xmlData); } } catch (Exception e) { e.printStackTrace(); } return jsonObject; } /** * 发送Soap请求,并返回数据 * @param url WebService接口地址 * @param soap 封装的请求参数 * @param SOAPAction 对应的调用方法uri * @return 返回xml数据,用一个字符串接收 */ public static String doPostSoap(String url, String soap, String SOAPAction) { // 请求体 String retStr = ""; // 创建HttpClientBuilder HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); // HttpClient CloseableHttpClient closeableHttpClient = httpClientBuilder.build(); HttpPost httpPost = new HttpPost(url); try { httpPost.setHeader("Content-Type", "text/xml;charset=UTF-8"); httpPost.setHeader("SOAPAction", SOAPAction); StringEntity data = new StringEntity(soap, Charset.forName("UTF-8")); httpPost.setEntity(data); CloseableHttpResponse response = closeableHttpClient .execute(httpPost); HttpEntity httpEntity = response.getEntity(); if (httpEntity != null) { // 打印响应内容 retStr = EntityUtils.toString(httpEntity, "UTF-8"); System.err.println("response:" + retStr); } // 释放资源 closeableHttpClient.close(); } catch (Exception e) { e.printStackTrace(); } return retStr; }
接下来需要根据返回的xml格式数据解析为Json格式,我们可以用Postman测试WebService接口,查看数据返回格式,如下图所示:
点击Send,返回的数据格式如下图所示:
数据太多,这里我给出返回的缩减的结构数据,如下
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <AAFlow002yResponse xmlns="http://tempuri.org/"> <AAFlow002yResult> <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="AAFlow002" msdata:UseCurrentLocale="true"> <xs:complexType> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="AAFlow002"> <xs:complexType> <xs:sequence> <xs:element name="F1000" type="xs:string" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema> <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"> <DocumentElement xmlns=""> <AAFlow002 diffgr:id="AAFlow0021" msdata:rowOrder="0"> <F1000>2596</F1000> </AAFlow002> </DocumentElement> </diffgr:diffgram> </AAFlow002yResult> </AAFlow002yResponse> </soap:Body> </soap:Envelope>
根据上面的信息,编写解析xml数据转换为Json格式数据代码如下:
/** * 解析webservice的返回结果,将xml解析为json格式数据 * @param xmlStr xml内容 * @return */ public static JSONObject xml2Json(String xmlStr) throws DocumentException { Document doc = DocumentHelper.parseText(xmlStr); Element root = doc.getRootElement(); Element body = root.element("Body"); Element response = body.element("AAFlow002yResponse"); Element result = response.element("AAFlow002yResult"); Element diffgram = result.element(new QName("diffgram", Namespace.get("urn:schemas-microsoft-com:xml-diffgram-v1"))); Element documentElement = diffgram.element("DocumentElement"); Element aaFlow002 = documentElement.element("AAFlow002"); JSONObject jsonObject = new JSONObject(); Iterator<Element> iterator = aaFlow002.elementIterator(); while (iterator.hasNext()) { Element element = iterator.next(); jsonObject.put(element.getName(), element.getText()); } return jsonObject; }
通过HttpClient的方式调用WebService接口,缺点是需要自己编写解析xml的代码,而WebServiceTemplate的方式可以自动解析为对应的Java类,但是个人更偏向于使用HttpClient的方式调用WebService接口,WebServiceTemplate方式,代码复杂度比较高,耦合性太强。
到此这篇关于SpringBoot调用第三方WebService接口的两种方法的文章就介绍到这了,更多相关SpringBoot调用WebService接口内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!