Question

J'ai une liste de beans dont chacun a une propriété qui est elle-même une liste d'adresses e-mail.

<c:forEach items="${upcomingSchedule}" var="conf">
    <div class='scheduled' title="${conf.subject}" id="scheduled<c:out value="${conf.id}"/>">
    ...
    </div>
</c:forEach>

Ceci restitue un <div> par bean dans la liste.

Pour la sous-liste, ce que je voudrais pouvoir faire est de concaténer chacune des entrées de la liste pour former une seule chaîne, qui sera affichée dans le cadre de l'attribut title de ${conf.subject} . Pourquoi? Parce que nous utilisons une bibliothèque javascript (mootools) pour transformer ce <=> en info-bulle flottante, cette bibliothèque convertit le <=> en texte de l'info-bulle.

Donc, si <=> était & "Sujet &" ;, j'aimerais que le <=> des <=> soit & "Sujet: blah@blah.com , blah2@blah2.com, etc. " ;, contenant toutes les adresses électroniques de la sous-liste.

Comment puis-je faire cela avec JSP EL? J'essaie d'éviter de mettre des blocs de scriptlets dans le fichier jsp.

Était-ce utile?

La solution 2

Vous avez trouvé une façon un peu sale de faire cela:

<c:forEach items="${upcomingSchedule}" var="conf">
    <c:set var="title" value="${conf.subject}: "/>
    <c:forEach items="${conf.invitees}" var="invitee">
        <c:set var="title" value="${title} ${invitee}, "/>
    </c:forEach>
    <div class='scheduled' title="${title}" id="scheduled<c:out value="${conf.id}"/>">
    ...
    </div>
</c:forEach>

Je viens d'utiliser <c:set> à plusieurs reprises, en faisant référence à sa propre valeur, pour ajouter / concaténer les chaînes.

Autres conseils

Le " nettoyer " Une façon de le faire serait d’utiliser une fonction. Comme la fonction JSTL join ne fonctionne pas sur un Collection, vous pouvez écrire le vôtre sans trop de problèmes et le réutiliser partout au lieu de copier / coller un gros morceau de code de boucle.

Vous avez besoin de l'implémentation de la fonction et d'un TLD pour que votre application Web sache où la trouver. Rassemblez-les dans un fichier JAR et déposez-le dans votre répertoire WEB-INF / lib.

Voici un aperçu:

com / x / taglib / core / StringUtil.java

package com.x.taglib.core;

public class StringUtil {

  public static String join(Iterable<?> elements, CharSequence separator) {
    StringBuilder buf = new StringBuilder();
    if (elements != null) {
      if (separator == null)
        separator = " ";
      for (Object o : elements) {
        if (buf.length() > 0)
          buf.append(separator);
        buf.append(o);
      }
    }
    return buf.toString();
  }

}

META-INF / x-c.tld:

<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>
  <short-name>x-c</short-name>
  <uri>http://dev.x.com/taglib/core/1.0</uri>
  <function>
    <description>Join elements of an Iterable into a string.</description>
    <display-name>Join</display-name>
    <name>join</name>
    <function-class>com.x.taglib.core.StringUtil</function-class>
    <function-signature>java.lang.String join(java.lang.Iterable, java.lang.CharSequence)</function-signature>
  </function>
</taglib>

Bien que le TLD soit un peu prolixe, il est utile de tout savoir sur les développeurs pour travailler avec JSP. Et, puisque vous avez choisi un standard tel que JSP, il y a de fortes chances que vous disposiez d'outils pour vous aider.

Cette approche présente de nombreux avantages par rapport à la possibilité d’ajouter davantage de méthodes au modèle sous-jacent. Cette fonction peut être écrite une fois et réutilisée dans n’importe quel projet. Il fonctionne avec une bibliothèque tierce à source fermée. Différents délimiteurs peuvent être pris en charge dans différents contextes, sans polluer une API de modèle avec une nouvelle méthode pour chacun.

Plus important encore, il prend en charge la séparation des rôles de développement de la vue et du contrôleur de modèle. Les tâches de ces deux domaines sont souvent exécutées par des personnes différentes à des moments différents. Maintenir un couplage lâche entre ces couches minimise la complexité et les coûts de maintenance. Même lorsqu'un changement anodin, tel que l'utilisation d'un délimiteur différent dans la présentation, nécessite qu'un programmeur modifie une bibliothèque, vous disposez d'un système très coûteux et fastidieux.

La classe StringUtil est la même, qu’elle soit exposée ou non en tant que fonction EL. Le seul & Quot; extra & Quot; nécessaire est le TLD, qui est trivial; un outil pourrait facilement le générer.

Pourriez-vous l'utiliser? On dirait qu'il veut un tableau au lieu d'une liste.

${fn:join(array, ";")}

http: // java .sun.com / products / jsp / jstl / 1.1 / docs / tlddocs / fn / join.fn.html

Si votre sous-liste est une liste de tableaux et que vous procédez comme suit:

<div class='scheduled' title="${conf.subject}: ${conf.invitees}" id="scheduled${conf.id}">

vous obtenez presque ce dont vous avez besoin.

La seule différence est que le titre sera: " Subject: [blah@blah.com, blah2@blah2.com, etc.] "..

Peut-être peut-être assez bon pour vous.

Je pense que c'est ce que vous voulez:

<c:forEach var="tab" items="${tabs}">
 <c:set var="tabAttrs" value='${tabAttrs} ${tab.key}="${tab.value}"'/>
</c:forEach>

Dans ce cas, j'avais un hashmap avec un onglet ID (clé) et une URL (valeur). La variable tabAttrs n'est pas définie avant cela. Donc, il suffit de définir la valeur sur la valeur actuelle de tabAttrs ('' pour commencer) plus l'expression clé / valeur.

Il suffit de mettre la chaîne à côté de la var du serveur, comme ceci:

<c:forEach items="${upcomingSchedule}" var="conf">
    <div class='scheduled' title="${conf.subject}" 

         id="scheduled${conf.id}">

    ...
    </div>
</c:forEach>

Trop tard !!!

La manière dont les bibliothèques de balises sont mises en œuvre semble avoir considérablement évolué depuis la publication de cette réponse. Je me suis donc mis à apporter des changements radicaux pour que les choses fonctionnent. Mon résultat final était:

Fichier de bibliothèque de balises:

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd">
  <tlib-version>1.0</tlib-version>
  <short-name>string_util</short-name>
  <uri>/WEB-INF/tlds/string_util</uri>
  <info>String Utilities</info>
  <tag>
    <name>join</name>
    <info>Join the contents of any iterable using a separator</info>
    <tag-class>XXX.taglib.JoinObjects</tag-class>
    <body-content>tagdependent</body-content>
    <attribute>
      <name>iterable</name>
      <required>true</required>
      <rtexprvalue>true</rtexprvalue>
      <type>java.lang.Iterable</type>
    </attribute>
    <attribute>
      <name>separator</name>
      <required>false</required>
      <rtexprvalue>false</rtexprvalue>
      <type>java.lang.String</type>
    </attribute>
  </tag>

  <tag>
    <name>joinints</name>
    <info>Join the contents of an integer array using a separator</info>
    <tag-class>XXX.taglib.JoinInts</tag-class>
    <body-content>tagdependent</body-content>
    <attribute>
      <name>integers</name>
      <required>true</required>
      <rtexprvalue>true</rtexprvalue>
      <type>java.lang.Integer[]</type>
    </attribute>
    <attribute>
      <name>separator</name>
      <required>false</required>
      <rtexprvalue>false</rtexprvalue>
      <type>java.lang.String</type>
    </attribute>
  </tag>
</taglib>

JoinInts.java

public class JoinInts extends TagSupport {

    int[] integers;
    String separator = ",";

    @Override
    public int doStartTag() throws JspException {
        if (integers != null) {
            StringBuilder buf = new StringBuilder();
            if (separator == null) {
                separator = " ";
            }
            for (int i: integers) {
                if (buf.length() > 0) {
                    buf.append(separator);
                }
                buf.append(i);
            }
            try {
                pageContext.getOut().print(buf);
            } catch (IOException ex) {
                Logger.getLogger(JoinInts.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return SKIP_BODY;
    }

    @Override
    public int doEndTag() throws JspException {
        return EVAL_PAGE;
    }

    public int[] getIntegers() {
        return integers;
    }

    public void setIntegers(int[] integers) {
        this.integers = integers;
    }

    public String getSeparator() {
        return separator;
    }

    public void setSeparator(String separator) {
        this.separator = separator;
    }
}

Pour l'utiliser:

<%@ taglib prefix="su" uri="/WEB-INF/tlds/string_util.tld" %>

[new Date(${row.key}), <su:joinints integers="${row.value}" separator="," />],

Vous pouvez utiliser l'API EL 3.0 Stream. Par exemple, si vous avez une liste de chaînes,

<div>${stringList.stream().reduce(",", (n,p)->p.concat(n))}</div>

Si vous avez une liste d'objets par exemple. Personne (firstName, lastName) et si vous souhaitez en concaténer une seule propriété (ex firstName), vous pouvez utiliser map,

<div>${personList.stream().map(p->p.getFirstName()).reduce(",", (n,p)->p.concat(n))}</div>

Dans votre cas, vous pouvez utiliser quelque chose comme ça (supprimer le dernier ',' également),

<c:forEach items="${upcomingSchedule}" var="conf">
    <c:set var="separator" value=","/>
    <c:set var="titleFront" value="${conf.subject}: "/>
    <c:set var="titleEnd" value="${conf.invitees.stream().reduce(separator, (n,p)->p.concat(n))}"/>
    <div class='scheduled' title="${titleFront} ${titleEnd.isEmpty() ? "" : titleEnd.substring(0, titleEnd.length()-1)}" id="scheduled<c:out value="${conf.id}"/>">
    ...
    </div>
</c:forEach>

Faites attention! Le L’API de flux EL 3.0 a été finalisée avant la API Java 8 Stream , ce qui est différent. Ils ne peuvent pas relier les deux apis car cela annulerait la compatibilité ascendante.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top