三层程序一直在讨论,但无论我看哪个三层,都觉得不对劲,唯一对劲的就是 WebService实现的三层。三层程序中,我们有一个数据管理层,这一层大家都交给DBMS了,如Sqlserver,Oracle.一层是业务逻辑,这一层我们要考虑,要编码的。还有一层是表现层。三层应是相互独立的。也就是说,逻辑层不知道下面的表现层是用delphi的win32表现还是Web形式的表现,反正只要符合一定的规则,就可以交流。逻辑层负责逻辑完了,与数据库交流,不管数据是什么系统,他都要能交流得上(比如用标准sql与数据库系统连接)这样一来,逻辑层只好用WebService了。
各位,我理解的三层与大众的理解不一定是一致的,这只是我的想法,欢迎拍砖。Ps,拍完砖顺便告诉我一下一直困扰我的 WebService 执行验证,大家是怎么解决的。。

解决方案 »

  1.   

    本来就是 数据包格式(xml/json/ini/...)+通讯方式(tcp/http/udp/...)的组合
    webservice只是其中的一个组合(xml@http)而已我觉得xml分析起来开销太大,改为ini:
    http://blog.csdn.net/sz_haitao/archive/2009/09/10/4539228.aspx
      

  2.   

    肯定不是了,WebService只是实现方式之一
      

  3.   

    别瞎费劲了,用JAVA写服务器端吧!
    如果用Delphi这破玩意儿写服务器端,线程池、连接池、ORM、SPRING这些都没有(难到不难,还要自己写,自己压力测,够你折腾一段时间的、除非你的项目很简单,不需要考虑以后的维护成本,可以简单地在逻辑层直接写SQL),而且一不小心有个内存泄露,那整个服务器就挂了,别在天真地找到一篇关于Delphi三层的文章就认为你能用它做出很好效果的三层!Delphi开发三层有成功的案例没?有,有多少,不知道!对于答案为"有"的是有前提的,公司必须要有几个牛人历经一年半载的来搭框架,反复测试,在实际上还要不断修改!对于一些动辄就三层三层的贴子,真TMD好笑!
    总之来讲:用JAVA写WEBSERVICE,把功能粒度分合适些(千万别搞得有N个service interface),让D端调用就行了!这样整个系统结构就比较松散了!
    对于1楼朋友总是把ini吹得神乎其神的,INI这个东西解析是不慢,语意表达上是不是要差一些!更重要的是需要把数据传上来,反序列化后,就是业务对象了,您这个是不是还要写helper类啊,可够累的...
    您如何把下面的树型结构用ini表示?<csdn>
      <develop tool>
         <XXX>
            <YYY>
            </YYY>
         </XXX>
      </develop tool>
    </csdn> 
      

  4.   

    谁说delphi写服务端就是要从头做起的?
    delphi写isapi,跑在iis下,网络通讯就完全免掉了
    所以,瞎费劲的关键在于瞎!不知道怎么借助现成、成熟的东西,自然费劲不讨好了至于ini描述树形,根本不是问题,再复杂的都很好办
    <csdn>
      <develop tool>
         <XXX>
            <YYY>
            </YYY>
         </XXX>
      </develop tool>
    </csdn>
    转为ini就是:
    csdn=xxxxxxxx
    csdn.develop tool=xxxxxxx
    csdn.develop tool.xxx=xxxxxxxx
    csdn.develop tool.xxx.yyy=xxxxxxx
    分析起来非常直接快捷!
      

  5.   

    3楼我说错话了,变更一下!
    在服务器端的话,用COM+,可以有COM+提供的对象池、Webservice可提供线程池,更正一下!
      

  6.   

    要不你也用用牛得不可一世的"CBX"
      

  7.   

    http://blog.csdn.net/sz_haitao/archive/2009/09/10/4539228.aspx里讲得很具体了:
    INI格式的思路则是取自Windows应用程序的配置文件xxxxx.ini,它非常简单,既吸收的XML的灵活性,又保持简单、高效。数据记录集即可以用ini表达为:
    [table1]
    ;以“;”开头的行为说明信息,实际不会出现
    FieldCount=5
    ;数据集table1的字段数为5
    ;以下描述了该数据集各字段的属性
    F1.name=id
    F1.type=Int
    F1.size=4
    F2.name=title
    F2.type=String
    F2.size=50
    ……
    F5.name=note
    F5.type=String
    F5.size=200RecordCount=320
    ;数据集table1的记录数为320
    ;以下为该数据集各字段的属性
    1.1=2345
    ;第1条记录的第1个字段的值
    1.2=关于市场业务的通知
    ;第1条记录的第2个字段的值

    1.5=一周内落实
    ;第1条记录的第5个字段的值2.1=2346
    ;第2条记录的第1个字段的值
    2.2=开展促销活动的效益回报
    ;第2条记录的第2个字段的值

    2.5=送各部门负责人
    ;第2条记录的第5个字段的值……
    ……320.1=2701
    ;第320的第1字段的值
    320.2=关于市场业务的通知
    ;第320的第2个字段的值

    320.5=一周内落实
    ;第320的第5字段的值
      

  8.   

    就如上面所说的,只要符合三层定义的标准,就是所谓的三层了,不管使用什么技术,当然WebServiec亦可实现。
      

  9.   

    用webservice还是不错的,不过安全是个问题,别人看一下WSDL就能调你的东西了。不知道有好的解决方法没有
      

  10.   

    不错,sz_haitao的那个架构流程图还没看懂,不过写的还是挺好的
      

  11.   

    WebService的确比较不错,但也有一些确点。
      

  12.   

    to #5请教个问题,你的INI结构如何表述XML中的属性呢?看你的例子,似乎只能设置元素的值。
      

  13.   


    属性和子节点 的确是一样看待的,就像treeview表达xml
    不过,一定要区分,也可以:
    a.b=xxxx 表示a节点的子节点b
    a.#c=xxxx 表示a节点的属性c
      

  14.   

    treeview表达xml,如何区分属性和子节点,的确是一个问题:
    http://blog.csdn.net/sz_haitao/archive/2009/10/30/4748629.aspx
    http://topic.csdn.net/u/20091112/11/6a337128-ec80-49f6-a1fc-bc0497e9f481.html后来专门实现了一个用stringgrid改造得tree-grid的类:
      TTreeGrid=class
      private
        treecol:Integer;
        sg:TStringGrid;
        bLine,bReadOnly:Boolean;
        cbtnbg,cbtnf,cbg, cf:Tcolor;
        //lastRow:Integer;
        function isNode(const s:String):Boolean; overload;
        function isNode(const r:Integer):Boolean; overload;
      public
        function getLevel(const s:String):Integer; overload;
        function getLevel(const r:Integer):Integer; overload;
        function isHided(const r:Integer):Boolean;
        procedure hideNode(const r:Integer;const h:Boolean);
        function Text2Node(const s:String;const l:Integer;const bHasSon:Boolean=false):String;
        function getStat(const s:String):byte; overload; //0: no son; 1: exped; 2: colled;
        function getStat(const r:Integer):byte; overload; //0: no son; 1: exped; 2: colled;
        procedure setStat(const r:Integer;const bExp:Boolean{;const bChg:Boolean=false});
        procedure switchStat(const r:Integer);
        procedure showSon(const r:Integer);    function getParent(const r:Integer):Integer;
        function getSonFirst(const r:Integer):Integer;
        function getBrotherUp(const r:Integer):Integer;
        function getBrotherDown(const r:Integer):Integer;    function GetNodeText(const s:String):String; overload;
        function GetNodeText(const r:Integer):String; overload;
        procedure setNodeText(const r:Integer;const s:String);    function AddNode(const r:Integer;const t:String):Integer;
        function AddSon(const r:Integer;const t:String):Integer;
        function DelNode(const r:Integer):Integer;    procedure DrawTreeNode(ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
        procedure ReDrawNode(r:Integer=-1);    procedure OnDrawCell(Sender: TObject; ACol, ARow: Integer;
          Rect: TRect; State: TGridDrawState);
        procedure OnMouseDown(Sender: TObject; Button: TMouseButton;
          Shift: TShiftState; X, Y: Integer);
        procedure OnSelectCell(Sender: TObject; ACol, ARow: Integer;
          var CanSelect: Boolean);
        procedure OnMouseWheel(Sender: TObject;
          Shift: TShiftState; MousePos: TPoint; var Handled: Boolean;bUp:Boolean);
        procedure OnMouseWheelUp(Sender: TObject;
          Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
        procedure OnMouseWheelDown(Sender: TObject;
          Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);    procedure initStrings;
        procedure LoadTreeFrom(ss:TStrings);
        procedure SaveTreeTo(ss:TStrings);    constructor create; overload;
        constructor create(Asg:Tstringgrid;const Atreecol:Integer;ss:TStrings=nil
          ;const Aline:Boolean=true
          ;const btnbg:Tcolor=clyellow;const btnf:Tcolor=clblue;const bg:Tcolor=clwhite;const f:Tcolor=clBlack); overload;
        procedure init(Asg:Tstringgrid;const Atreecol:Integer;ss:TStrings=nil
          ;const Aline:Boolean=true
          ;const btnbg:Tcolor=clyellow;const btnf:Tcolor=clblue;const bg:Tcolor=clwhite;const f:Tcolor=clBlack);    procedure ExpNode(const r:Integer;const bExp:Boolean;const bSub:Boolean);
      end;
      

  15.   

    JAVA是跨平台的,怎么能不实现什么这池那池的呢?如果把B/S看成一种特殊的C/S,DELPHI很难有个定位。一直看不清今后的DELPHI会如何发展,郁闷!
      

  16.   

    建议sz_haitao参考下xpath的语法,应该能解决你的问题
      

  17.   


    tree-grid里不同节点的属性个数不同 的问题?
    xpath好像是一种以xml为处理源的脚本,与显示方式没什么关系吧?
      

  18.   

    哦,我说的是如何区分INI的节点和属性这个问题上
      

  19.   

    不知道xpath是怎么区分的?xml的写法决定了2者是可以区分的treeview只有节点没有属性,是无法区分,一定要区分,可以通过stateiamgeini也一样,一定要区分,也可以通过:
    a.b=xxx  //a的子节点b
    a.#c=yyy  //a的属性c
    只要约定节点名不能以#开头就行了
    这应该也算是解决了
      

  20.   

    愿意交流下,delphi中三层的实现有四种方式,其中的一种走HTTP,也就是web了。前人具体做法又有:
    1、自己写一个类似tomcat.exe/php.exe的文件来,自己玩一套。
    2、webservice,这个是大家现在一直挂嘴边的。因为它是状态无关的,所以为了通过验证,到哪里都得把口令贴在脑门上。
    3、再不济的,就用ActiveX了。
    真没分了,请酌情多给点。
      

  21.   

    2、状态无关的,也不用 为了通过验证,到哪里都得把口令贴在脑门上

    安全性的实现:由于HTTP协议的上下文无关特性,任何B/W或C/W模式的应用,都离不开如何“以上下文无关的协议实现上下文有关的逻辑”的问题。如:正常的应用流程是“先用户登录,合法用户才可以进行内容访问操作”,而HTTP协议的上下文无关,使得用户登录与内容访问操作不存在必然的关系,即非法用户只要知道了内容访问操作的URL,也可以绕开用户登录而直接进入内容访问操作,这显然是一个很严重的安全漏洞!笨拙的解决办法是:要求内容访问操作也附加用户合法性验证的信息,但是每次操作都附加用户合法性验证的信息,一则数据冗余,二则增加了不安全因素。幸亏B/W模式的应用有了一个巧妙的通用解决措施:通过一次有效的SessionID。服务器维护一个“合法登录用户信息—随机码”的对照表,对于经过用户登录被验证为合法的用户,服务器生成一个随机码(可以是纯数字,也可以是字符串,只要足够长度以致非法用户难以伪造冒认),并将此随机码与该用户信息一起存入“合法登录用户信息—随机码”的对照表,同时将此随机码发给前端(浏览器),以后前端(浏览器)的内容访问操作必须附加这个随机码(而不是原本的用户合法性验证的信息)以供服务器验证,没有随机码或随机码不存在于“合法登录用户信息—随机码”对照表的请求被视为无效请求。“合法登录用户信息—随机码”对照表的内容,在对应用户显式退出或超过指定时间没有操作请求后,自动被服务器删除。这样,即使某个有效的随机码被非法用户截获,那么这个非法用户也只能盗用一段时间,下一次就仍然会拒之门外。

    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/sz_haitao/archive/2009/09/10/4539228.aspx
      

  22.   

    说到底是TCP/IP+数据包的问题。自己的程序自己用的话,用什么来实现数据的传输都无所谓。
    如果是“公共”使用的,遵守一定的标准就行了。WebService就是这么出来的。至于怎么“三层”,还是自己定,也就是自己“解析”数据就行了
      

  23.   

    以后Delphi可以做富客户端,走HTTP协议进行通讯,这样最好了
      

  24.   

    一直希望DELPHI走SMART CLIENT路线
      

  25.   

    谢谢sz_haitao用非常专业词语补充。
    当时我用了口令,而没有用帐号密码之类的的词汇,想它包括SessionID或者其他各种形式的key,或者是一句“芝麻开门”,我以为做过的人都能想到呢。
      

  26.   

    看了sz_haitao的这篇贴子受益非浅,学习到了另一种架构方式,但我比较关心的是数据转输速度,同在互联网的环境下可能速度相当,但如果在局域网内的INI@HTTP与DCOM的方式哪个速度快些,如果传输数据量在10W级,客户端等待数据转输会不会引起超时,有没有好的解决办法,如:分页传输数据等。谢谢!
      

  27.   

    ActiveX也算?
    MIDAS/DataSnap算不?虽然性能和稳定性上总是被指责对于分层设计,我想有架构设计和部署实现两个层面,两个层面有关联,但关注点不完全一致。
    总得说没有最好的设计或实现,只有最适合的。WebService作为一种实现方式最大的优势我想就是标准化。
      

  28.   


    我的实际应用遇到过最大:3万条记录,7M字节的ini数据,压缩后为2M,异地(同省)接收,客户端等待大约5-15秒,服务器为5M的adsl,客户端是4M的adsl
      

  29.   


    局域网只会更快,因为一般都是100M的连接。比上面的实例快了10倍。当然仅仅是传输快10倍,数据库的io、组包、压缩的速度是一样的
      

  30.   

    谢谢,下次在做项目选择架构方式时,又多了种可选的方案。你哪里有没有相关的DEMO呢?可不可以发份给我学习下呢? 邮箱:aipeli at 163 dot com 。
      

  31.   

    re tjianliangActiveX也算? 
    MIDAS/DataSnap算不?虽然性能和稳定性上总是被指责 对于分层设计,我想有架构设计和部署实现两个层面,两个层面有关联,但关注点不完全一致。 
    总得说没有最好的设计或实现,只有最适合的。 WebService作为一种实现方式最大的优势我想就是标准化
    -------------------------------------------------
    不好意思,我01年开始delphi编程两年半就转了dotnet&java了,所以现在只记得大概做法。
    ActiveX属于Internet编程,web上最直接的感受是flash player。我们当然可以用它来实现很多功能,因为能嵌入网页,所以偶尔也归于web。
    最早称为MIDAS(Multi-tier Distributed Application Services Suite),后来称为DataSnap,那只是一个架构的大概念,具体在delphi开发环境里也就是控件组的名字而已。使用DataSnap组里面的WebConnection控件,其过程就如上我说的第一种,只是我用的话糙点。
    不是信息本身累,而是交流方式累。看来我还要坚持“只看不说”的上网风格了,破例是想要点分还怀怀旧。我声明我什么都没说,也不要再有人就我的话回复,因为你一回我又得打字。
      

  32.   

    嗯,写的不错,学到不少东西,我现在需要做个Web应用程序,可是不会
      

  33.   

    使用 Delphi + WebService + DBMS 
    這中模式比較好, 可以跨平臺服務, 中間層用java些,
    利用XML 壓縮傳輸,速度嘛,還比較可以的,我從上海傳遞1萬條數據 到深圳,
    1、20秒吧。具體沒有測試研究。主要是 中間層的java強大 ,使用 java 比較靈活,  而客戶端使用Delphi 那是不爭的事實。兩者優點相互結合,我趨向于這中模式,至于使用socket 或者 ini什么的,我沒有試驗過。
    XML是通用網絡傳輸標準語言,還是跟標準走好。
      

  34.   

    socket 技术比较成熟
    另外也可以用Soap + WebService + COM+ 数据库
      

  35.   


    扯鸡8蛋。 我一直占着 这个 SessionID,一直发心跳包,不就可以不拉屎啦,这个盗用“一段时间”,从历史的长河中看,还真是一段。
      

  36.   

    lz、楼上也不用这么激动吧sessionid机制,是有这个被“暂时”盗用的可能,如果后台怕它一直刷新以便失效,可以把失效机制改为:登录n个小时,不管是不是还有请求,一律失效我认为这个机制好,是因为:如果帐号、密码被截取,损失更大另外,防止截取方面,还有一次性过程密钥、另外渠道获取附加校验码之类的做法(这个做法对于sessionid还是帐号密码都是适用的),就看是不是值得
      

  37.   

    如果中间层用webservice,客户端转输比较大数据时,可以压缩后,做BASE64运算,在封包,这样就不会存在安全问题了。-------如果服务器端的SOAP通过一定的运算转换,那么一般人也得不到实际的结口。(安不安全不是架构的问题,应该是人的问题)
      

  38.   

    中间层也用过JAVA+TOMCAT+Axis2,但是JAVA写的中间层有点变态,占用次源太高。
      

  39.   

    看的头都大了,不过先谢谢了>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>