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
) для вашего бобов.