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()));