JSF:为什么在请求范围的POST REDIRECT GET下的表单提交期间,在应用请求值阶段调用呈现中的空测试



这个问题源于对JSF2的部分回答:为什么组合中panelGroup的呈现中的空测试会阻止调用操作?

在下面的例子中,Element是一个有名称和id的@Entity。view.xhtml JSF页面将id作为viewParam,并使用@ManagedBean@RequestScoped ElementController的setID(Long id)来触发从数据库中按id加载相应的Element(这在问题中没有起到进一步的作用),并且这个找到的Element被设置为可用的"当前"Element(由于历史原因,名称略有不同)作为Element getSelected()。

view.xhtml页面执行一个渲染属性测试#{not empty elementController.selected},并有一个h:commandButton,该按钮具有执行faces重定向的操作,以及作为查询参数的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},在设置id(从而加载Element实体)之前,由于view.xhtml中的viewParam。

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

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

回调后rendered属性被查询两次或两次以上的原因是JSF在每个阶段都遍历组件树。

名称"rendered"可能不是最好的名称,因为它不仅使其应用的组件的呈现成为条件,而且实际上通常会处理

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

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

为了使您从GET请求中收到的id在post-back之后的操作方法中可用,您最好使用backingbean的视图范围(@ViewScoped)。

最新更新