`

JBoss Seam事件机制 (4):页面动作

    博客分类:
  • Seam
阅读更多
在JBoss Seam事件机制(1)概述中讲到,Seam中的页面动作发生在页面渲染之前,我们在WEB-INF/pages.xml文件中配置页面动作。我们还提到了page元素中的view-id不一定非要是JSP或者Facelet页面,这给整合其他WEB框架留了空间,并且能够让我们处理非JSF的请求。另外页面动作可以返回一个JSF输出,通过JSF输出来定制导向。除此之外,在page元素中,我们可以使用多个action元素来完成有条件的页面动作:
<pages>    <page view-id="/hello.jsp">        <action execute="#{helloWorld.sayHello}" if="#{not validation.failed}"/>        <action execute="#{hitCount.increment}"/>    </page></pages>
页面参数
我们知道一个JSF请求(表单提交)包括(封装)了动作和参数,所以一个页面动作也许需要参数。使用GET的请求可以做书签,因为
页面参数都作为可读的请求参数处理了。但是JSF表单使用的是POST。Seam能够让我们将请求参数和模型属性相关联和映射:
<pages>      <page view-id="/hello.jsp" action="#{helloWorld.sayHello}">          <param  value="#{person.firstName}"/>          <param name="lastName" value="#{person.lastName}"/>      </page>  </pages>
page元素中的param参数是双向的,就像JSF输入的值绑定一样。

当一个非Faces请求(GET)请求某个视图view-id的时候,Seam经过正确的类型转换后将请求的参数值赋给模型对象.

任何<s:link> 或者 <s:button> 都显式得包含请求参数。参数值由渲染阶段(<s:link>渲染)的值绑定计算结果来决定.

请求某个视图view-id的任何带有<redirect/>的导向规则都显式得包含请求参数 . 参数值由调用应用阶段结束时的值绑定计算来决定.

值通过任何对给定视图view-id的页面的JSF表单提交来传递. 这意味着视图参数有些类似于Faces请求中页面范围的上下文变量。

关键的思想是我们如何从另一个页面到/hello.jsp(或者从/hello.jsp又回到/hello.jsp), 在值绑定中的模型的值仍然被记住,而不需要任何的对话或者其他的服务器端的状态。
请求值的传递
如果只是name属性被指定的话,请求参数使用PAGE页面上下文(没有和模型属性映射)来传递。
<pages>      <page view-id="/hello.jsp" action="#{helloWorld.sayHello}">          <param name="firstName" /> // 没有value          <param name="lastName" />      </page></pages>
如果你想创建多层次主从模式的CRUD页面时,页面参数的传递就有必要了。你可以通过页面参数的传递来记住先前你在哪个视图上
(例如你在保存页面上,必须记住上个页面你正在编辑的实体)

如果参数以视图的页面参数列出的情况下,任何<s:link> 或者 <s:button> 显式的传递请求参数.

值通过任何对给定视图view-id的页面的JSF表单提交来传递. 这意味着视图参数有些类似于Faces请求中页面范围的上下文变量。

听起来太复杂了,这有必要么?当你用它的时候你就知道了。这值得下功夫去理解。页面参数是在非Faces请求间传递状态的最佳方式。如果你想让你的搜索结果页面也能做书签的话,我们就能够在同一个代码中使用它来处理POST和GET两种请求了。页面参数能够减少视图定义中请求参数列表的重复性,并且让在代码中处理重定向更加简单。
对话和验证
导向
在Seam中,你可以使用JSF的faces-config.xml文件来设置标准的JSF向导规则。但是JSF的向导规则有很多缺点:

在重定向的时候无法指定使用的请求参数.

无法根据规则来启动或者结束对话.

规则是根据动作方法返回的值来工作的,无法通过EL表达式来计算.

还有一个问题就是如果在Seam中使用标准的JSF导向,业务逻辑将散落在pages.xml和faces-config.xml两个配置文件中,很散乱。因此建议只是用pages.xml来配置页面导向。
我们看一下如何转换:
<navigation-rule> // JSF标准导向,在faces-config.xml中配置    <from-view-id>/editDocument.xhtml</from-view-id>        <navigation-case>        <from-action>#{documentEditor.update}</from-action>        <from-outcome>success</from-outcome>        <to-view-id>/viewDocument.xhtml</to-view-id>        <redirect/>    </navigation-case>    </navigation-rule>
<page view-id="/editDocument.xhtml"> // 等价的Seam导向,在pages.xml中配置        <navigation from-action="#{documentEditor.update}">        <rule if-outcome="success">            <redirect view-id="/viewDocument.xhtml"/>        </rule>    </navigation>    </page>
<page view-id="/editDocument.xhtml"> // 改良版1, 甚至不使用JSF返回的string        <navigation from-action="#{documentEditor.update}"                    evaluate="#{documentEditor.errors.size}">        <rule if-outcome="0"> // 如果错误数量为0,就代表OK            <redirect view-id="/viewDocument.xhtml"/>        </rule>    </navigation>    </page>
<page view-id="/editDocument.xhtml"> // 改良版2,判断错误是否为空        <navigation from-action="#{documentEditor.update}">        <rule if="#{documentEditor.errors.empty}">             <redirect view-id="/viewDocument.xhtml"/>        </rule>    </navigation></page>
<page view-id="/editDocument.xhtml"> // 如果你希望编辑后,结束对话        <navigation from-action="#{documentEditor.update}">        <rule if="#{documentEditor.errors.empty}">            <end-conversation/>            <redirect view-id="/viewDocument.xhtml"/>        </rule>    </navigation>    </page>
<page view-id="/editDocument.xhtml"> // 改良版3,或者你需要将参数传递下去    // 如果我们结束了对话,后续的请求无法知道哪个document我们感兴趣,我们需要将document id作为参数传递    <navigation from-action="#{documentEditor.update}">        <rule if="#{documentEditor.errors.empty}">            <end-conversation/>            <redirect view-id="/viewDocument.xhtml">                <param  value="#{documentEditor.documentId}"/>            </redirect>        </rule>    </navigation>    </page>
值得注意的是:JSF对于输出返回为Null的采用特殊处理,如果返回为Null的话指向原页面(重新显示页面)。但在Seam中不太一样。
<page view-id="/editDocument.xhtml">        <navigation from-action="#{documentEditor.update}">        <rule> // 这里的规则对非Null输出是有效的,但是对Null输出无效            <render view-id="/viewDocument.xhtml"/>        </rule>    </navigation>    </page>
需要变成:
<page view-id="/editDocument.xhtml">    // 去掉rule元素    <navigation from-action="#{documentEditor.update}">        <render view-id="/viewDocument.xhtml"/>    </navigation>    </page>
<page view-id="/editDocument.xhtml">    // view-id也可以使用EL表达式指定    <navigation if-outcome="success">        <redirect view-id="/#{userAgent}/displayDocument.xhtml"/>    </navigation>    </page>
细粒度的定义导向,页面动作和参数
如果你有很多页面动作和参数,或者有很多导向规则,你可能想使用多个文件来配置。这时候你可以使用view-id来创建响应的page.xml
文件。例如你有个view-id为/calc/calculator.jsp的页面,你可以创建calc/calculator.page.xml文件来配置,内容如下:

<page action="#{calculator.calculate}"> // 使用page元素作为根元素    <param name="x" value="#{calculator.lhs}"/> // 指定参数    <param name="y" value="#{calculator.rhs}"/>    <param name="op" converter="#{operatorConverter}" value="#{calculator.op}"/></page>
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics