根据f:viewParam有条件地调用f:viewAction

时间:2014-08-11 10:47:23

标签: jsf jsf-2.2 viewaction

我们有一个设置,我们将不同的可选视图参数传递给JSF页面,并在设置参数后处理后续视图操作。一个非常简单的例子如下所示:

page.xhtml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://xmlns.jcp.org/jsf/html"
  xmlns:f="http://xmlns.jcp.org/jsf/core">

<f:view>
    <f:metadata>
        <f:viewParam name="a" value="#{page.a}"/>
        <f:viewAction action="#{page.populateA()}" if="#{not empty page.a}"/>

        <f:viewParam name="b" value="#{page.b}"/>
        <f:viewAction action="#{page.populateB()}"/>
    </f:metadata>

    <h:outputLabel value="#{page.message}"/>
</f:view>
</html>

网页

import javax.faces.view.ViewScoped;
import javax.inject.Named;

@ViewScoped
@Named
public class Page {

    private String a;

    private String b;

    private String message;

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    public String getMessage() {
        return message;
    }

    public void populateA() {
        this.message = "Param a given: " + this.a;
    }

    public void populateB() {
        if (this.b != null) {
            this.message = "Param b given: " + this.b;
        }
    }
}

现在,区别在于a的处理不起作用(page.xhtml?a = 123),而b的处理就像魅力一样(page.xhtml?b = 123) - 尽管我认为我只是将旧的检查从Java移到了JSF。关于可读性,我宁愿在Java中省略额外的空值检查,并使视图参数处理完全位于JSF中,但是如何调整代码以使第一个场景有效?

编辑根据What is the purpose of rendered attribute on f:viewAction?接受的答案,if本身就有效,所以我怀疑执行顺序错误(首先评估行动条件,然后将值应用于模特)。

1 个答案:

答案 0 :(得分:6)

<f:viewAction if>属性基本上是重命名的<h:xxx rendered>属性(我会在中间离开,不管它是否更清楚,它至少有一个{{3}因此,它列出了rendered而不是if),因此在应用请求值阶段与所有其他UI组件一样具有完全相同的生命周期。此阶段调用视图中所有UI组件的UIComponent#decode()。对于bug in autogenerated documentation<f:viewAction>标记后面的UI组件类,UIViewAction描述如下:

  

如果满足以下任何条件,则不采取任何措施:

     
      
  • 当前请求是回发,并且实例已配置为不在回发上运行。请参阅decode()

  •   
  • if属性中声明的条件评估为false。请参阅isOnPostback()

  •   

所以,是的,你确实是对错误的执行顺序&#34;。在应用请求值阶段,它会检查if属性,如果它评估false,则解码不会发生,动作事件不会被取消排队。另请参阅UIViewAction isRendered()的第644行,其中isRendered() insice decode()测试false并且#{page.a}无法继续。在您的情况下,您在<f:viewAction if>中检查的#{param}仅在更新模型值阶段可用,该阶段之后 应用请求值阶段。

您希望测试在应用请求值阶段保证可用的其他内容。最佳候选者将是实际的请求参数本身。所有&#34;普通&#34;请求参数位于source code <f:viewParam name="a" value="#{page.a}"/> <f:viewAction action="#{page.populateA}" if="#{not empty param.a}"/> 的EL范围内,implicit EL object引用Map<String, String>并将参数名称作为键。

所以,总而言之,这应该做到:

<f:viewAction if>

更新以解决<o:viewAction>的不直观行为,JSF实用程序库OmniFaces将自2.2版开始提供ifUIViewAction在广播动作事件之前,在调用应用程序阶段进行评估。这个技巧是通过简单地扩展broadcast()组件并覆盖其isRendered()@Override public void broadcast(FacesEvent event) throws AbortProcessingException { if (super.isRendered()) { super.broadcast(event); } } @Override public boolean isRendered() { return !isImmediate() || super.isRendered(); } 来完成的,如下所示:

<f:viewParam name="a" value="#{page.a}"/>
<o:viewAction action="#{page.populateA}" if="#{not empty page.a}"/>

这使您可以更直观地使用标签:

{{1}}