我在PRG Pattern上做了几次测试。我还阅读了本网站关于后退按钮问题的许多答案。 我坚持认为代码是一个测试。 因此,在工作流程的开头,会话上放置一个令牌,最后我从会话中删除此令牌。 当我按下后退按钮时,我检查令牌是否不存在并创建facelet中使用的属性的新实例。从transaction_done.xhtml页面到transaction_confirm.xhtml,它可以工作:facelet显示一个带有错误消息的空表单;但是当我再次按下后退按钮进入transaction_register.xhtml页面时,页面会显示旧值并显示错误消息。
我调试代码,第6阶段的属性是一个新实例,所以我不明白为什么寄存器页面会检索旧值。我还注意到,如果我手动删除chrome中的jsessionid,旧值就会消失。 我也不是说当我按下工作流开始时的值的后退按钮时,注册页面上的视图状态不同。
这个测试因此在chrome中进行,默认情况下调用后退按钮上的服务器。 FireFox不会调用服务器,它会默认显示缓存中的页面。 我知道我必须把一个像无缓存这样的值的过滤器...但我想理解为什么它从完成确认页面而不是从确认到注册页面。
我把托管bean的代码和3 .xhtml。
放在一起提前感谢您的帮助。
一个。 ManagedBean
@ManagedBean
@RequestScoped
public class TransactionBean implements Serializable {
private ITransactionService transactionService;
private VirtualDbAccountRepository accountRepository;
private TransferTransaction currentItem;
private List<TransferTransaction> transactionList;
private List<SelectItem> accounts;
private String id;
private String nextOutcome;
private static final String INIT_VIEW = "/home.xhtml";
private static final String REGISTER_VIEW = "/transaction_register.xhtml";
private static final String CONFIRM_VIEW = "/transaction_confirm.xhtml";
private static final String DONE_VIEW = "/transaction_done.xhtml";
private static final String LISTING_VIEW = "/transaction_listing.xhtml";
private static final String CURRENT_ITEM = "currentItem";
private static final String TOKEN = "token";
private static final String CURRENT_ID = "currentId";
public TransactionBean() {
log();
}
@PostConstruct
public void init() throws IOException {
log();
transactionService = TransactionService.getInstance();
accountRepository = new VirtualDbAccountRepository();
handleByViewId(FacesUtil.getViewId());
}
private void handleByViewId(String viewId) throws IOException {
System.out.println("The ViewState value is: "
+ FacesUtil.getHttpServletRequest().getParameter(
"javax.faces.ViewState"));
log();
if (viewId.equals(INIT_VIEW))
handleInitView();
if (viewId.equals(REGISTER_VIEW))
handleRegisterView();
if (viewId.equals(CONFIRM_VIEW))
handleConfirmView();
if (viewId.equals(DONE_VIEW))
handleDoneView();
if (viewId.equals(LISTING_VIEW))
handleListingView();
}
private void handleInitView() {
FacesUtil.getSessionMap().put(CURRENT_ITEM, new TransferTransaction());
FacesUtil.getSessionMap().put(TOKEN, TokenUtil.getRandomHexString());
}
private void handleRegisterView() throws IOException {
log();
if (!FacesUtil.getFacesContext().isPostback()) {
// to handle edit on confirmation page
currentItem = (TransferTransaction) FacesUtil.getSessionMap().get(
CURRENT_ITEM);
String token = (String) FacesUtil.getSessionMap().get(TOKEN);
// only create new instance if token equals null.
if (null == token) {
currentItem = new TransferTransaction();
handleErrorPage();
}
FacesUtil.getSessionMap().put(CURRENT_ITEM, currentItem);
FacesUtil.getSessionMap()
.put(TOKEN, TokenUtil.getRandomHexString());
} else
currentItem = (TransferTransaction) FacesUtil.getSessionMap().get(
CURRENT_ITEM);
fillSelectItems();
}
private void handleConfirmView() throws IOException {
log();
currentItem = (TransferTransaction) FacesUtil.getSessionMap().get(
CURRENT_ITEM);
String token = (String) FacesUtil.getSessionMap().get(TOKEN);
if (null == token) {
currentItem = new TransferTransaction();
handleErrorPage();
}
}
private void handleErrorPage() throws IOException {
FacesUtil.getFacesContext().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_INFO,
"The transaction has already been executed.",
"The transaction has already been executed."));
}
private void handleDoneView() {
log();
id = (String) FacesUtil.getSessionMap().get(CURRENT_ID);
currentItem = transactionService.find(id);
}
private void handleListingView() {
log();
transactionList = new ArrayList<TransferTransaction>();
transactionList = VirtualDbTransferTransactionRepository.getInstance()
.list();
}
private void fillSelectItems() {
log();
accounts = new ArrayList<SelectItem>();
Collection<Account> values = accountRepository.list();
for (Account a : values) {
SelectItem sItem = new SelectItem(a, a.getAccountId()); // value,
// label
accounts.add(sItem);
}
}
public String initNewTransaction() {
return "transaction_register?faces-redirect=true";
}
public String register() {
log();
String outcome = null;
// to handle back button
if (null != nextOutcome)
outcome = nextOutcome;
else
outcome = "transaction_confirm?faces-redirect=true";
return outcome;
}
public String preEdit(String id) {
log();
String outcome = null;
currentItem = transactionService.find(id);
FacesUtil.getSessionMap().put(CURRENT_ITEM, currentItem);
FacesUtil.getSessionMap().put(TOKEN, TokenUtil.getRandomHexString());
outcome = "transaction_register?faces-redirect=true";
return outcome;
}
public String add() {
log();
String outcome = null;
TransactionResult transactionResult = transactionService
.addTransaction(currentItem);
if (!transactionResult.getStatusCodes().isEmpty()) {
List<StatusCode> statusCodes = transactionResult.getStatusCodes();
for (StatusCode statusCode : statusCodes) {
FacesUtil.getFacesContext().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_INFO, statusCode
.getStatus(), statusCode.getCode()));
}
outcome = "transaction_confirm?faces-redirect=true";
} else {
// FacesUtil.getSessionMap().put(CURRENT_ITEM, null);
// CURRENT_ID is used to handle done page
FacesUtil.getSessionMap().put(CURRENT_ID,
transactionResult.getModel().getId().toString());
FacesUtil.getSessionMap().put(TOKEN, null);
outcome = "transaction_done?faces-redirect=true";
// transactionList.add(transactionResult.getModel());
}
return outcome;
}
public String modifyDate() {
log();
String outcome = null;
TransactionResult transactionResult = transactionService
.modifyTransaction(currentItem.getId(), currentItem.getDate());
if (!transactionResult.getStatusCodes().isEmpty()) {
List<StatusCode> statusCodes = transactionResult.getStatusCodes();
for (StatusCode statusCode : statusCodes) {
FacesUtil.getFacesContext().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_INFO, statusCode
.getStatus(), statusCode.getCode()));
}
outcome = "transaction_confirm?faces-redirect=true";
} else {
// FacesUtil.getSessionMap().put(CURRENT_ITEM, null);
// CURRENT_ID is used to handle done page
FacesUtil.getSessionMap().put(CURRENT_ID,
transactionResult.getModel().getId().toString());
// outcome = "transaction_listing?faces-redirect=true";
outcome = "transaction_done?faces-redirect=true";
}
return outcome;
}
public TransferTransaction getCurrentItem() {
log();
return currentItem;
}
public void setCurrentItem(TransferTransaction currentItem) {
this.currentItem = currentItem;
}
public List<TransferTransaction> getTransactionList() {
return transactionList;
}
public List<SelectItem> getAccounts() {
log();
return accounts;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void log() {
PhaseId currentPhaseId = FacesContext.getCurrentInstance()
.getCurrentPhaseId();
System.out.println("+++ "
+ Thread.currentThread().getStackTrace()[2].getMethodName()
+ " in phase : " + currentPhaseId.getOrdinal() + " at : "
+ new UtilDate().getTime());
}
}
B中。页
1.B。 transaction_register.xhtml
<h:body>
<h:form>
<h2>Home Bank</h2>
<h4>Enter a new transaction</h4>
<table>
<tr>
<td>Debit Account Number</td>
<td>
<h:selectOneMenu id="debitAccount" value="#{transactionBean.currentItem.fromAccount}"
disabled="#{transactionBean.currentItem.id != '-1'}"
required="true" requiredMessage="Debit Account must be selected.">
<f:selectItem noSelectionOption="true" itemLabel="--------------"/>
<f:selectItems value="#{transactionBean.accounts}" />
<f:converter converterId="transferTransactionConverter" />
</h:selectOneMenu>
</td>
</tr>
<tr>
<td>Credit Account Number</td>
<td>
<h:selectOneMenu id="creditAccount" value="#{transactionBean.currentItem.toAccount}"
disabled="#{transactionBean.currentItem.id != '-1'}"
required="true" requiredMessage="Credit Account must be selected.">
<f:selectItem noSelectionOption="true" itemLabel="--------------"/>
<f:selectItems value="#{transactionBean.accounts}" />
<f:converter converterId="transferTransactionConverter" />
</h:selectOneMenu>
</td>
</tr>
<tr>
<td>Amount</td>
<td>
<h:inputText value="#{transactionBean.currentItem.amount}" disabled="#{transactionBean.currentItem.id != '-1'}" ></h:inputText>
</td>
</tr>
<h:panelGroup rendered="#{transactionBean.currentItem.id != '-1'}">
<tr>
<td>Execution date</td>
<td>
<h:inputText value="#{transactionBean.currentItem.date}">
<f:convertDateTime pattern="dd-MM-yyyy" />
</h:inputText>
</td>
</tr>
</h:panelGroup>
</table>
<p>
<h:commandLink value="Create Transaction" action="#{transactionBean.register}" />
</p>
</h:form>
</h:body>
</html>
2.B。 transaction_confirm.xhtml
<h:body>
<h2>Home Bank</h2>
<h4>Confirm new transaction</h4>
<h:messages showSummary="true" />
<table>
<tr>
<td>Debit Account Number :</td>
<td><h:outputText label="Debit Account Number"
value="#{transactionBean.currentItem.fromAccount.accountId}" /></td>
</tr>
<tr>
<td>Credit Account Number :</td>
<td><h:outputText label="Credit Account Number"
value="#{transactionBean.currentItem.toAccount.accountId}" /></td>
</tr>
<tr>
<td>Amount :</td>
<td><h:outputText label="Amount"
value="#{transactionBean.currentItem.amount}" /></td>
</tr>
<h:panelGroup rendered="#{transactionBean.currentItem.id != '-1'}">
<tr>
<td>Execution date</td>
<td><h:outputText value="#{transactionBean.currentItem.date}">
<f:convertDateTime pattern="dd-MM-yyyy" />
</h:outputText></td>
</tr>
</h:panelGroup>
</table>
<h:form>
<div>
<h:link value="Edit" outcome="transaction_register?faces-redirect=true&includeViewParams=true" />
</div>
<h:panelGroup rendered="#{transactionBean.currentItem.id eq '-1'}">
<div>
<h:commandButton value="Confirm" action="#{transactionBean.add}" />
</div>
</h:panelGroup>
<h:panelGroup rendered="#{transactionBean.currentItem.id gt '-1'}">
<div>
<h:commandButton value="Confirm date modification" action="#{transactionBean.modifyDate}" />
</div>
</h:panelGroup>
</h:form>
</h:body>
</html>
3.B。 transaction_done.xhtml
<h:body>
<h:form>
<h2>Home Bank</h2>
<h4>new transaction is executed.</h4>
<h:messages />
<table>
<tr>
<td>Debit Account Number :</td>
<td><h:outputText label="Debit Account Number"
value="#{transactionBean.currentItem.fromAccount.accountId}" /></td>
</tr>
<tr>
<td>Credit Account Number :</td>
<td><h:outputText label="Credit Account Number" value="#{transactionBean.currentItem.toAccount}" converter="transferTransactionConverter" /></td>
</tr>
<tr>
<td>Amount :</td>
<td><h:outputText label="Amount" value="#{transactionBean.currentItem.amount}" /></td>
</tr>
</table>
<br/>
<h:link outcome="home.xhtml" value="Menu" />
</h:form>
</h:body>
</html>