我有以下XHTML:
<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">
<head>
<title>TODO supply a title</title>
</head>
<body>
<f:metadata>
<f:viewParam id="productCV" name="productName" value="#{productBean.product}"
converter="#{productConverter}" required="true"/>
</f:metadata>
<ui:composition template="/templates/mastertemplate.xhtml">
<!-- Define the page title for this page-->
<ui:define name="pageTitle">
<h:outputFormat value="#{msgs.productPageTitle}">
<f:param value="#{productBean.product.description}"/>
</h:outputFormat>
</ui:define>
<!-- Pass the categoryName parameter to the sidebar so the category of this product is highlighted-->
<ui:param name="categoryName" value="#{productBean.product.categoryName}"/>
<ui:define name="content">
<!-- If productconversion failed, show this error-->
<h:message id="error" for="productCV" style="color: #0081c2;" rendered="#{productBean.product == null}" />
<!-- If productconversion succeeded show the product page-->
<h:panelGroup rendered="#{productBean.product != null}">
<p>#{productBean.product.description} #{productBean.product.categoryName}</p>
<h:form>
<h:commandLink action="#{cartBean.addItemToCart(productBean.product)}">
<f:ajax event="action" render=":cart :cartPrice" />
<h:graphicImage value="resources/img/addToCart.gif"/>
</h:commandLink>
</h:form>
</h:panelGroup>
</ui:define>
</ui:composition>
</body>
</html>
在顶部我接受一个String作为GET参数,我通过转换器运行然后得到一个Product
对象,我把它放在productBean.product
中,该bean有一个setter和getter for the Product
属性,就是这一切。
然后我使用此对象来显示信息等。这很好用。我还添加commandLink
以使用AJAX将其添加到我的购物车。如果ProductBean
位于RequestScope
,当我将SessionScope
放入RequestScope
时,这会拒绝合作,但只会添加产品一次。
我知道这应该是一个直截了当的SessionScope
,我不明白为什么它适用于ProductBean
。
我已阅读this帖子,但我认为我没有违反任何规则。
为了完整性,这是我的import be.kdg.shop.model.stock.Product;
import java.util.logging.Logger;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
@Named
@RequestScoped
public class ProductBean {
private static final Logger logger = Logger.getLogger(ProductBean.class.getName());
private Product product;
public ProductBean() {}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
:
{{1}}
答案 0 :(得分:9)
您的bean是请求作用域。因此,bean实例的存在时间与单个HTTP请求 - 响应周期一样长。
当第一次请求具有表单的页面时,会创建一个新的bean实例,该实例接收具体的product
属性作为视图参数。在生成并发送相关响应之后,bean实例被包含在内,因为它是请求的结束。
提交表单时,实际上会触发一个新的HTTP请求,从而创建一个新的bean实例,并将所有属性设置为default,包括product
属性。这种方式#{productBean.product}
对于整个请求都是null
。命令链接的父组件的rendered
属性将评估false
。因此,命令链接动作永远不会被解码。这与你已经找到的commandButton/commandLink/ajax action/listener method not invoked or input value not updated的第5点相匹配,但显然并没有真正理解。
解决方案是将bean放在视图范围内。只要您使用相同的JSF视图进行交互(提交/回发),视图范围的bean就会存在。标准JSF为此提供@ViewScoped
。当您使用CDI而不是JSF来管理bean时,最好的选择是CDI @ConversationScoped
。这是相对笨拙的(你必须自己开始和结束范围),所以提供@ViewAccessScoped
的{{3}}等CDI扩展可能更有用。