JSF2.0 Ajax 导航模式
非常感谢有关使用 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 页面上放置关联的表单,并使用渲染的属性来决定要显示的内容。这可行,但我不舒服在一页中有很多表格。理想情况下,我想将每个页面分开,但不知道如何使用 Ajax 实现这一点。任何想法将不胜感激。
编辑 - 这是原始的解决方案,但现在已在下面的答案中进行了改进。这可行,但参数似乎存在问题。当我单击 AAA 或 BBB 链接时,我需要传递一个参数,以便 ViewController bean 知道单击了什么以及在何处设置目标页面。但是,如果我单击 AAA.xhtml 中的“提交”按钮,内容不会更改,除非我还将
添加到命令按钮。我以为我已经在 ViewController 构造函数中处理了 null Param,但显然我错过了一些重要的东西。我唯一的想法就是与 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;
}
}
Would really appreciate some guidance concerning patterns for a Web App using JSF 2.0, PrimeFaces and Ajax. Our current system uses JSPs with standard submits and we have 1 JSP for each functional page in our app. Each JSP calls an action class for logic, navigation and EJB calls. Migrating to JSF using the same set up would be relatively simple i.e. 1 xhtml page and associated backing bean and navigation/logic done via a do method. However we want to submit via Ajax and this causes puzzles in my head. If I load abc1.xhtml and submit with ajax then I stay on abc1.xhtml although I might need to go to abc2.xhtml. I thought about having the associated forms on 1 xhtml page and using the rendered property to decide what to display. This works but I'm not comfortable having lots of forms in 1 page. Ideally I want to keep each page separate but don't know how this is possible with Ajax. Any ideas would be much appreciated.
Edit - This was original Solution but now has been refined in my answer below. This works but there seems to be issues with the Params. When I click on the AAA or BBB link I need to pass a param so that the ViewController bean knows what was clicked and where to set the Destination page. However if I click the Submit button in AAA.xhtml the content doesn't change unless I also add <f:param name="tranID" value="AAA"/>
to the command button. I'd thought I'd handled a null Param in the ViewController constructor but obviously I'm missing something important. My only thoughts were to do with the URL. When I click the menu link it adds the param on to the url ?tranID=AAA
. If I then don't add the param onto the subsequent submit is this effectively changing the url and causing some sort of mismatch?
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 and BBC.xhtml as above
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;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我对你的建议是,除非你需要,否则不要使用ajax。如果您需要在请求后实际调用另一个页面,那么使用ajax有什么意义呢?
尝试考虑应用程序工作流程并在必要时应用 ajax。您认为 ajax 会令人困惑的情况是因为您可能不应该使用它
干杯
My recomendation for you is, do not use ajax unless you need it. If you need to actually call another page after a request, what is the point in using ajax?
Try to think in the application workflow and apply ajax where it is necessary. The cases you think that ajax will be confusing, is because you probably should not be using it
Cheers
决定回答我自己的问题,因为我现在已经有了一个完整的、仅支持 ajax 的原型应用程序。这符合我最初的要求,即将每个视图保存为一个 .xhtml 页面,并且每个视图都有自己的支持 bean。这里没有进一步污染我的问题,而是简化的代码。 (感谢 BalusC 之前的回答,虽然现在已经消失了,但确实很有帮助)。
viewController.xhtml
mfa01.xhtml
mfa02.xhtml >
ViewController.java
mfa01BackingBean.java
mfa02BackingBean.java
Mfa01FormVO & Mfa02FormVO 只是带有 getter 和 getter 的值对象。 setters
我遇到的主要问题是在请求之间保存对象数据。当我从 mfa01 转到 mfa02 时,我会进行查找并填充一些 vo,然后将表单 vo 传递到 Flash 中。然后使用 vo 值构建 Mfa02 屏幕。我遇到的最大问题是 mfa02 上出现验证错误。最初,我将 bean 设置为 requestScoped,但是在验证失败后我丢失了 vo 对象。尽管我从 Flash 中获取该对象后立即将其添加回 Flash 中,但还是出现了这种情况。但奇怪的是,无法保证我什么时候会丢失该物体。如果我再次单击,有时我会立即丢失该对象,但有时它会再单击一次,然后我就会丢失它。
然后我将 mfa02backingbean 更改为 ViewScoped。然而,因为它完全是 ajax mfa02backingbean 没有在后续请求中重新初始化。这意味着我在第一次请求时设置的值将永远显示更多。我最终使用 ViewScoped 解决了这个问题,并将命令按钮更改为使用 Action 而不是 ActionListener,在该方法中我返回“viewController”字符串。我假设生命周期认为我正在返回一个新视图,因此它会清除视图范围中留下的任何内容。
我希望这段代码可以帮助其他正在寻找类似解决方案的人。
Decided to answer my own question as I have now have a full working ajax only prototype app. This fits my initial requirements of having each view saved as one .xhtml page and each view having it's own backing bean. Instead of further polluting my question here is the simplified code. (Thanks to BalusC for his previous answer that really helped although its now disappeared).
viewController.xhtml
mfa01.xhtml
mfa02.xhtml
ViewController.java
mfa01BackingBean.java
mfa02BackingBean.java
Mfa01FormVO & Mfa02FormVO are just value objects with getters & setters
The main issue I encountered was saving object data between requests. When I go from mfa01 to mfa02 I do a lookup populate some vos and then pass a form vo into the Flash. Mfa02 screen is then constructed with the vo values. The big issue I had was when there was a validation error on mfa02. Initially I had the bean set to requestScoped however I lost the vo object after the validation failed. This was despite me adding the object back into the flash as soon as I got it from the Flash. The strange thing about this though was there was no guarantee when I would lose the object. If I clicked again sometimes I would lose the object straight away but sometimes it would remain for 1 more click and then i'd lose it.
I then changed mfa02backingbean to ViewScoped. However because it's completely ajax mfa02backingbean was not getting reinitialised on subsequent requests. This meant that whatever I set the values to on the first request would then be displayed forever more. I finally resolved this using ViewScoped and changing the Command Button to use an Action rather than ActionListener and in that method I return "viewController" String. I assume the lifecycle thinks I'm returning to a new view so it clears out anything left in the viewscope.
I hope this code helps anyone else looking for a similar solution.