3

我有以下 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>

在顶部,我接受一个字符串作为 GET 参数,我通过转换器运行它然后获取一个Product对象,我将它放在 中productBean.product,该 bean 具有Product属性的 setter 和 getter,仅此而已。

然后我使用这个对象来显示信息等。这很好。我还commandLink使用 AJAX 将其添加到我的购物车中。ProductBean如果我在,这将拒绝工作RequestScope,当我把它放进去时,SessionScope它会起作用,但只会添加产品 1 次。

据我所知,这应该是直截了当的RequestScope,我不明白为什么它可以与SessionScope.

我已经阅读了这篇文章,但我认为我没有违反任何这些规则。

为了完整起见,这是我的ProductBean

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;
    }
}
4

1 回答 1

9

您的 bean 是请求范围的。因此,bean 实例的生命周期与单个 HTTP 请求-响应周期一样长。

当第一次请求带有表单的页面时,会创建一个新的 bean 实例,该实例接收一个具体product属性作为视图参数。在生成并发送相关响应后,bean 实例被丢弃,因为它是请求的结束。

提交表单时,实际上会触发一个新的 HTTP 请求,因此会创建一个新的 bean 实例,其中所有属性都设置为默认值,包括product属性。这种方式#{productBean.product}适用null于整个请求。命令链接的父组件的rendered属性将评估false。因此,命令链接动作永远不会被解码。这与未调用的 commandButton/commandLink/ajax 操作/侦听器方法的第 5 点相匹配,或者您已经找到的输入值未更新,但显然并没有真正理解。

解决方案是将 bean 放在视图范围内。只要您与同一个 JSF 视图交互(提交/回发),视图范围的 bean 就存在。标准的 JSF 提供@ViewScoped了这个。当您使用 CDI 而不是 JSF 来管理 bean 时,最好的选择是 CDI @ConversationScoped。这是相对笨拙的(您必须自己开始和结束范围),因此一些 CDI 扩展,例如提供 a 的MyFaces CODI@ViewAccessScoped可能更有用。

也可以看看:

于 2012-12-29T03:25:56.527 回答