您的位置:首页 > 其它

继续更新学习进度

2016-03-07 22:16 288 查看
为了不让过去走的弯路白走,所以自己一定要记录下这一路的“风景”。在之前我们实现了Delphi调用EJB,但是我们一直用的都是Delphi自己给我们生成的WSDL Importer,在接口文件中有根据wsdl分析得出的EJB方法,接下来问题就来了,如果我们每一次发布一个EJB工程,就需要每一次都Import一下,这样一来就十分不方便,所以为了改进,我们将所有EJB的方法都放在一个方法中,这个方法有两个参数,第一个参数代表第几个方法,也可以是方法名字,第二个参数是方法要传递到参数。这样做的好处有两点:1、我们可以不用改接口文件,同样在wsdl中就只有一个方法,比起有一大堆方法,这样加载起来更加迅速2、当别人通过浏览器看wsdl时也不知道我们写了什么方法,防止有人闲的无聊对服务器进行捣乱。。。然而对于第二个参数的传递我们有了实现好的约定,用字符串来传递并且用特定的分隔符将传进去的参数分隔开,在EJB中进行判断,然后将相应的参数存到相应的变量中,所以说这样一来对于参数的顺序有都变得随意,稍微简化了客户端的操作,当然函数返回的参数值是String类型。

接下来让我们来看下Importer生成的单元中系统给的代码。我的EJB中有两个方法DBConnection和UpdateInfo

<textarea readonly="readonly" name="code" class="Delphi">
unit DBConnection1;

interface

uses Soap.InvokeRegistry, Soap.SOAPHTTPClient, System.Types, Soap.XSBuiltIns;

const
IS_OPTN = $0001;
IS_UNQL = $0008;

type
//系统自动生成代码。。。

DBConnection = interface(IInvokable)
['{7846D3B7-919A-4FF5-4D9A-446678551BF4}']//GUID,128位数字通过算法结合网卡MAC地址和电脑自带的时钟把数字转化成左边的一串东东
function  GetDataSet(const arg0: string): string; stdcall;
procedure UpdateInfo(const arg0: string); stdcall;
end;

function GetDBConnection(UseWSDL: Boolean=System.False; Addr: string=''; HTTPRIO: THTTPRIO = nil): DBConnection;
//这是系统给我们的用于接口实例化的函数,我们可以传URL或者是WSDL

implementation
uses System.SysUtils;

function GetDBConnection(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): DBConnection;
const
defWSDL = 'http://localhost:8080/GetData/DBConnection?wsdl';
defURL  = 'http://localhost:8080/GetData/DBConnection';
defSvc  = 'DBConnectionService';
defPrt  = 'DBConnectionPort';
var
RIO: THTTPRIO;
begin
Result := nil;//因为我们在用WSDLImport的时候给了wsdl所以当我们再次接口实例化的时候如果传的部分参数是空,程序就会用一开始给的wsdl
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 DBConnection);
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
{ DBConnection }
InvRegistry.RegisterInterface(TypeInfo(DBConnection), 'http://getdata/', 'UTF-8');//其中<span style="font-family: Arial, Helvetica, sans-serif;">http://getdata/是我们EJB工程的目录,包的名字,为了我们每个人编写的方法可以一起用,多以我们把EJB的工程和包的名字作了约定,这样我们需要调用别人的方法时,只需要在接口实例化的时候把他的IP传过去就好了(因为EJB中的方法也约定好的就一个并且名字也一样)</span>

InvRegistry.RegisterDefaultSOAPAction(TypeInfo(DBConnection), '');
InvRegistry.RegisterInvokeOptions(TypeInfo(DBConnection), ioDocument);//其中ioDocument是由我们EJB代码决定的,@SOAPBinding(use = SOAPBinding.Use.LITERAL,style = SOAPBinding.Style.DOCUMENT)我选择的是DOCUMENT
{ DBConnection.GetDataSet }
InvRegistry.RegisterMethodInfo(TypeInfo(DBConnection), 'GetDataSet', '',
'[ReturnName="return"]', IS_OPTN or IS_UNQL);//在类加工厂注册函数和方法、这样才能实例化接口对象
InvRegistry.RegisterParamInfo(TypeInfo(DBConnection), 'GetDataSet', 'arg0', '',
'', IS_UNQL);
InvRegistry.RegisterParamInfo(TypeInfo(DBConnection), 'GetDataSet', 'return', '',
'', IS_UNQL);
{ DBConnection.UpdateInfo }
InvRegistry.RegisterParamInfo(TypeInfo(DBConnection), 'UpdateInfo', 'arg0', '',
'', IS_UNQL);

end.
</textarea>


Ps.在这里补充下关于GUID的相关小知识,因为GUID的使用有IID(接口标识),CLSID(class标识),而本质都是GUID,用于区分不同人编写的东西。

对于JBOSS我们也有了一些新的发现,在SessionBean开始我们写的import带入包,实际上只是在编译的时候可以不出语法错误,而真正的包引入还是依赖于JBOSS的模块。我们发现,当在开头写了import org.apache.xerces.impl.dv.util.Base64;但是在启动JBOSS时还是会报错说找不到类,而后我们在META-INF的MANIFEST中添加了依赖关系Dependencies: org.jdom,org.apache.xerces,JBOSS便不再报错。对此我们猜测在开始时部署了相应的jar包并没有真正的加载进来,也许JBOSS为了提高效率,采用动态加载模块,另外,我们这个Dependencies后跟的是module.xml的模块名字,加入我们把JBOSS的org.apache中文件夹xerces改成tom,把module.xml中模块名字也改成tom,我们还是能找到jar包,因为一个模块对应着一个jar包,而import后的关系是类关系,模块部署的名字是和它不同,只是平常我们建文件夹时的层次和名字和引入类的关系一致。

最后要总结下最近关于向数据库中存图片的过程,首先在本地加载图片,得到图的流(流相当于二进制字节数组+对数组的一些操作),而后对流按照Base64码制进行编码,之后再对生成的字符串进行压缩,压缩之后再次变成二进制,接着Base64编码,然后作为参数传过去就好了,在EJB方法中反着来一遍就好了,因为WebService只认可见字符,转换成Base64码制是必须的。另外关于BLOB类型的插入也需要先一条空的而后在Update。具体方法来自以下http://ligaosong.iteye.com/blog/1072719

FINAL---->老师说要把编程看成乐趣,自己大一并没有做到,现在是时候动手敲写代码啦!2016年3月7日差4分钟第二天
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: