Для чего можно использовать ‹f:metadata›, ‹f:viewParam› и ‹f:viewAction›?

Может ли кто-нибудь пояснить, как мы можем использовать этот фрагмент в целом или в реальном мире?

<f:metadata>
    <f:viewParam id="id" value="#{bean.id}" />
    <f:viewAction action="#{bean.init}" />
</f:metadata>

person Hanynowsky    schedule 16.06.2011    source источник


Ответы (2)


Обработать параметры GET

<f:viewParam> управляет установка, преобразование и проверка параметров GET. Это как <h:inputText>, но тогда для параметров GET.

Следующий пример

<f:metadata>
    <f:viewParam name="id" value="#{bean.id}" />
</f:metadata>

делает в основном следующее:

  • Получите значение параметра запроса по имени id.
  • Преобразуйте и проверьте его, если необходимо (вы можете использовать атрибуты required, validator и converter и вложить в него <f:converter> и <f:validator>, как с <h:inputText>)
  • Если преобразование и проверка прошли успешно, установите его как свойство компонента, представленное значением #{bean.id}, или, если атрибут value отсутствует, установите его как атрибут запроса с именем id, чтобы он был доступен #{id} в представлении.

Поэтому, когда вы открываете страницу как foo.xhtml?id=10, значение параметра 10 устанавливается в bean-компоненте таким образом, прямо перед визуализацией представления.

Что касается проверки, в следующем примере для параметра устанавливается значение required="true" и допускаются только значения от 10 до 20. Любая ошибка проверки приведет к отображению сообщения.

<f:metadata>
    <f:viewParam id="id" name="id" value="#{bean.id}" required="true">
        <f:validateLongRange minimum="10" maximum="20" />
    </f:viewParam>
</f:metadata>
<h:message for="id" />

Выполнение бизнес-действия с параметрами GET

Вы можете использовать <f:viewAction> для этого.

<f:metadata>
    <f:viewParam id="id" name="id" value="#{bean.id}" required="true">
        <f:validateLongRange minimum="10" maximum="20" />
    </f:viewParam>
    <f:viewAction action="#{bean.onload}" />
</f:metadata>
<h:message for="id" />

с участием

public void onload() {
    // ...
}

Однако <f:viewAction> является новым с JSF 2.2 (<f:viewParam> уже существует с JSF 2.0). Если вы не можете выполнить обновление, лучше всего использовать <f:event> вместо этого.

<f:event type="preRenderView" listener="#{bean.onload}" />

Однако это вызывается при каждом запросе. Вам нужно явно проверить, не является ли запрос обратной передачей:

public void onload() {
    if (!FacesContext.getCurrentInstance().isPostback()) {
        // ...
    }
}

Если вы хотите также пропустить случаи сбоя преобразования/проверки, сделайте следующее:

public void onload() {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    if (!facesContext.isPostback() && !facesContext.isValidationFailed()) {
        // ...
    }
}

Использование <f:event> таким образом, по сути, является обходным путем/хаком, именно поэтому <f:viewAction> был введен в JSF 2.2.


Передать параметры вида в следующий вид

Вы можете передать параметры просмотра в навигационных ссылках, установив для атрибута includeViewParams значение true или добавив параметр запроса includeViewParams=true.

<h:link outcome="next" includeViewParams="true">
<!-- Or -->
<h:link outcome="next?includeViewParams=true">

который генерирует с приведенным выше примером <f:metadata> в основном следующую ссылку

<a href="next.xhtml?id=10">

с исходным значением параметра.

Этот подход только требует, чтобы next.xhtml имел также <f:viewParam> для того же самого параметра, иначе он не будет передан.


Используйте формы GET в JSF

<f:viewParam> также можно использовать в сочетании с простыми HTML-формами GET.

<f:metadata>
    <f:viewParam id="query" name="query" value="#{bean.query}" />
    <f:viewAction action="#{bean.search}" />
</f:metadata>
...
<form>
    <label for="query">Query</label>
    <input type="text" name="query" value="#{empty bean.query ? param.query : bean.query}" />
    <input type="submit" value="Search" />
    <h:message for="query" />
</form>
...
<h:dataTable value="#{bean.results}" var="result" rendered="#{not empty bean.results}">
     ...
</h:dataTable>

В основном с этим компонентом @RequestScoped:

private String query;
private List<Result> results;

public void search() {
    results = service.search(query);
}

Обратите внимание, что <h:message> соответствует <f:viewParam>, а не простому HTML <input type="text">! Также обратите внимание, что входное значение отображает #{param.query}, когда #{bean.query} пусто, потому что в противном случае отправленное значение вообще не будет отображаться при ошибке проверки или преобразования. Обратите внимание, что эта конструкция недействительна для компонентов ввода JSF (она уже делает это скрыто).


Смотрите также:

person BalusC    schedule 16.06.2011
comment
@BalusC Какой должна быть область действия bean-компонента при использовании в сочетании с face-redirect=true ? Будет ли это работать должным образом, если для области задано значение @RequestScoped? - person Geek; 06.11.2012
comment
@Geek: перенаправление создает новый запрос GET. Область действия исходного и целевого компонентов значения не имеет. Однако вы должны принять во внимание возможные последствия нового запроса GET для запроса и просмотра компонента с областью действия. См. также stackoverflow .com/questions/7031885/ - person BalusC; 06.11.2012
comment
@BalusC Что именно вы подразумеваете под тем, что вы должны принять во внимание возможные последствия нового запроса GET для запроса и просмотра bean-компонента с областью действия. - person Geek; 06.11.2012
comment
@Geek: Они будут удалены и созданы заново, потому что их область действия будет заканчиваться и начинаться. - person BalusC; 06.11.2012
comment
@BalusC. Исчерпывающий ответ. Если вам нужно использовать функцию, подобную '@'PostConstruct, для bean-компонентов с областью видимости, которая не вызывается при каждом запросе, проверьте, не является ли запрос обратной передачей. Если он не вызывается при каждом запросе, то зачем проверять, является ли запрос обратной передачей или нет? - person Uluk Biy; 06.02.2013
comment
@UlukBiy: где вы прочитали, что <f:event type="preRenderView"> не вызывается при каждом запросе? Он вызывается при каждом запросе. - person BalusC; 06.02.2013
comment
Я процитировал ваш ответ выше в моем предыдущем комментарии. Я имел в виду, если '@'PostConstruct был помещен в метод init(), упомянутый в ответе, тогда нам все равно нужно было проверить FacesContext.isPostback()? - person Uluk Biy; 06.02.2013
comment
@UlukBiy: я думаю, вы перепутали их обоих. @PostConstruct bean-компонента с областью видимости не вызывается при каждом запросе. - person BalusC; 06.02.2013
comment
Обратите внимание, что было изменено пространство имен для ‹f:viewAction›, и это относится только к последней версии JSF и т. д. См.: stackoverflow.com/questions/6377798/ - person Darrell Teague; 13.12.2013
comment
@BalusC относительно этой части, если атрибут value отсутствует, установите его как атрибут запроса для имени id, чтобы он был доступен #{id} в представлении., вы говорите об использовании тега c:set? (Я не вижу точного значения, наверное, меня смущает #{param.id} ) - person Tarik; 07.03.2015
comment
@BalusC Для JSF 2.1 я использовал <f:event type="preRenderView" listener="#{bean.onload}" /> для доступа к параметру представления в onload после удаления @PostContruct из onload. У меня есть раскрывающийся список на странице (не ajax, так как я собираюсь отправить изменение при отправке). При отправке страницы (перенаправление) измененное значение этого раскрывающегося списка сбрасывается до значения по умолчанию (первый элемент), я вижу, что установщик раскрывающегося списка вызывается дважды. Во-первых, за изменение, внесенное пользователем, а во-вторых, за его автоматический сброс, как я уже сказал. Когда я снова возвращаюсь к @PostConstruct, все становится нормально. Сеттер вызывается только один раз для последнего выбора пользователя. Что я могу здесь сделать? - person user2918640; 04.04.2016
comment
Этот раздел предназначен для комментариев к ответу, а не для дополнительных / оффтопных вопросов. Для этого нажмите кнопку «Задать вопрос» справа вверху. - person BalusC; 04.04.2016
comment
@BalusC Извините, я задал это как новый вопрос здесь .com/questions/36402368/ - person user2918640; 04.04.2016
comment
@BalusC: действие просмотра также имеет возможности навигации, а прослушиватель событий preRenderView - нет. В то время как действие представления может естественным образом выполнять задачи навигации (возвращать идентификатор представления из метода действия и происходит перенаправление), прослушиватель событий preRenderView требует явной навигации на основе JSF API (я имею в виду использование ConfigurableNavigationHandler). Вы должны знать это очень хорошо. Я имею в виду, что вы можете включить это тоже в свой ответ. - person Farhan Shirgill Ansari; 19.04.2016

