ExternalContext#redirect() с includeViewParams=true

Использование списка валют в виде строк осуществляется следующим образом.

<p:selectOneMenu id="currency"
                 value="#{currencyRateBean.currency}"
                 onchange="changeCurrency([{name: 'currency', value: this.value}]);">

    <f:selectItems var="row"
                   value="#{currencyBean.currencies}"
                   itemLabel="#{row}"
                   itemValue="#{row}"/>
</p:selectOneMenu>

Вдоль <p:remoteCommand>,

<p:remoteCommand ignoreAutoUpdate="true"
                 name="changeCurrency"
                 partialSubmit="true"
                 process="@this"
                 update="@none"
                 action="#{currency.currencyAction}"/>

Управляемый bean-компонент, задающий значение валюты, передаваемое через <p:remoteCommand> в качестве параметра для функции JavaScript.

@Named
@RequestScoped
public class Currency {

    @Inject
    @HttpParam
    private String currency;

    @Inject
    private CurrencyRateBean currencyRateBean;

    public Currency() {}

    public String currencyAction() throws MalformedURLException, IOException {

        try (Scanner scanner = new Scanner(new URL("http://www.exchangerate-api.com/INR/" + currency + "/1?k=FQRxs-xT2tk-NExQj").openConnection().getInputStream(), "UTF-8");) {
            currencyRateBean.setCurrencyRate(scanner.nextBigDecimal());
            currencyRateBean.setCurrency(currency);
        } catch (UnknownHostException | ConnectException e) {}

        return FacesContext.getCurrentInstance().getViewRoot().getViewId() + "?faces-redirect=true&includeViewParams=true";
    }
}

Предоставленное значение валюты затем устанавливается на другой управляемый бин в рамках сеанса CurrencyRateBean изнутри метода действия currencyAction() выше которого, наконец, делает перенаправление на основе текущего значения viewId вместе с includeViewParams=true что важно


Теперь история меняется, когда #{currencyRateBean.currencies} был изменен, чтобы иметь список составных объектов, который до сих пор был списком строк.

Следующий сценарий не будет работать с includeViewParams=true что важно.

<p:selectOneMenu value="#{currencyRateBean.currencyHolder}">

    <f:selectItems var="row" value="#{currencyBean.currencies}"
                   itemLabel="#{row.currency}"
                   itemValue="#{row}"/>

    <p:ajax event="change"
            listener="#{currency.currencyAction}"
            partialSubmit="true"
            process="@this"
            update="@none"/>
</p:selectOneMenu>
public void currencyAction()  throws IOException {
    // ...
    FacesContext facesContext = FacesContext.getCurrentInstance();
    String viewId = facesContext.getViewRoot().getViewId();

    ExternalContext externalContext = facesContext.getExternalContext();
    externalContext.redirect(externalContext.getRequestContextPath() + viewId + "?includeViewParams=true");
}

includeViewParams=true был добавлен только для украшения. Это не сработает.

поскольку listener в <p:ajax> неспособен сделать переадресацию на основе результатов случая навигации, как это сделано action из <p|h:commandXxx>, ExternalContext#redirect() должен быть использован в любом случае.

<p:remoteCommand> может быть использован на полной <p:ajax> но это потребует двух циклов обращения к серверу без необходимости: сначала установить значение валюты для соответствующего управляемого компонента, а затем выполнить перенаправление.

Как сделать редирект с includeViewParams=true в приведенном примере?

1 ответ

Решение

Подобно faces-redirect=true, includeViewParams=true работает только в результатах навигации, а не в "простых" URL, которые вы передаете ExternalContext#redirect(),

использование NavigationHandler#handleNavigation(),

FacesContext context = FacesContext.getCurrentInstance();
String outcome = viewId + "?includeViewParams=true";
context.getApplication().getNavigationHandler().handleNavigation(context, null, outcome);

Или с помощью OmniFaces.

Faces.navigate(viewId + "?includeViewParams=true");

Сомнительная альтернатива - собрать все параметры просмотра самостоятельно и преобразовать их в строку запроса, чтобы вы могли использовать ExternalContext#redirect() тем не мение. Это проще с OmniFaces.

Faces.redirect(viewId + "?" + Servlets.toQueryString(Faces.getViewParameterMap()));
Другие вопросы по тегам