Évaluer list.contains string dans JSTL


88

J'ai besoin de masquer un élément si certaines valeurs sont présentes dans le JSP

Les valeurs sont stockées dans une liste alors j'ai essayé:

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

Mais ça ne marche pas.

Comment puis-je évaluer si une liste contient une valeur dans JSTL, la liste et les valeurs sont des chaînes.


17
Notez que la syntaxe donnée fonctionne comme prévu depuis EL 2.2 (qui fait partie de Servlet 3.0 / JSP 2.2 qui a été publié en décembre 2009).
BalusC

Réponses:


69

Malheureusement, je pense que JSTL ne supporte rien d'autre qu'une itération à travers tous les éléments pour comprendre cela. Dans le passé, j'ai utilisé la méthode forEach dans la bibliothèque de balises principale:

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

Après cette exécution, $ {contains} sera égal à "true" si myList contenait myValue.


10
fonctionne bien si la liste est petite. Réalisez simplement qu'il y a un coût de performance à faire de cette façon.
Chii

Ouais, il y en aurait si vous deveniez assez haut. Je l'ai utilisé pour des collections de 10 à 20 objets et je n'ai rencontré aucun problème de performances. La chose que je pense est pire est le nombre de lignes de JSTL. Pourtant, je pense que c'est le seul moyen de ne pas créer votre propre TLD (ce qui n'est pas trop difficile et peut très bien en valoir la peine).
Kaleb Brasee le

97

il n'y a pas de fonction intégrée pour vérifier cela - ce que vous feriez est d'écrire votre propre fonction tld qui prend une liste et un élément, et appelle la méthode contains () de la liste. par exemple

//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>

Créez ensuite une classe appelée Yourclass et ajoutez une méthode statique appelée contains avec la signature ci-dessus. Je suis sûr que la mise en œuvre de cette méthode est assez explicite:

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);
   }
}

Ensuite, vous pouvez l'utiliser dans votre jsp:

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

La balise peut être utilisée à partir de n'importe quelle JSP du site.

edit: plus d'infos sur le fichier tld - plus d'infos ici


4
Je recommande d'utiliser Collectionau lieu de Listdans le taglib - cela fonctionne de la même manière mais prend en charge plus de types de collection comme Sets
Ralph

28

Une autre façon de procéder consiste à utiliser une Map (HashMap)paire clé avec valeur représentant votre objet.

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

Dans JSTL

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

Cela devrait retourner vrai si la paire existe dans la carte


2
C'est aussi ma méthode préférée, configurer des hashmaps dans le viewmodel pour tout ce dont j'ai besoin dans une vue. Ils s'intègrent parfaitement à la syntaxe EL et sont ultra-rapides lors de la recherche.
Boris B.

Encore une chose, si la clé existe mais que la valeur est nulle ou vide, elle renverra false.
Zai

1
Ou si la carte détient booléens, test="${isPresentByValue[myValue]}".
Noumenon

14

Vous devez utiliser la fonction fn:contains()ou 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>

ou

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

Remarque: cela fonctionnera commemylist.toString().contains("apple")et si ce n'est pas ce que vous recherchez, utilisez une autre approche.


2
Ce n'est pas la bonne approche. Il se comportera essentiellement comme mylist.toString().contains("apple")ce qui n'est absolument pas ce à quoi vous vous attendiez au départ.
BalusC

ohh .. ouais ce n'est pas ce que j'attends. Quoi qu'il en soit, je mettrai à jour ma réponse avec cette amende.
tk_

2

Ce qui suit est plus une solution de contournement qu'une réponse à votre question, mais c'est peut-être ce que vous recherchez. Si vous pouvez mettre vos valeurs dans une carte au lieu d'une liste, cela résoudra votre problème. Mappez simplement vos valeurs à une valeur non nulle et faites-le <c:if test="${mymap.myValue ne null}">style='display:none;'</c:if>ou vous pouvez même mapper style='display:none;et simplement afficher${mymap.myValue}


Je suppose que la syntaxe doit être <c: if test = "$ {mymap [myValue] ne null}"> style = 'display: none;' </ c: if> Sinon, la variable "myValue" n'est pas évaluée.
Andreas

2
${fn:contains({1,2,4,8}, 2)}

OU

  <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

Si vous utilisez EL 3.0+ , la meilleure approche dans ce cas est celle expliquée dans une autre rubrique:

Pour un Collectionc'est facile, utilisez simplement la Colleciton#contains() méthode en 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>

Pour un Object[](tableau), vous avez besoin d'un minimum de EL 3.0 et utilisez sa nouvelle prise en charge 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>

Si vous n'êtes pas encore sur EL 3.0, vous devez créer une fonction EL personnalisée. [...]


-1

Si vous utilisez Spring Framework, vous pouvez utiliser Spring TagLib et 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>

-1

J'ai trouvé cette solution incroyable.

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

La sortie pour le code ci-dessus est

Ma liste est [un, deux, trois]

Ma liste en contient deux

Ma liste contient,

J'espère que cela aide quelqu'un.


-2
<c:if test="${fn:contains(task.subscribers, customer)}">

Cela fonctionne bien pour moi.


18
Cela fait la vérification après la conversion des deux éléments en chaîne. La liste est convertie en une chaîne et n'est pas vérifiée par élément. Si task.subscribers est une liste ["un", "deux", "vingt et un"] ce sera: vrai pour le client = "un" (correspondant deux fois) faux pour le client = "trois" (pas de correspondance) vrai pour le client = "vingt" (ce qui n'est pas ce que vous cherchez)
Ricardo Marimon

2
Étant conscient de l'avertissement de rmarimon, cette réponse correspondait à mon cas d'utilisation exact.
CodeReaper
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.