I'm changing an application so that it stops being cached, using cache-control parameters to the requests' headers to achieve this. Unfortunately this resulted in "Confirm form resubmission" messages whenever I submit a form and press the Back button, which is a big NO...
I've been reading about Form Resubmission and Post-Redirect-Get but I'm still struggling with this.
In most navigation cases I have 2 pages:
page1 contains the form AND (after submitting the form) the results, it's used twice.
page2 shows details of the result clicked by the user.
The beans are RequestScoped and navigation from page1 to page2 is made like this:
'''
<h:dataTable value="#{page1.resultTable}">
<h:column>
<h:commandLink action="#{page2.getById(resultTable.id)}">
<h:outputText value="#{resultTable.id}"/>
</h:commandLink>
</h:column>
(...)
'''
After using PRG, the resultTable.id became null on page2 loading. I solved this using Flash Scope, but the issue with the page1 remains, when going back from page2.
Is there a safe and elegant way to keep page1's data after visiting page2, keeping in mind that it contains sensitive information (financial app)?
All pages are based on a template.xhtml that contains a back-button, and their respective beans are implementation classes of a templateInterface. I thought I could use an "elegant" solution by having custom code on template.xhtml's back-button that would use Flash Scope again to load the data in the previously-visited bean. However, once I click the back button, I immediately get the missing cache message.
I did manage to automatically refresh the previously visited page by including js "window.history.replaceState( null, null, window.location.href )" but all the form data is lost by doing so... Is this there a better solution?
EDIT:
page1.xhtml looks like this:
<?xml version='1.0' encoding='UTF-8' ?>
<ui:composition xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
template="/WEB-INF/templates/transaction-template.xhtml"
xmlns:t="http://myfaces.apache.org/tomahawk"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:components="http://java.sun.com/jsf/composite/components">
<ui:define name="mainContent">
<h:form id="form">
<h:inputHidden id="_itemId" value="#{listItem.itemId}" />
<fieldset class="fieldsetTransaction">
<table class="formTransaction">
<tr>
<td class="labelsCol">
<h:outputText value="#{labels.itemId}" />
</td>
<td class="valuesCol">
<h:inputText value="#{listItem.itemId}" />
</td>
</tr>
<tr>
<td class="labelsCol">
<h:outputText value="#{labels.itemName}" />
</td>
<td class="valuesCol">
<h:inputText value="#{listItem.itemName}" />
</td>
</tr>
<tr class="formActions">
<td colspan="4">
<h:commandButton value="#{labels.search}"
title="#{labels.search}"
type="submit"
id="search"
action="#{listItem.list()}"
styleClass="default formButton">
<f:ajax execute="@form" render="resultPanel"/>
</h:commandButton>
</td>
</tr>
</table>
</fieldset>
<h:panelGroup id="resultPanel">
<fieldset class="fieldsetTransaction">
<h:dataTable value="#{listItem.listReply.itemList}"
cellpadding="1" id="itemList_"
border="0" width="100%" columnClasses="c, l, c, l"
rowClasses="odd, even"
styleClass="list" var="itemList" cellspacing="1"
rendered="#{not empty listItem.listReply.itemList}">
<h:column>
<f:facet name="header">
<h:outputText value="#{labels.itemId}" />
</f:facet>
<h:commandLink action="#{editItem.getById(itemList.itemId)}"
id="searchItemLink"
title="#{menu['search.item']}">
<h:outputText value="#{itemList.itemId}" />
</h:commandLink>
<!-- new working code -->
<h:link action="#{editItem.getById(itemList.itemId)}"
id="searchItemLink_"
title="#{menu['search.item']}">
<h:outputText value="#{itemList.itemId}" />
<f:param name = "itemId" value"#{editItem.itemId}" />
</h:link>
</h:column>
</h:dataTable>
</fieldset>
</h:panelGroup>
<t:saveState value="#{listItem.listReply}" />
</h:form>
</ui:define>
<ui:define name="filename">
item\itemManagement\list_items.xhtml
</ui:define>
</ui:composition>
Page1 bean:
@Named("listItem")
@RequestScoped
public class ListItemIdsBean extends AbstractBean {
private BigInteger itemId;
private String itemName;
// dummy code, just to represent irrelevant business logic that returns a list of items
private ExtAppListReply listReply;
public BigInteger getItemId() {
return itemId;
}
public void setItemId(BigInteger itemId) {
this.itemId = itemId;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public ExtAppListReply getExtAppTransaction() {
if( listReply == null ) {
listReply = new ExtAppListReply();
}
return listReply;
}
public void setExtAppTransaction(ExtAppListReply trx) {
this.trx = trx;
}
private void list(BigInteger itemId, String itemName) {
ExtAppTransaction trx = ExtAppTransactionFeeder.feeder(this, itemId, itemName);
ExtAppListReply listReply = super.executeTransaction(trx);
if( listReply != null && !listReply.isSetRefusalCode() ) {
setExtAppTransaction(listReply);
} else {
if( !(type == BACKWARD || type == FORWARD) ) {
setExtAppTransaction(null);
}
}
// show results in the same page
return null;
}
}