Delphi和 C# Java实现webservice架构 1,2

来源:互联网 发布:kindle txt转mobi mac 编辑:程序博客网 时间:2024/05/22 00:41

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;

    ----------------

原创粉丝点击