【问题标题】:omnifaces.SelectItemsConverter returns nullomn​​ifaces.SelectItemsConverter 返回 null
【发布时间】:2014-10-07 03:26:54
【问题描述】:

我正在使用 jsf spring hibernate 和 primefaces 进行项目。我有一个添加项目的表单。该表单的一个字段不是原始类型,而是自定义对象。我知道我必须使用转换器并获得我选择的对象。我尝试了一个自定义转换器,但没有成功,因为我无法注入服务并且始终为空。所以我转向了全能,让我的生活更轻松并继续前进。不幸的是,我也有这个问题。我一遍又一遍地查看我的代码,但我看不出有什么问题。下面我添加与问题相关的代码: 首先是我使用omnifaces的页面:

<html xmlns="http://www.w3.org/1999/xhtml"  
 xmlns:h="http://java.sun.com/jsf/html"      
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:p="http://primefaces.org/ui"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:o="http://omnifaces.org/ui"
    xmlns:of="http://omnifaces.org/functions">
<h:head><title>Welcome to OTV_JSF_Spring_Hibernate_Project</title></h:head>  
<h:body>
    <ui:include src="/pages/topMenu.xhtml"/>
    <h:form>
        <table>
            <tr>
                <td><h:outputLabel for="itemId" value="id: "/></td>
                <td><h:inputText id="itemId" value="#{inventoryItemsMB.itemId}"></h:inputText></td>
            </tr>


            <tr>
                <td><h:outputLabel for="RefItemCategories" value="Category Code"/></td>
                <td>
                    <h:selectOneMenu value="#{inventoryItemsMB.refItemCategories}" id="refItemCategories" immediate="true" converter="omnifaces.SelectItemsConverter">

                        <f:selectItems  value="#{refItemCategoriesMB.refItemCategoriesList}" var="ref" itemLabel="#{ref.itemCategoryDescription}" itemValue="#{ref}"/>
                        <!--<f:converter converterId="catConverter"/>-->
                    </h:selectOneMenu>
                </td>
            </tr>

            <tr>
                <td><h:outputLabel for="description" value="Description"/></td>
                <td><h:inputText id="description" value="#{inventoryItemsMB.description}" immediate="false"></h:inputText></td>
            </tr>

            <tr>
                <td><h:outputLabel for="AvgMonthlyUsage" value="Average Monthly Usage: "/></td>
                <td><h:inputText id="AvgMonthlyUsage" value="#{inventoryItemsMB.avgMonthlyUsage}"></h:inputText></td>
            </tr>
            <tr>
                <td><h:outputLabel for="reorderQuantity" value="Reorder Quantity: "/></td>
                <td><h:inputText id="reorderQuantity" value="#{inventoryItemsMB.reorderQuantity}"></h:inputText></td>
            </tr>
            <tr>
                <td><h:outputLabel for="Price" value="Price: "/></td>
                <td><h:inputText id="Price" value="#{inventoryItemsMB.price}"></h:inputText></td>
            </tr>
            <tr>
                <td><h:outputLabel for="ItemStockLevels" value="Item stock levels: "/></td>
                <td><h:inputText id="ItemStockLevels" value="#{itemStockLevelsMB.quantityInStock}"></h:inputText></td>
            </tr>
            <tr>
                <td><p:commandButton id="addInventoryItems" value="ADD" action="#{inventoryItemsMB.addInventoryItems}" ajax="false" immediate="false"/></td>
            </tr>
        </table>
    </h:form>

</h:body>

其次是我的 managedBeans:

@ManagedBean(name="inventoryItemsMB")
   @RequestScoped
   public class InventoryItemsManagedBean implements Serializable {

private static final long serialVersionUID = 1L;
private static final String SUCCESS = "successInventoryItems";
private static final String ERROR   = "error";

@ManagedProperty(value="#{InventoryItemsService}")
IInventoryItemsService inventoryItemsService;

List<InventoryItems> inventoryItemsList;

private int id;
private String avgMonthlyUsage;
String description;
Set<ItemStockLevels> itemStockLevels;
float price;
String reorderQuantity;
RefItemCategories refItemCategories;
byte[] photo;

public String addInventoryItems(){
    try{
        InventoryItems inventoryItems = new InventoryItems();
        //RefItemCategories refItemCategories = new RefItemCategories();
        inventoryItems.setAvgMonthlyUsage(getAvgMonthlyUsage());//DONE is it a string?look at impl
        inventoryItems.setDescription(getDescription());//DONE
        inventoryItems.setItemId(getItemId());//DONE
        inventoryItems.setItemStockLevels(getItemStockLevels());//DONE ----- why is it a set?
        inventoryItems.setPhoto(getPhoto());
        inventoryItems.setPrice(getPrice());//DONE
        inventoryItems.setRefItemCategories(getRefItemCategories());//DONE---why refItemCategories
        inventoryItems.setReorderQuantity(getReorderQuantity());//DONE-----why string?
        //refItemCategories.getItemCategoryCode();
        //refItemCategories.getItemCategoryDescription();
        getInventoryItemsService().addInventoryItems(refItemCategories, inventoryItems);
        return SUCCESS;
    } catch (DataAccessException e) {
        e.printStackTrace();
    }
    return ERROR;
}

public List<InventoryItems> getInventoryItemsList() {
    inventoryItemsList = new ArrayList<InventoryItems>();
    inventoryItemsList.addAll(getInventoryItemsService().getInventoryItems());
    return inventoryItemsList;
}

public IInventoryItemsService getInventoryItemsService() {
return inventoryItemsService;
}


public void setInventoryItemsService(IInventoryItemsService inventoryItemsService) {
this.inventoryItemsService = inventoryItemsService;
}

public void setInventoryItemsList(List<InventoryItems> inventoryItemsList) {
this.inventoryItemsList = inventoryItemsList;
}

public int getItemId() {
    return id;
}

public void setItemId(int id) {
    this.id = id;
}

public void setAvgMonthlyUsage(String avgMonthlyUsage){
    this.avgMonthlyUsage = avgMonthlyUsage;
}

public String getAvgMonthlyUsage(){
    return avgMonthlyUsage;
}

public void setDescription(String description){
    this.description = description;
}

public String getDescription(){
    return description;
}

public void setItemStockLevelses(Set<ItemStockLevels> itemStockLevels){
    this.itemStockLevels = itemStockLevels;
}

public Set<ItemStockLevels> getItemStockLevels(){
    return itemStockLevels;
}

public void setPrice(float price){
    this.price = price;
}

public float getPrice(){
    return price;
}

public void setReorderQuantity(String reorderQuantity){
    this.reorderQuantity = reorderQuantity;
}

public String getReorderQuantity(){
    return reorderQuantity;
}

public void setRefItemCategories(RefItemCategories refItemCategories){
    this.refItemCategories = refItemCategories;
}

public RefItemCategories getRefItemCategories(){
    return refItemCategories;
}

public byte[] getPhoto(){
    return photo;
}

public void setPhoto(byte[] photo){
    this.photo = photo;
}

}

和其他托管bean

 @ManagedBean(name="refItemCategoriesMB")
@RequestScoped
public class RefItemCategoriesManagedBean implements Serializable{
    private static final long serialVersionUID = 1L;
    private static final String SUCCESS = "addCategorySuccess";
    private static final String ERROR   = "error";

@ManagedProperty(value="#{RefItemCategoriesService}")
IRefItemCategoriesService refItemCategoriesService;

List<RefItemCategories> refItemCategoriesList;

private int id;
private String description;

public String addRefItemCategories(){
    try{
        RefItemCategories refItemCategories = new RefItemCategories();
        refItemCategories.setItemCategoryCode(getItemCategoryCode());
        refItemCategories.setItemCategoryDescription(getItemCategoryDescription());
        getRefItemCategoriesService().addRefItemCategories(refItemCategories);
        return SUCCESS;
    } catch (DataAccessException e){
        e.printStackTrace();
    }
    return ERROR;
}

public List<RefItemCategories> getRefItemCategoriesList() {
    refItemCategoriesList = new ArrayList<RefItemCategories>();
    refItemCategoriesList.addAll(getRefItemCategoriesService().getRefItemCategories());
    return refItemCategoriesList;
}

public IRefItemCategoriesService getRefItemCategoriesService() {
return refItemCategoriesService;
}

public void setRefItemCategoriesService(IRefItemCategoriesService refItemCategoriesService) {
this.refItemCategoriesService = refItemCategoriesService;
}

public void setRefItemCategoriesList(List<RefItemCategories> refItemCategoriesList) {
this.refItemCategoriesList = refItemCategoriesList;
}

public String DeleteCategory(RefItemCategories refItemCategoriesList){
    getRefItemCategoriesService().deleteRefItemCategories(refItemCategoriesList);
    return SUCCESS;
}


public void setItemCategoryCode(int id){
    this.id = id;
}

public int getItemCategoryCode(){
    return id;
}

public void setItemCategoryDescription(String description){
    this.description = description;
}

public String getItemCategoryDescription(){
    return description;
}

 @Override
public boolean equals(Object object){
if(this.id == ((RefItemCategories) object).getItemCategoryCode()) {
    return true;
}else {
    return false;
}

}

}

我无法注入的服务:

 @Transactional(readOnly = true)
@Service("RefItemCategoriesService")
public class RefItemCategoriesService implements IRefItemCategoriesService{

    @Autowired
    RefItemCategoriesDAOImpl refItemCategoriesDAO;

    @Transactional(readOnly = false)
    @Override
    public void addRefItemCategories(RefItemCategories refItemCategories) {
        getRefItemCategoriesDAO().addRefItemCategories(refItemCategories);
    }

    @Transactional(readOnly = false)
    @Override
    public void updateRefItemCategories(RefItemCategories refItemCategories) {
        getRefItemCategoriesDAO().updateRefItemCategoriesUser(refItemCategories);
    }

    @Transactional(readOnly = false)
    @Override
    public void deleteRefItemCategories(RefItemCategories refItemCategories) {
        getRefItemCategoriesDAO().deleteRefItemCategories(refItemCategories);
    }

    @Override
    public RefItemCategories getRefItemCategoriesByID(int id) {
        return getRefItemCategoriesDAO().getRefItemCategoriesById(id);
    }

    @Override
    public List<RefItemCategories> getRefItemCategories() {
        return getRefItemCategoriesDAO().getRefItemCategories();
    }

    public RefItemCategoriesDAO getRefItemCategoriesDAO(){
        return refItemCategoriesDAO;
    }
}

这样我得到一个事务错误,其中 item_cat_code(db 表)不能为空。 感谢您的宝贵时间。

【问题讨论】:

  • 有关您未来问题中的代码 sn-ps,请阅读stackoverflow.com/help/mcve。到目前为止发布的代码中存在太多噪音。当然,例如 HTML &lt;table&gt; 元素、price 输入字段和 updateRefItemCategories() 方法不会在问题中发挥作用。当您删除它们时,问题仍然会出现。大约 70% 的代码都是这样。这对于仅通过查看代码来发现问题的原因没有帮助。将来,只要问题仍然存在,请将代码复制粘贴到新项目并删除尽可能多的行。好吗?

标签: jsf jsf-2 converter omnifaces


【解决方案1】:

根据documentationomnifaces.SelectItemsConverter 依赖于待转换对象的Object#toString() 表示以正确匹配所选项目。您没有显示您的RefItemCategories 实体的代码,所以这只是猜测,但症状表明您确实没有@Override 实体上的toString(),因此它依赖于default FQN@hashcode representation .只有当可用项目(&lt;f:selectItems&gt; 的值)完全相同在同一视图上的回发中相同时,这一切才会起作用。

但是,提供可用项目的RefItemCategoriesManagedBean 支持bean 是请求范围的,并将它们加载到getter 中。每次命中 getter 时,都会返回一个包含全新实例的全新列表。这些与已加载到可用项目列表中的哈希码不同,因此提交的选定项目永远不会与任何新加载的项目匹配。

因此至少有 2 个设计问题。

  1. You should choose the right bean scope for the data it holds。至少是@ViewScoped
  2. You should never interact with the DB in a getter method。在@PostConstruct 中进行操作。

如果你同时解决这两个问题,那么问题应该会消失。

或者,只需为您的实体实现toString()。例如

public class RefItemCategories {

    @Override
    public String toString() {
        return "RefItemCategories[" + id + "]";
    }

}

顺便说一句,在RefItemCategoriesManagedBean 支持bean 类上看到equals() 方法很奇怪。你不是想把它放在RefItemCategories 实体上吗?无论如何,请仔细阅读SelectItemsConverterdocumentation 如何正确使用它以及如何正确设计您的实体。

【讨论】:

  • 非常感谢您的回答和指导。我不仅解决了问题,而且获得了相当多的知识。我通过在 RefItemCategories 中实现 toString()、equals() 解决了这个问题,并将范围注释更改为 ViewScope 到两个 bean。您对我帖子中的噪音也是正确的,我会进一步查看您提供的链接。再次感谢。
猜你喜欢
  • 2013-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-28
  • 1970-01-01
  • 1970-01-01
  • 2014-10-18
  • 1970-01-01
相关资源
最近更新 更多