Отправлять параметры из представления в другое представление, из представления отправителя в представление получателя использовать viewParam и includeViewParams=true

В отправителе

  1. Объявить параметры для отправки. Мы можем отправить строку, объект,…

Отправитель.xhtml

<f:metadata>
      <f:viewParam name="ID" value="#{senderMB._strID}" />
</f:metadata>
  1. Мы собираемся отправить идентификатор параметра, он будет включен с “includeViewParams=true” в ответ Строка события нажатия кнопки Нажмите кнопку запуска senderMB.clickBtnDetail(dto) с dto от senderMB._arrData

Отправитель.xhtml

<p:dataTable rowIndexVar="index" id="dataTale"value="#{senderMB._arrData}" var="dto">
      <p:commandButton action="#{senderMB.clickBtnDetail(dto)}" value="見る" 
      ajax="false"/>
</p:dataTable>

В senderMB.clickBtnDetail(dto) мы назначаем _strID с аргументом, который мы получили из события кнопки (dto), здесь это Sender_DTO и назначаем senderMB._strID

Sender_MB.java
    public String clickBtnDetail(sender_DTO sender_dto) {
        this._strID = sender_dto.getStrID();
        return "Receiver?faces-redirect=true&includeViewParams=true";
    }

Ссылка при нажатии станет http://localhost:8080/my_project/view/Receiver.xhtml?*ID=12345*

В ресивере

  1. Get viewParam Receiver.xhtml В Receiver мы объявляем f:viewParam для получения параметра из запроса на получение (получение), имя параметра получателя должно совпадать с отправителем (страницей)

Receiver.xhtml

<f:metadata><f:viewParam name="ID" value="#{receiver_MB._strID}"/></f:metadata>

Он получит идентификатор параметра из представления отправителя и назначит его параметру Receiver_MB._strID.

  1. Использовать viewParam В Receiver мы хотим использовать этот параметр в sql-запросе до рендеринга страницы, чтобы мы использовали событие preRenderView. Мы не собираемся использовать конструктор, потому что конструктор будет вызываться до того, как будет получен viewParam.

Receiver.xhtml

<f:event listener="#{receiver_MB.preRenderView}" type="preRenderView" />

в тег метаданных f:

Receiver.xhtml

<f:metadata>
<f:viewParam name="ID" value="#{receiver_MB._strID}" />
<f:event listener="#{receiver_MB.preRenderView}"
            type="preRenderView" />
</f:metadata>

Теперь мы хотим использовать этот параметр в нашем методе чтения базы данных, он доступен для использования

Receiver_MB.java
public void preRenderView(ComponentSystemEvent event) throws Exception {
        if (FacesContext.getCurrentInstance().isPostback()) {
            return;
        }
        readFromDatabase();
    }
private void readFromDatabase() {
//use _strID to read and set property   
}
person vuvo    schedule 12.09.2020