Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Jsf 通过缓存客户端数据避免转换器类的getAsObject方法中的额外DB读取?_Jsf_Jsf 2_Primefaces_Converter - Fatal编程技术网

Jsf 通过缓存客户端数据避免转换器类的getAsObject方法中的额外DB读取?

Jsf 通过缓存客户端数据避免转换器类的getAsObject方法中的额外DB读取?,jsf,jsf-2,primefaces,converter,Jsf,Jsf 2,Primefaces,Converter,我正在显示一个自动完成输入元素中的建议项列表。为此,我需要实现一个转换器,将实体转换为实体名,反之亦然。然而,在实现这一点时,我意识到我必须多次读取数据库才能找到所选entityName的对应entityId(而getAsObject()),我想知道为什么它不存储在客户端的某个地方,以便在选择entityName时可以传递entityId 有什么方法可以避免这种额外的阅读吗?这确实是“按设计”的,可能是JSF规范中的一点疏忽。从理论上讲,您可以通过从UIComponent参数中提取项并与它们进行

我正在显示一个
自动完成
输入元素中的建议项列表。为此,我需要实现一个
转换器
,将
实体
转换为
实体名
,反之亦然。然而,在实现这一点时,我意识到我必须多次读取数据库才能找到所选entityName的对应entityId(而
getAsObject()
),我想知道为什么它不存储在客户端的某个地方,以便在选择
entityName
时可以传递
entityId

有什么方法可以避免这种额外的阅读吗?

这确实是“按设计”的,可能是JSF规范中的一点疏忽。从理论上讲,您可以通过从
UIComponent
参数中提取项并与它们进行比较来完全避免这种情况。不过,这是一项工作。我的同事Arjan Tijms写了一篇关于这一点的博客:

这里是一个相关的摘录;下面是您需要扩展的基本转换器:

public abstract class SelectItemsBaseConverter implements Converter {
    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {        
        return SelectItemsUtils.findValueByStringConversion(context, component, value, this);    
    }    
}
下面是部分复制自Mojarra源代码的
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();
        }
    }
}

更新上述概念最终以以下转换器的风格出现在JSF实用程序库中:

  • -用于基于
    对象的
    #toString()
  • -用于基于项目索引的
  • -例如,基于
    对象的
    #toString()
  • -例如,基于项目索引的

我发现的唯一方法是使转换器不需要访问DB,即使转换器成为托管bean,以便它可以访问存储AutoComplete组件建议值列表的其他bean

大概是这样的:

@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)
  { ... }
@ManagedBean
@请求范围
公共类EntityConverter实现转换器
{
@ManagedProperty(value=“#{autoCompleteBean}”)
私有自动完成bean自动完成bean;
public void setAutoCompleteBean(AutoCompleteBean AutoCompleteBean)
{
this.autoCompleteBean=autoCompleteBean;
}
@凌驾
公共对象getAsObject(FacesContext上下文、UIComponent组件、,
字符串值)
{
最终列表实体=autoCompleteBean.getCachedSuggestions();
对于(最终实体:实体)
{
if(entity.getIdAsString().equals(value))
{
返回实体;
}
}
抛出新的IllegalStateException(“未找到实体!”);
}
@凌驾
公共字符串getAsString(FacesContext上下文、UIComponent、,
对象值)
{ ... }
在jsf页面中,确保将转换器引用为bean。即:

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


@BalusC:谢谢你的想法&很抱歉我在这方面反应太晚。我需要为primefaces
AutoComplete
component()实现这一点,你能告诉我如何在这个上下文中应用你的sol吗?谢谢。为什么是SomeEntity而不是SomeEntity?实例来自哪里?断开的链接(第一个)
        <p:autoComplete value="#{autoCompleteBean.selectedEntity}"
          completeMethod="#{autoCompleteBean.getSuggestions}" var="theEntity"
          itemValue="#{theEntity}" itemLabel=#{theEntity.someValue}
          converter="#{entityConverter}">