0

我有一个组件来显示一个条目。这个组件可以在同一个页面中出现多次,因此只需要一个实体,将它传递给组件的支持 bean,所有的魔法都会发生。

组件的外观会受到各种参数的影响。

现在,一个要求是,无论我有 1 个还是 10 个这些组件,都应该可以使用深度链接恢复“相同”的视图状态。

假设我的组件如下所示:

<composite:interface componentType="itemView" >
  <composite:attribute name="item" required="true" shortDescription="The item to display."/>
  <composite:attribute name="urlPrefix" required="true" />
</composite:interface>

<composite:implementation>
    <f:event type="preRenderComponent" listener="#{cc.init}" />

   ....     
</composite:implementation>

它有一个对应的backing Bean,我可以访问。(省略这个,因为它不是必需的)

现在,这些组件被嵌入到一个页面中,如下所示:

   <f:metadata>
        <f:viewParam name="itemType"
            value="#{listController.itemType}"></f:viewParam>

    </f:metadata>

    <ui:define name="content">

    <!-- multiple occurences, ui repeat over list of items -->
    <my:itemView item="#{currentItem}" urlPrefix="#{listController.nextLetter}">

如前所述,每个项目的状态都可能受到影响,并且更改后的状态必须可以通过深度链接访问。所以,我的想法是,<h:link>在组件内部使用,为每个属性添加前缀并使用includeViewParams="true",这样每个(非默认)状态都是 url 的一部分。

<composite:interface componentType="itemView" >
  <composite:attribute name="item" required="true" shortDescription="The item to display."/>
  <composite:attribute name="urlPrefix" required="true" />
</composite:interface>

<composite:implementation>
    <f:event type="preRenderComponent" listener="#{cc.init}" />

 <h:link includeViewParams="true">
<f:param name="#{cc.attrs.urlPrefix}size" value="#{cc.largerSize}" />
    larger 
  </h:link>

   ....     
</composite:implementation>

就像“更大”的链接一样,最多有 10 个链接,提供不同的选项。

问题: include-view-params确实包含来自同一组件及其父级 (itemType) 的所有视图参数,但不包含来自其他组件的所有视图参数。所以,基本上改变“一个”组件的样式,会丢弃另一个组件的参数。

预期:网址已经看起来像?itemType=something&asize=5&abackground=green 单击b组件上的“更大”链接会给我:?itemType=something&asize=5&abackground=green&bsize=5

发生了什么:单击链接后,网址如下所示:?itemType=something&bsize=5 因此“a”的属性被删除。

我注意到,如果我<f:metadata>在列表页面上扩展对象时使用<f:viewParam name="asize" />aSize 参数之类的东西,当从“b”中单击某些东西时,将被保留 - 但当然,如果我需要列出所有类似的参数,我不需要组件,因为我无法预测项目的数量。

所以,我试图在组件内添加它(如 f:event):<f:viewParam name="#{cc.urlPrefix}size" />- 但这不起作用。

对此有任何想法(或替代解决方案?注意:将视图状态保存在数据库中,并且简单地使用“单个”id 来引用该状态基本上是不好的,因为这会导致大量数据污染。视图状态需要保持短暂,但可恢复:0))

4

1 回答 1

0

最后我找到了解决方案。这不是最好的,但至少可以工作;)

我在组件的 bean 上创建了一个方法,它将返回一个查询字符串,其中包含除作为参数传递的值之外的所有值。

因此,每当我想更改参数时asize=5,我都会使用 param 调用此函数size并附加新参数(函数将仅在 prefi 匹配时排除此参数,因此不会影响其他组件样式。):

public String buildUrlWithout(String keyString) {
        List<String> keys = ConversionHelper.Explode(keyString, ",");

        // get all parameters from the url.
        String prefix = this.getAttributes().get("urlPrefix").toString();
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();

        Map<String, String> params = externalContext.getRequestParameterMap();
        List<KeyValuePair<String, String>> result = new LinkedList<KeyValuePair<String, String>>();

        outerfor: for (Map.Entry<String, String> kvp : params.entrySet()) {
            for (String s : keys) {
                if (kvp.getKey().equals(prefix + s)) {
                    continue outerfor;
                }
            }

            // keep param
            result.add(new KeyValuePair<String, String>(kvp.getKey(), kvp.getValue()));
        }

        String qStr = KeyValuePair.toQueryString(result);
        return qStr;
    }

KeyValuePairist 只是一个 Helper-Class,其行为类似于 aMap<S,T>但提供了多个函数join(),例如split()等。(在这种情况下toQueryString()使用)

最后,在一个组件中,我这样使用它:

<h:outputLink
  value="#{cc.buildUrlWithout('size')}&amp;#{cc.attrs.urlPrefix}size={cc.size +1}">
    larger
</h:outputLink>

<h:outputLink
  value="#{cc.buildUrlWithout('size')}&amp;#{cc.attrs.urlPrefix}size={cc.size -1}">
    smaller
</h:outputLink>

<h:outputLink
  value="#{cc.buildUrlWithout('background,border')}&amp;#{cc.attrs.urlPrefix}background=red&amp;#{cc.attrs.urlPrefix}border=green">
    red background + green border
</h:outputLink>
于 2013-09-12T18:52:24.437 回答