jsf passing parameters in a method expression fail

2020-05-01 04:05发布

I have jsf page backed by a ViewScoped bean which lists a bunch of transactions like below

<ui:repeat value="#{transactions_byaccount.pageList}" var="item">
            <tr class="dataRow">
                <td class="dataCell cltdtransactionsdatetransaction">
                      <h:outputText value="#{item.datetransaction}" >
                        <f:convertDateTime pattern="EEE dd-MMM-yyyy HH:mm" />
                      </h:outputText>
                </td>
                ...
                ...

                <td colspan="2">
                    <span class="pagerDBspan" style="font-weight: bold;">
                        <h:commandLink action="#{transactions_byaccount.updateCategory('', item)}" >
                            <h:outputText value="Update"></h:outputText>        
                            <f:param name="pageNo" value="#{param.pageNo}" />
                            <f:param name="accountId" value="#{param.accountId}" />
                            <f:param name="sortOrder" value="#{param.sortOrder}" />
                            <f:param name="orderColumn" value="#{param.orderColumn}" />                                                                         
                        </h:commandLink>
                    </span>                                         
                </td>

when a user navigates to the page, the link has the accountId passed in as a parameter which is mapped to a managed property on the bean like below

@ManagedProperty("#{param.accountId}")
private int accountId;

at this point calls to the method #{transactions_byaccount.updateCategory('', item)} passing 'item' works as expected.

the user is also able to change the account id by selecting a drop down on the page which is bound to the accountId field above and clicking a refresh button which will call the relevant DAO to get a list of transactions of the selected account. However when the user clicks on the button to call #{transactions_byaccount.updateCategory('', item)} does not list me the item from the new account, it uses the item from the list of the first account.

It appears the problem is at the point of the restore bit of the JSF lifecycle.

Any help would be appreciated. Will add more details if needed.

Thanks Mani

Edit: My bean

package applogic.transactions;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ViewScoped;
import javax.faces.model.SelectItem;

import applogic.Conns;

import finance.bean.TransactionsListBean;
import finance.dao.AccountsDAO;
import finance.dao.TransactionsDAO;
import finance.daobase.BusinessDAO;
import finance.model.Accounts;
import finance.model.Transactions;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@ManagedBean(name = "transactions_byaccount")
@ViewScoped
public class Transactions_Byaccount extends TransactionsListBean implements Serializable {
    List<Transactions> resultList;

    boolean initialized;

    @ManagedProperty("#{param.accountId}")
    private int accountId;

    public SelectItem[] accountsSelections;

    @ManagedProperty("#{param.sortOrder}")
    private int sortOrder;

    public SelectItem[] sortOrderSelections;

    @ManagedProperty("#{param.orderColumn}")
    private int orderColumn;

    public SelectItem[] orderColumnSelections;

    public Transactions_Byaccount() {
         Connection cons = Conns.getConFinanceDB();
         List<Accounts> accountsList = AccountsDAO.List(cons);
         List<SelectItem> listOfAccountsSelectItems = new
         ArrayList<SelectItem>();

         for( Accounts temp : accountsList ) {
             listOfAccountsSelectItems.add(new SelectItem(temp.getId(), temp.getTitle()));
         }

         accountsSelections = listOfAccountsSelectItems.toArray(new SelectItem[listOfAccountsSelectItems.size()]);

         List<SelectItem> sortOrderList = new ArrayList<SelectItem>();
         sortOrderList.add(new SelectItem(1, "Asc"));
         sortOrderList.add(new SelectItem(2, "Desc"));       
         sortOrderSelections = sortOrderList.toArray(new SelectItem[sortOrderList.size()]);

         List<SelectItem> orderColumnList = new ArrayList<SelectItem>();
         orderColumnList.add(new SelectItem(1, "Transaction Date"));
         orderColumnList.add(new SelectItem(2, "Action Date"));      
         orderColumnList.add(new SelectItem(3, "Reconciled Date"));
         orderColumnSelections = orderColumnList.toArray(new SelectItem[orderColumnList.size()]);
    }

    public String updateCategories(String redirectURL) {
        String result = redirectURL;

        Connection cons = Conns.getConFinanceDB();
        for( Transactions temp : (List<Transactions>)this.getPageList() )
            TransactionsDAO.Update(cons, temp);

        resultList = null;

        if( redirectURL != null && redirectURL.length() == 0 )
            redirectURL = null;

        return redirectURL;
    }

    public String updateCategory(String redirectURL, Transactions arg) {
        String result = redirectURL;

        Connection cons = Conns.getConFinanceDB();
        TransactionsDAO.Update(cons, arg);

        resultList = null;

        if( redirectURL != null && redirectURL.length() == 0 )
            redirectURL = null;

        return result;
    }

    @PostConstruct
    public void refresh() {
        Connection con = Conns.getConFinanceDB();
        resultList = TransactionsDAO.ListByaccount(con, accountId, getCurrentPageNo(), getPageSize(), orderColumn, sortOrder);
        initialized = true;

    }

    public void reload() {
        Connection con = Conns.getConFinanceDB();
        resultList = TransactionsDAO.ListByaccount(con, accountId, getCurrentPageNo(), getPageSize(), orderColumn, sortOrder);
        initialized = true;

    }

    public String reload(String returnUrl) {
        Connection con = Conns.getConFinanceDB();
        resultList = TransactionsDAO.ListByaccount(con, accountId, getCurrentPageNo(), getPageSize(), orderColumn, sortOrder);
        initialized = true;     
        return returnUrl;
    }

    public Object getPageList() {


        return resultList;
    }

    public int getMaxCount() {
        Connection con = Conns.getConFinanceDB();
        int result = TransactionsDAO.CountByaccount(con, accountId);
        return result;
    }

    public int getAccountId() {
        return accountId;
    }

    public void setAccountId(int accountId) {
        this.accountId = accountId;
    }

    public SelectItem[] getAccountsSelections() {
        return accountsSelections;
    }

    public void setAccountsSelections(SelectItem[] accountsSelections) {
        this.accountsSelections = accountsSelections;
    }

    public int getSortOrder() {
        return sortOrder;
    }

    public void setSortOrder(int sortOrder) {
        this.sortOrder = sortOrder;
    }

    public SelectItem[] getSortOrderSelections() {
        return sortOrderSelections;
    }

    public void setSortOrderSelections(SelectItem[] sortOrderSelections) {
        this.sortOrderSelections = sortOrderSelections;
    }

    public int getOrderColumn() {
        return orderColumn;
    }

    public void setOrderColumn(int orderColumn) {
        this.orderColumn = orderColumn;
    }

    public SelectItem[] getOrderColumnSelections() {
        return orderColumnSelections;
    }

    public void setOrderColumnSelections(SelectItem[] orderColumnSelections) {
        this.orderColumnSelections = orderColumnSelections;
    }   

    public boolean isInitialized() {
        return initialized;
    }

    public void setInitialized(boolean initialized) {
        this.initialized = initialized;
    }

    public List<Transactions> getResultList() {
        return resultList;
    }

    public void setResultList(List<Transactions> resultList) {
        this.resultList = resultList;
    }
}

And now my page

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:t="http://myfaces.apache.org/tomahawk"
    xmlns:f="http://java.sun.com/jsf/core" xml:lang="en" lang="en">


<ui:composition template="/WEB-INF/templates/template_main.xhtml">
    <ui:param name="title" value="transactions"></ui:param>

    <ui:define name="operationalbar">
        <div>
            <span>
                <h:selectOneMenu value="#{transactions_byaccount.accountId}" >
                    <f:selectItems value="#{transactions_byaccount.accountsSelections}"/>
                </h:selectOneMenu>
            </span>
            <span>
                <h:commandLink action="#{transactions_byaccount.reload('')}">
                    <h:outputText value="Reload"></h:outputText>
                    <f:param name="pageNo" value="#{param.pageNo}" />
                    <f:param name="accountId" value="#{param.accountId}" />
                    <f:param name="sortOrder" value="#{param.sortOrder}" />
                    <f:param name="orderColumn" value="#{param.orderColumn}" />
                </h:commandLink>
            </span>         
            <span>
                <h:commandLink action="#{transactions_byaccount.updateCategories('')}">
                    <h:outputText value="Update Categories"></h:outputText>
                    <f:param name="pageNo" value="#{param.pageNo}" />
                    <f:param name="accountId" value="#{param.accountId}" />
                    <f:param name="sortOrder" value="#{param.sortOrder}" />
                    <f:param name="orderColumn" value="#{param.orderColumn}" />
                </h:commandLink>        
            </span>
        </div>
    </ui:define>

    <ui:define name="pagingbar">
        <div>
            <span>
                <h:commandLink title="Go to page first page" >
                    <h:outputText value="first"></h:outputText>
                        <f:param name="pageNo" value="#{transactions_byaccount.firstPage}" />
                        <f:param name="accountId" value="#{param.accountId}" />
                        <f:param name="sortOrder" value="#{param.sortOrder}" />
                        <f:param name="orderColumn" value="#{param.orderColumn}" />             
                </h:commandLink>
            </span>
            <span>
                <h:commandLink title="Go to page prev page">
                    <h:outputText value="prev"></h:outputText>
                        <f:param name="pageNo" value="#{transactions_byaccount.prevPage}" />
                        <f:param name="accountId" value="#{param.accountId}" />
                        <f:param name="sortOrder" value="#{param.sortOrder}" />
                        <f:param name="orderColumn" value="#{param.orderColumn}" />
                </h:commandLink>

            </span>
                <ui:repeat value="#{transactions_byaccount.pages}" var="item">
                    <span style="font-weight: #{item == transactions_byaccount.currentPageNo ? 'bold' : 'lighter' }">
                        <h:commandLink>
                            <h:outputText value="#{item}"></h:outputText>
                            <f:param name="pageNo" value="#{item}" />
                            <f:param name="accountId" value="#{param.accountId}" />
                            <f:param name="sortOrder" value="#{param.sortOrder}" />
                            <f:param name="orderColumn" value="#{param.orderColumn}" />

                        </h:commandLink>
                    </span>
                </ui:repeat>                

            <span>
                <h:commandLink title="Go to page next page">
                    <h:outputText value="next"></h:outputText>
                        <f:param name="pageNo" value="#{transactions_byaccount.nextPage}" />
                        <f:param name="accountId" value="#{param.accountId}" />
                        <f:param name="sortOrder" value="#{param.sortOrder}" />
                        <f:param name="orderColumn" value="#{param.orderColumn}" />
                </h:commandLink>
            </span>
            <span>
                <h:commandLink title="Go to page last page">
                    <h:outputText value="last"></h:outputText>
                        <f:param name="pageNo" value="#{transactions_byaccount.lastPage}" />
                        <f:param name="accountId" value="#{param.accountId}" />
                        <f:param name="sortOrder" value="#{param.sortOrder}" />
                        <f:param name="orderColumn" value="#{param.orderColumn}" />

                </h:commandLink>                
            </span>         
        </div>
        <div class="currentPagerIndex">

        </div>
    </ui:define>
    <ui:define name="maincontent">
        <table class="datatable">
            <thead>
                <tr class="headRow">
                    <td>datetransaction</td>
                    <td>description</td>
                    <td>amount</td>
                    <td>Edit</td>
                    <td>Delete</td>
                </tr>
            </thead>
            <ui:repeat value="#{transactions_byaccount.pageList}" var="item">
                <tr class="dataRow">
                    <td class="dataCell cltdtransactionsdatetransaction">
                          <h:outputText value="#{item.datetransaction}" >
                            <f:convertDateTime pattern="EEE dd-MMM-yyyy HH:mm" />
                          </h:outputText>
                    </td>
                    <td class="dataCell cltdtransactionsdescription">#{item.description}</td>
                    <td class="dataCell cltdtransactionsamount">#{item.amount}</td>
                    <td style="width: 45px">
                        <span class="pagerDBspan" style="font-weight: bold;">                   
                            <h:link outcome="transactions_edit" style="font-weight: bold;">
                                <h:outputText value="Edit"></h:outputText>
                                <f:param name="pageNo" value="#{param.pageNo}" />
                                <f:param name="itemId" value="#{item.id}" />
                            </h:link>
                        </span>                 
                    </td>
                    <td style="width: 45px">
                        <span class="pagerDBspan" style="font-weight: bold;">
                            <h:link  outcome="transactions_edit" >
                                <h:outputText value="Delete"></h:outputText>
                                <f:param name="pageNo" value="#{param.pageNo}" />
                                <f:param name="itemId" value="#{item.id}" />
                                <f:param name="deleteFlag" value="true" />                                  
                            </h:link>       
                        </span>                 
                    </td>
                </tr>
                <tr class="dataRow">
                    <td class="dataCell"></td>
                    <td class="dataCell" colspan="2">
                        <h:selectOneMenu value="#{item.fkCategoriesId}" >
                            <f:selectItems value="#{categories_edit.categories}"/>
                        </h:selectOneMenu>
                    </td>
                    <td colspan="2">
                        <span class="pagerDBspan" style="font-weight: bold;">
                            <h:commandLink action="#{transactions_byaccount.updateCategory('', item)}" >
                                <h:outputText value="Update"></h:outputText>        
                                <f:param name="pageNo" value="#{param.pageNo}" />
                                <f:param name="accountId" value="#{param.accountId}" />
                                <f:param name="sortOrder" value="#{param.sortOrder}" />
                                <f:param name="orderColumn" value="#{param.orderColumn}" />                                                                         
                            </h:commandLink>
                        </span>                                         
                    </td>
                </tr>
                <tr>
                    <td class="cssBottomLine" colspan="0"></td>
                </tr>                   
            </ui:repeat>
        </table>
    </ui:define>

    <ui:define name="bottomoperationalbarhost">
    </ui:define>

</ui:composition>
</html>

1条回答
等我变得足够好
2楼-- · 2020-05-01 04:14

That will happen when the #{transactions_byaccount.pageList} has incompatibly changed during processing of the form submit as compared to how it was during displaying the form.

During the new HTTP request of processing the form submit, JSF will reiterate over it to find the action invoked and to prepare the #{item} in order to pass it. Note that this is thus not prepared during the HTTP request of rendering the HTML form for display.

This problem indicates that you're initializing #{transactions_byaccount.pageList} based on an outdated (or a too new) variable which caused it to incompatibly change. You should not do that. You should rewrite your bean logic as such that it initializes on postback exactly the same list as it was during display and then change it only when the action has actually been invoked (thus, inside the action method).

Given that you're using a view scoped bean, you should actually already be set as it actually remembers all properties for subsequent requests. Perhaps you're performing initialization in the getter method of the list. You should not be performing business logic in getter methods at all. You should do that in (post)constructor or action method.

查看更多
登录 后发表回答