Multiple instances of managed bean

2020-04-15 11:09发布

问题:

I'm using prime-faces Tabs to display multiple input forms. The problem is, there are times when I need to instantiate 2 of the same form. They both of course use the same Managed Bean which causes the input of the first initialized form to override the other with the same data. I need to be able to put different data in each form and submit both of them collectively. Each form goes into a list and forwarded on for calculation. I've been reading scope scope scope scope but the only scope that works somewhat is "Sessioned". Session only allows one instance of the Managed Bean and places the form data into the list, "Request, View scope" Doesn't place the data into the list respectively nor does it hold the data. The Managed Bean is serializable and in sessioned scope. I've read the other post and they don't work. Any ideas?

Backing Bean

@ManagedBean
@SessionScoped

public class RequestCalculation {
    private CalculationRequest calcReq;
    private List<ViewTabs> formTabs;
    private String id;
    private boolean calcButton;

    public RequestCalculation() {
        calcReq = new CalculationRequest();
        formTabs = new ArrayList<ViewTabs>();
        calcButton = false;

    }

    public String loadForm(TcsBase loadForm) {

        id = loadForm.getId();

        ViewTabs tab = new ViewTabs();
        tab.setFormTitle("Form".concat(id));
        tab.setFormPage("Form".concat(id).concat(".xhtml"));
        formTabs.add(0, tab);
        calcReq.getFormCollection().add(0, loadForm);
        loadCalcButton();
        return "Main";
    }

    public void loadCalcButton() {
        if (formTabs.isEmpty())
            isCalcButton();
        else {
            calcButton = true;
        }
    }

    public void onTabClosed(TabCloseEvent e) {
        TabView tabView = (TabView) e.getComponent();
        int closingTabIndex = tabView.getChildren().indexOf(e.getTab());
        removeForm(closingTabIndex);
        formTabs.remove(closingTabIndex);
        loadCalcButton();
    }

    public void removeForm(int index) {
        TcsBase formIndex = calcReq.getFormCollection().get(index);
        String formId = formIndex.getId();

        // Creates a new instance of the selected form
        FacesContext fc = FacesContext.getCurrentInstance();
        fc.getELContext().getELResolver()
                .setValue(fc.getELContext(), null, "form".concat(formId), null);

        calcReq.getFormCollection().remove(index);
        formTabs.remove(index);
    }

    public String calculate() {
    CalculateService service = new CalculateService();
        CalculatorInterface calculateInterface = service.getCalculatePort();

        XStream xstream = new XStream(new StaxDriver());
        xstream.registerConverter(new JodaTimeConverter());

        // Here is where the client request (input) is converted to an Xml
        // string before going
        // to the Web Service

        String xml = xstream.toXML(calcReq);
        String request = calculateInterface.calculate(xml);

        // Here the response back from the Web Service is converted back from
        // Xml to a string
        // to be displayed to the user in Xhtml

        calcReq = (CalculationRequest) xstream.fromXML(request);

        FacesContext fc = FacesContext.getCurrentInstance();

        for (int i = 0; i < calcReq.getFormCollection().size(); i++) {

            TcsBase newFrm = calcReq.getFormCollection().get(i);
            String frmId = newFrm.getId();
            fc.getELContext()
                    .getELResolver()
                    .setValue(fc.getELContext(), null, "form".concat(frmId),
                            newFrm);
        }

        return null;

    }

    public List<ViewTabs> getFormTabs() {
        return formTabs;
    }

    public void setFormTabs(List<ViewTabs> formTabs) {
        this.formTabs = formTabs;
    }

    public boolean isCalcButton() {
        return calcButton;
    }

    public void setCalcButton(boolean calcButton) {
        this.calcButton = calcButton;
    }

}

**Html Menu **

<!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:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui">

<head>

</head>

<f:view>
    <h:body>

        <h:commandLink action="#{requestCalculation.loadForm(formA)}" value="FormA"  /> <br/>
        <h:commandLink action="#{requestCalculation.loadForm(formB)}" value="FormB" /> <br/><br/><br/>

    </h:body>
</f:view>
</html>

Html Main page

<!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:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui"
    xmlns:c="http://java.sun.com/jsp/jstl/core">
<f:view>    

    <h:head>
        <title> TCS </title>

    </h:head>

    <h:form >


        <p:layout style="min-width:400px;min-height:700px " >
            <p:layoutUnit  position="north" style="text-align:center">
            <p style="text-align:center; font-size:28px">Tax Computation Service</p>
            </p:layoutUnit>

            <p:layoutUnit header="Menu" position="west" style="min-width:190px; min-height:50px; ">
                <p:panelMenu>
                    <p:submenu label="Forms">
                        <p:submenu label="Individual Forms">
                            <p:menuitem>
                                <ui:include src="Menu.xhtml" />
                            </p:menuitem>
                        </p:submenu>
                    </p:submenu>
                </p:panelMenu>
            </p:layoutUnit>

            <p:layoutUnit position="center" >
                <p:tabView  onTabShow="focus" widgetVar="tabView">
                    <p:ajax event="tabClose" listener="#{requestCalculation.onTabClosed}"/>
                    <c:forEach items="#{requestCalculation.formTabs}" var="listItem">
                        <p:tab  title="#{listItem.formTitle}"  closable="true" >
                            <ui:include src="#{listItem.formPage}" />
                         </p:tab>
                    </c:forEach>
                </p:tabView>

                    <p:panelGrid columns="0" >
                        <p:commandButton value="Calculate" action = "#{requestCalculation.calculate}"   ajax="false" rendered="#{requestCalculation.calcButton}" /> 
                    </p:panelGrid>
            </p:layoutUnit>

        </p:layout>

    </h:form>

</f:view>   
</html>

FormA Html

<!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:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui">

    <f:view>

        <h:head>
            <title> FormA</title>
        </h:head>

        <h:body>

            <p:focus />

            <p:panelGrid id="panelGridA" columns="2">
                <p:outputLabel value="Form ID: "  style="width: 725px" />
                <p:outputLabel value="#{formA.id}"  />        

                <p:outputLabel value="4.  . . "  style="width: 725px" />        
                <p:inputText id="input1" style="text-align:right" value="#{formA.line4}" converter="bdNullableConverter" onfocus="this.select()"/> 
                <p:outputLabel value="5. . . . . . . "  style="width: 725px" />        
                <p:inputText style="text-align:right" value="#{formA.line5}" converter="bdNullableConverter" onfocus="this.select()" /> 
                <p:outputLabel value="6.  . . . . . . . "  style="width: 725px" />        
                <p:outputLabel value="#{formA.line6}" converter="bdNullableConverter" /> 
            </p:panelGrid>
        </h:body>

    </f:view>
</html>

回答1:

Instead of trying to use multiple instances of a managed bean, use ONE managed bean that gives access to multiple instances of a class via e.g. a hashmap or arraylist or whatever you want to use. Just like you would in plain old java programming. You cannot have two variables with the same name:

@ViewScoped
@Named
public class RequestCalculations {

    Map<String, RequestCalculation> hm;

    @PostConstruct
    public init() {
        hm = new HashMap<>();
        // prepopulate if known upfront
        hm.put("1", new RequestCalculation());
        hm.put("2", new RequestCalculation());
    }

    public HashMap<String, RequestCalculation> getCalculations() {
        return hm;
    }
}

Then use the tabIndex of the tab as the key to the hashmap (or an array list). And in your xhtml do something like

#{requestCalculations.calculations[myTabIndex]}

You might need to pass this on to the include via a include param if you need this IN the include (as I think you do)



回答2:

If you want to use the multiple instance of manager bean, then you can declared it in faces-config.xml file with different names and use its independently. See example

<managed-bean>
    <managed-bean-name>productSearchForm</managed-bean-name>
    <managed-bean-class>com.company.package.ProductSearchForm</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

<managed-bean>
    <managed-bean-name>productChildFilter</managed-bean-name>
    <managed-bean-class>com.company.package.ProductSearchForm</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

<managed-bean>
    <managed-bean-name>productAttachFilter</managed-bean-name>
    <managed-bean-class>com.company.package.ProductSearchForm</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
</managed-bean>