Статьи

JSF и «немедленный» атрибут — командные компоненты

Непосредственный атрибут в JSF обычно неправильно понимается. Если вы мне не верите, проверьте переполнение стека . Частичная путаница, вероятно, связана с тем, что они немедленно доступны как для входных (т.е. <h: inputText />), так и для командных (т. Е. <H: commandButton />) компонентов, каждый из которых по-разному влияет на жизненный цикл JSF.

Вот стандартный жизненный цикл JSF:

В этой статье я предполагаю, что вы знакомы с основами жизненного цикла JSF. Если вам нужно введение или обновление памяти, посмотрите Учебное пособие по Java EE 6 — Жизненный цикл приложения JavaServer Faces .

Примечание: примеры кода в этой статье предназначены для JSF 2 (Java EE 6), но принципы одинаковы для JSF 1.2 (Java EE 5).

немедленный = true для компонентов Command

В стандартном жизненном цикле JSF атрибут действия в компоненте Command оценивается на этапе вызова приложения . Например, скажем, у нас есть объект User / bean:

01
02
03
04
05
06
07
08
09
10
11
public class User implements Serializable {
 @NotBlank
 @Length(max = 50)
 private String firstName;
 
 @NotBlank
 @Length(max = 50)
 private String lastName;
 
 /* Snip constructors, getters/setters, a nice toString() method, etc */
}

И UserManager, который будет служить нашим управляемым компонентом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
@SessionScoped
@ManagedBean
public class UserManager {
 private User newUser;
 
 /* Snip some general page logic... */
 
 public String addUser() {
  //Snip logic to persist newUser
 
  FacesContext.getCurrentInstance().addMessage(null,
    new FacesMessage("User " + newUser.toString() + " added"));
 
  return "/home.xhtml";
 }

И базовая страница Facelets, newUser.xhtml , для визуализации представления:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<h:form>
 <h:panelGrid columns="2">
 
  <h:outputText value="First Name: " />
  <h:panelGroup>
   <h:inputText id="firstName"
    value="#{userManager.newUser.firstName}" />
   <h:message for="firstName" />
  </h:panelGroup>
 
  <h:outputText value="Last Name: " />
  <h:panelGroup>
   <h:inputText id="lastName" value="#{userManager.newUser.lastName}" />
   <h:message for="lastName" />
  </h:panelGroup>
 
 </h:panelGrid>
 
 <h:commandButton value="Add User" action="#{userManager.addUser()}" />
</h:form>

Которые все объединяются, чтобы произвести эту прекрасную форму:

Когда пользователь нажимает кнопку « Добавить пользователя» , на этапе Invoke Application будет вызван # {userManager.addUser} ; это имеет смысл, потому что мы хотим, чтобы поля ввода были проверены, преобразованы и применены к newUser до его сохранения.

Теперь давайте добавим кнопку «Отмена» на страницу, если пользователь передумает. Мы добавим еще одну <h: commandButton /> на страницу:

1
2
3
4
5
6
<h:form>
 <!-- Snip Input components -->
 
 <h:commandButton value="Add User" action="#{userManager.addUser()}" />
 <h:commandButton value="Cancel" action="#{userManager.cancel()}" />
</h:form>

И метод cancel () для UserManager :

1
2
3
4
5
6
7
8
public String cancel() {
 newUser = new User();
 
 FacesContext.getCurrentInstance().addMessage(null,
   new FacesMessage("Cancelled new user"));
 
 return "/home.xhtml";
}

Выглядит хорошо, правда? Но когда мы на самом деле пытаемся использовать кнопку отмены, мы получаем сообщения об ошибках, требующие ввода имени и фамилии:

Это связано с тем, что # {userManager.cancel} не вызывается до фазы вызова приложения , которая происходит после фазы проверки процесса ; так как мы не ввели имя и фамилию, проверки не прошли до вызова # {userManager.cancel} , а ответ будет обработан после фазы проверки процесса .

Мы, конечно, не хотим требовать от конечного пользователя ввести действительного пользователя перед отменой! К счастью, JSF предоставляет непосредственный атрибут для компонентов Command. Если для компонента Instant установлено значение true в компоненте Command, действие вызывается на этапе применения значений запроса :

Это идеально подходит для нашего варианта отмены. Если мы добавим немедленное = true в Cancel, # {userManager.cancel} будет вызван на этапе применения значений запроса , прежде чем произойдет какая-либо проверка.

1
2
3
4
5
6
<h:form
 <!-- Snip Input components -->
 
 <h:commandButton value="Add User" action="#{userManager.addUser()}" />
 <h:commandButton value="Cancel" action="#{userManager.cancel()}" immediate="true" />
</h:form>

Поэтому теперь, когда мы нажимаем кнопку «Отмена», на этапе « Применить значения запроса» вызывается # {userManager.cancel} , и мы возвращаемся на домашнюю страницу с ожидаемым сообщением об отмене; нет ошибок проверки!


А как насчет компонентов ввода?

Входные компоненты также имеют непосредственный атрибут, который также перемещает всю их логику в фазу Применить значения запроса . Однако поведение немного отличается от компонентов Command, особенно в зависимости от того, успешно ли выполнена проверка на компоненте Input. Моя следующая статья будет посвящена немедленному = true для компонентов ввода. На данный момент, вот предварительный просмотр того, как затрагивается жизненный цикл JSF: