三层架构delphi+Java+Oracle模式的实现

本文介绍了一种基于Delphi客户端与Java服务端的跨平台通信架构,使用Oracle数据库作为后端。该架构利用TclientDataSet进行数据交互,通过TCP/IP协议与Indy通信套件实现高效的数据交换。文章深入探讨了TclientDataSet的数据包格式和Delta属性的应用,以及如何处理Oracle数据库中的大对象字段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【架构简介】
*本架构以delphi作为客户端,Java作为服务端,oracle作为后台数据库数据。其中delphi客户端的封装为了保持与原来的开发方式兼容都是基于TclientDataSet实现的;

*本架构选择基于阻塞模式的Indy通信套件作为通信工具;以tcp/ip作为通信协议 ,直接以流的的形式与Java服务端进行交互;

*本架构的通信过程如下:
 请求开始->打包压缩请求数据->发送请求数据->delphi端阻塞等待->Java端多线程响应请求->解压解包请求数据->处理请求->打包压缩处理结果->发送处理结果->
 delphi端停止阻塞接收处理结果->解压解包处理结果->显示结果
 
*本架构主要解决以下问题:
1.如何将Java从数据库中读出来的数据打包成TClientDataSet可以读取的数据包;要解决这个问题就需要深入了解TclientDataSet的DataPackage的xml格式。
2.如何将新增-修改-删除后的TClientDataSet数据通过Java保存到数据库中;要解决这个问题就需要深入了解TclientDataSet的Delta属性。
3.如何处理Oracle的大对象字段类型(clob或blob)。
4.delphi端如何调用Java端定义的对应的业务逻辑供。
5.Java端多用户并发处理效率问题。
6.数据包的格式定义‘打包解包‘压缩解压’加密解密问题。

1.【TclientDataSet的DataPackage格式】
TclientDataSet的DataPackage格式一般如下:
<?xml version="1.0" standalone="yes" ?>
- <DATAPACKET Version="2.0">
- <METADATA>
- <FIELDS>
  <FIELD attrname="PORT_ID" fieldtype="fixed" WIDTH="12" />
  <FIELD attrname="OP_STATE" fieldtype="fixed" DECIMALS="1" WIDTH="38" />
  <FIELD attrname="B_POL" fieldtype="fixed" WIDTH="38" />
  <FIELD attrname="PORT_CUSTOMS_CODE" fieldtype="r8" />
  <FIELD attrname="B_DEL" fieldtype="fixed" WIDTH="38" />
  <FIELD attrname="B_SEA_PORT" fieldtype="r8" />
  <FIELD attrname="PORT_AIRCODE" fieldtype="string" SUBTYPE="FixedChar" WIDTH="1" />
  <FIELD attrname="PORT_SEACODE" fieldtype="string" SUBTYPE="FixedChar" WIDTH="2" />
  <FIELD attrname="CREATE_DATE" fieldtype="dateTime" />
  <FIELD attrname="B_BASIC" fieldtype="string" WIDTH="55" />
  <FIELD attrname="EDI_CODE3" fieldtype="fixed" WIDTH="38" />
  <FIELD attrname="B_LOCAL" fieldtype="fixed" DECIMALS="2" WIDTH="10" />
  </FIELDS>
  <PARAMS />
  </METADATA>
- <ROWDATA>
  <ROW PORT_ID="10" OP_STATE="20.0" B_POL="3" />
  <ROW PORT_ID="1" OP_STATE="2.0" B_POL="3" />
  </ROWDATA>
  </DATAPACKET>
 
2.【DataPackage的结构分析】
整个XML定义了一个DataPacket;DataPacket包括两个部分:MetaData和RowData。MetaData包括Fields和Params,即包括数据字段定义和数据集参数。
RowData为具体记录。 下面详细分析数据字段定义的方法。
Field节点的定义主要包括:
1>attrname指FieldName
2>fieldtype指字段类型
3>width指需要宽度的字段类型的宽度或数字的有效位数;
4>decimals指小数点右边的位数;

