非常感谢有关使用JSF 2.0,PrimeFaces和Ajax的Web App模式的一些指导。我们当前的系统使用带有标准提交的JSP,我们的应用程序中的每个功能页面都有1个JSP。每个JSP都调用逻辑,导航和EJB调用的动作类。使用相同的设置迁移到JSF将相对简单,即1 xhtml页面和相关的辅助bean以及通过do方法完成的导航/逻辑。但是我们想通过Ajax提交,这会引起我头脑中的谜题。如果我加载abc1.xhtml并使用ajax提交然后我留在abc1.xhtml,虽然我可能需要转到abc2.xhtml。我想在1 xhtml页面上使用关联的表单并使用rendered属性来决定要显示的内容。这有效,但我不习惯在1页中有很多表格。理想情况下,我希望将每个页面分开,但不知道如何使用Ajax实现这一点。任何想法都会非常感激。
编辑 - 这是原始解决方案,但现在已在我的答案中进行了改进 。这有效,但Params似乎存在问题。当我点击AAA或BBB链接时,我需要传递一个参数,以便ViewController bean知道点击了什么以及在哪里设置目标页面。但是,如果我单击AAA.xhtml中的“提交”按钮,则内容不会更改,除非我还将<f:param name="tranID" value="AAA"/>
添加到命令按钮。我以为我在ViewController构造函数中处理了一个空Param,但显然我错过了一些重要的东西。我唯一的想法是使用URL。当我点击菜单链接时,它会将参数添加到网址?tranID=AAA
。如果我然后不将param添加到后续提交中,这是否会有效地更改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;
}
}
答案 0 :(得分:0)
我的推荐是,除非你需要,否则不要使用ajax。如果您需要在请求后实际调用另一个页面,那么使用ajax有什么意义?
尝试在应用程序工作流程中思考并在必要时应用ajax。您认为ajax会令人困惑的案例是因为您可能不应该使用它
干杯
答案 1 :(得分:0)
决定回答我自己的问题,因为我现在有一个完整的工作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&amp; Mfa02FormVO只是具有吸气剂和放大器的价值对象。 setter方法
我遇到的主要问题是在请求之间保存对象数据。当我从mfa01转到mfa02时,我会查找填充一些vos然后将表单vo传递给Flash。然后用vo值构造Mfa02屏幕。我遇到的最大问题是mfa02上存在验证错误。最初我将bean设置为requestScoped但是在验证失败后丢失了vo对象。尽管我从Flash中获取了该对象,但我还是将其添加回了闪存中。关于这一点的奇怪之处在于,当我丢失物体时,我无法保证。如果我再次点击,有时我会立即失去对象,但有时会再次点击一次,然后我会失去它。
然后我将mfa02backingbean更改为ViewScoped。但是因为它完全是ajax mfa02backingbean没有在后续请求中重新初始化。这意味着无论我在第一次请求中设置值,都将永远显示出来。我最终使用ViewScoped解决了这个问题并更改了Command Button以使用Action而不是ActionListener,并在该方法中返回“viewController”字符串。我假设生命周期认为我正在返回一个新视图,因此它会清除视图中留下的任何内容。
我希望这段代码可以帮助其他人寻找类似的解决方案。