2012-02-05 51 views
5

我在autocomplete輸入元素中顯示了建議項目的列表。爲此我需要實施converterentity<entityName, entityId>轉換爲entityName &反之亦然。但是同時實施,我才意識到我必須讀dB大於1周的時間來尋找相應的ENTITYID爲選定的entityName(而getAsObject()),我很奇怪,爲什麼沒有這個地方存儲客戶端,以便entityId可以通過當選擇entityname時。通過緩存數據客戶端避免額外的數據庫讀取轉換器類的getAsObject方法?

有什麼辦法,我可以避免額外讀?

回答

6

這的確是「設計」,並在JSF規範也許有點疏忽。您理論上可以通過從UIComponent參數中提取項目並與其進行比較來完全避免它。這是一個工作。我的同事阿爾揚Tijms寫了博客這個問題:Automatic to-Object conversion in JSF selectOneMenu & Co.

下面是相關的提取物;以下是基本轉換器,你就需要去繼承:

public abstract class SelectItemsBaseConverter implements Converter { 
    @Override 
    public Object getAsObject(FacesContext context, UIComponent component, String value) {   
     return SelectItemsUtils.findValueByStringConversion(context, component, value, this);  
    }  
} 

這裏的SelectItemsUtils類這部分是從鑽嘴魚科的源代碼複製:

public final class SelectItemsUtils { 

    private SelectItemsUtils() {} 

    public static Object findValueByStringConversion(FacesContext context, UIComponent component, String value, Converter converter) { 
     return findValueByStringConversion(context, component, new SelectItemsIterator(context, component), value, converter);   
    } 

    private static Object findValueByStringConversion(FacesContext context, UIComponent component, Iterator<SelectItem> items, String value, Converter converter) { 
     while (items.hasNext()) { 
      SelectItem item = items.next(); 
      if (item instanceof SelectItemGroup) { 
       SelectItem subitems[] = ((SelectItemGroup) item).getSelectItems(); 
       if (!isEmpty(subitems)) { 
        Object object = findValueByStringConversion(context, component, new ArrayIterator(subitems), value, converter); 
        if (object != null) { 
         return object; 
        } 
       } 
      } else if (!item.isNoSelectionOption() && value.equals(converter.getAsString(context, component, item.getValue()))) { 
       return item.getValue(); 
      } 
     }   
     return null; 
    } 

    public static boolean isEmpty(Object[] array) { 
     return array == null || array.length == 0;  
    } 

    /** 
    * This class is based on Mojarra version 
    */ 
    static class ArrayIterator implements Iterator<SelectItem> { 

     public ArrayIterator(SelectItem items[]) { 
      this.items = items; 
     } 

     private SelectItem items[]; 
     private int index = 0; 

     public boolean hasNext() { 
      return (index < items.length); 
     } 

     public SelectItem next() { 
      try { 
       return (items[index++]); 
      } 
      catch (IndexOutOfBoundsException e) { 
       throw new NoSuchElementException(); 
      } 
     } 

     public void remove() { 
      throw new UnsupportedOperationException(); 
     } 
    } 
} 

下面是你應該如何使用它自己的轉換器,你只需要執行getAsString()(該getAsObject()已處理):

@FacesConverter("someEntitySelectItemsConverter") 
public class SomeEntitySelectItemsConverter extends SelectItemsBaseConverter { 

    @Override 
    public String getAsString(FacesContext context, UIComponent component, Object value) { 
     return ((SomeEntity) value).getId().toString(); 
    } 
} 

更新上述概念已經結束了在JSF工具庫OmniFaces下面的轉換器的味道:

+0

@BalusC:感謝您的想法和對不起,我對此很晚迴應。我需要爲primefaces'AutoComplete'組件實現這個(http://www.primefaces.org/showcase-labs/ui/autoCompletePojo.jsf),你能告訴我如何在這種情況下應用你的sol?謝謝。 – 2012-02-09 20:12:51

+0

爲什麼是SomeEntity而不是實體?實例在哪裏發起? – Thufir 2012-04-17 03:10:30

+0

斷開鏈接(第一個) – 2017-06-12 09:43:36

0

我發現要做到這一點,使您的轉換並不需要訪問數據庫的唯一方法,是使轉換器一個託管bean,以便它可以訪問存儲建議值的列表中的一些其他的bean的AutoComplete組件。

事情是這樣的:

@ManagedBean 
@RequestScoped 
public class EntityConverter implements Converter 
{ 
    @ManagedProperty(value = "#{autoCompleteBean}") 
    private AutoCompleteBean autoCompleteBean; 

    public void setAutoCompleteBean(AutoCompleteBean autoCompleteBean) 
    { 
    this.autoCompleteBean = autoCompleteBean; 
    } 

    @Override 
    public Object getAsObject(FacesContext context, UIComponent component, 
     String value) 
    { 
    final List<Entity> entities = autoCompleteBean.getCachedSuggestions(); 

    for (final Enity entity : entities) 
    { 
     if (entity.getIdAsString().equals(value)) 
     { 
     return entity; 
     } 
    } 
    throw new IllegalStateException("Entity was not found!"); 
    } 

    @Override 
    public String getAsString(FacesContext context, UIComponent component, 
     Object value) 
    { ... } 

在JSF頁面中,請確保您引用轉換爲一個bean。即:

 <p:autoComplete value="#{autoCompleteBean.selectedEntity}" 
      completeMethod="#{autoCompleteBean.getSuggestions}" var="theEntity" 
      itemValue="#{theEntity}" itemLabel=#{theEntity.someValue} 
      converter="#{entityConverter}"> 
相關問題