Seam的页面流pageflow是很容易让人迷惑的。
这里首先要弄清楚术语,Web程序通常都是在不同页面间来回跳转来实现应用逻辑的,所以通常的说法是页面导航Page Navigation, 这是最普遍和广泛的说法。因此对于页面导航Page Navigation的约定,被称为页面导航规则Page Navigation Rule。这几个术语是独立于语言和具体Web框架的。
例如,在JSF开发中,我们使用outcome来实现页面导航。outcome本身就是一个字符串,我们通过某个方法返回的outcome字符串来判断下一步的逻辑步骤。当然这个工作需要通过页面和outcome字符串的匹配设置来完 成。例如在Seam的猜数字应用中,我们也可以使用JSF的outcome来实现页面导航:
<navigation-rule> <from-view-id>/numberGuess.jsp </from-view-id> <navigation-case> <from-outcome>guess</from-outcome> <to-view-id>/numberGuess.jsp</to-view-id> <redirect/> </navigation-case> <navigation-case> <from-outcome>win </from-outcome> <to-view-id>/win.jsp </to-view-id> <redirect/> </navigation-case> <navigation-case> <from-outcome>lose</from-outcome> <to-view-id>/lose.jsp</to-view-id> <redirect/> </navigation-case> </navigation-rule>
我们可以看到JSF页面导航配置的三要素:
但是你可能立刻就能发现这种处理方式的弊病来:
这种方式的页面导航被称为无状态 的页面导航。
需要强调的是:对于这种无状态的页面导航方式,除了JSF导航(使用navigation.xml)外,Seam还支持一种自己实现的无状态页面导航(使用pages.xml或者某个页面的xxx.page.xml):
<page view-id="/admin/admin.xhtml ">
<navigation >
<rule if-outcome="ship">
<redirect view-id="/admin/ship.xhtml"/>
</rule>
<rule if-outcome="accept">
<redirect view-id="/admin/accept.xhtml"/>
</rule>
</navigation>
</page>
这里Seam也使用了类似JSF的页面导航三要素:
如果,在你的Seam应用程序中你准备使用无状态的页面导航 的话,你有两种选择:
我们将在后面的文章中比较这两种选择。
Seam不仅仅只支持这种无状态的页面导航!更棒的是,Seam支持有状态的页面导航 !
提醒:在Seam中,Seam实现的页面导航被成为页面流Pageflow 。
在我们讲解有状态的页面导航之前,我们先回顾一下无状态页面导航的弊病包括:虽然页面配置简单,但是代码中要控制页面导航规则;无法很容易的看清楚导航规则,因为约束小。
Seam通过使用JBPM来帮助我们支持创建有状态的页面导航 !
需要注意的是:Seam在两种层次上使用JBPM:
这两者的层次是不一样的,这也是容易导致Seam初学者迷惑的地方,在这里我们先弄清楚这一点:JBPM是独立的流程管理引擎,在Seam中它被使用在两个不同的地方:页面导航和流程管理中。
实际上,Seam开发人员利用JBPM强大的定制功能,专门为页面导航定制了流程管理。Seam的使用者应该记住在Seam有状态的页面导航中page元素是JBPM节点Node的一种!这从侧面证明了JBPM强大的功能!
OK, 我们接着说JBPM在Seam中的使用。
首先看一下JBPM在页面导航中的作用:用来实现有状态的页面导航。
JBPM在这里用来定义单个对话中的页面流。一个Seam对话指的是单个 用户相对短时期内的交互 。
我们再来看一下JBPM在流程管理中的作用:用来进行流程管理。
业务流程可以跨越多个用户,多个对话 。其流程被持久化到JBPM数据库中,所以它是长时期 的。当然,管理多用户活动当然比管理单个用户活动复杂的多,包括复杂的任务管理和多路径并发管理。
你可能在你的应用程序中同时在这两个地方都使用JBPM!
OK,让我们回到有状态页面导航的主题上来。
还是使用猜数字应用。这回我们需要用xxx.jpdl.xml文件来配置有状态的页面导航(pageflow.jpdl.xml):
<pageflow-definition name="numberGuess"> <start-page name="displayGuess" view-id="/numberGuess.jsp"> <redirect/> <transition name="guess" to="evaluateGuess"> <action expression="#{numberGuess.guess}" /> </transition> </start-page> <decision name="evaluateGuess" expression="#{numberGuess.correctGuess}"> <transition name="true" to="win"/> <transition name="false" to="evaluateRemainingGuesses"/> </decision> <decision name="evaluateRemainingGuesses" expression="#{numberGuess.lastGuess}"> <transition name="true" to="lose"/> <transition name="false" to="displayGuess"/> </decision>
<process-state
name="cheat">
<sub-process
name="cheat"/>
<transition name="displayGuess"/>
</process-state>
<page
name="win" view-id="/win.jsp">
<redirect/>
<end-conversation />
</page>
<page name="lose" view-id="/lose.jsp">
<redirect/>
<end-conversation />
</page>
</pageflow-definition>
我们可以看到有状态的页面流是通过JBPM的JPDL(xxx.jpdl.xml)来配置的,几个要素: