我开始使用JSF(Mojarra 2.2和Glassfish 4),目前正在练习一个Web应用程序,它的工作是将客户和他们的订单存储在DB中。
当创建一个新的订单时,有一个功能是允许从JSF的客户机中选择一个现有的客户机。<h:selectOneMenu>
. 一个订单实体在其他属性中存储了一个客户实体......
我按照BalusC的伟大回答,预先填充一个 <h:selectOneMenu>
从数据库 (此处),并成功地从存储在急切的ApplicationScoped ManagedBean中的数据中填充了我的数据,但我无法在支持Bean中以复杂对象的形式检索所选项目。它总是空的。
这快把我逼疯了,真的很感谢您的帮助!以下是相关代码片段。
@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>
CreerCommandeBean
是 @RequestScoped
. 这意味着它将只为一个请求而存在。当您选择一个客户机被分配到 #{creerCommandeBean.commande.client}
你通过请求来实现。#{creerCommandeBean.commande.client}
现在是选定的客户端。然后请求结束,Bean被销毁,你的 "更改 "也就丢失了。当你试图检索这些数据时,你会再次通过请求来完成。一个新的实例 CreerCommandeBean
被创建,并且构造函数将属性分配给了 commande
与新的 Commande
其所属 client
又可能是 null
.
解决办法。 使用更广泛的范围,例如 @ViewScoped
这使得Bean "活 "了下来,只要你呆在同一个视图中--无论你做多少次请求。
提示:使用更广泛的范围。阅读 BalusC的帖子 Communication is JSF 2.0
. 在JSF 2.2中,部分内容可能略有不同,但仍然是一个不错的全面介绍。
我也被类似的问题卡住了,后来才发现我的Object.Client类中忘记了实现equals()和hashCode()方法。在这种情况下,我的Object.Client类中忘了实现equals()和hashCode()方法。
要怪就怪我自己跳过了在 BalusC的博客.
"...请注意:
Object#equals()
实现。这对于JSF来说是非常重要的。 转换后,它会将所选项目与列表中的项目进行比较。由于Object#equals()
还需要Object#hashCode()
,这也是实施......"