【问题标题】:Retrieving selectOneMenu complex object as selected item检索 selectOneMenu 复杂对象作为选定项
【发布时间】:2013-10-19 21:34:32
【问题描述】:

我从 JSF(Mojarra 2.2 和 Glassfish 4)开始,目前正在练习一个 Web 应用程序,该应用程序的工作是将客户及其订单存储在数据库中。

创建新订单时,一项功能是允许从 JSF <h:selectOneMenu> 中选择现有客户端。 Order 实体将 Client 实体存储在其他属性中...

我遵循了 BalusC 关于从数据库 (here) 预填充 <h:selectOneMenu> 的出色回答,并成功地从存储在急切的 ApplicationScoped ManagedBean 中的数据中填充了我的数据,但我无法检索所选项目在 backing bean 中作为复杂对象。它始终为空。

这让我发疯,您的帮助将不胜感激! 以下是相关代码sn-ps:

@ManagedBean(eager = true)
@ApplicationScoped
public class Data implements Serializable {

    private static final long serialVersionUID = 1L;

    @EJB
    private ClientDao clientDao;

    private List<Client> clients;

    @PostConstruct
    private void init() {
        clients = clientDao.lister();
    }

    public List<Client> getClients() {
        return clients;
    }

}

订单创建bean(注意:'commande' 表示订单;)

@ManagedBean
@RequestScoped
public class CreerCommandeBean implements Serializable {
    private static final long serialVersionUID = 1L;
    private Commande commande;

    private String choixNouveauClient = "nouveauClient";

    @EJB
    private CommandeDao commandeDao;

    public CreerCommandeBean() {
        commande = new Commande();
    }

    public void inscrire() {

        System.out.println("client : " + commande.getClient()); // prints **NULL**
            // ... orderService to store in DB
    }
... getters and setters

客户端转换器:

@FacesConverter(value = "clientConverter", forClass = Client.class)
public class ClientConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value == null) {
            return null;
        }

        Data data = context.getApplication().evaluateExpressionGet(context, "#{data}", Data.class);
        for (Client c : data.getClients()) {
            if (c.getId().toString().equals(value)) {
                return c;
            }
        }
        throw new ConverterException(new FacesMessage(String.format("Cannot convert %s to Client", value)));
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        return (value instanceof Client) ? String.valueOf(((Client) value).getId()) : null;
    }
}

Facelet 摘录:

<p:outputPanel id="gridContainerAncienClient">
            <p:selectOneMenu value="#{creerCommandeBean.commande.client}"
                rendered="#{creerCommandeBean.choixNouveauClient == 'ancienClient'}">
                <f:converter converterId="clientConverter" />
                <f:selectItems value="#{data.clients}" var="cli"
                    itemValue="#{cli}" itemLabel="#{cli.prenom} #{cli.nom}" />
            </p:selectOneMenu>
        </p:outputPanel>

【问题讨论】:

    标签: jsf facelets selectonemenu


    【解决方案1】:

    CreerCommandeBean@RequestScoped。这意味着它只会为一个请求而存在。
    当您选择要分配给#{creerCommandeBean.commande.client} 的客户端时,您会通过请求执行此操作。 #{creerCommandeBean.commande.client} 现在是选定的客户端。然后请求结束,bean 被销毁,您的“更改”丢失。
    当您尝试检索该数据时,您会再次通过请求执行此操作:创建 CreerCommandeBean 的新实例,并且构造函数将属性 commande 分配给 Commande 的新实例,其属性 client 再次可能是null

    解决方案:
    使用更广泛的范围。例如@ViewScoped 只要您保持在同一个视图中,bean 就会“活跃” - 无论您提出多少请求。

    提示: 阅读BalusC's Post on Communication is JSF 2.0。 JSF 2.2 中的部分可能略有不同,但它仍然是一个很好且全面的介绍。

    【讨论】:

    • 非常感谢莱斯特!现在一切正常。感谢您提供的链接,与 BalusC 的帖子一样,该链接非常出色;-)
    【解决方案2】:

    我遇到了类似的问题,只是意识到我忘记在我的对象中实现 equals() 和 hashCode() 方法。本例中的客户端类。

    我应该责怪自己跳过了BalusC's blog中的说明。

    "...请注意Object#equals()的实现。这对JSF非常重要。转换后,它将选择的项目与列表中的项目进行比较。如Object#equals()还需要Object#hashCode(),这个也实现了...."

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-12
      • 2013-11-10
      • 2012-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-12
      • 2013-12-19
      相关资源
      最近更新 更多