`
alienj
  • 浏览: 78795 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

第7章 对话与工作空间管理

阅读更多

7 对话与工作空间管理

 

现在是理解Seam对话模型更多细节的时候了。

 

从历史的观点上说,Seam“对话”概念来自三个不同的想法:

 

* 工作空间的想法,我在2002维多利亚政府的一个项目遇到。在这个项目里,我被迫在Struts的顶层实现工作空间管理,我乞求不要再体验那种经历。

 

*应用程序的乐观语义学事务和存在的基于一个无状态体系结构的框架不能提供有效扩展持久化管理(Hibernate项目真是受够了对LazyInitializationExceptions“延迟初始化异常”的过失处理,其并不是真的Hibernate故障,而是相当的故障源于无状态体系结构如Spring框架和传统J2EE的无状态会话正面模型对极端限制的持久化上下文模型的支持)实现结果的想法。

 

*工作流任务的想法。

 

通过统一这些想法并在框架中提供更进一步的支持,我们实现了一个超强的结构,其让我们与以前相比能用很少的代码构建富裕和更有效的应用程序。

 

7.1. Seam对话模型

 

迄今为止,我们看过的例子,是利用下面这些原则的很简单的对话模型:

 

*在申请请求值期间、处理校验、更新模型值、调用应用程序和JSF请求生命周期的渲染响应阶段,总有一个对话上下文活动。

 

* JSF请求生命周期的恢复视窗结束阶段, Seam 尝试恢复任何前面的长运行对话上下文。如果不存在,Seam创建一个新的临时对话上下文。

 

*当遇到一个@Begin方法,临时对话上下文被提升为一个长运行上下文。

 

*当遇到一个@End方法, 任何长运行对话上下文被提升为一个临时对话。

 

* JSF请求生命周期的渲染响应阶段结束时,Seam恢复长运行对话上下文的内容或者摧毁一个临时对话上下文的内容。

 

*任何faces 请求(一个JSF回调)会传播会话上下文。缺省时,非faces 请求(例如,GET请求)不传播对话上下文,但是,有关这些内容可看下面更多信息。

 

* 如果JSF请求生命周期被重定向省略,Seam显然地存储并恢复当前对话上下文——除非对话通过@End(beforeRedirect=true)已被结束。

 

在越过JSF 回调和重定向时,Seam显然地传播对话上下文 (包括临时对话上下文)如果你不做任何指定,一个非 faces请求(例如,GET请求)不会传播对话上下文,并且会在一个新的临时的对话中被处理。通常是——但并不总是——想得到的行为。

 

如果你想越过一个非faces请求时传播一个Seam对话,你需要明确地编码Seam对话id作为一个请求参数:

<a href="main.jsf?conversationId=#{conversation.id}">Continue</a>

 

或者,更多JSF-ish

<h:outputLink value="main.jsf">

    <f:param name="conversationId" value="#{conversation.id}"/>

    <h:outputText value="Continue"/>

</h:outputLink>

 

如果你使用Seam 标签库,这是等价的:

<h:outputLink value="main.jsf">

    <s:conversationId/>

    <h:outputText value="Continue"/>

</h:outputLink>

 

如果你希望在一个回调时对话上下文传播失效,一个相似的技巧被用:

<h:commandLink action="main" value="Exit">

    <f:param name="conversationPropagation" value="none"/>

</h:commandLink>

 

如果你使用Seam 标签库,这是等价的:

<h:commandLink action="main" value="Exit">

    <s:conversationPropagation type="none"/>

</h:commandLink>

 

注意,让对话上下文传播失效是完全不同于对话结束。

 

conversationPropagation 请求参数,或者<s:conversationPropagation> 标签,甚至能被使用在开始和结束对话,或者开始一个嵌套对话。

<h:commandLink action="main" value="Exit">

    <s:conversationPropagation type="end"/>

</h:commandLink>

<h:commandLink action="main" value="Select Child">

    <s:conversationPropagation type="nested"/>

</h:commandLink>

<h:commandLink action="main" value="Select Hotel">

    <s:conversationPropagation type="begin"/>

</h:commandLink>

<h:commandLink action="main" value="Select Hotel">

    <s:conversationPropagation type="join"/>

</h:commandLink>

 

这种对话模型使构建恰当的涉及多窗器操作的行为的应用程序很容易。对多数应用程序,这是足够了。一些复杂的应用程序有下面一个或两个附加要求:

 

* 一个对话跨多个小的用户界面单元,连续或者甚至并发执行的单元。小单元嵌套的对话有它们自己独立的对话状态,并且也访问外部对话的状态。

* 在同一个游览器窗器内,用户能在许多对话之间切换。这个特色被称为工作空间管理。

 

7.2. 嵌套的对话

 

一个嵌套对话被创建,通过在一个存在的对话范围内调用@Begin(nested=true) 标记的一个方法。一个嵌套对话有它自己的对话上下文,并且也能只读访问外部对话的上下文(它能读外部的对话的上下文变量,但不能写它们)。当随后遇到一个@End时,嵌套对话将会被摧毁,并且外部对话将会恢复,通过“弹出”对话堆栈。对话可以被嵌套到任意深度。某些用户动作(工作空间管理,或者返回按钮),在内部嵌套结束前,可能引起对话恢复。在这种情况下,有多个并发嵌套对话属于同一个外部对话是可能的。如果在一个嵌套对话结束之前外部嵌套结束,Seam将会随同外部嵌套摧毁所有嵌套对话上下文。

 

一个对话可以被认为是一个可持续状态。嵌套对话允许应用程序在一个用户界面的不同点捕获一个一致的可持续状态,因而真正地确保在返回按钮和工作空间管理“面”的正确行为

 

TODO: 一个例子显示了一个嵌套对话,当你用返回按钮时如何预防坏的东西发生。

 

通常,如果一个组件存在当前嵌套对话的一个父对话中,嵌套对话将使用同一个实例。偶尔,在每一个嵌套对话中有一不同实例是有用的,所以,存在于父对话的组件实例对子对话是不可见。你能通过@PerNestedConversation注释组件达到这种行为。

 

7.3. GET 请求启动对话

 

当一个非faces请求(例如,一个HTTP GET请求)访问一个页面时,JSF并没有定义被触发的任何一种类型的动作侦听器。如果用户标记了页面,或者如果我们通过<h:outputLink>导航到这个页面,这能发生。

 

有时候,我们想页面被访问时马上开始一个对话。因为没有JSF动作方法,我们不能用通常的方法解决问题,通过用@Begin注释动作。

 

如果页面需要取一些状态放进一个上下文变量,一个更深一层的问题发生。我们已经看到两种方法解决这种问题。如果状态维持在一个Seam组件,我们能用一个@Create 方法取得状态,如果没有,我们能为一个上下文变量定义一个@Factory方法。

 

如果没有这些选项目为你工作,Seam让你在pages.xml中定义一个页面动作。

<pages>

    <page view-id="/messageList.jsp" action="#{messageManager.list}"/>

    ...

</pages>

 

在渲染响应阶段的开始,这个动作方法被调用,随时页面将要被渲染。如果一个页面返回一个非空结果,Seam会处理任何适当的JSFSeam导航控制,可能导致一个完全不同的页面被渲染。

 

如果你想在渲染页面前开始一个对话,你只能使用一个内建动作方法去完成:

<pages>

    <page view-id="/messageList.jsp" action="#{conversation.begin}"/>

    ...

</pages>

 

注意,你也能从一个JSF调用这个内建动作,并且,相似的,你能使用#{conversation.end}结束对话。

 

如果你想更多控制,加入存在的对话或开始一个嵌套对话,开始一个页面流或一个原子对话,你应用使用<begin-conversation>元素。

<pages>

    <page view-id="/messageList.jsp">

       <begin-conversation nested="true" pageflow="AddItem"/>

    <page>

    ...

</pages>

 

也有一个 <end-conversation> 元素。

<pages>

    <page view-id="/home.jsp">

       <end-conversation/>

    <page>

    ...

</pages>

 

为解决第一个问题,我们有五种选项:

 

*@Begin注释@Create方法

*@Begin注释@Factory方法

*@Begin注释Seam 页面动作

* 使用 <begin-conversation> pages.xml

* 使用 #{conversation.begin}作为Seam 页面动作方法

 

7.4.使用<s:link><s:button>

 

JSF命令链接总是通过JavaScript处理一个表单提交,这打破了网页游览器“打开在新窗口”或者“打开在新标签”特色。 在简单JSF中,如果你需要使用这种功能,你需要使用 <h:outputLink>。但是对<h:outputLink>有两个主要限制。

* JSF没有提供方法糸动作侦听器到<h:outputLink>

*因为没有实际表单提交,JSF不传播所选的一个DataModel 行。

 

Seam提供页面动作概念帮助解决第一个问题,但是对第二问题没有帮助。我们能环绕这工作,通过使用传一个请求参数的RESTful 方法和询问在服务器边所选的对象。在一些情况下——例如象Seam blog例子应用程序——这确实是最好的方法。RESTful 式样支持下书签,因为它不要求服务器边状态。在其它情况下,我们不关心书签,@DataModel @DataModelSelection的使用正好是这样方便和明晰!

 

为填补这缺少的功能,和使对话传播在管理上更简单,Seam提供了<s:link>标签。

这个链接可以只指定JSF视窗id:

 

<s:link view="/login.xhtml" value="Login"/>

 

或者,它能指定一个动作方法(在那个情况下动作结果决定页面结果):

<s:link action="#{login.logout}" value="Logout"/>

 

如果指定两者,一个JSF视窗和动作方法,除非动作方法返回了一个非空结果,“视窗”将会被使用:

<s:link view="/loggedOut.xhtml"  action="#{login.logout}" value="Logout"/> 

 

链接自动传播所选的一个使用在<h:dataTable>内的DataModel的行

<s:link view="/hotel.xhtml" action="#{hotelSearch.selectHotel}" value="#{hotel.name}"/>

 

你也能离开一个存在的对话范围:

<s:link view="/main.xhtml" propagation="none"/>

 

你能开始,结束,或者嵌套对话:

 <s:link action="#{issueEditor.viewComment}" propagation="nest"/>

 

如果链接开始了一个对话,你甚至能指定使用一个页面流:

<s:link action="#{documentEditor.getDocument}" propagation="begin"

        pageflow="EditDocument"/>

 

taskInstance属性,如果为使用jBPM任务列表:

<s:link action="#{documentApproval.approveOrReject}" taskInstance="#{task}"/>

 

(DVD Store 演示的例子应用程序。)

 

最后,如果你需要“link”被渲染成一个按钮,使用<s:button>

<s:button action="#{login.logout}" value="Logout"/>

 

7.5.成功消息

 

显示一条消息给用户指示一个动作的成功或失败是相当普遍。为这使用JSF  FacesMessage很方便的。不幸的,一个成功的动作常要求一个游览器重定向,并且JSF越过重定向不传播faces消息。这使得在简单JSF中显示消息十分困难。

 

内建在对话范围的名为facesMessages Seam组件解决了这个问题。

(你必须安装了Seam 过滤器)

 

@Name("editDocumentAction")

@Stateless

public class EditDocumentBean implements EditDocument {

    @In EntityManager em;

    @In Document document;

    @In FacesMessages facesMessages;

   

    public String update() {

        em.merge(document);

        facesMessages.add("Document updated");

    }

}

 

任何增加到facesMessages 消息被使用在当前对话的下一次渲染阶段。这当没有长运对话时甚至也能工作,因为Seam 保护一致性临时对话上下文越过重定向。

 

你甚至能在一个faces消息汇总中包括JSF EL表达式:

facesMessages.add("Document #{document.title} was updated");

 

你可以用普通的方法显示消息,例如:

 <h:messages globalOnly="true"/>

 

7.6. 自然对话ids

 

当用对话处理持久化对象进行工作时,使用对象的自然业务关键字替代标准的是令人想要的,“代理”对话id:

 

容易重定向到存在的对话

 

如果用户请求同样的操作两次,重定向到一个存在的对话是有益的。举这样的例子:“你在ebay,半途通过一个正好赢得的付款项目,当为你的双亲一个圣诞礼物。按理说你会直接发送给他们——你进入你的支付详细资料,但是你忘记了他们的地址。你偶然地重用同样的浏览器查找出他们的地址。现在你需要返回,支付这个项目”

 

用一个自然对话让用户重新加入到存在的对话真是容易的,并获得他们离去的地方——正好获得他们重新加入的带有项目id的支付项目对话作为对话id

使用友好的URL

 

对我而言,这由一个导航层级(我能通过编辑url来导航)和一个有目的的url(象这个Wiki的用法——那样不使用随机ids确定事物)构成。当然,对一些应用程序用户友好的URL是不重要的。

 

用一个自然对话,当你构建你的hotel  booking系统时(或者,当然,无论你的应用程序是哪一种),你能产生一个URL,如http://seam-hotels/book.seam?hotel=BestWesternAntwerpen(当然,hotel映射到你的领域模型的无论哪个参数必须是唯一的),并且用URLRewriteURL重写)容易转换这到http://seam-hotels/book/BestWesternAntwerpen

 

太好了!

 

7.7. 创建一个自然对话

 

自然对话被定义在pages.xml

  <conversation name="PlaceBid"

                  parameter-name="auctionId"

                  parameter-value="#{auction.auctionId}"/>

 

在上面定义中要注意的第一件事是对话有一个名字,在这种案例中的PlaceBid。这个名字唯一地标识这特殊的命名对话,并且通过页面定义标识一个参与的命名对话被使用。下一个属性, parameter-name 定义了会包含自然对话id的请求参数, 代替缺省的对话id参数。在这个例子, parameter-name auctionId 这意谓一个出现在你的页面的URL中的对话参数如cid=123,它会被auctionId=765432 替代。

 

在上面配置中的最后一个属性parameter-value,定义了一个EL表达式,产生自然业务关键字的值,用来作为对话id。在这个例子中,对话id会是当前范围的auction实例的主关键的值。

 

在下面,我们定义的页面会传播命名对话。通过对一个页面定义指定对话属性来实现:

 

  <page view-id="/bid.xhtml" conversation="PlaceBid" login-required="true">

      <navigation from-action="#{bidAction.confirmBid}">       

          <rule if-outcome="success">

              <redirect view-id="/auction.xhtml">

                  <param name="id" value="#{bidAction.bid.auction.auctionId}"/>

              </redirect>

          </rule>       

      </navigation>

  </page>

 

 

 

7.8.重定向到一个自然对话

 

当启动,或重定向到一个自然对话时,为指定自然对话的名字有一些选项。让我们从看看下面的页面定义开始:

 

  <page view-id="/auction.xhtml">

    <param name="id" value="#{auctionDetail.selectedAuctionId}"/>

      

    <navigation from-action="#{bidAction.placeBid}">

      <redirect view-id="/bid.xhtml"/>

    </navigation>

  </page>

 

从这里,从我们的auction拍卖视窗,我们能看到那个调用动作#{bidAction.placeBid}(用这种方法,所有这些例子取自Seam中的seamBay例子),我们会重定向到/bid.xhtml,那个,如我们前看的,是用自然对话PlaceBid配置的。对我们动作方法的声明看起来如这样:

   @Begin(join = true)

   public void placeBid()

 

当命名对话在<page/>元素中被指定时,在动作方法已经被调用后,对命名对象的重定向,象导航控制的部分一样发生。 当重定向到一个存在的对话这是一个问题,因为重定向需要发生在动作方法被调用前。因而,当动作被调用时,指定对话名是必要的。做这个的一个方法是通过用s:conversationName标签:

    <h:commandButton  id="placeBidWithAmount"  styleClass="placeBid"

 action="#{bidAction.placeBid}">

    <s:conversationName value="PlaceBid"/>

  </h:commandButton>

 

另一个选择是指定conversationName属性,当使用s:link s:button:

  <s:link value="Place Bid" action="#{bidAction.placeBid}" conversationName="PlaceBid"/>

 

7.9. 工作空间管理

 

工作空间管理有能力在一个单一窗口切换对话。Seam使得工作空间管理在Java代码级完全透明。为了能用工作空间管理,你需要做:

 

*为每一个视窗id(当使用JSF或者Seam导航控制时)或者页面节点(当使用jPDL页面流时)提供描述文本。这个描述文本通过工作空间切换器显示给用户。

 

分享到:
评论

相关推荐

    MFC程序开发参考大全第7--12章 源代码

    本书的第7至12章涵盖了MFC的多个关键主题,通过源代码实例帮助读者深入理解和应用这些概念。 在第7章中,重点讲述了MFC中的文档/视图架构。这一架构是MFC设计的核心部分,用于处理用户界面与数据模型之间的交互。...

    第六章管理信息系统的系统设计.pdf

    3. **信息系统流程图**:这种图反映了管理业务流程,用于描绘新系统的工作流程,是系统设计的关键部分。 4. **系统设计原则**:系统设计过程中应先进行输出设计,再进行输入设计,确保系统功能符合用户需求。 5. *...

    How to Start a Conversation and Make Friends - Don Gab

    - **第七章:礼貌地结束对话**:教授如何优雅地结束对话,既不让对方感到被忽视,也不显得突兀。 - **第八章:建立友谊**:提供了一些建立长期关系的策略,如保持联系的方式、共同兴趣的探索等。 5. **第四部分:...

    JBoss Seam: Simplicity and Power Beyond Java EE

    - **第七章:事务管理** - **事务基础**:讲解 Seam 中的事务管理机制,包括如何确保数据的一致性。 - **最佳实践**:分享在实际开发过程中如何有效利用 Seam 的事务管理功能。 #### 五、数据模型与表现层的集成...

    informix 实用大全

    第7章 informix与数据仓库 7.1 何谓数据仓库 7.2 informix对数据仓库的投资 7.3 更多信息 7.4 informix与其他参考资料 第二部分 lnpormlx sql 第8章 生成数据库与表格 8.1 规划磁盘布局与存储要求 8.2...

    瞬间之美__WEB界面设计如何让用户心动

    第7章 为界面做标记 55 7.1 停止标记你的“假设” 56 第8章 生动传神的视频 59 8.1 视频演示胜过千言万语 60 8.1.1 使用视频来表述问题 61 8.1.2 使用视频来表述想法 62 8.2 极为简单的视频演示艺术 ...

    第三章--网络体系结构和网络协议.ppt

    * 会话层:在传输连接的基础上提供增值服务,对端用户间的对话进行协调和管理。 * 表示层:对数据进行编码和解码,以便于不同系统之间的数据交换。 * 应用层:提供各种网络服务,如文件传输、电子邮件等。 TCP/IP...

    第二章 Windows XP操作系统.pdf

    本章主要介绍了Windows XP操作系统的基础知识,包括界面元素、快捷方式、系统功能、文件管理以及用户交互等方面。 1. 对话框元素:对话框是Windows XP中用于与用户交互的窗口,通常包含标题栏、单选按钮、标签等...

    精通Qt4编程(第二版)源代码

    \第7章 拖放操作和剪贴板 212 \7.1 拖放操作 212 \7.1.1 拖放操作 212 \7.1.2 定义新的拖放操作类型 214 \7.1.3 Graphics View框架下的拖放 \7.1.3 操作 215 \7.2 使用剪贴板 217 \7.3 小结 218 \第8章 文件...

    精通qt4编程(源代码)

    \ 第7章 拖放操作与剪贴板 蔡志明 本章简要地说明了基于MIME的拖放操作和剪贴板的使用,关于Graphics View框架的拖放操作也在本章。 212 \ 第8章 文件处理 蔡志明介绍了Qt的文件处理,包括基于流的文本文件和二进制...

    Visual C++程序设计及实践.rar

    第7章《MFC文档视图》:此章详细阐述MFC中的文档和视图模型,这是MFC应用程序设计的核心。会讲解如何实现数据的存储和显示,以及文档和视图之间的通信。 第8章《MFC对话框》:涵盖MFC对话框的创建和使用,包括模态...

    VIW虚拟因特网教室.doc

    第六章和第七章则是关于产品安装和设置的指导,包括如何在Linux操作系统上安装和配置收集管理系统,以及如何启动VIW2000互联网课堂。安装过程包括两个主要步骤:一是安装Linux网络操作系统,二是安装和设置VIW2000...

    网通交换培训教材

    第7章 事务能力处理部分TCAP 242 7.1 概述 242 7.2 TC的结构及功能 244 7.2.1 TC的基本结构 244 7.2.2 成份子层 244 7.2.3 事务处理子层 248 7.3 TCAP消息格式及编码 250 7.3.1 信息单元结构 250 7.3.2 TCAP消息的...

    2021-2022年收藏的精品资料证劵投资 第二章:财务分析我.doc

    3. **投资策略**:巴菲特与肯·察斯的对话体现了重视投资回报率而非单一利润额的理念。他更倾向于选择资本收益率高的小型企业,而不是低回报的大公司。他关注现金流周转速度,并强调股东利益的重要性,当遇到公司...

    毕业设计(论文)-基于JAVA的多人聊天室设计.doc

    第 5 章 系统测试与优化 本章将对系统进行全面的功能测试和性能测试,以确保其满足设计需求,并针对测试结果进行必要的优化调整。 第 6 章 结论 总结整个项目的设计与实现过程,评估系统的效果和潜在改进空间,为...

    数据结构与算法分析java版

    第三章和第七章分别介绍了简单的排序算法(如冒泡排序、选择排序)和更高效的排序算法(如归并排序、快速排序)。这些算法不仅展示了不同的时间复杂度和空间复杂度,也反映了数据结构对算法性能的影响。 #### 2. ...

    C++ GUI Programming with Qt4(2nd).pdf

    ##### 第7章:事件处理 - **重写事件处理器**:介绍如何通过重写事件处理函数来响应特定类型的事件。 - **安装事件过滤器**:讲解如何使用事件过滤器来拦截并处理事件。 - **保持响应性**:讨论如何确保在执行密集...

Global site tag (gtag.js) - Google Analytics