我从JSF(Mojarra 2.2和Glassfish 4)开始,目前正在使用Web应用程序,该应用程序的职责是将客户端及其订单存储在数据库中。
创建新订单时,一个功能是允许从JSF <h:selectOneMenu>
中选择现有客户端。 Order实体将Client实体存储在其他属性中......
我遵循BalusC关于从数据库(here)预先填充<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>
答案 0 :(得分: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中,部件可能略有不同,但它仍然是一个很好的全面介绍。
答案 1 :(得分:0)
遇到类似的问题,只是意识到我忘了在我的对象中实现equals()和hashcode()方法。在这种情况下的客户端类。
应该责备自己跳过BalusC博客中的说明。http://balusc.blogspot.in/2007/09/objects-in-hselectonemenu.html
&#34; ...请注意Object#equals()实现。 这对JSF非常重要。转换后,它会将所选项目与列表中的项目进行比较。由于Object#equals()也需要Object#hashCode(),因此也可以实现....&#34;