1. 程式人生 > >httpclient妙用一 httpclient作為客戶端呼叫webservice

httpclient妙用一 httpclient作為客戶端呼叫webservice

httpclient作為客戶端呼叫webservice

1.個人觀點

      webservice框架有很多,比如axis、axis2、cxf、xFire等等,做服務端和做客戶端都可行,個人感覺使用這些框架的好處是減少了對於介面資訊的解析,最主要的是減少了對於傳遞於網路中XML的解析,代價是你不得不在你的框架中新增對於這些框架的依賴。個人觀點是:服務端使用這些框架還行,如果做客戶端,沒必要使用這些框架,只需使用httpclient即可。

2.需求場景

     已經拿到對於介面的描述檔案WebServiceFromB.wsdl,需要建立客戶端進行呼叫,WebServiceFromB.wsdl內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://webservices.b.com" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://webservices.b.com" xmlns:intf="http://webservices.b.com" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--WSDL created by Apache Axis version: 1.4
Built on Apr 22, 2006 (06:55:48 PDT)-->
 <wsdl:types>
  <schema targetNamespace="http://webservices.b.com" xmlns="http://www.w3.org/2001/XMLSchema">
   <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
   <complexType name="OrderRequest">
    <sequence>
     <element name="mobile" nillable="true" type="soapenc:string"/>
     <element name="orderStatus" type="xsd:int"/>
     <element name="productCode" nillable="true" type="soapenc:string"/>
    </sequence>
   </complexType>
   <complexType name="OrderResponse">
    <sequence>
     <element name="status" type="xsd:int"/>
    </sequence>
   </complexType>
   <complexType name="QueryRequest">
    <sequence>
     <element name="endTime" nillable="true" type="xsd:dateTime"/>
     <element name="mobile" nillable="true" type="soapenc:string"/>
     <element name="startTime" nillable="true" type="xsd:dateTime"/>
    </sequence>
   </complexType>
   <complexType name="QueryResponse">
    <sequence>
     <element name="product" nillable="true" type="soapenc:string"/>
     <element name="status" type="xsd:int"/>
    </sequence>
   </complexType>
  </schema>
 </wsdl:types>
   <wsdl:message name="queryRequest">
      <wsdl:part name="in0" type="impl:QueryRequest"/>
   </wsdl:message>
   <wsdl:message name="orderResponse">
      <wsdl:part name="orderReturn" type="impl:OrderResponse"/>
   </wsdl:message>
   <wsdl:message name="queryResponse">
      <wsdl:part name="queryReturn" type="impl:QueryResponse"/>
   </wsdl:message>
   <wsdl:message name="orderRequest">
      <wsdl:part name="in0" type="impl:OrderRequest"/>
   </wsdl:message>
   <wsdl:portType name="WebServiceFromB">
      <wsdl:operation name="order" parameterOrder="in0">
         <wsdl:input message="impl:orderRequest" name="orderRequest"/>
         <wsdl:output message="impl:orderResponse" name="orderResponse"/>
      </wsdl:operation>
      <wsdl:operation name="query" parameterOrder="in0">
         <wsdl:input message="impl:queryRequest" name="queryRequest"/>
         <wsdl:output message="impl:queryResponse" name="queryResponse"/>
      </wsdl:operation>
   </wsdl:portType>
   <wsdl:binding name="WebServiceFromBSoapBinding" type="impl:WebServiceFromB">
      <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name="order">
         <wsdlsoap:operation soapAction=""/>
         <wsdl:input name="orderRequest">
            <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://webservices.b.com" use="encoded"/>
         </wsdl:input>
         <wsdl:output name="orderResponse">
            <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://webservices.b.com" use="encoded"/>
         </wsdl:output>
      </wsdl:operation>
      <wsdl:operation name="query">
         <wsdlsoap:operation soapAction=""/>
         <wsdl:input name="queryRequest">
            <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://webservices.b.com" use="encoded"/>
         </wsdl:input>
         <wsdl:output name="queryResponse">
            <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://webservices.b.com" use="encoded"/>
         </wsdl:output>
      </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name="WebServiceFromBService">
      <wsdl:port binding="impl:WebServiceFromBSoapBinding" name="WebServiceFromB">
         <wsdlsoap:address location="http://localhost:8080/services/WebServiceFromB"/>
      </wsdl:port>
   </wsdl:service>
</wsdl:definitions>

     3.獲取呼叫報文

        1.首先得安裝soapUI 4.5.2,安裝後開啟,截圖如下:



     

      2.右鍵點選“Projects”建立工程,截圖如下:



     

        3.雙擊展開左側建立的工程下所有節點,最後雙擊“Request 1”節點,在右側即可拿到soap格式訊息,這個就是我們後面作為客戶端呼叫服務端的報文內容,截圖如下:



        拿到的呼叫order的soap訊息為:

<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://webservices.b.com">
   <soapenv:Header/>
   <soapenv:Body>
      <web:order soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <in0 xsi:type="web:OrderRequest">
            <mobile xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">?</mobile>
            <orderStatus xsi:type="xsd:int">?</orderStatus>
            <productCode xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">?</productCode>
         </in0>
      </web:order>
   </soapenv:Body>
</soapenv:Envelope>

    拿到的呼叫query的soap訊息為:

<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://webservices.b.com">
   <soapenv:Header/>
   <soapenv:Body>
      <web:query soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <in0 xsi:type="web:QueryRequest">
            <endTime xsi:type="xsd:dateTime">?</endTime>
            <mobile xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">?</mobile>
            <startTime xsi:type="xsd:dateTime">?</startTime>
         </in0>
      </web:query>
   </soapenv:Body>
</soapenv:Envelope>

 4.用httpclient傳送soap訊息

   maven依賴如下:
     <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.2</version>
      </dependency>
      <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>fluent-hc</artifactId>
        <version>4.3.2</version>
      </dependency>
      <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>http-core</artifactId>
        <version>4.3.2</version>
      </dependency>


   直接上程式碼,程式碼如下:

import java.nio.charset.Charset;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

public class HttpClientCallSoapUtil {
	static int socketTimeout = 30000;// 請求超時時間
	static int connectTimeout = 30000;// 傳輸超時時間
	static Logger logger = Logger.getLogger(HttpClientCallSoapUtil.class);

	/**
	 * 使用SOAP1.1傳送訊息
	 * 
	 * @param postUrl
	 * @param soapXml
	 * @param soapAction
	 * @return
	 */
	public static String doPostSoap1_1(String postUrl, String soapXml,
			String soapAction) {
		String retStr = "";
		// 建立HttpClientBuilder
		HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
		// HttpClient
		CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
		HttpPost httpPost = new HttpPost(postUrl);
                //  設定請求和傳輸超時時間
		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(socketTimeout)
				.setConnectTimeout(connectTimeout).build();
		httpPost.setConfig(requestConfig);
		try {
			httpPost.setHeader("Content-Type", "text/xml;charset=UTF-8");
			httpPost.setHeader("SOAPAction", soapAction);
			StringEntity data = new StringEntity(soapXml,
					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");
				logger.info("response:" + retStr);
			}
			// 釋放資源
			closeableHttpClient.close();
		} catch (Exception e) {
			logger.error("exception in doPostSoap1_1", e);
		}
		return retStr;
	}

	/**
	 * 使用SOAP1.2傳送訊息
	 * 
	 * @param postUrl
	 * @param soapXml
	 * @param soapAction
	 * @return
	 */
	public static String doPostSoap1_2(String postUrl, String soapXml,
			String soapAction) {
		String retStr = "";
		// 建立HttpClientBuilder
		HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
		// HttpClient
		CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
		HttpPost httpPost = new HttpPost(postUrl);
                // 設定請求和傳輸超時時間
		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(socketTimeout)
				.setConnectTimeout(connectTimeout).build();
		httpPost.setConfig(requestConfig);
		try {
			httpPost.setHeader("Content-Type",
					"application/soap+xml;charset=UTF-8");
			httpPost.setHeader("SOAPAction", soapAction);
			StringEntity data = new StringEntity(soapXml,
					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");
				logger.info("response:" + retStr);
			}
			// 釋放資源
			closeableHttpClient.close();
		} catch (Exception e) {
			logger.error("exception in doPostSoap1_2", e);
		}
		return retStr;
	}

	public static void main(String[] args) {
		String orderSoapXml = "<?xml version = \"1.0\" ?>"
				+ "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://webservices.b.com\">"
				+ "   <soapenv:Header/>"
				+ "   <soapenv:Body>"
				+ "      <web:order soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
				+ "         <in0 xsi:type=\"web:OrderRequest\">"
				+ "            <mobile xsi:type=\"soapenc:string\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">?</mobile>"
				+ "            <orderStatus xsi:type=\"xsd:int\">?</orderStatus>"
				+ "            <productCode xsi:type=\"soapenc:string\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">?</productCode>"
				+ "         </in0>" + "      </web:order>"
				+ "   </soapenv:Body>" + "</soapenv:Envelope>";
		String querySoapXml = "<?xml version = \"1.0\" ?>"
				+ "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://webservices.b.com\">"
				+ "   <soapenv:Header/>"
				+ "   <soapenv:Body>"
				+ "      <web:query soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
				+ "         <in0 xsi:type=\"web:QueryRequest\">"
				+ "            <endTime xsi:type=\"xsd:dateTime\">?</endTime>"
				+ "            <mobile xsi:type=\"soapenc:string\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">?</mobile>"
				+ "            <startTime xsi:type=\"xsd:dateTime\">?</startTime>"
				+ "         </in0>" + "      </web:query>"
				+ "   </soapenv:Body>" + "</soapenv:Envelope>";
		String postUrl = "http://localhost:8080/services/WebServiceFromB";
		//採用SOAP1.1呼叫服務端,這種方式能呼叫服務端為soap1.1和soap1.2的服務
		doPostSoap1_1(postUrl, orderSoapXml, "");
		doPostSoap1_1(postUrl, querySoapXml, "");

		//採用SOAP1.2呼叫服務端,這種方式只能呼叫服務端為soap1.2的服務
		//doPostSoap1_2(postUrl, orderSoapXml, "order");
		//doPostSoap1_2(postUrl, querySoapXml, "query");
	}
}

 5.總結

       優點:

       1.使用httpclient作為客戶端呼叫webservice,不用關注繁瑣的webservice框架,只需找到SOAP訊息格式,新增httpclient依賴就行。

       2.使用httpclient呼叫webservice,建議採用soap1.1方式呼叫,經測試使用soap1.1方式能呼叫soap1.1和soap1.2的服務端。

       缺點:

       唯一的缺點是,你得自己解析返回的XML,找到你關注的資訊內容。