2010/07/28

[Java] 在 Java 程式中呼叫 .Net 的 Web Service

開發工具:
  • Java: Netbeans6.5 (plugins: Web Services)
  • dotNet: Microsoft Visual Studio 2008
dotNet 部分 (Web Service Server) :
  1. 透過 VS2008 在網站 (Ex: MyTest) 中建立一個名為 HelloWs.asmx 的 Web 服務.
    HelloWs.cs 的程式碼如下:
    using System.Web.Services;
    using System.Web.Services.Protocols;
    /// <summary> 
    /// HelloWs 的摘要描述:
    /// Namespace("http://tempuri.org/")將會對應至Java程式的package
    /// </summary>
    [WebService(Namespace = http://tempuri.org/)]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class HelloWs : System.Web.Services.WebService {
        public HelloHeader objHelloHeader;
        public HelloWs () {
            //如果使用設計的元件,請取消註解下行程式碼
            //InitializeComponent();
        }
        /// <summary>
        /// 測試用的函式:輸出此函式的參數與HelloHeader的PassKey
        /// </summary>
        /// <param name="name">名字</param>
        /// <returns>測試用的輸出</returns>
        [WebMethod]
        [SoapHeader("objHelloHeader", Direction = SoapHeaderDirection.In)]
        public string HelloWorld(string name) {
            return string.Format("Hello {0}, your PassKey is {1}", name, objHelloHeader.PassKey);
        }
    }
    /// <summary>
    /// HelloHeader繼承自SoapHeader, 僅包含一個PassKey的屬性
    /// </summary>
    public class HelloHeader : SoapHeader
    {
        private string strPassKey;    
        public string PassKey
        {
            get { return strPassKey; }
            set { strPassKey = value; }
        }
    }
  2. 在瀏覽器中輸入 http://127.0.0.1/MyTest/HelloWs.asmx , 再點選頁面中的函式名稱 (Ex: HelloWorld), 可檢視 SOAP 1.1 與 1.2 要求與回應的範例.
    以下是發出 SOAP1.1 Request 的 SOAP內容:
    POST /MyTest/HelloWs.asmx HTTP/1.1
    Host: 127.0.0.1
    Content-Type: text/xml; charset=utf-8
    Content-Length: length
    SOAPAction: "http://tempuri.org/HelloWorld"
    <?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:Header>
        <HelloHeader xmlns="http://tempuri.org/">
          <PassKey>string</PassKey>
        </HelloHeader>
      </soap:Header>
      <soap:Body>
        <HelloWorld xmlns="http://tempuri.org/">
          <name>string</name>
        </HelloWorld>
      </soap:Body>
    </soap:Envelope> 
Java 部分 (Web Service Client):
  1. 開啟 Netbeans6.5, 並建立一個 Java Application (Ex: JavaTestApp).
  2. 建立一個測試用的 Java 程式 (Ex: TestHelloWorld.java).
    以下有兩種呼叫 dotNet Web Service 的方式: 一種是使用 JAX-WS 2.1, 一種是使用 ksoap2.
    1. 使用 JAX-WS 2.1:
      Step1. 在專案上建立一個 Web Service Client: 
      在 JavaTestApp 專案上按滑鼠右鍵 -> New -> Web Service Client… -> 輸入 WSDL 的 URL 路徑 -> 按下 Finish.
      建立一個Web Service Client
      Step2. Netbeans 會幫你建立這個 Web Service Client 的相關檔案, 可在 Netbeans 中切換至 Files 模式看到以下的檔案:
      Web Service Client 程式檔
      • 程式的 package 與 Web Service 的 Namespace 是相關的
      • 用來產生 Soap 相關物件: ObjectFactory.java
      • Web Service Client 主要的程式: HelloWs.java 與 HelloWsSoap.java
      • Soap Header: HelloHeader.java
      • Soap 函式: HelloWorld.java
      Step3. 在 Netbeans 中, 將 JAX-WS 2.1 加入至 Libraries, 不過這篇文章只需要用到以下兩個 jar:
      • NetBeans 6.5\java2\modules\ext\jaxws21\jaxws-rt.jar
      • NetBeans 6.5\ide10\modules\ext\jaxb\jaxb-impl.jar
      Step4. 在 Netbeans 中, TestHelloWorld.java 的 main 中按滑鼠右鍵 -> Web Service Client Resources -> Call Web Service Operation… -> 按下 OK.
      選取SOAP1.1的HelloWorld
      Step5. 在 main 中會產生呼叫 Web Service的 程式碼. 加入 Soap Header 的設定, 就能呼叫 dotNet 的 Web Service, 並傳回結果.
      程式碼如下:
      import com.sun.xml.ws.developer.WSBindingProvider;
      import org.tempuri.HelloHeader;
      public class TestHelloWorld {
        public static void main(String[] argd) {
          try {
            //呼叫Web Service的基本程式碼
            org.tempuri.HelloWs service = new org.tempuri.HelloWs();
            org.tempuri.HelloWsSoap port = service.getHelloWsSoap();
            //設定Soap Header:HelloHeader1
            HelloHeader header = new HelloHeader();
            header.setPassKey("12345678");
            WSBindingProvider bp = (WSBindingProvider) port;
            //透過org.tempuri.ObjectFactory, 將HelloHeader轉換為JAXBElement<HelloHeader>
            org.tempuri.ObjectFactory factory = new org.tempuri.ObjectFactory();
            bp.setOutboundHeaders(factory.createHelloHeader(header));
            // 設定呼叫HelloWorld的參數
            String name = "徐武功";
            // 呼叫Web Service, 並傳回結果
            String result = port.helloWorld(name);
            //將輸出: "Hello 徐武功, your PassKey is 12345678"
            System.out.println(result);
          } catch (Exception ex) {
            ex.printStackTrace(System.out);
          }
        }
      }
    2. 使用 ksoap2: 此做法不需要另外建立 Web Service Client.
      Step1. 下載 ksoap2 和 kxml 套件: Step2. 參考以下程式碼的說明:
      import java.io.StringReader;
      import org.ksoap2.SoapEnvelope;
      import org.ksoap2.serialization.SoapObject;
      import org.ksoap2.serialization.SoapSerializationEnvelope;
      import org.ksoap2.transport.HttpTransportSE;
      import org.kxml2.io.KXmlParser;
      import org.kxml2.kdom.Document;
      import org.kxml2.kdom.Element;
      import org.xmlpull.v1.XmlPullParser;
        
      public class TestHelloWorld {
        
        public static void main(String[] argd) {
          try {
            //產生soap header的兩種方法
            //第一種利用kxml的Element, 產生header的Element[]
            Element[] headers = new Element[1];
            //e1是<HelloHeader xmlns="http://tempuri.org/"></HelloHeader>
            Element e1 = new Element();
            e1.setName("HelloHeader");
            e1.setNamespace("http://tempuri.org/");
            //e2是<PassKey>87654321</PassKey>
            Element e2 = new Element();
            e2.setName("PassKey");
            e2.setNamespace("http://tempuri.org/");
            //加入一個文字"87654321"
            e2.addChild(Element.TEXT, "87654321");
            e1.addChild(Element.ELEMENT, e2);
            //將e1設定至header的Element[]
            headers[0] = e1;
        
            //第二種利用XmlPullParser, 將header的XML字串轉為kxml的Element
            String strHeader = "<HelloHeader xmlns=\"http://tempuri.org/\">"
               +"<PassKey>87654321</PassKey></HelloHeader>";
            XmlPullParser parser = new KXmlParser();
            parser.setInput(new StringReader(strHeader));
            Document doc = new Document();
            doc.parse(parser);
            Element[] headSoap = new Element[1];
            //將root element設定至headSoap的Element[]
            headSoap[0] = doc.getRootElement();
        
            String strServiceNamespace = "http://tempuri.org/";
            String strServiceUrl = "http://127.0.0.1/MyTest/HelloWs.asmx?wsdl";
            String strMethodName = "HelloWorld";
            String strSoapAction = "http://tempuri.org/HelloWorld";
        
            SoapObject request = new SoapObject(strServiceNamespace, strMethodName)
            //設定呼叫HelloWorld的name參數
            request.addProperty("name", "徐武功");
            //設定呼叫SOAP1.1
            SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11)
            envelope.dotNet = true;
            //設定soap header, 可設定為headers或headSoap
            envelope.headerOut = headers;
            //設定soap body
            envelope.setOutputSoapObject(request);
            envelope.bodyOut = request;
            HttpTransportSE ht = new HttpTransportSE(strServiceUrl);
            //呼叫HelloWorld(name)
            ht.call(strSoapAction, envelope);
            //輸出"Hello 徐武功, your PassKey is 87654321"
            System.out.println(envelope.getResponse());
          } catch (Exception ex) {
              ex.printStackTrace(System.out);
          }
        }
      }
      ksoap2 的 SOAP1.2 版我沒試成功, 因為執行時發生 xml parsing 的 exception.
      如果有人試成功, 歡迎提供解決方法.

沒有留言: