【问题标题】:JSF2.0 Ajax Navigation PatternJSF2.0 Ajax 导航模式
【发布时间】:2011-12-07 17:24:23
【问题描述】:

非常感谢有关使用 JSF 2.0、PrimeFaces 和 Ajax 的 Web 应用程序模式的指导。我们当前的系统使用带有标准提交的 JSP,我们的应用程序中的每个功能页面都有 1 个 JSP。每个 JSP 为逻辑、导航和 EJB 调用调用一个动作类。使用相同的设置迁移到 JSF 会相对简单,即 1 个 xhtml 页面和关联的支持 bean 以及通过 do 方法完成的导航/逻辑。但是我们想通过 Ajax 提交,这在我的脑海中引起了困惑。如果我加载 abc1.xhtml 并使用 ajax 提交,那么我会继续使用 abc1.xhtml,尽管我可能需要转到 abc2.xhtml。我想过在 1 个 xhtml 页面上有关联的表单,并使用渲染属性来决定要显示的内容。这行得通,但我不喜欢在 1 页中有很多表格。理想情况下,我希望将每个页面分开,但不知道 Ajax 是如何实现的。任何想法将不胜感激。

编辑 - 这是最初的解决方案,但现在我在下面的回答中进行了改进。这可行,但参数似乎存在问题。当我单击 AAA 或 BBB 链接时,我需要传递一个参数,以便 ViewController bean 知道单击了什么以及在哪里设置目标页面。但是,如果我单击 AAA.xhtml 中的提交按钮,除非我还将 <f:param name="tranID" value="AAA"/> 添加到命令按钮,否则内容不会改变。我以为我在 ViewController 构造函数中处理了一个空参数,但显然我错过了一些重要的东西。我唯一的想法是与 URL 有关。当我单击菜单链接时,它会将参数添加到 url ?tranID=AAA。如果我不将参数添加到后续提交中,这是否有效地更改了 url 并导致某种不匹配?

viewController.xhtml

<h:body>
    <h:panelGroup layout="block" id="transactionControl">

                    <h4>
                        <h:outputLink id="mfa" value="#{facesContext.externalContext.requestContextPath}/xhtml/viewController.xhtml" styleClass="menuLink">
                            <h:outputText value="AAA"></h:outputText>
                            <f:param name="tranID" value="AAA"/>
                        </h:outputLink>
                    </h4>

                    <h4>
                        <h:outputLink id="inq" value="#{facesContext.externalContext.requestContextPath}/xhtml/viewController.xhtml" styleClass="menuLink">
                            <h:outputText value="BBB"></h:outputText>
                            <f:param name="tranID" value="BBB"/>
                        </h:outputLink>
                    </h4>



    </h:panelGroup>

    <h:panelGroup layout="block" id="content" style="border-style: solid;">

        <ui:include src="#{viewController.destinationPage}.xhtml"></ui:include>

    </h:panelGroup>

</h:body>

AAA.xhtml

<h:body>
    <h:form prependId="false">
        <h:outputText value="Click the button to go to AAB"></h:outputText>

        <p>
            <p:commandButton id="submitButton" value="Go" ajax="true" actionListener="#{viewController.doAAAtoAAB}"
                             process="@form"
                             update="content">
                <f:param name="tranID" value="AAA"/>
            </p:commandButton>
        </p>

    </h:form>

</h:body>

AAB.xhtml

<h:body>
    <h:panelGroup layout="block" id="subContent">
        <h:outputText value="This is the AAB content"></h:outputText>
    </h:panelGroup>
</h:body>

BBB.xhtml 和 BBC.xhtml 同上

ViewController bean

package com.mcpplc.supportclient.webapp.managedBeans;


import javax.faces.context.FacesContext;    
import java.io.Serializable;

@ManagedBean
@ViewScoped
public class ViewController implements Serializable
{
    String destinationPage = "splash";
    FacesContext context;
    String callingTranID;

    public ViewController ()
    {
        context = FacesContext.getCurrentInstance();
        callingTranID = context.getExternalContext().getRequestParameterMap().get("tranID");

        if (callingTranID != null )
        {
            destinationPage = callingTranID;
        }
    }


    public void doAAAtoAAB()
    {
         destinationPage = "AAB";
    }

    public void doBBBtoBBC()
    {
         destinationPage = "BBC";
    }

    public String getDestinationPage()
    {
        return destinationPage;
    }

    public void setDestinationPage( String destinationPage )
    {
        this.destinationPage = destinationPage;
    }
}

【问题讨论】:

    标签: java ajax jsf-2


    【解决方案1】:

    我对你的建议是,除非你需要,否则不要使用 ajax。如果您需要在请求后实际调用另一个页面,那么使用 ajax 有什么意义?

    尝试在应用程序工作流程中进行思考,并在必要时应用 ajax。您认为 ajax 会令人困惑的情况是因为您可能不应该使用它

    干杯

    【讨论】:

    • 理解您的意思,但使用 ajax 的原因是仅在用户使用系统时更新我们的内容部分。我们目前在顶部和左侧有框架,在用户工作流程期间通常是静态的。我们想用标准的 css 样式的 div 替换这些,但这些不应该在正常的工作流程中提交。
    【解决方案2】:

    决定回答我自己的问题,因为我现在拥有一个完整的仅 ajax 原型应用程序。这符合我将每个视图保存为一个 .xhtml 页面并且每个视图都有自己的支持 bean 的初始要求。简化的代码不是进一步污染我的问题。 (感谢 BalusC 之前的回答,虽然现在已经消失,但确实很有帮助)。

    viewController.xhtml

    <h:body>
        <h:panelGroup layout="block" id="transactionControl">
    
                        <h:form>
                    <h4>
    
                        <p:commandLink id="mfa" ajax="true" process="@form" update="content transactionBannerContent" styleClass="menuLink" oncomplete="showTransaction01Screens();">
                            <h:outputText value="MFA"></h:outputText>
                            <f:setPropertyActionListener target="#{viewController.destinationPage}" value="MFA01"/>
                        </p:commandLink>
    
                    </h4>
    
                    <h4>
                        <p:commandLink id="inq" ajax="true" process="@form" update="content transactionBannerContent" styleClass="menuLink" oncomplete="showTransaction01Screens();">
                            <h:outputText value="INQ"></h:outputText>
                            <f:setPropertyActionListener target="#{viewController.destinationPage}" value="INQ01"/>                            
                        </p:commandLink>
    
    
                    </h4>
    
                </h:form>
    
    
    
        </h:panelGroup>
    
        <h:panelGroup layout="block" id="content" style="border-style: solid;">
    
            <ui:include src="#{viewController.destinationPage}.xhtml"></ui:include>
    
        </h:panelGroup>
    
    </h:body>
    

    mfa01.xhtml

    <h:panelGroup layout="block" id="mfa01">
    
                <h:form id="mfa01Form">
    
                    <p>
                        <span>
                            <h:outputLabel value="UCN" for="ucn"/>
                            <h:inputText id="ucn" value="#{mfa01BackingBean.mfa01FormVO.ucn}" size="20"/>
                        </span>
                    </p>
    
    
                    <p class="submitButton">
                        <p:commandButton id="submitButton" value="Go" ajax="true" actionListener="#{mfa01BackingBean.doMFA01}" process="@form"
                                         update="content transactionBannerContent" oncomplete="ajaxFinished('MFA01')">
                        </p:commandButton>
                    </p>
    
                </h:form>
    
            </h:panelGroup>
    

    mfa02.xhtml

    <h:panelGroup layout="block" id="mfa02">
    
    
                <h:form id="mfa02Form" prependId="true">
    
                    <p>
                        <span style="width:25%">
                            <h:outputLabel value="Vessel Name"/>
                            <h:outputText id="vesselName"
                                         value="#{mfa02BackingBean.mfa02FormVO.vesselName}"/>
                        </span>
    
    
                        <span style="width:75%">
                            <h:outputLabel value="ETA"/>
                            <h:outputText id="eta"
                                         value="#{mfa02BackingBean.mfa02FormVO.eta}"/>
                        </span>
    
                    </p>
    
    
    
    
                    <p>
                        <span>
                            <h:outputLabel value="Unit ID" for="unitID"/>
                            <h:inputText id="unitID"
                                         value="#{mfa02BackingBean.mfa02FormVO.unitID}"
                                         size="20"
                                         required="true" validator="#{mfa02BackingBean.validateData}"/>
                        </span>
                    </p>
    
    
                    <p class="submitButton">
                        <p:commandButton id="submitButton" value="Go" ajax="true" action="#{mfa02BackingBean.doMFA02}"
                                         process="@form" update="content transactionBannerContent" oncomplete="ajaxFinished('MFA02')">
                            <f:param name="randomString" value="AAA"/>
                                         </p:commandButton>
                    </p>
    
    
                </h:form>
            </h:panelGroup>
    

    ViewController.java

    package com.mcpplc.supportclient.webapp.managedBeans;
    
    
    import javax.faces.bean.*;
    import java.io.Serializable;
    
    @ManagedBean (name = "viewController")
    @SessionScoped
    public class ViewController implements Serializable
    {
        String destinationPage = "splash";
        String transactionID;
    
    
        public String getDestinationPage()
        {
            return destinationPage;
        }
    
        public void setDestinationPage( String destinationPage )
        {
            this.destinationPage = destinationPage;
            transactionID = destinationPage.toUpperCase();
        }
    
        public String getTransactionID()
        {
            return transactionID;
        }
    
        public void setTransactionID( String transactionID )
        {
            this.transactionID = transactionID;
        }
    }
    

    mfa01BackingBean.java

    package com.mcpplc.supportclient.webapp.managedBeans;
    
    import com.mcpplc.supportclient.webapp.Utils.JSFUtils;
    import com.mcpplc.supportclient.webapp.valueObjects.*;
    
    import javax.annotation.PostConstruct;
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.ManagedProperty;
    import javax.faces.bean.RequestScoped;
    
    @ManagedBean
    @RequestScoped
    public class Mfa01BackingBean
    {
        @ManagedProperty(value = "#{viewController}")
        private ViewController viewController;
    
        private ImportConsignmentVO importConsignmentVO;
        private VoyageVO voyageVO;
    
        private Mfa01FormVO mfa01FormVO;
    
        private Mfa02FormVO mfa02FormVO;
    
        @PostConstruct
        public void init()
        {
            mfa01FormVO = new Mfa01FormVO();
        }
    
        public void doMFA01()
        {
            //pretend to get VOs
            importConsignmentVO = new ImportConsignmentVO();
            voyageVO = new VoyageVO();
    
            //set some VO stuff
            if ( mfa01FormVO.getUcn().equalsIgnoreCase( "123" ) )
            {
                importConsignmentVO.setUnitID("AJF1");
                voyageVO.setVesselName("Ever Glade");
            }
            else {
                importConsignmentVO.setUnitID("ZZZ1");
                voyageVO.setVesselName("Ever Champion");
            }
            importConsignmentVO.setType("41G1");
            importConsignmentVO.setWeight("25000");
            voyageVO.setEta("01/01/2011");
    
            constructMFA02Form();
    
            viewController.setDestinationPage("mfa02");
    
        }
    
        private void constructMFA02Form()
        {
            mfa02FormVO = new Mfa02FormVO();
            mfa02FormVO.setUnitID(importConsignmentVO.getUnitID());
            mfa02FormVO.setType(importConsignmentVO.getType());
            mfa02FormVO.setWeight(importConsignmentVO.getWeight());
            mfa02FormVO.setMfaRef("12345");
            mfa02FormVO.setVesselName(voyageVO.getVesselName());
            mfa02FormVO.setEta(voyageVO.getEta());
    
            JSFUtils.addObjectToRequest(Mfa02FormVO.class.getName(), mfa02FormVO);
        }
    
      .....getters&setters
    
    }
    

    mfa02BackingBean.java

    package com.mcpplc.supportclient.webapp.managedBeans;
    
    import com.mcpplc.supportclient.webapp.Utils.JSFUtils;
    import com.mcpplc.supportclient.webapp.valueObjects.*;
    
    import java.io.Serializable;
    import java.util.*;
    
    import javax.annotation.PostConstruct;
    import javax.faces.application.FacesMessage;
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.ManagedProperty;
    import javax.faces.bean.ViewScoped;
    import javax.faces.component.UIComponent;
    import javax.faces.component.UIInput;
    import javax.faces.context.FacesContext;
    
    @ManagedBean
    @ViewScoped
    public class Mfa02BackingBean implements Serializable
    {
        @ManagedProperty(value = "#{viewController}")
        private ViewController viewController;
    
    
        private Mfa02FormVO mfa02FormVO;    
    
        @PostConstruct
        public void init()
        {
           mfa02FormVO = (Mfa02FormVO) JSFUtils.getObjectFromRequest(Mfa02FormVO.class.getName());
    
        }
    
        public String doMFA02()
        {
            viewController.setDestinationPage("mfa01");
            return "viewController";
        }
    
    
         public void validateData ( FacesContext facesContext, UIComponent uiComponentToValidate, Object value)
        {
            String message = "";
            String requestData = (String) value;
            if ( !requestData.contains( "0" )  )
                {
                    ((UIInput )uiComponentToValidate).setValid( false );
                    message = "Incorrect format for Unit ID";
                    facesContext.addMessage( uiComponentToValidate.getClientId(facesContext), new FacesMessage(message) );
                    //JSFUtils.addObjectToRequest(Mfa02FormVO.class.getName(), mfa02FormVO);
    
                }
    
    
    
        }
    
    .....getters&setters
    }
    

    Mfa01FormVO 和 Mfa02FormVO 只是带有 getter 和 setter 的值对象

    我遇到的主要问题是在请求之间保存对象数据。当我从 mfa01 转到 mfa02 时,我会查找填充一些 vos,然后将表单 vo 传递到 Flash。然后用 vo 值构建 Mfa02 屏幕。我遇到的最大问题是 mfa02 上出现验证错误。最初我将 bean 设置为 requestScoped 但是在验证失败后我丢失了 vo 对象。尽管我从 Flash 中得到对象后立即将其添加回 Flash。奇怪的是,我无法保证我什么时候会丢失物品。如果我再次单击,有时我会立即丢失对象,但有时它会再单击 1 次,然后我会丢失它。

    然后我将 mfa02backingbean 更改为 ViewScoped。但是,因为它完全是 ajax,所以 mfa02backingbean 没有在后续请求中重新初始化。这意味着无论我在第一个请求中设置的值如何,都将永远显示更多。我最终使用 ViewScoped 解决了这个问题,并将命令按钮更改为使用 Action 而不是 ActionListener,在该方法中我返回“viewController”字符串。我假设生命周期认为我正在返回一个新视图,因此它会清除视图范围中剩余的任何内容。

    我希望这段代码可以帮助其他寻找类似解决方案的人。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-31
      • 2011-09-14
      • 1970-01-01
      • 2012-08-08
      • 2016-01-28
      • 2014-02-24
      • 2014-01-20
      • 2012-07-24
      相关资源
      最近更新 更多