Oracle主要字段类型具体的对应信息如下表:
_____________________________________________________________________
OracleType | fieldtype   | WIDHT | SUBTYPE      | DECIMALS | READONLY
---------------------------------------------------------------------
Char              | string       |     1            FixedChar  
---------------------------------------------------------------------
Char(n)         | string       |     n            FixedChar  
---------------------------------------------------------------------
Varchar(n)    | string       |      n   
---------------------------------------------------------------------
Varchar2(n)  | string       |      n   
---------------------------------------------------------------------     
data              | dateTime |   
---------------------------------------------------------------------     
Number(s,p) | fixed        |      s                                       p 
---------------------------------------------------------------------
Number(*,p) | fixed       |      38                                     p 
----------------------------------------------------------------------
Number(s)    | fixed       |        s   
----------------------------------------------------------------------
Number        | fixed       |        38   
----------------------------------------------------------------------
int                | fixed        |       38   
----------------------------------------------------------------------
Smallint       | fixed        |        38   
----------------------------------------------------------------------
Dec(s,p)      | fixed        |         s                                     p 
----------------------------------------------------------------------
Float            | R8           |
----------------------------------------------------------------------
Real             | R8           |
----------------------------------------------------------------------   
其中用SubType属性来帮助决定类型。表中没有值的单元格,表示该属性没有用到。
并且DataPakage中如果想包含中文的话,记得要在第一句的中间加上encoding=”GB2312”,否则用数据库相关控件读出来的只会是乱码。
记住位置很重要的。你必须写成下面的形式:
<?xml version="1.0" encoding="GB2312" standalone="yes"?>
如果写成下面的也是不满足形式良好的规范的:
<?xml version="1.0" standalone="yes" encoding="GB2312"?>

3.【XML的转义字符】
在XML语言中,用实体对特殊字符进行转义.
如果在XML文档中使用类似"<" 的字符, 那么解析器将会出现错误,因为解析器会认为这是一个新元素的开始。
所以不应该像下面那样书写代码:
<message>if salary < 1000 then</message>
为了避免出现这种情况,必须将字符"<" 转换成实体,像下面这样:
<message>if salary &lt; 1000 then</message>

下面是五个在XML文档中预定义好的实体:
---------------------
 &lt;  | < | 小于号
---------------------
 &gt;  | > | 大于号
---------------------
&amp;  | & | 和
---------------------
&apos; | ' | 单引号
---------------------
&quot; | " | 双引号
---------------------

实体必须以符号"&"开头,以符号";"结尾。
注意: 只有"<"字符和"&"字符对于XML来说是严格禁止使用的。剩下的都是合法的,为了减少出错,使用实体是一个好习惯。

4.【Oracle的大对象字段类型(clob和blob)】
因为TclientDataSet不支持clob和blob等大对象字段类型,所以我们要使用别的方法来实现相应的读写操作;

5.【关于TClientDataSet的Delta属性】
TClientDataSet.Delta属性表示当前操作的ClientDataSet中记录变化的信息
Delta信息可以用另外的ClientDataSet来显示;如myCDS.Data := OrgCDS.Delta
TclientDataSe的UpdateStatus属性反映当前记录的更新状态; 根据更新数据的情况其可能的值分别为:
1.新增一条记录时,在Delta中会有一条记录,标记为usInserted;
2.修改记录时,在Delta中对于同一条记录会产生且仅产生两条记录:第一条为原始记录,标记为usUnmodified,第二条只有修改过的字段才有值,标记为usModified
3.刪除记录时,在Delta中会产生一条记录,标记为usDeleted;
根据以上Delta属性就可以生成相应的更新SQL语句;

6.【数据包的格式定义】
6.1.数据包采用变长字符串的方式组织,一般由数据节点和分隔符及结束符组成。具体结构如下图:

|  数据节点  |分隔符 |  数据节点  |分隔符 |  数据节点  |分隔符 | ... |结束符 |

6.2.数据节点一般由数据长度和数据值组成。

6.3.当数据值的长度小于等于999时数据节点的组成如下图:

|数据长度 |  数据值  |分隔符 |数据长度 |  数据值    |分隔符 | ... |结束符 |

6.4.当数据值的长度大于999时数据节点的组成如下图:

|003  |数据长度的长度 |  /   |数据长度 |  数据值    |分隔符 | ... |结束符 |
 
6.5数据包格式定义说明:
#数据长度为数据值长度的长度字符串;
#数据长度的长度为数据值长度的长度字符串的长度字符串;
#分隔符一般为冒号;当数据值的长度大于999时分隔符为"/";


