JSF: почему пустой тест в отображаемом файле вызывается во время фазы применения значений запроса во время отправки формы в области запроса POST REDIRECT GET

Этот вопрос порожден частичным ответом на JSF2: почему пустой рендеринг в рендеринге PanelGroup в составной части предотвращает вызов действия?

В следующем элементе является @Entity с именем и идентификатором. JSF-страница view.xhtml принимает идентификатор в качестве viewParam и использует setID(Long id) @ManagedBean @RequestScoped ElementController для запуска загрузки соответствующего элемента по id из базы данных (что не играет никакой дальнейшей роли в вопросе), и это находит Элемент устанавливается как "текущий" элемент, доступный (по историческим причинам под немного другим именем) как элемент getSelected().

Страница view.xhtml выполняет визуализированный атрибут test #{not empty elementController.selected} и имеет a h:commandButton с действием, которое выполняет перенаправление граней, вместе с id в качестве параметра запроса, обратно на страницу view.xhtml.

По какой-то причине я не до конца понимаю, что при отправке формы тест (и, следовательно, getSelected) вызывается как на этапе применения запроса, так и на этапе проверки процесса до того, как может быть установлен идентификатор viewParam (и, следовательно, до того, как текущий / выбранный элемент может быть найдены и установлены) на этапе обновления значений модели.

Очень сокращенная страница 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} перед установка идентификатора (и, следовательно, загрузка сущности Element) может происходить благодаря viewParam в view.xhtml.

Вопрос в том, почему rendered=#{not empty elementController.selected} вообще вызывается на этапе применения запроса и на этапе проверки процесса?

Он не вызывается во время этих фаз, когда я выполняю начальную загрузку GET файла view.xhtml с параметром id, только во время отправки формы POST и последующего перенаправления и GET.

1 ответ

Решение

Причина в том, что rendered Атрибут используется дважды или более после того, как сообщение вернулось, потому что JSF пересекает дерево компонентов в каждой фазе.

Имя 'rendered', возможно, не самое лучшее имя, так как оно не только делает рендеринг компонента, к которому он применяется, условным, но и фактически обрабатывает его в целом.

Прежде всего, обращаются за "применением значений запроса", чтобы увидеть, следует ли обрабатывать этот компонент и его дочерние элементы, чтобы применить к ним эти значения запроса. С ним снова обращаются в "проверках процесса", поскольку его значение могло меняться между фазами.

Он не вызывается "во время тех фаз, когда я выполняю начальную загрузку GET", потому что, когда вы выполняете GET, дерево компонентов не просматривается на этих фазах (обрабатываются только метаданные, поэтому параметры представления помещаются в специальный раздел метаданных).

Для того, чтобы сделать id что вы получили из GET-запроса, доступного в методе действия после публикации, лучше всего использовать область просмотра (@ViewScoped) для вашего бобов.

Другие вопросы по тегам