Статьи

Как параметры просмотра получаются / прикрепляются из / к строке запроса URL (примеры)?

Давайте разберем несколько простых случаев использования и посмотрим, как работают параметры представления (имена параметров представления не обязательны для соответствия параметрам запроса, переданным через строку запроса URL, но в этом посте мы сосредоточимся на этом случае):

ДЕЛО 1

На странице index.xhtml мы имеем:

01
02
03
04
05
06
07
08
09
10
<f:metadata>
 <f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>          
 <f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
...
<h:form>
 Enter name:<h:inputText value="#{playersBean.playerName}"/>
 Enter surname:<h:inputText value="#{playersBean.playerSurname}"/>
 <h:commandButton value="Send" action="results?faces-redirect=true&includeViewParams=true"/>                
</h:form>

На странице results.xhtml мы имеем:

1
2
3
4
5
6
7
<f:metadata>
 <f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>          
 <f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
 
You requested name: <h:outputText value="#{playersBean.playerName}"/><br/>
You requested surname: <h:outputText value="#{playersBean.playerSurname}"/>

В PlayersBean мы имеем:

1
2
3
4
5
6
7
8
@Named
@RequestScoped
public class PlayersBean {
 
 private String playerName;
 private String playerSurname;
 ...
}

Что происходит, когда приложение достигает (не важно, как вы задали строку запроса; вы можете сделать это вручную или перейти через с участием здесь) index.xhtml?playernameparam=rafael&playersurnameparam=nadal ?

  1. Имена параметров запроса совпадают с именами параметров представления, поэтому параметры представления принимают значения параметров запроса и, наконец, сохраняют их в управляемом компоненте playerName под playerName и playerSurname . Таким образом, грубо говоря, вы устанавливаете поля управляемого компонента с помощью параметров просмотра.
  2. Представление отображается (HTML-разметка создается и отправляется в браузер), поэтому вы можете видеть rafael и nadal в текстовых входах, так как они выбираются из свойств управляемого компонента (это #{playersBean.playerName} и #{playersBean.playerSurname} ).
  3. Вы (как пользователь) можете вручную изменить эти значения (тексты) при вводе текста (или оставить их такими). Теперь, когда вы нажимаете на
    Кнопка Отправить, вы практически отправляете форму с текущими значениями (часть, разделенная <h:form>
    </h:form> ). Таким образом, имя и фамилия передаются и переопределяют / инициализируют текущие значения в модели данных (даже если вы их не изменяли). Во время кодирования (рендеринга) представления JSF будет кодировать параметры представления также в PlayersBean управляемого компонента PlayersBean .
  4. Кроме того, JSF замечает, что вы хотите присоединить параметры представления (вы сигнализируете это как: ?faces-redirect=true&amp;includeViewParams=true ) перед переходом на следующую целевую страницу ( results.xhtml ). Параметры представления были оценены PlayersBean управляемого компонента PlayersBean ранее в этом запросе. Итак, JSF обрабатывает параметры представления и присоединяет к URL действия соответствующую строку запроса, вычисленную из имен и значений параметров представления.
  5. JSF переходит к целевому URL (который теперь содержит строку запроса). Это видно благодаря faces-redirect=true .

ДЕЛО 2

На странице index.xhtml мы имеем:

01
02
03
04
05
06
07
08
09
10
<f:metadata>
 <f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>          
 <f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
 
<h:form>
 Enter name:<h:inputText value="#{playersBean.playerName}"/>
 Enter surname:<h:inputText value="#{playersBean.playerSurname}"/>
 <h:commandButton value="Send" action="results?faces-redirect=true&includeViewParams=true"/>                
</h:form>

На странице results.xhtml мы имеем:

1
2
3
4
5
6
7
<f:metadata>
 <f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>          
 <f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
 
You requested name: <h:outputText value="#{playersBean.playerName}"/><br/>
You requested surname: <h:outputText value="#{playersBean.playerSurname}"/>

В PlayersBean мы имеем:

1
2
3
4
5
6
7
8
@Named
@RequestScoped
public class PlayersBean {
 
 private String playerName = "roger";
 private String playerSurname = "federer";
 ...
}

Что происходит, когда приложение попадает в index.xhtml? (без строки запроса)

  1. Нет строки запроса (нет параметров запроса). Таким образом, параметры представления не могут быть инициализированы из строки запроса, и они также ничего не устанавливают в PlayersBean !
  2. Представление отображается (HTML-разметка создается и отправляется в браузер), а текстовые вводы отражают
    данные federer initalization и federer initalization (это результат оценки #{playersBean.playerName} и #{playersBean.playerSurname} ).
  3. Вы (как пользователь) можете изменять эти значения при вводе текста (или нет!). Теперь, когда вы нажимаете кнопку « Send , вы практически отправляете форму (данные, принадлежащие части, разделенной <h:form>
    </h:form> ). Итак, имя и фамилия передаются и переопределяют / инициализируют текущие значения в модели (даже если вы их не изменяли). Во время кодирования (рендеринга) представления JSF будет кодировать параметры представления также в PlayersBean управляемого компонента PlayersBean .
  4. Кроме того, JSF замечает, что вы хотите присоединить параметры представления (вы сигнализируете это как: ?faces-redirect=true&amp;includeViewParams=true ) перед переходом на следующую целевую страницу ( results.xhtml ). Параметры представления были оценены PlayersBean управляемого компонента PlayersBean ранее в этом запросе. Итак, JSF обрабатывает параметры представления и присоединяет к URL действия соответствующую строку запроса, вычисленную из имен и значений параметров представления.
  5. JSF переходит к целевому URL (который теперь содержит строку запроса). Это видно благодаря faces-redirect=true .

ДЕЛО 3

На странице index.xhtml мы имеем:

1
2
3
4
5
6
<f:metadata>
 <f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>          
 <f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
 
<h:link value="Send" outcome="results" includeViewParams="true"/>

На странице results.xhtml мы имеем:

1
2
3
4
5
6
7
<f:metadata>
 <f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>          
 <f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
 
You requested name: <h:outputText value="#{playersBean.playerName}"/><br/>
You requested surname: <h:outputText value="#{playersBean.playerSurname}"/>

В PlayersBean мы имеем:

1
2
3
4
5
6
7
8
@Named
@RequestScoped
public class PlayersBean {
 
 private String playerName;
 private String playerSurname;
 ...
}

Что происходит, когда приложение достигает (не важно, как вы задали строку запроса; вы можете сделать это вручную или перейти через с участием здесь) index.xhtml?playernameparam=rafael&playersurnameparam=nadal ?

  1. Имена параметров запроса совпадают с именами параметров представления, поэтому параметры представления принимают значения параметров запроса и сохраняют их в управляемом компоненте в playerName и playerSurname . Итак, вы устанавливаете поля управляемого компонента через параметры просмотра.
  2. Представление отображается (разметка HTML генерируется и отправляется в браузер), поэтому в текстовых входах вы можете видеть rafael и nadal , так как они выбираются из управляемого компонента (это результаты оценки #{playersBean.playerName} и #{playersBean.playerSurname} ). Во время кодирования (рендеринга) представления JSF будет кодировать параметры представления также в PlayersBean управляемого компонента PlayersBean . Теперь проверьте исходный код страницы и обратите внимание, что <a href> соответствующий <h:link> был сгенерирован, как <a href> ниже (обратите внимание, что это fix ! ). Итак, JSF преобразует <h:link> в <a href> и присоединяет строку запроса, содержащую параметры представления, прямо из исходного запроса. includeViewParams="true" вызывает ссылку ниже:
  3. Когда вы нажимаете на ссылку, вы НЕ ПРЕДОСТАВЛЯЕТЕ никаких данных ( <h:link> никогда не должна быть в <h:form> ). Вы просто выполняете приведенный выше статический HTML-код, который представляет собой простой запрос GET!
  4. JSF переходит к целевому URL через этот GET (который содержит строку запроса). Нет необходимости в faces-redirect=true .

ДЕЛО 4

На странице index.xhtml мы имеем:

1
2
3
4
5
6
<f:metadata>
 <f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>          
 <f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
 
<h:link value="Send" outcome="results" includeViewParams="true"/>

На странице results.xhtml мы имеем:

1
2
3
4
5
6
7
<f:metadata>
 <f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>          
 <f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
 
You requested name: <h:outputText value="#{playersBean.playerName}"/><br/>
You requested surname: <h:outputText value="#{playersBean.playerSurname}"/>

В PlayersBean мы имеем:

1
2
3
4
5
6
7
8
@Named
@RequestScoped
public class PlayersBean {
 
 private String playerName = "roger";
 private String playerSurname = "federer";
 ...
}

Что происходит, когда приложение попадает в index.xhtml? (без строки запроса)

  1. Нет параметров запроса. Таким образом, параметры представления не могут быть инициализированы из строки запроса. Параметры вида также ничего не устанавливают в управляемом бине!
  2. Представление отображается (разметка HTML создается и отправляется в браузер), поэтому вы можете видеть roger и federer в текстовых входах, так как они выбираются из управляемого компонента (это результат оценки #{playersBean.playerName} и #{playersBean.playerSurname} ). Во время кодирования (рендеринга) представления JSF будет кодировать параметры представления также в PlayersBean управляемого компонента PlayersBean (получение roger и federer ). Теперь проверьте исходный код страницы и обратите внимание, что <a href> соответствующий <h:link> был сгенерирован, как <a href> ниже (обратите внимание, что это fix ! ). Итак, JSF преобразует <h:link> в <a href> и присоединяет строку запроса, содержащую параметры представления, прямо из исходного запроса. includeViewParams="true" вызывает ссылку ниже:
  3. Когда вы нажимаете на ссылку, вы не предоставляете никаких данных. Вы просто выполняете приведенный выше статический HTML-код, который представляет собой простой запрос GET!
  4. JSF переходит к целевому URL через этот GET (который содержит строку запроса). Там нет необходимости
    faces-redirect=true .

ДЕЛО 5

На странице index.xhtml мы имеем:

1
2
3
4
5
6
<f:metadata>
 <f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>          
 <f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
 
<h:link value="Send" outcome="results" includeViewParams="true"/>

На странице results.xhtml мы имеем:

1
2
3
4
5
6
7
<f:metadata>
 <f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>          
 <f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
 
You requested name: <h:outputText value="#{playersBean.playerName}"/><br/>
You requested surname: <h:outputText value="#{playersBean.playerSurname}"/>

В PlayersBean мы имеем:

1
2
3
4
5
6
7
8
@Named
@RequestScoped
public class PlayersBean {
 
 private String playerName;     // this is null
 private String playerSurname;  // this is null
 ...
}

Что происходит, когда приложение попадает в index.xhtml? (без строки запроса)

  1. Нет параметров запроса. Таким образом, параметры представления не могут быть инициализированы из строки запроса. Параметры вида ничего не устанавливают в bean-компоненте!
  2. Представление отображается (HTML-разметка создается и отправляется в браузер), поэтому в текстовых входах ничего не видно, так как они выбираются из компонента (это #{playersBean.playerName} и #{playersBean.playerSurname} которые являются null — вы не можете ожидать увидеть текст null! ). Во время кодирования (рендеринга) представления JSF будет кодировать параметры представления также в PlayersBean управляемого компонента PlayersBean (получение null ). Теперь проверьте исходный код страницы и обратите внимание, что <a href> соответствующий <h:link> был сгенерирован, как <a href> ниже (обратите внимание, что это fix ! ). Итак, JSF преобразует <h:link> в <a href> , но нет строки запроса, содержащей параметры представления, потому что JSF видит includeViewParams="true" , но он не может сгенерировать этот HTML: <a href = ” /…/results.xhtml? playernameparam = null & amp; Playersurnameparam = null «> Отправить </a> Итак, JSF будет« игнорировать » null значения и нет строки запроса для прикрепления: <a href=oted/…/results.xhtml книг> Отправить </a>
  3. Когда вы нажимаете на ссылку, вы не предоставляете никаких данных. Вы просто выполняете приведенный выше статический HTML-код, который представляет собой простой запрос GET!
  4. JSF переходит к целевому URL через этот GET (который содержит строку запроса). Нет необходимости в face-redirect = true.

Случай 6 — для лучшего понимания нулевых значений

На странице index.xhtml мы имеем:

01
02
03
04
05
06
07
08
09
10
<f:metadata>
 <f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>          
 <f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
 
<h:form>
 Enter name:<h:inputText value="#{playersBean.playerName}"/>
 Enter surname:<h:inputText value="#{playersBean.playerSurname}"/>
 <h:commandButton value="Send" action="results?faces-redirect=true&includeViewParams=true"/>                
</h:form>

На странице results.xhtml мы имеем:

1
2
3
4
5
6
7
<f:metadata>
 <f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>          
 <f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
 
You requested name: <h:outputText value="#{playersBean.playerName}"/><br/>
You requested surname: <h:outputText value="#{playersBean.playerSurname}"/>

В PlayersBean мы имеем:

1
2
3
4
5
6
7
8
@Named
@RequestScoped
public class PlayersBean {
 
 private String playerName;     // this is null
 private String playerSurname;  // this is null
 ...
}

Что происходит, когда приложение попадает в index.xhtml? (без строки запроса)

  1. Нет параметров запроса. Таким образом, параметры представления не могут быть инициализированы из строки запроса. Параметры вида также ничего не устанавливают в bean-компоненте!
  2. Представление отображается (HTML-разметка создается и отправляется в браузер), и вы можете видеть два пустых текстовых ввода (это результаты оценки #{playersBean.playerName} и #{playersBean.playerSurname} ). Вы не можете ожидать увидеть текст, ноль!
  3. Как пользователь, не вводите ничего в эти текстовые поля и нажмите кнопку « Send . Практически вы отправите форму (данные, принадлежащие части, разделенной <h:form> </h:form> ). Итак, имя и фамилия (которые являются пустыми местами) передаются и переопределяют / инициализируют текущие значения в модели. Во время кодирования (рендеринга) представления JSF будет кодировать параметры представления также PlayersBean управляемого компонента PlayersBean (получит пустые места).
  4. Кроме того, JSF замечает, что вы хотите присоединить параметры представления (вы сигнализируете это как: ?faces-redirect=true&amp;includeViewParams=true ) перед переходом на следующую целевую страницу ( results.xhtml ). Параметры представления были оценены PlayersBean управляемого компонента PlayersBean ранее в этом запросе. Итак, JSF обрабатывает параметры представления и присоединяет к URL действия соответствующую строку запроса, вычисленную из имен и значений параметров представления.
  5. JSF переходит к целевому URL (который теперь содержит строку запроса). Это видно благодаря faces-redirect=true .

http://localhost:8080/.../results.xhtml?playernameparam=&playersurnameparam=

Обратите внимание на значения playernameparam и playersurnameparam! Так как вы отправили пустые места, это то, что вы увидите. Конечно, это выглядит «некрасиво» и довольно бесполезно. Может быть, вы предпочтете рассматривать пустые места как null значения. Для этого вы можете установить в web.xml следующий параметр контекста:

1
2
3
4
<context-param>
 <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
 <param-value>true</param-value>
</context-param>

Теперь очистите и соберите приложение и запустите его снова с тем же сценарием. На этот раз, когда вы нажимаете на
Кнопка Отправить, вы заметили эту ссылку:

  • HTTP: // локальный: 8080 / ch2_6 / лица / results.xhtml

Таким образом, ни одна строка запроса не отражает наличие параметров вида! Ну, вы только что проинструктировали JSF обрабатывать отправленную пустую строку как null значения Но, как вы знаете, null значения «игнорируются», когда параметры вида прикреплены.

НОТА

Способ прикрепления параметров представления можно увидеть в Mojarra, в com.sun.faces.application.view.MultiViewHandler . Особенно в:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Mojarra 2.2.9, MultiViewHandler#addViewParameters()
protected void addViewParameters(FacesContext ctx,
                                     String viewId,
                                     Map<String,List<String>> existingParameters) {
 
 UIViewRoot currentRoot = ctx.getViewRoot();
 String currentViewId = currentRoot.getViewId();
 Collection<UIViewParameter> toViewParams = Collections.emptyList();
 Collection<UIViewParameter> currentViewParams;
 boolean currentIsSameAsNew = false;
 currentViewParams = ViewMetadata.getViewParameters(currentRoot);
 
 if (currentViewId.equals(viewId)) {
     currentIsSameAsNew = true;
     toViewParams = currentViewParams;
 } else {
     ViewDeclarationLanguage pdl = getViewDeclarationLanguage(ctx, viewId);
     ViewMetadata viewMetadata = pdl.getViewMetadata(ctx, viewId);
     if (null != viewMetadata) {
         UIViewRoot root = viewMetadata.createMetadataView(ctx);
         toViewParams = ViewMetadata.getViewParameters(root);
     }
 }
 
 if (toViewParams.isEmpty()) {
     return;
 }
 
 for (UIViewParameter viewParam : toViewParams) {
      String value = null;
      // don't bother looking at view parameter if it's been overridden
      if (existingParameters.containsKey(viewParam.getName())) {
          continue;
      }
          
      if (paramHasValueExpression(viewParam)) {
          value = viewParam.getStringValueFromModel(ctx);
      }
 
      if (value == null) {
          if (currentIsSameAsNew) {
              value = viewParam.getStringValue(ctx);
          } else {
              value = getStringValueToTransfer(ctx, viewParam, currentViewParams);
          }
      }
            
      // SO, IF VALUE IS NULL, DON'T CONSIDER THIS A VIEW PARAM
      if (value != null) {
          List<String> existing = existingParameters.get(viewParam.getName());
          if (existing == null) {
              existing = new ArrayList<String>(4);
              existingParameters.put(viewParam.getName(), existing);
          }
          existing.add(value);
      }
 }
}