7.【JAVA应用服务器】
应用服务器最重要的就是稳定,支持高效的多用户并发处理;所以应用服务器应该是无状态的;然后是易于部署的;
java天生就是用来编写服务器的;成熟的j2ee企业级应用;丰富的开源思想;于是java就成了实现应用服务器的不二选择;
JAVA应用服务器具体实现以下功能:
1>使用一个ServerSocket监听Delphi客户端发送请求的命令;
2>针对每个Delphi客户端发送的请求开启线程解析处理请求;通过JAVA端的多线程来达到高效处理多用户并发的情况。
3>通过反射和command设计模式来分派Delphi端请求的相应的业务逻辑对象进行处理;
3>通过JDBC与Oracle数据库交互;
其实只要数据到了java端,那么只要你愿意你可以选择任意的中间件技术:weblogic,websphere,jboss等等作为应用服务器,
而尽想其提供的丰富的管理功能;

8.【接口规划】
*************************************************************************************************************************
函数功能: 发送操作命令和数据到应用服务器
函数声明: function StreamCommand(ASendText:WideString;ASendStream:TStream=nil):TStream;stdcall;external Communication;
参数说明: -------------------------------------------------------
           参数名称                      描述                            
           -------------------------------------------------------
           ASendText       要发送的字节数据(一般应包括命令信息)        
           -------------------------------------------------------
           ASendStream     要发送的内存流或文件流等数据(默认为nil)
           -------------------------------------------------------
函数说明:正常返回字节流数据(可能返回空串);异常返回nil;此函数一般供DLL中的接口函数调用;
用例:Result:=StreamCommand('013SelectCommand:045SELECT * FROM CRM_CUSTOMER WHERE B_COMPANY=1 :');
       这个语句的意思是发送一个查询命令到AppServer,命令的内容为SELECT * FROM CRM_CUSTOMER WHERE B_COMPANY=1;
       如果命令能正确执行,那么AppServer会把查询的结果打包发送到客户端,以字节流的形式返回.
 
**************************************************************************************************************************
函数功能: 查询单个数据集
函数声明: function SelectCommand(ACDS: TClientDataSet;const ASelectText: string):Boolean;stdcall;external Communication;
参数说明: -------------------------------------------------------
           参数名称                      描述                            
           -------------------------------------------------------
            ACDS           存放查询结果集的TClientDataSet        
           -------------------------------------------------------
           ASelectText     要发送的单条查询语句
           -------------------------------------------------------
函数说明: 成功返回[true](包括只有数据元的空数据集);失败返回[false]
 
用例: Result:=SelectCommand(cdsTemp,'SELECT * FROM CRM_CUSTOMER');这个语句的意思是:
       发送一个查询语句到AppServer,如果命令能正确执行,那么AppServer会把查询的结果集打包发送到客户端事先创建好的cdsTemp中.
      
*************************************************************************************************************************************
函数功能:同时查询多个数据集
函数声明:function SelectCommands(ACDS:Array of TClientDataSet;const ASelectText: TStringList):Boolean;stdcall;external Communication;
参数说明:-------------------------------------------------------
           参数名称                      描述                            
           -------------------------------------------------------
            ACDS           存放查询结果集的多个TClientDataSet列表        
           -------------------------------------------------------
           ASelectText     要发送的多条查询语句列表
           -------------------------------------------------------
函数说明:成功返回[true](包括只有数据元的空数据集);失败返回[false]
 
用例:
var
  sSql:string;
  sList:TStringList;
  cdsTemp1,cdsTemp2,cdsTemp3:TClientDataSet;
begin
  try
    cdsTemp1:=TClientDataSet.Create(nil);
    cdsTemp2:=TClientDataSet.Create(nil);
    cdsTemp3:=TClientDataSet.Create(nil);
    sList:=TStringList.Create;

    try
      sSql:='SELECT * FROM Table1';
      sList.Add(sSql);

      sSql:='SELECT * FROM Table2';
      sList.Add(sSql);

      sSql:='SELECT * FROM Table3';
      sList.Add(sSql);

     //把第一条查询语句的结果集存放到cdsTemp1,把第二条查询语句的结果集存放到cdsTemp2,依次类推存放顺序
     SelectCommands([cdsTemp1,cdsTemp2,cdsTemp3],sList);
    finally
      if Assigned(cdsTemp1) then FreeAndNil(cdsTemp1);
      if Assigned(cdsTemp2) then FreeAndNil(cdsTemp2);
      if Assigned(cdsTemp3) then FreeAndNil(cdsTemp3);
      if Assigned(sList) then FreeAndNil(sList);
    end;
   
  except

  end;

