Оценить список. Содержит строку в JSTL

89

Мне нужно скрыть элемент, если в JSP присутствуют определенные значения

Значения хранятся в списке, поэтому я попробовал:

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

Но это не работает.

Как я могу оценить, содержит ли список значение в JSTL, если список и значения являются строками.

OscarRyz
источник
17
Обратите внимание, что данный синтаксис работает так, как задумано, начиная с EL 2.2 (который входит в состав Servlet 3.0 / JSP 2.2, выпущенного в декабре 2009 г.).
BalusC

Ответы:

70

К сожалению, я думаю, что 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>

После этого $ {contains} будет равно "true", если myList содержит myValue.

Калеб Брази
источник
10
хорошо работает, если список невелик. Просто поймите, что это требует снижения производительности.
Chii
Да, было бы, если бы ты достаточно высоко поднялся. Я использовал его для коллекций из 10-20 вещей и не испытывал никаких проблем с производительностью. Что хуже, я считаю, это количество строк JSTL. Тем не менее, я думаю, что это единственный способ без создания собственного TLD (что не так уж сложно и вполне может того стоить).
Калеб Брази,
97

встроенной функции для проверки нет - вам нужно написать свою собственную функцию 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 - подробнее здесь

Чии
источник
4
Я рекомендую использовать Collectionвместо Listtaglib - он работает так же, но поддерживает больше типов коллекций, таких как Sets
Ральф
28

Другой способ сделать это - использовать 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]}">

Это должно вернуть истину, если пара существует на карте

Tamersalama
источник
2
Это мой предпочтительный способ - настроить хэш-карты в модели просмотра для всего, что мне нужно в представлении. Они прекрасно интегрируются с синтаксисом EL и молниеносны при поиске.
Борис Б.
Еще одна вещь: если ключ существует, но значение равно нулю или пусто, он вернет false.
Zai
1
Или , если карта имеет булевы, test="${isPresentByValue[myValue]}".
Ноумен
15

Вам нужно использовать функцию 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")и если это не то, что вы ищете, лучше используйте другой подход.

tk_
источник
2
Это неправильный подход. По сути, он будет вести себя mylist.toString().contains("apple")совершенно не так, как вы изначально ожидали.
BalusC
ох .. да это не то, что я ожидал. В любом случае я дополню свой ответ этим штрафом.
tk_ 05
2

Следующее - это скорее обходной путь, чем ответ на ваш вопрос, но, возможно, это именно то, что вы ищете. Если вы можете поместить свои значения на карту вместо списка, это решит вашу проблему. Просто сопоставьте свои значения с ненулевым значением и сделайте это, <c:if test="${mymap.myValue ne null}">style='display:none;'</c:if>или вы даже можете сопоставить style='display:none;и просто вывести${mymap.myValue}

свачон
источник
Я предполагаю, что синтаксис должен быть <c: if test = "$ {mymap [myValue] ne null}"> style = 'display: none;' </ c: if> В противном случае переменная «myValue» не оценивается.
Андреас
2
${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>
Тони Хунг
источник
0

Если вы используете EL 3.0+ , лучший подход в этом случае - это другой ответ, объясненный в другой теме:

Для 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. [...]

Лукас Баскеротто
источник
-1

Если вы используете 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>
xxg
источник
-1

Я нашел это решение потрясающим.

<%@ 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>

Вывод для приведенного выше кода:

Мой список [один, два, три]

В моем списке два

Мой список содержит,

Надеюсь, это кому-то поможет.

oOXAam
источник
-2
<c:if test="${fn:contains(task.subscribers, customer)}">

У меня это отлично работает.

Владислав
источник
18
Это проверка после преобразования обоих элементов в строку. Список преобразуется в строку и не проверяется для отдельных элементов. Если task.subscribers - это список ["один", "два", "двадцать один"], он будет: true для customer = "one" (совпадение дважды) false для customer = "three" (совпадение отсутствует) true для customer = «двадцать» (это не то, что вы смотрите)
Рикардо Маримон
2
Зная о предупреждении Рмаримона, этот ответ соответствовал моему точному варианту использования.
CodeReaper 07