谢谢关注补充一些:显示一个框架页面,竟然要再请求自己2次,这不是有病么?页面还好说,复杂不到哪里去,但是我觉得现在的Action太TMD复杂和弱智了,而且ActionForm把PO、QO作为成员这个符合最佳规范么?我的感觉就是因为M层设计不合理导致了C层的混乱。这种struts+DAO模式的方式是否应该由struts + hibernate(+ spring)方式代替?

解决方案 »

  1.   

    谢谢关注补充一些:显示一个框架页面,竟然要再请求自己2次,这不是有病么?页面还好说,复杂不到哪里去,但是我觉得现在的Action太TMD复杂和弱智了,而且ActionForm把PO、QO作为成员这个符合最佳规范么?我的感觉就是因为M层设计不合理导致了C层的混乱。这种struts+DAO模式的方式是否应该由struts + hibernate(+ spring)方式代替?
      

  2.   

    和楼主有同样的感觉,觉得action越写越复杂了,是不是我们对struts的理解还不够啊,不过我没有楼主强,只用struts做了个模拟证券交易的系统,大概才用了半个月,有时候想把v层作的好,很伤脑筋。
      

  3.   

    原帖描述有点不准确,应该说“现在的C层让人崩溃、M层让人迷惑”。
    楼上的兄弟说明一个问题:用struts了、页面无代码了、我们改善页面UI的能力也被约束了。还是那个左侧导航页面,一个最简单的竖排目录(没有层、不是树)都作的死难看,想象不出来2、3层的树型目录要怎么用struts标签来作!struts的M层要如何设计?
    这种struts+DAO模式的方式是否应该由struts + hibernate(+ spring)方式代替?
      

  4.   

    对了,楼主,你说如果用了struts,但是有些东西,还是在jsp页面本身实现起来比较方便,那在jsp页面里加了java代码,这样是不是就不太好呢,以前我也发过一贴,求证这样的设计模式是否合理的问题。
      

  5.   

    权威的说法当然是页面不要JAVA代码,全标签。说实话我不知道这样有什么好处,页面上的JSP和JSP注释都是在服务端处理完毕的,不会到达客户端,到达客户浏览器的只有HTML标记和HTML注释,所以我不理解所谓暴露了业务逻辑的说法。如果说标签体现了封装,那我觉得这是偏执。要作漂亮强大的动态页面势必要JSP、javascript、xmlhttp紧密合作,用struts限制了这种做法。关键是对于struts + DAO模式这样的设计是否最佳?这样子直接导致了Action的混乱臃肿。
      

  6.   

    在J道找到一篇好像类似的帖子,下面是板桥老师的一部分回复:>domain model完全可以传到展现层,使用FormBean有时候反而会造成混乱
    非常正确,在我的Jdon框架里,我推荐FormBean是Model的完全拷贝,除非你在界面有一些只与界面相关的小功能,可以增加FormBean的一些字段。有的系统使用FormBean中调用Model(就是Model是FormBean的字段变量)的做法(如IBatis JPetstore),这实际将两者变成了一种调用关系,一旦成为关系,就打开潘多拉盒子,变得复杂或者混乱,我不喜欢这样使用。尚未深入过模式,再研究研究这个帖子,地址:
    http://www.jdon.com/jive/article.jsp?forum=91&thread=23672
      

  7.   

    学习中,他所推荐的formBean是Model的完全拷贝是什么意思,难道是说,比如我有一个userBean,然后我的formBean就和这个userBean的结构一模一样,而并不要把userBean作为formBean的一个实例变量来使用,也就是说不要用formBean来传送数据到view层咯?不过用formBean来传数据也正是struts的一大精髓阿?请楼主指点
      

  8.   

    声明:下边文章是我以前在网上找的,作者名字我没有存,放到这里供大家参考!-------------------------------------------------------------
    Struts+Hibernate谈J2EE的数据表示
    在 struts+ hibernate 这种结构中,是不应该把Hibernate产生的PO直接传递给JSP的,不管他是Iterator,还是List,这是一个设计错误。  我来谈谈在J2EE架构中各层的数据表示方法:  Web层的数据表示是FormBean,数据来源于HTML Form POST   业务层的数据表示是VO  持久层的数据表示是PO,其数据来源于数据库,持久层的数据表示例如CMP。在一个规范的J2EE架构中,不同层的数据表示应该被限制在层内,而不应该扩散到其它层,这样可以降低层间的耦合性,提高J2EE架构整体的可维护性和可扩展性。比如说Web层的逻辑进行了修改,那么只需要修改FormBean的结构,而不需要触动业务层和持久层的代码修改。同样滴,当数据库表进行了小的调整,那么也只需要修改持久层数据表示,而不需要触动业务层代码和Web层代码。  不过由于Hibernate的强大功能,例如动态生成PO,PO的状态管理可以脱离Session,使得在应用了Hibernate的J2EE框架中,PO完全可以充当VO,因此我们下面把PO和VO合并,统称为PO。  先来谈谈ActionFormBean和持久层的PO之间的重大区别:  在简单的应用中,ActionFormBean和PO几乎是没有区别,所以很多人干脆就是用ActionFormBean来充当PO,于是ActionFormBean从JSP页面到Servlet控制层再到业务层,然后穿过持久层,最后一直映射到数据库表。真是一竿子捅到了底!  但是在复杂的应用中,ActionFormBean和PO是分离的,他们也不可能一样。ActionFormBean是和网页里面的Form表单一一对应的,Form里面有什么元素,Bean里面就有什么属性。而PO和数据库表对应,因此如果数据库表不修改,那么PO也不会修改,如果页面的流程和数据库表字段对应关系不一致,那么你又如何能够使用ActionFormBean来取代PO呢?  比如说吧,用户注册页面要求注册用户的基本信息,因此HTML Form里面包含了基本信息属性,于是你需要一个ActionFormBean来一一对应(注意:是一一对应),每个Bean属性对应一个文本框或者选择框什么的。  而用户这个持久对象呢?他的属性和ActionFormBean有什么明显不同呢?他会有一些ActionFormBean所没有的集合属性,比如说用户的权限属性,用户的组属性,用户的帖子等等。另外还有可能的是在ActionFormBean里面有3个属性,分别是用户的First Name, Middle Name, Last Name,而在我的User这个持久对象中就是一个 Name 对象属性。  假设我的注册页面原来只要你提供First Name,那么ActionFormBean就这一个属性,后来我要你提供全名,你要改ActionFormBean,加两个属性。但是这个时候PO是不应该修改滴,因为数据库没有改。  那么在一个完整的J2EE系统中应该如何进行合理的设计呢?  JSP(View) ---> Action Form Bean (Module) ---> Action(Control)  Action Form Bean是Web层的数据表示,它和HTML页面Form对应,只要Web页面的操作流程发生改变,它就要相应的进行修改,它不应该也不能被传递到业务层和持久层,否则一旦页面修改,会一直牵连到业务层和持久层的大面积的代码进行修改,对于软件的可维护性和可扩展性而言,是一个灾难,Actiont就是他的边界,到此为止!  Action(Web Control) ---> Business Bean ---> DAO ---> ORM --->DB  而PO则是业务层和持久层的数据表示,它在业务层和持久层之间进行流动,他不应该也不能被传递到Web层的View中去,而ActionServlet就是他的边界,到此为止!  然后来看一看整个架构的流程:  当用户通过浏览器访问网页,提交了一个页面。于是Action拿到了这个FormBean,他会把FormBean属性读出来,然后构造一个PO对象,再调用业务层的Bean类,完成了注册操作,重定向到成功页面。而业务层Bean收到这个PO对象之后,调用DAO接口方法,进行持久对象的持久化操作。  当用户查询某个会员的信息的时候,他用全名进行查询,于是Action得到一个UserNameFormBean包括了3个属性,分别是first name, middle name, last name,然后Action把UserNameFormBean的3个属性读出来,构造Name对象,再调用业务Bean,把Name对象传递给业务Bean,进行查询。  业务Bean取得Name(注意: Name对象只是User的一个属性)对象之后调用DAO接口,返回一个User的PO对象,注意这个User不同于在Web层使用的UserFormBean,他有很多集合属性滴。然后业务Bean把User对象返回给Action。  Action拿到User之后,把User的基本属性取出(集合属性如果不需要就免了),构造UserFormBean,然后把UserFormBean request.setAttribute(...),然后重定向到查询结果页面。  查询页面拿到request对象里面的ActionFormBean,自动调用tag显示之。  总结:  Form Bean 是Web层的数据表示,他不能被传递到业务层;PO是持久层的数据表示,在特定情况下,例如Hibernate中,他可以取代VO出现在业务层,但是不管PO还是VO都必须限制在业务层内使用,最多到达Web层的Control,绝不能被扩散到View去。  Form Bean 和PO之间的数据转化是在Action中进行滴。
      

  9.   

    Form Bean 和PO之间的数据转化是在Action中进行滴。——关键的一句。to:Michael_javavb() 我觉得板桥的观点是项目之初首先利用建模工具以面向对象方法作项目设计,这里首先确定了中间层C层用到的javabean,暂称为BO吧(这个BO要兼容并包),然后以这个BO为准去设计ActionForm和PO...这个BO就是域模型,所以他的方式叫域模型驱动。
    其实我也不知道这样子理解对不对。谢谢朱,我再消化消化...
      

  10.   

    和楼主有同感!我们的项目不是很大,如此复杂严重影响了开发速度.特别是hibernate.由于数据库设计的不合理,用hibernate查询起来真是不方便.
        我们现在根据别人(好像是胡开明吧)的思想写了一个PVO,负责查询.在action(controller)中做数据接收和流程控制,在BO中只写SQL语句调用PVO,在前台用JSTL标签. 真的很爽! 开发速度大大提升了. 如果想修改业务逻辑,直接修改BO中的SQL语句就行了. PVO查询出来的东西JSTL可以直接显示,VO就省了!
      

  11.   

    to:zeq258(近朱者赤)    我想如果在JSP页面要显示PO里面的集合属性呢?那FormBean显然是做不到这点的,因此,我想是不是在M层写一个javabean,里面的属性是JSP页面所需要,这样就可以保证在显示的时候,PO不会渗入到V层。以上做法不知道恰当否,请大大们指教!
      

  12.   

    参考板桥的论述,基本确认我们的问题是从一开始就使用工具从传统的面向过程设计的数据库生成PO、DAO,属于“面向对象对面向过程的屈从”。
      

  13.   

    学习了,最近才开始使用Struts,感觉挺好的,各个层次耦合性很低
      

  14.   

    jsp --- form --- VO --- action(Control) --- PO 
                                 \            /
                                  \          /
                                   \        /
                                    \      /
                                     \    /
                                     Model
                                        |
                                        |
                                        |
                                       调用相应的持久化方法,把PO作为参数
      

  15.   

    jsp --- form --- VO --- action(Control) --- PO 
                                     \            /
                                      \          /
                         调用业务层对象\        /作为参数传到业务层
                                        \      /
                                         \    /
                                         Model
                                          |
                                          |
                                          |
                                       调用相应的持久化方法,把PO作为参数
    -------------------------------------
    jsp --- form --- VO
    这三者,我们都可以理解为是展示层的东西,
    action是控制层,
    Model 是业务层,业务层可能要调用持久层的一些方法。在展示层,我们只能够操作 VO ,
    在业务和持久层,我们只能操作 PO ,
    在action 中,我们可以对 两者之间进行转换,
    这样就达到了分层的目的,而且,在页面不会出现持久化对象,在业务层也不会出现值对象。好的分层,可以是各个层次之间的偶合度很小,当一个部分发生改变的时候,只需要改变相应层次之间的映射,而不必改变其他的层。
      

  16.   

    由于Struts已经为我们提供了一个非常好的MVC框架,我们利用Struts开发MVC系统时可以大大加快开发的速度。在开发时可以采用的一个开发流程如下:1、收集和定义应用需求。 
    2、基于数据采集和显示的原则定义和开发"屏幕显示"需求 。 
    3、为每一个"屏幕显示"定义访问路径。 
    4、定义ActionMappings建立到应用业务逻辑之间的联系。 
    5、开发满足"屏幕显示"需求的所有支持对象。 
    6、基于每一个"屏幕显示"需求提供的数据属性来创建对应的ActionForm对象 
    7、开发被ActionMapping调用的Action对象。 
    8、开发应用业务逻辑对象 (Bean,EJB,等等)。 
    9、对应ActionMapping设计的流程创建JSP页面。 
    10、建立合适的配置文件struts-config.xml , web.xml。 
    11、开发/测试/部署 具体在使用Struts框架时,对应各个部分的开发工作主要包括:
    1、Model部分:采用JavaBean和EJB组件,设计和实现系统的业务逻辑。根据不同的请求从Action派生具体Action处理对象。完成"做什么"的任务来调用由Bean构成的业务组件。创建由ActionForm 的派生类实现对客户端表单数据的封装。 
    2、Controller部分:Struts为我们提供了核心控制部分的实现。我们只需要配置ActionMapping对象 
    3、View部分:为了使用Model中的ActionForm 对象,我们必须用Struts提供的自定义标记创建HTML 表单。利用Struts提供的自定义标记库编写用户界面把应用逻辑和显示逻辑分离。Struts框架通过这些自定义标记建立了View和Model之间的联系。Struts的自定义标记还提供了很多定制页面的功能。 同时需要编辑两个配置文件:web.xml和struts-config.xml。
      

  17.   

    再贴一篇还是MDA和面向数据表设计的译文,希望对更多人有益:The Object-Relational Impedance Mismatch现在设计应用系统时,主要有两个派别:传统的面向数据表设计和现在流行的面向对象设计。数据库专家(DBA等)开发设计出数据表结果(SQL或使用powerdesign之类工具建模),而应用程序员则写它们的程序代码,这两种任务在过去一直是独立地进行着,互相不干扰,我曾经在Jdon看到一篇帖子,说网易的一个DBA很厉害,写出的数据表结构如何好,这代表着过去的一种数据库系统开发的方式。这两种工作是没有联系的,因为数据模型只完成数据实体和数据关系,而应用模型只要实现如何操作这些数据,也就是完成SQL语句或存储过程语句。当面向对象技术诞生后,从数据专家观点来看,他们觉得这一技术对他们影响不大,但是一些数据库专家已经快速地意识到这是软件开发的一场革命,由此加入新的领域,并且这样的群体不断在增长。非常不幸的是,还有许多数据库专家仍然认为面向对象的分析流程只是一种暂时现象,根本不接受这种新的变化,依然使用过去方式来分析设计数据库。这两个阵营目前在互相攻击,出现了严重分裂,但是数据库专家正在遭受更严峻的挑战,特别是使用EJB的实体bean或Hibernate来实现数据持久时,很多以前的数据表设计概念要接受挑战,这也是很多项目设计的痛苦根源。令数据库专家惊慌的是:面向对象技术UML比数据建模技术更加robust鲁棒。并且可以证明:UML是数据模型的父集,很明显,现在天平已经倾向与面向对象设计了。这里有很多概念误区:许多数据库专家错误地认为类图只不过是带有行为操作的数据模型,他们没有认识到这其中有些细微地区别,他们没有认识到模型行为的复杂性要超过类图。面向对象和面向数据表的分裂造成很多恶劣的结果:
    1. 项目由于未能及时完成而失败。
    2. The technical impedance mismatch技术阻抗加剧
    3. 数据建模与对象建模相比,无法涵括项目的全部需求设计,增加内部来回反复折腾。如何愈合这种分裂?
    1.项目参与人员必须同时掌握了解对象和数据表技术
    2.按照减少耦合、封装分派等概念重构数据表。
      

  18.   

    用动态表单直接从数据库字段映射过来,这样FORM就轻松了.
    ACTION不做业务,只负责调用M,调用完后做个转向.
      

  19.   

    STRUTS没有M层,一般都结合其他的框架,比如EJB
      

  20.   

    在“Struts+Hibernate谈J2EE的数据表示”一文中:  “Web层的数据表示是FormBean
      业务层的数据表示是VO
      持久层的数据表示是PO...
        比如说Web层的逻辑进行了修改,那么只需要修改FormBean的结构,而不需要触动业务层和持久层的代码修改。同样滴,当数据库表进行了小的调整,那么也只需要修改持久层数据表示,而不需要触动业务层代码和Web层代码”
        ——这不是废话吗?“Web层的逻辑进行了修改”试问Web层的逻辑为什么进行修改?还不是十有八九是因为流程修改?流程修改能不涉及数据库修改吗?谈什么只修改web层呢?大家开发维护当中绝大部分修改都是页面、数据库一起改的。  “Action Form Bean是Web层的数据表示,...Actiont就是他的边界,到此为止!
      PO则是业务层和持久层的数据表示,它在业务层和持久层之间进行流动,他不应该也不能被传递到Web层的View中去,而ActionServlet就是他的边界,到此为止!”
        ——PO的边界也应该是Actiont吧,笔误?  “总结:
      Form Bean 和PO之间的数据转化是在Action中进行滴。”
        ——总结这一句足矣,正是因为在Action中进行Form Bean和PO、QO之间的数据转化才造成混乱。
      

  21.   

    FormBean既是struts的优点也是它的缺点所在,而WebWork2在这方面就好很多,
    没有了Form Bean和PO之间的数据转化,代码省了不少,更不会造成搂主所说的混乱。