end;


**************************************************************************************************************************
函数功能: 发送一条或多条update or insert or delete类型的SQL语句到应用服务器执行
函数声明: function ExecuteCommands(const AExecuteText: TStringList): integer;stdcall;external Communication;
参数说明: -------------------------------------------------------
           参数名称                      描述                            
           -------------------------------------------------------           
           AExecuteText     AppServer能解析的SQL语句
           -------------------------------------------------------
函数说明: 正常返回0;异常返回非0;本函数主要供ApplyUpdates函数调用;
用例:
      
**************************************************************************************************************************
函数功能: 发送一条update or insert or delete类型的SQL语句到应用服务器执行
函数声明: function ExecuteCommand(const ACommandText:WideString):integer; stdcall;external Communication;
参数说明: -------------------------------------------------------
           参数名称                      描述                            
           -------------------------------------------------------           
           ACommandText     要执行的SQL语句
           -------------------------------------------------------
函数说明: 正常返回0;异常返回非0;
用例:


**************************************************************************************************************************
函数功能: 根据数据集列表的修改信息自动生成相应的SQL语句
函数声明: function CreateUpdates(const ATableNames: array of string ;ACDS:array of TClientDataSet;var sSqlList:string): Boolean;stdcall; external Communication;
参数说明: -------------------------------------------------------
           参数名称                      描述                            
           -------------------------------------------------------
            ATableNames     数据集列表对应的表名列表         
           -------------------------------------------------------
            ACDS            修改过的数据集列表         
           -------------------------------------------------------
           sSqlList         存放对应生成的SQL语句
           -------------------------------------------------------
函数说明: 成功返回[true];失败返回[false]
          本函数根据数据集中的修改信息自动生成Insert,Update,Delete类型的多条SQL语句.
 
用例: 1>Result:=CreateStatement(['TableName1','TableName2','TableName3','TableName4'],[cds1,cds2,cds3,cds4]); 或者
      2>Result:=CreateStatement(['TableName1'],[cds1]);                        
                           
       本用例会根据数据集列表中每个数据集的修改信息自动生成相应的SQL语句,这样就完成了操作界面到SQL语句之间的直接映射.
      

 

**************************************************************************************************************************
函数功能: 更新多个数据集
函数声明: function ApplyUpdates(const ATableNames: array of string ; ACDS:array of TClientDataSet): Boolean;stdcall; external Communication;
参数说明: -------------------------------------------------------
           参数名称               描述                            
           -------------------------------------------------------
            ACDS           要更新的数据集列表         
           -------------------------------------------------------
           ATableNames     要更新的表名列表
           -------------------------------------------------------
函数说明: 成功返回[true];失败返回[false]
          表名列表与数据集列表应该一一对应
 
用例: Result:=ApplyUpdates(['TableName1','TableName2','TableName3','TableName4'],
                           [cds1,cds2,cds3,cds4]);
       本用例会根据数据集列表中每个数据集的修改信息自动生成相应SQL语句,然后把所有的SQL语句一起发送到AppServer进行事务处理.


*****************************************************************************************************************
函数功能: 保存Oracle大对象字段类型(clob或blob)
函数声明: function SaveBlob(SqlText:WideString;LobID:WideString;LobContent:TStream):integer;stdcall; external Communication;
参数说明: -------------------------------------------------------
           参数名称               描述                            
           -------------------------------------------------------
            SqlText           保存前要执行的SQL语句         
           -------------------------------------------------------
            LobID             包含Oracle大对象字段类型的记录的ID
           -------------------------------------------------------
            LobContent        要保存的Oracle大对象字段类型的内容
           -------------------------------------------------------
函数说明: 成功返回[0];失败返回[非0]          
用例:

 

*****************************************************************************************************************
函数功能: 显示Oracle大对象字段类型(clob或blob)
函数声明: function SelectBlob(LobID:WideString):TStream;stdcall; external Communication;
参数说明: -------------------------------------------------------
           参数名称               描述                            
           -------------------------------------------------------
            LobID         包含Oracle大对象字段类型的记录的ID
           -------------------------------------------------------
函数说明: 成功返回Oracle大对象字段类型对应的流;失败返回[nil];
用例:

 

9.【扩展功能】
1>客户端数据缓存机制保证运行的高效性:客户端可以缓存大量的客户端数据,并提供了一定程度的离线操作功能;
  这样在提高户交互效率的同时,减少网络数据通讯量;还能降低服务器的负载。
