2008-11-17 62 views
15

我有一個bean列表,每個bean都有一個屬性,它本身就是一個電子郵件地址列表。在JSP EL中連接字符串?

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

這使得每個bean在列表中呈現一個<div>

對於子列表,我希望能夠做的是連接列表中的每個條目以形成一個單獨的字符串,以顯示爲的title屬性的一部分。爲什麼?因爲我們使用JavaScript庫(mootools)將此<div>轉換爲浮動工具提示,並且庫將title轉換爲工具提示的文本。

所以,如果${conf.subject}是「主題」,最終我想了<div>title是「主題:[email protected][email protected]等」,包含所有電子郵件地址的子列表。

我該如何使用JSP EL來做到這一點?我試圖遠離將scriptlet塊放入jsp文件中。

+0

的可能的複製[JSP EL字符串連接(http://stackoverflow.com/questions/3189642/jsp-el-string-concatenation) – 2015-10-22 12:57:20

回答

8

想出了一個有點髒的方式做到這一點:

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

我只是用<c:set>多次,引用它自己的價值,追加/串聯的字符串。

+0

我覺得這是你可以不寫自己的功能做了最好的(這是不是太難)沿着fn的線:加入 – erickson 2008-11-17 18:50:53

1

如果你的子列表是一個ArrayList和你這樣做:

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

你獲得你需要什麼差不多。

唯一的區別是標題將是: 「主題:[[email protected][email protected]等]」。

也許對你來說足夠好。

+0

如果底層列表是一個ArrayList,那麼做的工作排序,但我不希望有機會,它是一些其他List實現沒有相同的toString()實行。 – 2008-11-17 19:07:50

16

「乾淨」的方法是使用一個函數。由於JSTL join函數在Collection上不起作用,所以您可以自己編寫而不會有太多麻煩,並且可以在整個位置重複使用它,而不是剪切並粘貼大量循環代碼。

您需要功能實現和一個頂級域名讓您的Web應用程序知道在哪裏可以找到它。將它們放在一個JAR中,並放到WEB-INF/lib目錄中。

這裏有一個輪廓:

COM/X /標籤庫/核心/ 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/xc.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> 

雖然TLD是有一點冗長,知道你的解決方法對於任何使用JSP的開發人員來說都是一項很好的技能。而且,由於您選擇了像JSP這樣的標準進行演示,因此很有可能您的工具可以幫助您解決問題。

與添加更多方法到基礎模型的替代方法相比,此方法具有許多優點。這個函數可以寫一次,並在任何項目中重用。它適用於封閉源代碼的第三方庫。不同的分隔符可以在不同的上下文中得到支持,而不會爲每個模型使用新的方法來污染模型API。

最重要的是,它支持視圖和模型控制器開發角色的分離。這兩個領域的任務往往由不同的人在不同的時間進行。保持這些層之間的鬆散耦合將複雜性和維護成本降至最低。如果在演示文稿中使用不同的分隔符等簡單的更改需要程序員修改庫,那麼您的系統會非常昂貴且繁瑣。

StringUtil類是相同的,無論它是否暴露EL功能。唯一「額外」必要的是TLD,這是微不足道的;一個工具可以很容易地生成它。

+0

爲什麼你認爲編寫一個自定義的jstl函數比輔助bean中的另一個方法更好?這不是一個挑釁性的問題。在這樣的情況下,我會在bean中寫入一個方法,比如getInviteesAsString()。這有什麼問題? – alexmeia 2008-11-17 22:04:55

+0

我對我的回答添加了回覆。我會對你提出同樣的問題:你爲什麼認爲改變後臺bean更好? – erickson 2008-11-18 00:39:57

0

我想這是你想要什麼:

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

在這種情況下,我曾與標籤ID(鍵)和URL(值)是一個HashMap。在此之前,tabAttrs變量未設置。所以它只是將該值設置爲tabAttrs的當前值(「開始」)加上鍵/值表達式。

0

只要把字符串byside了var從服務器,就像這樣:

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

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

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

太晚了!

0

的途徑標籤庫實現似乎相當感動以來這個答案最初發布,所以我最終作出一些劇變把事情的工作。我最終的結果是:

標籤庫文件:

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

要使用它:

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

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

可以使用EL 3.0流API。例如,如果你有一個字符串列表,

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

如果你有恩對象的列表。人(名字,姓氏),你想Concat的只是其中的財產(例如的firstName),你可以使用地圖,

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

你的情況,你可以使用類似的東西(刪除最後一個「」還) ,

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

要小心!EL 3.0 Stream API是在Java 8 Stream API之前完成,這是比不同。它們無法同時兼顧apis,因爲它會打破向後兼容性。