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;
----------------