2>客户端自动更新机制:便于客户端的部署和版本更新
3>权限管理:包括功能权限和数据权限;
4>客户端采用模块化(DLL)设计保证系统的可扩展性;
5>运行时自定义报表;
6>JAVA应用服务器可采用数据库连接池来提高访问效率;

MateyFrame是一款由Delphi开发的三层架构框架,经过多年的升级改进,版本由MateyFrame V1.0升级到了当前的MateyFrame V5.0版本。MateyFrame V5.0具有功能强大、负载量大、安全性高、可扩展性强、同时支持B/S与C/S运行模式、开发简单等特性。MateyFrame V5.0由中间层服务端客户端框架、MateyWeb组件三部分组成,同时支持 Oracle、MSSQL、MySQL数据库。 中间层服务端 采用面向对象方法设计而成,具有稳定性强、安全性高、负载量大、可扩展性强等特性。 采用数据库连接池技术,支持多数据库应用及多种数据库的应用,可以很好的处理断网、数据库重新启动等异常情况,一旦外界环境恢复后,连接池将重新连接数据库,不需要重启服务程序。 使用HTTP协议与客户端进行通信,可以适合企业内网及企业外网等任何网络环境,更适合在Internet网络上运行程序。 服务端支持多种类型的大型数据库一起使用,支持的数据库有:Oracle、MSSQL、MySQL。 服务端采用插件技术开发,系统核心插件可以直接使用,另外用户可轻松地扩展自己需要的服务插件。 服务端采用会话管理技术,为每个客户端会话分配唯一的加密密钥,交互数据在底层进行加密传输,保证了数据在传输过程中的高安全性。 服务端支持多实例运行模式,当客户端用户量大增时,可以适当增加中间层实例,解决大并发量的问题。 服务端插件实现了真三层、伪三层的核心插件,用户可以根据安全级别选用任何一种模式进行应用。 服务端使用Win服务运行模式,重启服务器不需登录系统开启服务程序,服务端即可自动运行。 具有客户端程序发布功能,可以为客户端软件的自动更新服务。 客户端框架 客户端设计成 EXE+BPL+DLL 的文件结构模式,具有扩展性强、易于开发、易于维护、使用简单等特点; 程序框架同时支持B/S、C/S模式,即可以通过客户端运行程序,也可以通过浏览器运行程序,并且支持两种模式同时存在。 使用插件开发模式,业务功能根据实际需要封装在不同的模块 DLL 中,即插即用; 封装了强大的基类,底层数据访问、出错处理、权限控制等; 系统功能根据业务模块信息自动生成,可以手动配置功能菜单列表; 框架中包含用户及权限管理插件,拿来即用,此模块可严格控制各功能Form 的详细权限(添加、修改、删除)、特殊数据的读取权限; 框架中包含了数据字典、系统参数的设置功能,拿来即可用。 框架采用调用时下载相关依赖文件的模式进行程序更新,具有更新文件少、更新速度快等特点; 框架支持程序文件流加载模式,更新的程序文件不需要保存在客户端的机器上,可大大增强程序的安全性。 框架有设计模式与运行模式之分,在设计模式客户端通过框架功能用SQL可以直接读取到数据库的数据,方便程序开发;但在运行模式中,此功能不可用,这样可以保证数据的安全性。 框架设计了通用的报表设计模块,用户只需简单调,就可以得到自己所需要的报表模板设计,得到功能所需要的报表。 可选用分页数据处理技术,使大批量数据分页返回,分解服务器的压力; 具有负载平衡的功能,当连接的中间层服务器端负载过大或者崩溃时,会自动转向其它可用中间层服务器。 具有断线重连功能,当网络的异常恢复时,系统底层连接会重新连接,不用重启程序就可使用。 框架提供超级查询组件,组件可以根据编号、名称、五笔码、拼音码对需要查询的数据进行快速过滤。 MateyWeb组件 MateyWeb组件是一款能被IE加载运行的ActiveX控件,它是客户端程序在B/S模式下运行的载体。 MateyWeb组件支持WinXP、Win2000、Win2003、Win7、Vista等操作系统。 MateyWeb组件支持IE及以IE为内核的所有浏览器。 应用场合 非常适合开发各种应用于Internet之上的大中型的MIS管理软件
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值