http://www.360doc.com/content/070519/12/10584_508473.html
http://www.cnblogs.com/jin20000/archive/2009/01/08/1371720.html
用
java建立webservice是快捷的,但是用java在製作用戶端的感覺上總是不如
Delphi的(個人感覺,java高手們不要笑話我),那我們就用java實現webservice的服務端程式,delphi製作用戶端。
一.環境搭建
jdk和tomcat的安裝和配置我在這裡不進行行介紹了。說明一點我的tomcat是安裝在D:/tomcat,設定連接埠是8099。
安裝Axis
1.可以從http://ws.apache.org/axis/
下載axis的最新版本,我使用的是axis1.2。
2.解壓縮axis-bin-1_2beta.zip,將axis-1_2beta目錄中webapps下的axis目錄全部拷貝到tomcat的安裝目錄中webapps下。
3.將axis/lib中的所有jar檔案都添加到classpath系統變數中。
注(使用者需根據自己的安裝路徑變更):
.;
d:/tomcat/webapps/axis/WEBINF/lib/axis.jar;
d:/tomcat/webapps/axis/WEB-INF/lib/saaj.jar;
d:/tomcat/webapps/axis/WEB-INF/lib/commons-logging.jar;
d:/tomcat/webapps/axis/WEB-INF/lib/commons-discovery.jar;
d:/tomcat/webapps/axis/WEB-INF/lib/wsdl4j.jar;
d:/tomcat/webapps/axis/WEBINF/lib/jaxrpc.jar;
4.啟動tomcat訪問http://cbf107:8099/axis/index.html
(這裡使用的主機名稱和連接埠號碼和使用的tomcat所配置一致)。
可以見到如下頁面:
二.Web Service服務端開發
寫一個java小程式:
public class Test{
public int add(int p1, int p2) {
return p1 + p2;
}
public int subtract(int p1, int p2) {
return p1 - p2;
}
}
在D:/Tomcat/webapps/axis 目錄下建立一個test檔案夾,將它儲存在裡面,注意:尾碼名改為jws,也就是Test.jws 。
在瀏覽器裡訪問:http://cbf107:8099/axis/test/Test.jws
可以看到
點擊“Click to see the WSDL”出現
將這頁另存新檔xml文檔(我們在使用delphi製作用戶端的時候會使用)
三.delphi實現Web Service用戶端開發
開啟delphi建立工程,在form上放置兩個edit和兩個button,button的name命名為
btnadd和btnsubtract,caption命名為add和subtract。
再file->new->other,選擇webservice裡的WSDL importer
在search UDDI..裡選擇前面我們儲存的那個xml檔案,點擊next最後finish
全部儲存,我們發現delphi的工程中多了test1.pas
開啟發現有這樣一段介面申明:
Test = interface(IInvokable)
['{52882FF0-46E2-6644-A77B-CE714D4CBFD5}']
function add(const p1: Integer; const p2: Integer): Integer; stdcall;
function subtract(const p1: Integer; const p2: Integer): Integer; stdcall;
end;
那我們可以直接調用這個介面了,這時候我們回到介面,從delphi的webservices面版中托放一個soap到form上。
設定屬性
最後我們可以完成我們的代碼了:
1.在uses裡添加test1
因為我們要引用這個單元。
2.添加全域變數t1:test;
(t1是一個test介面)
3.為兩個button添加click事件
procedure TForm1.btnaddClick(Sender: TObject);
var
i,j,z:integer;
begin
i:=strtoint(edit1.Text);
j:=strtoint(edit2.Text);
t1:=(HttPRIO1 as test);
z:=t1.add(i,j);
t1._Release;
showmessage(inttostr(z));
end;
procedure TForm1.btnsubstractClick(Sender: TObject);
var
i,j,z:integer;
begin
i:=strtoint(edit1.Text);
j:=strtoint(edit2.Text);
t1:=(HttPRIO1 as test);
z:=t1.subtract(i,j);
t1._Release;
showmessage(inttostr(z));
end;
4.F9運行程式進行測試
看我們有用delphi實現了java寫的那段程式,不是嗎。
5.也許到這裡你認為應該已經完成了,沒錯!不過對webservice還不夠瞭解的
朋友你再修改一下那個java程式,也就是將Test.jws裡的這個方法
public int add(int p1, int p2) {
return p1 + p2;
}
改為
public int add(int p1, int p2) {
return p1 + p2+10;
}
再運行一下你的用戶端程式看看。
四.註:unit1的所有代碼
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Rio, SOAPHTTPClient,Test1;
type
TForm1 = class(TForm)
HTTPRIO1: THTTPRIO;
Edit1: TEdit;
Edit2: TEdit;
btnadd: TButton;
btnsubstract: TButton;
procedure Edit2KeyPress(Sender: TObject; var Key: Char);
procedure btnaddClick(Sender: TObject);
procedure btnsubstractClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
t1:test;
implementation
{$R *.dfm}
//這裡是為了讓 兩個edit只能輸入數字,edit1的onkeypress直接調用這個就可以了。
procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char);
begin
if key in ['0'..'9']=false then
key:=#0;
end;
procedure TForm1.btnaddClick(Sender: TObject);
var
i,j,z:integer;
begin
i:=strtoint(edit1.Text);
j:=strtoint(edit2.Text);
t1:=(HttPRIO1 as test);
z:=t1.add(i,j);
t1._Release;
showmessage(inttostr(z));
end;
procedure TForm1.btnsubstractClick(Sender: TObject);
var
i,j,z:integer;
begin
i:=strtoint(edit1.Text);
j:=strtoint(edit2.Text);
t1:=(HttPRIO1 as test);
z:=t1.subtract(i,j);
t1._Release;
showmessage(inttostr(z));
end;
end.
對WebService的使用和調試做一下記錄。備忘。
因使用JB2005+AXIS 發布WebService,總有一些奇奇怪怪的問題,故使用JB9。
(一)使用 JB9+AXIS 發布 WebService 服務
1.建立Project--Project,建立Web--Web Application;
2.建立Web Service--Web Services Configuration;
3.WebApp選擇剛建立的Web Application的名字,其他預設;
4.建立WebService服務端的類(test.java)。
-----------------------------
public class test {
private static int a;
private static int b;
public test() {
}
public void setA(int x) {
this.a=x;
}
public void setB(int y) {
this.b=y;
}
public int getSum() {
int c=a+b;
//System.out.println("a:"+a);
//System.out.println("b:"+b);
//System.out.println("c:"+c);
return c;
}
}
-----------------------------
5.發布 WebService 服務
(1)右擊要發布的類,選擇“Export as a Web Service”;
(2)如果勾選了“Generate client stub”,則發布後同時產生用戶端的類及介面測試類別。可以不勾擇此項;
(3)“Deploy scope”中可以選擇該項為“Session”,其他預設;
(4)“Selection mode”中選擇“Allow selected methods”,然後在“Methods in”中選中類要發布的介面方法。可多選。
(5)其他預設,點擊“Finish”完成發布後,自動產生WSDL(Web Service Description Language)檔案。
6.注意
類的屬性使用了private static修飾符。如“private static int a”。
類的方法不能使用static修飾符,如“public int getSum()”,因為靜態類方法是不能發布為WebService介面的。
(二)使用 Delphi7 編寫 WebService 的用戶端
1.建立Project & Application;
2.New-Other-WebService-WSDL Importer,選擇WebService服務的WSDL描述檔案,也可選擇WSDL檔案的URL;
3.單擊“Finish”按鈕,產生WSDL檔案對應*.pas單元檔案;
其內容大致如下:
------------------------------------------------------
test = interface(IInvokable)
['{787CE852-EF00-40BA-5802-9BF9DFBF79F0}']
procedure setA(const a: Integer); stdcall;
procedure setB(const b: Integer); stdcall;
function getSum: Integer; stdcall;
end;
function Gettest(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): test;
implementation
function Gettest(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): test;
const
defWSDL = 'http://127.0.0.1:8088/test/services/test?wsdl';
defURL = 'http://127.0.0.1:8088/test/services/test';
defSvc = 'testService';
defPrt = 'test';
var
RIO: THTTPRIO;
begin
Result := nil;
if (Addr = '') then
begin
if UseWSDL then
Addr := defWSDL
else
Addr := defURL;
end;
if HTTPRIO = nil then
RIO := THTTPRIO.Create(nil)
else
RIO := HTTPRIO;
try
Result := (RIO as test);
if UseWSDL then
begin
RIO.WSDLLocation := Addr;
RIO.Service := defSvc;
RIO.Port := defPrt;
end else
RIO.URL := Addr;
finally
if (Result = nil) and (HTTPRIO = nil) then
RIO.Free;
end;
end;
initialization
InvRegistry.RegisterInterface(TypeInfo(test), 'http://127.0.0.1:8088/test/services/test', 'UTF-8');
InvRegistry.RegisterDefaultSOAPAction(TypeInfo(test), '');
end.
------------------------------------------------------
4.建議:儲存由WSDL檔案產生的*.pas單元檔案時要重新命名(webtest.pas),最好不使用預設名字;
5.Delphi7編寫的WebService用戶端調用代碼:
-----------------------------
uses webtest;
var atest: test; //test類
sum:Integer;
begin
atest:=Gettest(); //要uses wsdl對應*.pas單元檔案。
atest.setA(1);
atest.setB(2);
sum:=atest.getSum();
ShowMessage(IntToStr(sum));
end;
-----------------------------
6.注意
如果服務端類的屬性沒有加static描述,則Delphi7編寫的用戶端使用setA()、setB()後再getSum()時不能得到正確的結果。
因為WebService是不需連線的,每次使用類方法時均得到一個新的對象應用,setA()、setB()後再getSum()操作不是針對同一個對象的。
但加上static後,所有的對象共同使用類的同一個值。如此即可。
另外,如果在JB9+AXIS發布WebService時,“Deploy scope”中選擇的是“Session”,而不是預設的“Request”,
在服務端類的屬性即使不使用static約束,在Delphi的用戶端使用setA()、setB()後再getSum(),也是可以得到正確的傳回值。
神奇。^_^
7.建議
本例只做測試和解決問題。如果要給WebService服務端傳遞資料,最好在介面方法中使用參數。
如修改為getSum(int x,int y)後再發布介面,這個即可使用一個介面方法就可以完成操作,而不必先使用set方法傳遞參數資料。
(三)使用JB9編寫 WebService 的用戶端
1.建立Project--Project;
2.建立Web Service--Import a Web Service;
3.在WSDL URL中選擇wsdl檔案的URL,也可選擇WebService服務的WSDL描述檔案;
4.因為是建立WebService的用戶端,所以“Generate server-side classes”選擇可以不勾選;
5.在“Package options”中可以修改“Name”為合適的名字;
6.其餘選擇預設值,單擊“Finish”產生用戶端的jajva類檔案。一般是6個檔案,有其自己的命名規則。可參看JB。
7.JB9編寫的WebService用戶端測試類別
-----------------------------
public class client {
public client() {
}
public static void main(String[] args) {
try {
TestService service = new TestServiceLocator();
Test aClient = service.gettest();
aClient.setA(1);
aClient.setB(2);
int sum = aClient.getSum();
System.out.println("Sum is:"+sum);
}
catch (Exception e) {
System.err.println("Execution failed. Exception: " + e);
}
}
-----------------------------
8.注意
如果服務端類的屬性沒有加static描述,則JB編寫的用戶端使用setA()、setB()後再getSum()時亦不能得到正確的結果。
建議使用帶參數的介面方法來傳遞參數資料。避免使用set方法。
(四)使用Delphi7調用C#編寫的WebService服務
Delphi7編寫的用戶端調用C#編寫的WebService服務時,如果函數中傳遞的參數為漢字時,可能出現亂碼現象。
在網上搜尋了一些資料,找到解決辦法:將HTTPRIO的UseUTF8InHeader屬性改為true即可。
即編輯由WSDL檔案產生的*.pas單元檔案,在Get函數中增加一句:RIO.HTTPWebNode.UseUTF8InHeader:=True。
代碼片斷大致如下:
------------------
try
RIO.HTTPWebNode.UseUTF8InHeader:=True; //添加一句,修改編碼方案。
Result := (RIO as test);
if UseWSDL then
begin
RIO.WSDLLocation := Addr;
RIO.Service := defSvc;
RIO.Port := defPrt;
end else
RIO.URL := Addr;
finally
if (Result = nil) and (HTTPRIO = nil) then
RIO.Free;
end;
----------------