【问题标题】:Evaluate list.contains string in JSTL评估 JSTL 中的 list.contains 字符串
【发布时间】:2010-12-02 04:28:37
【问题描述】:

如果 JSP 中存在某些值,我需要隐藏一个元素

这些值存储在一个列表中,所以我尝试了:

<c:if test="${  mylist.contains( myValue ) }">style='display:none;'</c:if>

但是,它不起作用。

如何评估列表是否包含 JSTL 中的值,列表和值是字符串。

【问题讨论】:

标签: java jsp jstl


【解决方案1】:

没有内置功能可以检查 - 您要做的是编写自己的 tld 函数,该函数接受一个列表和一个项目,并调用列表的 contains() 方法。例如

//in your own WEB-INF/custom-functions.tld file add this
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
        "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib
        xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
        version="2.0"
        >
    <tlib-version>1.0</tlib-version>
    <function>
        <name>contains</name>
        <function-class>com.Yourclass</function-class>
        <function-signature>boolean contains(java.util.List,java.lang.Object)
        </function-signature>
    </function>
</taglib>

然后创建一个名为 Yourclass 的类,并添加一个名为 contains 的静态方法,具有上述签名。我确信该方法的实现是不言自明的:

package com; // just to illustrate how to represent the package in the tld
public class Yourclass {
   public static boolean contains(List list, Object o) {
      return list.contains(o);
   }
}

然后你就可以在你的jsp中使用它了:

<%@ taglib uri="/WEB-INF/custom-functions.tld" prefix="fn" %>
<c:if test="${  fn:contains( mylist, myValue ) }">style='display:none;'</c:if>

该标签可用于站点中的任何 JSP。

编辑:有关 tld 文件的更多信息 - more info here

【讨论】:

  • 我建议在 taglib 中使用 Collection 而不是 List - 它的工作原理相同,但支持更多的集合类型,如 Sets
【解决方案2】:

遗憾的是,我认为 JSTL 只支持遍历所有元素以解决此问题。过去,我在核心标签库中使用过forEach方法:

<c:set var="contains" value="false" />
<c:forEach var="item" items="${myList}">
  <c:if test="${item eq myValue}">
    <c:set var="contains" value="true" />
  </c:if>
</c:forEach>

运行后,如果 myList 包含 myValue,${contains} 将等于“true”。

【讨论】:

  • 如果列表很小,效果很好。只需意识到这样做会产生性能成本。
  • 是的,如果你足够高,就会有。我已经用它收集了 10-20 件东西,并且没有遇到任何性能问题。我认为更糟糕的是JSTL的行数。不过,我认为这是不设置您自己的 TLD 的唯一方法(这不是太难,而且很可能是值得的)。
【解决方案3】:

另一种方法是使用Map (HashMap) 和代表您的对象的键值对。

Map<Long, Object> map = new HashMap<Long, Object>();
map.put(new Long(1), "one");
map.put(new Long(2), "two");

在 JSTL 中

<c:if test="${not empty map[1]}">

如果该对存在于地图中,这应该返回 true

【讨论】:

  • 这也是我的首选方式,在视图模型中为视图中需要的所有内容设置哈希图。它们与 EL 语法完美集成,搜索速度极快。
  • 还有一件事,如果 key 存在但 value 为 null 或为空,那么它将返回 false。
  • 或者如果地图包含布尔值,test="${isPresentByValue[myValue]}"
【解决方案4】:

您需要使用fn:contains()fn:containsIgnoreCase() 函数。

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

...

 <c:if test="${not fn:containsIgnoreCase(mylist, 'apple')}">
        <p>Doesn't contain 'apple'</p>
    </c:if>

<c:if test="${not fn:contains(mylist, 'Apple')}">
            <p>Contains 'Apple'</p>
        </c:if>

注意: 这将像 mylist.toString().contains("apple") 一样工作,如果这不是您想要的,最好使用其他方法。

【讨论】:

  • 这不是正确的方法。它的行为基本上类似于mylist.toString().contains("apple"),这绝对不是您最初所期望的。
  • 哦.. 是的,这不是我所期望的。无论如何,我会用这个罚款来更新我的答案。
