監(jiān)理公司管理系統(tǒng) | 工程企業(yè)管理系統(tǒng) | OA系統(tǒng) | ERP系統(tǒng) | 造價(jià)咨詢管理系統(tǒng) | 工程設(shè)計(jì)管理系統(tǒng) | 甲方項(xiàng)目管理系統(tǒng) | 簽約案例 | 客戶案例 | 在線試用
X 關(guān)閉

技巧:通過(guò)Web Service讓Delphi/Visual Basic程序訪問(wèn)EJB

申請(qǐng)免費(fèi)試用、咨詢電話:400-8352-114

AMTeam.org

技巧:通過(guò)Web Service讓Delphi/Visual Basic程序訪問(wèn)EJB    

 
 
陳凱琪 (
chenkq@sina.com)

2002 年 5 月

問(wèn)題的提出

EJB是使用Java語(yǔ)言編寫(xiě)分布式的、面向?qū)ο蟮?、商業(yè)應(yīng)用的標(biāo)準(zhǔn)組件架構(gòu)(參見(jiàn)EJB 1.1規(guī)范)。一些企業(yè)正在將他們以前的基于COM+組件的應(yīng)用移植到EJB組件技術(shù),或者采用EJB構(gòu)建新的應(yīng)用,同時(shí)為保護(hù)以前的IT投入還要保留以前的采用Delphi或者Visual Basic等編程語(yǔ)言編寫(xiě)的客戶端應(yīng)用。這就提出了Delphi/Visual Basic訪問(wèn)EJB的需求。

本篇文章將首先介紹Delphi/Visual Basic訪問(wèn)EJB的兩種方法,然后介紹Delphi/Visual Basic如何通過(guò)Web Service訪問(wèn)EJB:

將EJB封裝為Web Service并發(fā)布到應(yīng)用服務(wù)器上

Delphi訪問(wèn)Web Service

Visual Basic訪問(wèn)Web Service

最后文章中討論了在Delphi和Visual Basic中調(diào)用Web service時(shí)遇到的中文問(wèn)題。

Delphi/Visual Basic訪問(wèn)EJB的兩種方法

Delphi通過(guò)CORBA ORB訪問(wèn)EJB

Delphi企業(yè)版中含有CORBA Visibroker server,可以在Borland App Server服務(wù)器端將EJB封裝為CORBA服務(wù),然后在客戶端用SIDL (Simple IDL)的來(lái)描述封裝EJB的CORBA服務(wù),最后用Delphi工具idl2pas將描述文件翻譯成pascal程序。這個(gè)方案在部署的時(shí)候需要在客戶端安裝Visibroker server。

Visual Basic通過(guò)ActiveX to EJB Bridge訪問(wèn)EJB

IBM WebSphere Application Server Enterprise Edition 4.x中的Enterprise Service當(dāng)中包含ActiveX to EJB bridge,它為VB、VBScript以及ASP提供了一個(gè)ActiveX組件來(lái)方便地訪問(wèn)EJB。

客戶端程序首先初始化一個(gè)ActiveX控件,該控件初始化一個(gè)Java虛擬機(jī),ActiveX控件和Java虛擬機(jī)通過(guò)JNI(Java Native Interface)的方式交互。Java虛擬機(jī)通過(guò)Java ORB和運(yùn)行在應(yīng)用服務(wù)器上的EJB進(jìn)行交互。Active Bridge支持使用J2EE Client Container或者直接通過(guò)JNDI的方式訪問(wèn)EJB。

圖一:ActiveX to EJB Bridge系統(tǒng)結(jié)構(gòu)


通過(guò)Web Service讓Delphi/Visual Basic訪問(wèn)EJB

采用Web Service的方式封裝EJB,我們理論上可以讓支持Web Service的任何編程語(yǔ)言來(lái)訪問(wèn)該EJB,比如Java, Visual Basic, Visual C++,Delphi,perl,PHP等。

將EJB封裝為web service的工具有很多種,這里我們以開(kāi)放源碼的Apache SOAP為例來(lái)說(shuō)明這個(gè)開(kāi)發(fā)流程,開(kāi)發(fā)工具采用WSAD(IBM WebSphere Studio Application Developer)。這是一個(gè)以Java語(yǔ)言編寫(xiě)的,可以運(yùn)行在Windows和Linux平臺(tái)上的J2EE開(kāi)發(fā)工具,支持servlet、jsp、ejb、web service和xml的開(kāi)發(fā)和調(diào)試,可以在http://www-3.ibm.com/software/ad/studioappdev/免費(fèi)下載試用版。我們將以一個(gè)程序員都非常熟悉的例子-HelloWorld來(lái)展示開(kāi)發(fā)流程。下面,是我們動(dòng)手開(kāi)始做的時(shí)間了!

第一步,編寫(xiě)一個(gè)EJB,名字叫做HelloWorld。

1)建立一個(gè)EJB項(xiàng)目(EJB project):在J2EE perspective選擇菜單File > New > EJB Project,輸入Project Name為HelloWorldEJB,Enterprise Application project name為HelloWorldEAR,選擇Finish建立該EJB項(xiàng)目,如圖二所示:

圖二:建立EJB項(xiàng)目


2)建立EJB:在J2EE perspective中的J2EE View中選擇EJB Modules > HelloWorldEJB,然后選擇菜單File > New > Enterprise Bean,輸入Bean Name為HelloWorld,Bean class為ejbs.HelloWorld(這里使用package名為ejbs)。選擇Finish建立該EJB。如圖三所示:

圖三 建立EJB


3)給HelloWorldBean添加一個(gè)方法:在J2EE perspective中的J2EE View中選擇EJB Modules > HelloWorldEJB > HelloWorld > HelloWorldBean,鼠標(biāo)雙擊打開(kāi)并編輯該EJB。在該EJB后面加入方法sayHelloWorld
 /** sayHello
  * @return "Hello someone"
   * @param theName the name of someone
  */
 public String sayHello(String theName) {
  return "Hello " + theName;
 }

圖四 給HelloWorldBean增加一個(gè)方法sayHello


4)將新添加的方法sayHello加入到EJB remote interface中:鼠標(biāo)選中WSAD左下角處Java的Outline窗口中的方法sayHelloWorld,選擇鼠標(biāo)右鍵菜單Enterprise Bean > Promote to Remote Interface。WSAD將在HelloWorld EJB的remote Interface HelloWorld中加入一行: public String sayHello(String theName) throws java.rmi.RemoteException;

遠(yuǎn)程接口HelloWorld.java的完整的代碼:
package ejbs;
/**
 * Remote interface for Enterprise Bean: HelloWorld
 */
public interface HelloWorld extends javax.ejb.EJBObject {
 /** sayHello
  * @return "Hello someone"
   * @param theName the name of someone
  */
 public String sayHello(String theName) throws java.rmi.RemoteException;
}

圖五 將新添加的方法sayHello加入到EJB remote interface中


5)讓W(xué)SAD生成EJB的部署代碼(Deploy code)。如圖六操作即可。

圖六 生成EJB的部署代碼


6)現(xiàn)在我們可以部署并測(cè)試HelloWorld EJB了! 如圖七所示,運(yùn)行HelloWorld EJB。

圖七 選擇在服務(wù)器上運(yùn)行EJB


我們將看到WSAD將這個(gè)EJB項(xiàng)目發(fā)布到一個(gè)WebSphere v4.0 Test Environment中,啟動(dòng)該WebSphere測(cè)試環(huán)境。在控制臺(tái)中可以看到
02.04.14 11:56:59:171 CST] 55e67dfe EJBEngine     I WSVR0037I:正在啟動(dòng) EJB jar:HelloWorldEJB
[02.04.14 11:56:59:661 CST] 55e67dfe EJBEngine     I WSVR0038I:未找到 HelloWorld 的 JNDI 名,綁定起始對(duì)象名為 HelloWorldHome

[02.04.14 11:57:05:830 CST] 55e67dfe Server        A WSVR0023I:服務(wù)器 Default Server 為電子商務(wù)開(kāi)放

最后WSAD將打開(kāi)一個(gè)EJB Test Client窗口。選擇EJB References > HelloWorld > HelloWorldHome > HelloWorld create()方法,EJB Test Client獲得一個(gè)HelloWorld EJB Home Stub。如圖八所示:

圖八 使用EJB Test Client測(cè)試EJB(1)


7)調(diào)用HelloWorld EJB Home Stub對(duì)象的方法sayHello測(cè)試EJB。

圖九 使用EJB Test Client測(cè)試EJB(2)


第二步,使用WSAD中的 Web Service生成向?qū)砂b該EJB的Web Service、測(cè)試該Web Service的java proxy(一個(gè)Java Bean)和JSP測(cè)試程序,最后運(yùn)行生成的程序來(lái)測(cè)試這個(gè)Web Service。

1)建立一個(gè)名叫HelloWorldWeb的Web Project:選擇菜單File > New > Web Project,輸入project name為HelloWorldWeb,選擇Enterprise Application project name為HelloWorldEAR,如圖十所示。選擇next命令按鈕,選中available dependent JARs HelloWorldEJB.jar,如圖十一所示。

圖十                                                                                                                        圖十一



 選擇HelloWorldWeb > source,選擇菜單File > New > Web Service,如圖十二所示:

圖十二


在"Web Service"窗口中選擇部署該Web Service的Web project為HelloWorldWeb,如圖十三所示:

圖十三


選擇Next進(jìn)入下一個(gè)向?qū)Т翱?,選擇Web service type為EJB Web service。

選擇Next進(jìn)入下一個(gè)向?qū)Т翱?,選擇命令按鈕"Browse EJB Bean…",在彈出窗口中選擇EAR Project為HelloWorldEAR,EJB bean為HelloWorld(如圖十四所示)

圖十四


關(guān)閉彈出窗口,輸入EJB JNDI name 為HelloWorldHome,如圖十五所示。

圖十五


選擇Next進(jìn)入下一個(gè)向?qū)Т翱冢驅(qū)⒁筝斎隬eb service URI的名稱(chēng)和多個(gè)描述文件的文件名,如圖十六、十七所示。Web service URI是符合uniform resource Naming convention標(biāo)準(zhǔn)(http://www.ietf.org/rfc/rfc2141.txt)web service的標(biāo)識(shí)符,應(yīng)用程序訪問(wèn)Web service的時(shí)候需要指定這個(gè)參數(shù)。

ISD文件是Apache SOAP內(nèi)部使用的web service的發(fā)布描述文件。/wsdl/HelloWorld-service.wsdl文件描述了相關(guān)的web service port信息,應(yīng)用程序可以通過(guò)該文件獲得服務(wù)器上各種web service的信息。

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="HelloWorldService"
 targetNamespace="
http://localhost:8080/HelloWorldWeb/wsdl/HelloWorld-service.wsdl"
 xmlns="
http://schemas.xmlsoap.org/wsdl/"
 xmlns:tns="
http://localhost:8080/HelloWorldWeb/wsdl/HelloWorld-service.wsdl"
 xmlns:binding="
http://www.helloworld.com/definitions/HelloWorldRemoteInterface"
 xmlns:soap="
http://schemas.xmlsoap.org/wsdl/soap/">
  <import namespace="
http://www.helloworld.com/definitions/HelloWorldRemoteInterface"
  location="
http://localhost:8080/HelloWorldWeb/wsdl/HelloWorld-binding.wsdl"/>
  <service name="HelloWorldService">
    <port name="HelloWorldPort" binding="binding:HelloWorldBinding">
      <soap:address location="
http://localhost:8080/HelloWorldWeb/servlet/rpcrouter"/>
    </port>
  </service>
</definitions>
 /wsdl/HelloWorld-bind.wsdl則具體定義了具體一個(gè)portType的操作和消息的消息格式和協(xié)議。
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="HelloWorldRemoteInterface"
 targetNamespace="
http://www.helloworld.com/definitions/HelloWorldRemoteInterface"
 xmlns="
http://schemas.xmlsoap.org/wsdl/"
 xmlns:tns="
http://www.helloworld.com/definitions/HelloWorldRemoteInterface"
 xmlns:xsd="
http://www.w3.org/2001/XMLSchema"
 xmlns:soap="
http://schemas.xmlsoap.org/wsdl/soap/">
  <message name="sayHelloRequest">
    <part name="theName" type="xsd:string"/>
  </message>
  <message name="sayHelloResponse">
    <part name="result" type="xsd:string"/>
  </message>
  <portType name="HelloWorldJavaPortType">
    <operation name="sayHello">
      <input name="sayHelloRequest" message="tns:sayHelloRequest"/>
      <output name="sayHelloResponse" message="tns:sayHelloResponse"/>
    </operation>
  </portType>
  <binding name="HelloWorldBinding" type="tns:HelloWorldJavaPortType">
    <soap:binding style="rpc" transport="
http://schemas.xmlsoap.org/soap/http"/>
    <operation name="sayHello">
      <soap:operation soapAction="" style="rpc"/>
      <input name="sayHelloRequest">
        <soap:body use="encoded" encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/" namespace="http://tempuri.org/ejbs.HelloWorld"/>
      </input>
      <output name="sayHelloResponse">
        <soap:body use="encoded" encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/" namespace="http://tempuri.org/ejbs.HelloWorld"/>
      </output>
    </operation>
  </binding>
</definitions>

圖十六

 

圖十七


3)WSAD可以生成訪問(wèn)剛才發(fā)布的Web service的Java類(lèi),如圖十八、十九所示。該類(lèi)的方法 public synchronized java.lang.String sayHello(java.lang.String theName) throws Exception包裝了發(fā)布為Web service的EJB HelloWorld的方法sayHello(java.lang.String theName)。在發(fā)布EJB為Web service的向?qū)е锌梢陨蛇@個(gè)Java類(lèi)(web service binding proxy),同時(shí)還可以生成使用這個(gè)類(lèi)訪問(wèn)web service的jsp頁(yè)面。

圖十八

 

圖十九


最后,你可以選擇將Web Service發(fā)布為到UDDI服務(wù)器(比如免費(fèi)的IBM的UDDI4J)上。

第三步,在Delphi中調(diào)用Web Service

使用Delphi Web Services importer將定義Web Service的WSDL文件(可以是從Web服務(wù)器上下載下來(lái)的本地wsdl文件,也可以是一個(gè)指向該文件的HTTP URL,比如http://localhost:8080/HelloWorldWeb/wsdl/HelloWorld-service.wsdl)導(dǎo)入,這將自動(dòng)生成定義和注冊(cè)interfaces and types的pascal代碼。

選擇菜單File > New > Other… > 出現(xiàn)New Iterms窗口,選擇WebServices,選擇Web Services importer。如圖二十、二十一所示:

圖二十

 

圖二十一


生成的代碼如下:
Unit Unit_2;
interface
uses Types, XSBuiltIns;
type

HelloWorldJavaPortType = interface(IInvokable)
    ['{521A5B71-4CB9-4FAA-82AD-0F9CCF423FB9}']
//為方便使用,我們把Delphi聲明的過(guò)程 sayHello改為方法
    //procedure sayHello(const theName: WideString; out result: WideString);  stdcall;
function sayHello(const theName: WideString): WideString;  stdcall;
end;
implementation
uses InvokeRegistry;
initialization
  InvRegistry.RegisterInterface(TypeInfo(HelloWorldJavaPortType), '', 'UTF-8');
end.

現(xiàn)在,我們可以利用THTTPRio對(duì)象來(lái)調(diào)用Web Service。THTTPRio是Delphi提供的支持SOAP over HTTP的有源代碼的SOAP支持類(lèi)庫(kù)。部分代碼如下:

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, SoapHTTPClient, Unit2, StdCtrls;

procedure TForm_main.Button_callClick(Sender: TObject);
var
        //使用Delphi的Unit SoapHTTPClient,Delphi
        X :THTTPRio;
        //使用Unit_2中定義的HelloWorld Interface
        InterfaceVariable: HelloWorld;
        para1, para2: WideString;
begin
        X := THTTPRio.Create(nil);
        //設(shè)置Delphi在提出HTTP請(qǐng)求的時(shí)候設(shè)置Content-Type為text/xml; charset= UTF-8
       X.HTTPWebNode.UseUTF8InHeader := true ;

        //WSDLLocation也可以是在本地文件系統(tǒng)中的wsdl文件。
        X.WSDLLocation := 'http://localhost:8080/HelloWorldWeb/wsdl/HelloWorld-service.wsdl';
       
// THTTPRio 的Service參數(shù)和Port參數(shù)對(duì)應(yīng)HelloWorld-service.wsdl文件中的定義。
// <service name="HelloWorldService">
//    <port name="HelloWorldPort" binding="binding:HelloWorldBinding">
  //      <soap:address location="
http://localhost:8080/HelloWorldWeb/servlet/rpcrouter"/>
   //    </port>
  //</service>
        X.Service := 'HelloWorldService';
        X.Port := 'HelloWorldPort';

        InterfaceVariable := X as HelloWorld;
        para1 := '中文';
        //從輸入文本框中獲得輸入?yún)?shù)
        para1 := Edit_para1.Text;
        para2 := InterfaceVariable.sayHello(para1);
        //顯示調(diào)用web service返回的結(jié)果
        Label_return_value.Caption := 'Return Value: ' + para2;
        X.free;
end;

使用Microsoft SOAP Toolkit 編寫(xiě)SOAP客戶端程序

使用Microsoft SOAP Toolkit - High Level API編寫(xiě)SOAP客戶端程序非常簡(jiǎn)單,只需要四條語(yǔ)句就可以完成基本的SOAP請(qǐng)求。使用SOAP Toolkit之前,需要在項(xiàng)目增加Microsoft XML v3.0和Microsoft SOAP Type Library的引用(reference)。

如下是訪問(wèn)HelloWorld web service的代碼:

'定義Client為可以發(fā)送SOAP請(qǐng)求到服務(wù)器并能處理服務(wù)器返回的應(yīng)答的SoapClient Object

Private Client As SoapClient

Set Client = New SoapClient

'使用WSDL文件作為輸入文件初始化SoapClient

Client.mssoapinit "
http://localhost:8080/HelloWorldWeb/wsdl/HelloWorld-service.wsdl"

'調(diào)用sayHello方法

txtEquals.Text = CStr(Client.sayHello(txtA.Text)

這段使用High Level API的代碼在運(yùn)行的時(shí)候,MS SOAP Toolkit將報(bào)錯(cuò):

WSDLReader: No valid schema specification was found. This version of the SOAP Toolkit only supports 1999 and 2000 XSD schema specifications

 錯(cuò)誤的原因是使用High Level API,Microsoft SOAP Toolkit提交的XML格式的SOAP請(qǐng)求和Apache SOAP要求的格式不同。文章http://www-1.ibm.com/support/techdocs/atsmastr.nsf/PubAllNum/TD100540詳細(xì)地介紹了格式的具體不同。

使用Low Level API編寫(xiě)SOAP客戶端程序需要使用程序員使用SoapConnector的一個(gè)實(shí)現(xiàn)HttpConnector來(lái)建立HTTP連接,使用SoapSerializer object來(lái)建立一個(gè)SOAP message并發(fā)出SOAP請(qǐng)求;SoapReader從HttpConnector對(duì)象中獲得返回結(jié)果,生成一個(gè)XML DOM對(duì)象SoapReader.DOM,使用Microsoft XML API分析SoapReader.DOM獲得返回結(jié)果。

文章http://www.soapuser.com/client4.html非常清楚地介紹了如何使用Low Level API編寫(xiě)SOAP客戶端程序。訪問(wèn)HelloWorld EJB Web Service的demo代碼請(qǐng)?jiān)诖颂幭螺d。

Delphi Web Service中文問(wèn)題

通過(guò)監(jiān)控SOAP調(diào)用的全過(guò)程我們發(fā)現(xiàn)Delphi向Web Server提出HTTP請(qǐng)求的時(shí)候,數(shù)據(jù)是以UTF-8編碼通過(guò)POST方式提交給Web服務(wù)器的,但是另一方面,Delphi在HTTP請(qǐng)求頭中設(shè)置Content-Type為text/xml,造成Apache SOAP Toolkit認(rèn)為POST方式的數(shù)據(jù)是iso8859-1編碼,出現(xiàn)了所謂中文問(wèn)題。

我們可以設(shè)置Delphi在提出HTTP請(qǐng)求的時(shí)候設(shè)置Content-Type為text/xml; charset= UTF-8。具體做法是在創(chuàng)建了 THTTPRio對(duì)象之后設(shè)置它的屬性UseUTF8InHeader

X.HTTPWebNode.UseUTF8InHeader := true ;

需要注意SoapHTTPTrans.pas代碼 header := 'text/xml charset=UTF-8'; 當(dāng)中少了一個(gè)分號(hào)";",這造成服務(wù)器認(rèn)為soap 客戶程序POST上來(lái)的數(shù)據(jù)是iso8859-1編碼。

在Delphi選擇Project > Add to Project,加入Delphi6SourceSoapSoapHTTPTrans.pas。修改該行代碼為:header := 'text/xml; charset=UTF-8';

微軟SOAP Toolkit 2.0 with SP2的中文問(wèn)題

微軟SOAP Toolkit 2.0 with SP2的中文問(wèn)題的原因和Delphi一樣。

HttpConnector有一個(gè)在SOAP Toolkit 文檔中沒(méi)有標(biāo)明的屬性HTTPCharset,設(shè)置為utf-8即可。 Connector.Property("HTTPCharset") = "utf-8"

Web Service程序的調(diào)試

我們可以使用監(jiān)控程序來(lái)監(jiān)控Web Service的全過(guò)程,XML格式的HTTP訪問(wèn)請(qǐng)求和返回。

微軟的SOAP Toolkit中帶的SOAP Toolkit監(jiān)視器MSSoapT、Apache soap toolkit中的工具、或者其他的網(wǎng)絡(luò)監(jiān)控工具(比如network sniffer)。

結(jié)束語(yǔ):

Web Service為傳統(tǒng)的GUI程序提供了使用遠(yuǎn)程過(guò)程調(diào)用(RPC)的一種很好的方式,但是各家廠商對(duì)于Web Service的實(shí)現(xiàn)還是稍有差異(正如EJB, CORBA),這就提出了不同實(shí)現(xiàn)的互相操作性的問(wèn)題。此外,在我們國(guó)家的應(yīng)用當(dāng)中,還需要注意中文問(wèn)題。

參考資料:

  • 下載本文中用到的樣本代碼。
  • Apache SOAP

    http://xml.apache.org/soap/index.html
  • Apache Axis

    http://xml.apache.org/axis/
  • IBM WebSphere Application Server

    http://www-4.ibm.com/software/info/websphere/wstechnology.html
  • MS SOAP Toolkit download area
  • 一篇很好SOAP快速入門(mén)
  • Microsoft MSSOAP client to IBM HTTP/Apache server interoperability issue

作者簡(jiǎn)介:

陳凱琪:對(duì)Java和Linux有濃厚的興趣,精通J2EE應(yīng)用服務(wù)器方面的技術(shù),可以通過(guò)
chenkq@sina.com 與他聯(lián)系  

發(fā)布:2007-03-25 13:28    編輯:泛普軟件 · xiaona    [打印此頁(yè)]    [關(guān)閉]
相關(guān)文章:
石家莊OA系統(tǒng)
聯(lián)系方式

成都公司:成都市成華區(qū)建設(shè)南路160號(hào)1層9號(hào)

重慶公司:重慶市江北區(qū)紅旗河溝華創(chuàng)商務(wù)大廈18樓

咨詢:400-8352-114

加微信,免費(fèi)獲取試用系統(tǒng)

QQ在線咨詢