Delphi 连接 Java和.Net WebService 整理

Delphi对接WebService大致分两种, 详细如下:

第一种(这种比较常见):

      方便看效果, 本地写了一个基于Axis2的WebService(这个就不描述了), 使用Delphi导入wsdl,Delphi代码如下(注释部分都删掉了):


unit CalcuteStringService;

interface

uses InvokeRegistry, SOAPHTTPClient, Types, XSBuiltIns;

const
  IS_OPTN = $0001;
  IS_NLBL = $0004;
  IS_REF  = $0080;

type
  CalcuteStringServicePortType = interface(IInvokable)
  ['{4AAF990C-CA65-8B5F-D3DF-3719C6BB14C0}']
    function  plus2String(const x: Single; const y: Single): string; stdcall;
    function  multiply2String(const x: Single; const y: Single): string; stdcall;
    function  divide2String(const x: Single; const y: Single): string; stdcall;
    function  minus2String(const x: Single; const y: Single): string; stdcall;
  end;

function GetCalcuteStringServicePortType(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): CalcuteStringServicePortType;


implementation
  uses SysUtils;

function GetCalcuteStringServicePortType(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): CalcuteStringServicePortType;
const
  defWSDL = 'C:\Users\cwx\Desktop\DelphiXE\CalcuteStringService.wsdl';
  defURL  = 'http://localhost:8080/axis2/services/CalcuteStringService.CalcuteStringServiceHttpSoap11Endpoint/';
  defSvc  = 'CalcuteStringService';
  defPrt  = 'CalcuteStringServiceHttpSoap11Endpoint';
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;
  RIO.HTTPWebNode.UseUTF8InHeader := True;
  try
    Result := (RIO as CalcuteStringServicePortType);
    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
  { CalcuteStringServicePortType }
  InvRegistry.RegisterInterface(TypeInfo(CalcuteStringServicePortType), 'http://svr.cwx.com', 'UTF-8');
  InvRegistry.RegisterDefaultSOAPAction(TypeInfo(CalcuteStringServicePortType), 'urn:%operationName%');
  InvRegistry.RegisterInvokeOptions(TypeInfo(CalcuteStringServicePortType), ioDocument);

end.

      常见的调用方式如下:

procedure TfrmMain.Button5Click(Sender: TObject);
var
  fResult: string;
  obj: CalcuteStringServicePortType;
begin
  obj:= GetCalcuteStringServicePortType;
  fResult:= obj.plus2String(1, 3);
  ShowMessage(Format('%s', [fResult]));
end;

      也可以界面丢一个THTTPRIO控件, name为"HTTPRIO1"

      将CalcuteStringService.pas单元的defURL值拷贝到HTTPRIO1的属性URL中,调用如下:

procedure TfrmMain.Button8Click(Sender: TObject);
begin
  ShowMessage(Format('%s', [(HTTPRIO1 as CalcuteStringServicePortType).minus2String(10, 3)]));
end;

第二种(这种比较少见):

      这种情况是,接口的传进去的参数和返回来的参数都分别揉合成一团, 以下展示部分代码:

      首先是接口doc文档提供了如下两个方法:

      public string SignIn(out nStaNum,out nThirdType,out nSecret1,out sSecret2);

      public string Payment(string sIDNo, int nIDType, int nStaNum, int nOptNum, int nDealerNum,

            int nEWalletNum, int nMonDeal,out uint nStaSID);

      使用Delphi导入后,和之前描述的第一种有很大不同, 且单元开头有很多的class和TRemotable,以下为部分代码:

unit ThirdWebservice;

interface

uses InvokeRegistry, SOAPHTTPClient, Types, XSBuiltIns;

const
  IS_OPTN = $0001;
  IS_REF  = $0080;

type
  ...
  SecurityHeader       = class;
  SecurityHeader2      = class;
  SignIn               = class;
  SignInResponse       = class;
  Payment              = class;
  PaymentResponse      = class;
  ...

  SecurityHeader = class(TSOAPHeader)
  private
    FThirdType: Integer;
    FSecret1: Integer;
    FSecret2: WideString;
    FSecret2_Specified: boolean;
    procedure SetSecret2(Index: Integer; const AWideString: WideString);
    function  Secret2_Specified(Index: Integer): boolean;
  published
    property ThirdType: Integer     read FThirdType write FThirdType;
    property Secret1:   Integer     read FSecret1 write FSecret1;
    property Secret2:   WideString  Index (IS_OPTN) read FSecret2 write SetSecret2 stored Secret2_Specified;
  end;

  SecurityHeader2 = class(SecurityHeader)
  private
  published
  end;

  SignIn = class(TRemotable)
  private
  public
    constructor Create; override;
  published
  end;

  SignInResponse = class(TRemotable)
  private
    FSignInResult: WideString;
    FSignInResult_Specified: boolean;
    Fstanum: Integer;
    FThirdType: Integer;
    FSecret1: Integer;
    FSecret2: WideString;
    FSecret2_Specified: boolean;
    procedure SetSignInResult(Index: Integer; const AWideString: WideString);
    function  SignInResult_Specified(Index: Integer): boolean;
    procedure SetSecret2(Index: Integer; const AWideString: WideString);
    function  Secret2_Specified(Index: Integer): boolean;
  public
    constructor Create; override;
  published
    property SignInResult: WideString  Index (IS_OPTN) read FSignInResult write SetSignInResult stored SignInResult_Specified;
    property stanum:       Integer     read Fstanum write Fstanum;
    property ThirdType:    Integer     read FThirdType write FThirdType;
    property Secret1:      Integer     read FSecret1 write FSecret1;
    property Secret2:      WideString  Index (IS_OPTN) read FSecret2 write SetSecret2 stored Secret2_Specified;
  end;

  Payment = class(TRemotable)
  private
    FsIDNo: WideString;
    FsIDNo_Specified: boolean;
    FnIDType: Integer;
    FnStaNum: Integer;
    FnOptNum: Integer;
    FnDealerNum: Integer;
    FnEWalletNum: Integer;
    FnMonDeal: Integer;
    procedure SetsIDNo(Index: Integer; const AWideString: WideString);
    function  sIDNo_Specified(Index: Integer): boolean;
  public
    constructor Create; override;
  published
    property sIDNo:       WideString  Index (IS_OPTN) read FsIDNo write SetsIDNo stored sIDNo_Specified;
    property nIDType:     Integer     read FnIDType write FnIDType;
    property nStaNum:     Integer     read FnStaNum write FnStaNum;
    property nOptNum:     Integer     read FnOptNum write FnOptNum;
    property nDealerNum:  Integer     read FnDealerNum write FnDealerNum;
    property nEWalletNum: Integer     read FnEWalletNum write FnEWalletNum;
    property nMonDeal:    Integer     read FnMonDeal write FnMonDeal;
  end;

  PaymentResponse = class(TRemotable)
  private
    FPaymentResult: WideString;
    FPaymentResult_Specified: boolean;
    FnStaSID: Cardinal;
    procedure SetPaymentResult(Index: Integer; const AWideString: WideString);
    function  PaymentResult_Specified(Index: Integer): boolean;
  public
    constructor Create; override;
  published
    property PaymentResult: WideString  Index (IS_OPTN) read FPaymentResult write SetPaymentResult stored PaymentResult_Specified;
    property nStaSID:       Cardinal    read FnStaSID write FnStaSID;
  end;

  ...

  ThirdWebserviceSoap = interface(IInvokable)
  ['{B1E30F59-F39F-B343-44CD-83FFFF665CFA}']
   
        ...
    // Cannot unwrap: 
    //     - More than one strictly out element was found
    // Headers: SecurityHeader:pIn
    function  SignIn(const parameters: SignIn): SignInResponse; stdcall;

    // Cannot unwrap: 
    //     - More than one strictly out element was found
    // Headers: SecurityHeader:pIn
    function  Payment(const parameters: Payment): PaymentResponse; stdcall;
    ...

  end;

function GetThirdWebserviceSoap(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): ThirdWebserviceSoap;


implementation
uses SysUtils;

...
省略
...

initialization
  ...
  InvRegistry.RegisterInvokeOptions(TypeInfo(ThirdWebserviceSoap), ioDocument);
  ...
end.

    可以看到SignIn方法和Payment方法的参数都成了一个类,而且返回也成了一个类,那么调用的时候,和之前的有所不同.

    方法名和参数名的类定义重名,需要注意

    SignIn方法的参数parameters是类SignIn类的实例,Sign方法返回的是对象SignInResponse,可以从上面看出这个对象包含了哪些 参数。从接口文档看出,虽然SignIn的参数都是out,那么在调用的时候,SignIn参数类还是要Create一下。调用方式如下:

var
  client: ThirdWebserviceSoap;
  outParams: SignInResponse;
  inParams: SignIn;
begin
  inParams:= SignIn.Create;        //传进去的参数集
  client:= GetThirdWebserviceSoap;
  try
    outParams:= client.SignIn(inParams);  //传出来的参数集
    if outParams<> nil then
    begin
      edt_nstanum.Text:= Format('%d', [outParams.stanum]);
      edt_nThirdType.Text:= Format('%d', [outParams.ThirdType]);
      edt_nSecret1.Text:= Format('%d', [outParams.Secret1]);
      edt_sSecret2.Text:= Format('%s', [outParams.Secret2]);
      Memo1.Lines.Add('Over!');
//      ShowMessage(Format('%s %d %d %d %s', [outParams.SignInResult, outParams.stanum, outParams.ThirdType, outParams.Secret1, outParams.Secret2]));
    end;
  finally
    client:= nil;
    FreeAndNil(inParams);
  end;
end;

      Payment方法有in进去的参数,又有out回来的参数,调用和上面一样,稍微增加了一点。调用方式如下:

var
  client: ThirdWebserviceSoap;
  outParams: PaymentResponse;
  inParams: Payment;
begin
  edt_order.Text:= '';
  inParams:= Payment.Create;
  inParams.sIDNo:= '4';            //给传递进去的参数赋值
  inParams.nIDType:= 4;
  inParams.nStaNum:= StrToInt(edt_nstanum.Text);
  inParams.nOptNum:= 1005;
  inParams.nDealerNum:= 1018;
  inParams.nEWalletNum:= 1;
  inParams.nMonDeal:= 1;
  client:= GetThirdWebserviceSoap;
  try
    outParams:= client.Payment(inParams);
    if outParams<> nil then
    begin
      edt_order.Text:= Format('%u', [outParams.nStaSID]);   //取值
    end;
  finally
    client:= nil;
    FreeAndNil(inParams);
  end;
end;

      其实这个Payment方法是需要安全验证的,信息写在安全头SecurityHeader2中, 在wsdl的生成单元的最下面initialization部分可以看到

InvRegistry.RegisterHeaderClass(TypeInfo(ThirdWebserviceSoap), SecurityHeader2, 'SecurityHeader', '...省略了...');

       那么Paymentde调用代码要修改下, 主要是看h, header变量的操作

var
  client: ThirdWebserviceSoap;
  outParams: PaymentResponse;
  inParams: Payment;
  h: SecurityHeader;
  header: ISOAPHeaders;
  code: string;
begin
  edt_order.Text:= '';
  inParams:= Payment.Create;
  h:= SecurityHeader2.Create;   //安全头创建
  try
    code:= Trim(edt_code.Text);
    h.ThirdType:= StrToInt(edt_nThirdType.Text);
    h.Secret1:= StrToInt(edt_nSecret1.Text);
    h.Secret2:= edt_sSecret2.Text;
    inParams.sIDNo:= code;            //给传递进去的参数赋值
    inParams.nIDType:= 4;
    inParams.nStaNum:= StrToInt(edt_nstanum.Text);
    inParams.nOptNum:= 1005;
    inParams.nDealerNum:= 1018;
    inParams.nEWalletNum:= 1;
    inParams.nMonDeal:= 1;
    client:= GetThirdWebserviceSoap;
    header:= (client as ISOAPHeaders);
    header.Send(h);
    outParams:= client.Payment(inParams);
    if outParams<> nil then
    begin
      edt_order.Text:= Format('%u', [outParams.nStaSID]);   //取值
      Memo1.Lines.Add('Payment code: '+ outParams.PaymentResult);
    end;
  finally
    client:= nil;
    FreeAndNil(inParams);
    FreeAndNil(h);
  end;
end;

 

完毕!

      其次整理了下网上的相关知识:

         1. 如果传递的内容存在中文的情况,需要添加 RIO.HTTPWebNode.UseUTF8InHeader := True;

         2. initialization部分 合理使用如下两个

             InvRegistry.RegisterInvokeOptions(TypeInfo(ThirdWebserviceSoap), ioDocument);
             InvRegistry.RegisterInvokeOptions(TypeInfo(ThirdWebserviceSoap), ioLiteral);

 

      再次,Delphi 2007的bin目录下有一个WSDLImp.exe, XE 10.1的bin目录下有WSDLImp.exe和WSDLImp.sym。我单独拷贝出来放在D盘下方便测试。

      除了常见的Delphi->New-> Oher-> WSDL Importer, 还可以通过WSDLIml.exe来导入, 回来WSDLIml.exe所在目录直接生成一个pas文件, 操作如下:

结束!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值