2

这个问题是从对 JSF2 的部分回答中产生的:为什么复合中 panelGroup 呈现的空测试会阻止调用操作?

在下文中,元素是具有名称和 id 的 @Entity。view.xhtml JSF 页面将 id 作为 viewParam 并使用 @ManagedBean @RequestScoped ElementController 的 setID(Long id) 来触发从数据库中通过 id 加载相应的元素(这在问题中没有进一步的作用)并且发现元素设置为可用的“当前”元素(由于历史原因,名称略有不同),如 Element getSelected()。

view.xhtml 页面执行渲染属性测试#{not empty elementController.selected},并具有 ah:commandButton 和执行 faces-redirect 的操作,以及作为查询参数的 id,返回到 view.xhtml 页面。

出于某种原因,我不完全理解,在提交表单时,在应用请求阶段和流程验证阶段都会调用测试(因此 getSelected),然后才能设置 viewParam id(因此在当前/选定元素可以之前)被找到并设置)在更新模型值阶段。

大大缩写的 view.xhtml 页面是:

<f:view>
 <f:metadata>
    <f:viewParam name="id" value="#{elementController.id}"/>
 </f:metadata>
</f:view>
<h:body>   
 <h:form>
   <h:panelGroup rendered="#{not empty elementController.selected}">
       <h:outputText value="#{elementController.selected.name}"/>
   </h:panelGroup>

   <h:commandButton value="Apply" action="#{elementController.action}" />

 </h:form>
</h:body>

(上面失去了表单提交的意义,但对这个问题来说无所谓。)

ElementController 扩展了 RequestController:

public void setId(Long id) {
log_debug("setId","id",id);
if (id != null) {
    this.id = id;
    T found = (T) getAbstractFacade().find(id);
    if (found == null) {
        String $error = "No object with id(" + id + ") found for class " + getManagedClass().getSimpleName();
        log_error($error);
    }
    setCurrent(found);
 }
}

public T getSelected() {
  log_debug("getSelected","current",current);        
  if (current == null) {
    log_warn("getSelected","null current Element");
   }
 return current;
}

public Object action() {
    String $i = "action";
    log_debug($i);
    if (current==null) {
        log_warn($i, "can't generate action outcome for null current element");
        return null;
    }
    return "/view?faces-redirect=true&id="+current.getId();
 }

现在在提交表单时,getSelected() 碰巧被调用了两次,当 current==null 时,一次是在应用请求值阶段,一次是在流程验证阶段,因为之前的测试 #{not empty elementController.selected}由于 view.xhtml 中的 viewParam,可以设置 id(以及因此加载 Element 实体)。

问题是,为什么在应用请求阶段和流程验证阶段完全调用了 render=#{not empty elementController.selected} ?

当我使用 id 参数执行 view.xhtml 的初始 GET 加载时,不会在这些阶段调用它,仅在表单提交 POST 和后续重定向和 GET 期间调用。

4

1 回答 1

4

rendered回发后属性被查询两次或更多次的原因是因为 JSF 在每个阶段都会遍历组件树。

'rendered' 这个名字可能不是最好的名字,因为它不仅使渲染它应用的组件有条件,而且实际上通常处理它。

首先咨询“应用请求值”以查看是否应该处理该组件及其子组件以将这些请求值应用于它们。在“过程验证”中再次参考它,因为它的值可能在阶段之间发生了变化。

它不会在“在我执行初始 GET 加载时的那些阶段”被调用,因为当您执行 GET 时,不会在这些阶段遍历组件树(仅处理元数据,这就是视图参数被放入特殊的原因元数据部分)。

为了使id您从 GET 请求收到的内容在回发后在 action 方法中可用,您最好将视图范围 ( @ViewScoped) 用于您的支持 bean。

于 2012-04-01T12:20:17.640 回答