【解决方案5】:

以下更多的是一种解决方法,而不是您问题的答案,但它可能是您正在寻找的。 如果您可以将值放在地图而不是列表中,那将解决您的问题。只需将您的值映射到非空值并执行此操作 &lt;c:if test="${mymap.myValue ne null}"&gt;style='display:none;'&lt;/c:if&gt; 或者您甚至可以映射到 style='display:none; 并简单地输出 ${mymap.myValue}

【讨论】:

  • 我猜语法应该是 style='display:none;' 否则变量 " myValue" 未评估。
【解决方案6】:
${fn:contains({1,2,4,8}, 2)}

  <c:if test = "${fn:contains(theString, 'test')}">
     <p>Found test string<p>
  </c:if>

  <c:if test = "${fn:contains(theString, 'TEST')}">
     <p>Found TEST string<p>
  </c:if>

【讨论】:

    【解决方案7】:

    如果您使用的是 EL 3.0+,这种情况下的最佳方法是 this other answer 在另一个主题中解释:

    对于Collection,这很简单,只需使用Colleciton#contains() EL中的方法。

    <h:panelGroup id="p1" rendered="#{bean.panels.contains('p1')}">...</h:panelGroup>
    <h:panelGroup id="p2" rendered="#{bean.panels.contains('p2')}">...</h:panelGroup>
    <h:panelGroup id="p3" rendered="#{bean.panels.contains('p3')}">...</h:panelGroup>
    

    对于Object[](数组),您至少需要 EL 3.0 并使用 它的新 Lambda 支持。

    <h:panelGroup id="p1" rendered="#{bean.panels.stream().anyMatch(v -> v == 'p1').get()}">...</h:panelGroup>
    <h:panelGroup id="p2" rendered="#{bean.panels.stream().anyMatch(v -> v == 'p2').get()}">...</h:panelGroup>
    <h:panelGroup id="p3" rendered="#{bean.panels.stream().anyMatch(v -> v == 'p3').get()}">...</h:panelGroup>
    

    如果您尚未使用 EL 3.0,则需要创建自定义 EL 功能。 [...]

    【讨论】:

      【解决方案8】:

      你不能使用 fn:contains(),因为它是一个字符串比较。所以假设你的列表包含 11,12,13 并且你写了 fn:contains(list,'1'),它会给你“真实”的结果。但我希望你期待 false 因为 1 不在列表中。您应该创建自己的自定义标签以使用 list.contains(Object o)。

      【讨论】:

        【解决方案9】:

        如果你使用的是 Spring Framework,你可以使用 Spring TagLib 和 SpEL:

        <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
        ---
        <spring:eval var="containsValue" expression="mylist.contains(myValue)" />
        <c:if test="${containsValue}">style='display:none;'</c:if>
        

        【讨论】:

          【解决方案10】:

          我发现这个解决方案很棒。

          <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
          <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
          <%
             ArrayList list = new ArrayList();
             list.add("one");
             list.add("two");
             list.add("three");
          %>
          <c:set var="list" value="<%=list%>" />
          <html>
          <body>
                  My list is ${list}<br/>
          <c:if test='${fn:contains(list, "two")}'>
                  My list contains two <br/>
          </c:if>
          <c:if test='${fn:contains(list, ",")}'>
                  My list contains , 
          </c:if>
          </body>
          </html>
          
          

          上面代码的输出是

          我的清单是[一、二、三]

          我的列表包含两个

          我的列表包含,

          我希望它对某人有所帮助。

          【讨论】:

            【解决方案11】:
            <c:if test="${fn:contains(task.subscribers, customer)}">
            

            这对我来说很好。

            【讨论】:

            • 这是在将两个元素都转换为字符串后进行检查。该列表被转换为字符串,而不是基于每个元素进行检查。如果 task.subscribers 是一个列表 [ "one", "two", "twentyone" ],它将是: true for customer = "one"(匹配两次) false for customer = "three"(不匹配) true for customer = “二十”(这不是你要找的)
            • 意识到 rmarimon 的警告,这个答案符合我的确切用例。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-04-20
            • 2014-01-28
            相关资源
            最近更新 更多