这个问题是从对 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 期间调用。