Beanのリストがあり、各Beanには、それ自体が電子メールアドレスのリストであるプロパティがあります。
<c:forEach items="${upcomingSchedule}" var="conf">
<div class='scheduled' title="${conf.subject}" id="scheduled<c:out value="${conf.id}"/>">
...
</div>
</c:forEach>
これにより、リスト内のBeanごとに1つの<div>
がレンダリングされます。
サブリストの場合、リスト内の各エントリを連結して1つの文字列を形成し、<div>
のtitle
属性の一部として表示できるようにします。 。どうして? javascriptライブラリ(mootools)を使用してこの<div>
をフローティングツールチップに変換し、ライブラリがtitle
をツールチップのテキストに変換するためです。
したがって、${conf.subject}
が「件名」の場合、最終的には<div>
のtitle
を「件名:blah @ blah.com、blah2 @ blah2.comなど」にします。 。 "、サブリストのすべての電子メールアドレスが含まれています。
JSP ELを使用してこれを行うにはどうすればよいですか?スクリプトレットブロックをjspファイルに配置しないようにしています。
これを行うためのやや汚い方法を考え出した:
<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>
を繰り返し使用し、それ自体の値を参照して、文字列を追加/連結します。
これを行う「クリーンな」方法は、関数を使用することです。 JSTL join
関数はCollection
で機能しないため、大きなチャンクをカットアンドペーストする代わりに、問題なく独自に記述して、あらゆる場所で再利用できます。ループコードの。
関数の実装と、Webアプリケーションにそれを見つける場所を知らせるためのTLDが必要です。これらをJARにまとめて、WEB-INF/libディレクトリにドロップします。
概要は次のとおりです。
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>
TLDは少し冗長ですが、TLDを回避する方法を知ることは、JSPを使用する開発者にとって優れたスキルです。また、プレゼンテーションにJSPのような標準を選択したので、役立つツールがある可能性が高くなります。
このアプローチには、基礎となるモデルにメソッドを追加するという選択肢に比べて多くの利点があります。この関数は一度作成すれば、どのプロジェクトでも再利用できます。クローズドソースのサードパーティライブラリで動作します。モデルAPIをそれぞれの新しいメソッドで汚染することなく、さまざまなコンテキストでさまざまな区切り文字をサポートできます。
最も重要なことは、ビューとモデルコントローラー開発の役割の分離をサポートします。これら2つの領域のタスクは、多くの場合、異なる時間に異なる人々によって実行されます。これらの層間の疎結合を維持することで、複雑さとメンテナンスコストを最小限に抑えます。プレゼンテーションで別の区切り文字を使用するような些細な変更でさえ、プログラマーがライブラリーを変更する必要がある場合、非常に高価で面倒なシステムになります。
StringUtil
クラスは、EL関数として公開されているかどうかに関係なく同じです。必要な唯一の「余分な」ものはTLDであり、これは些細なことです。ツールで簡単に生成できます。
これ使ってもらえますか?リストではなく配列が必要なようです。
${fn:join(array, ";")}
http://Java.Sun.com/products/jsp/jstl/1.1/docs/tlddocs/fn/join.fn.html
サブリストがArrayListであり、これを行う場合:
<div class='scheduled' title="${conf.subject}: ${conf.invitees}" id="scheduled${conf.id}">
あなたはほとんどあなたが必要とするものを手に入れます。
唯一の違いは、タイトルが「件名:[blah @ blah.com、blah2 @ blah2.comなど]」になることです。
たぶんあなたにとっては十分かもしれません。
EL 3.0 StreamAPIを使用できます。たとえば、文字列のリストがある場合、
<div>${stringList.stream().reduce(",", (n,p)->p.concat(n))}</div>
たとえば、オブジェクトのリストがある場合。 Person(firstName、lastName)で、マップを使用できるプロパティ(firstNameなど)を1つだけ連結したい場合は、
<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とそれの前に完成しましたそれとは異なります。下位互換性が損なわれるため、両方のAPIをサンクすることはできません。
この回答が最初に投稿されて以来、タグライブラリの実装方法はかなり進んでいるようです。そのため、動作させるために大幅な変更を加えることになりました。私の最終結果は次のとおりです。
タグライブラリファイル:
<?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="," />],
次のように、サーバーの変数の横に文字列を配置するだけです。
<c:forEach items="${upcomingSchedule}" var="conf">
<div class='scheduled' title="${conf.subject}"
id="scheduled${conf.id}">
...
</div>
</c:forEach>
遅すぎる!!!
私はこれがあなたが望むものだと思います:
<c:forEach var="tab" items="${tabs}">
<c:set var="tabAttrs" value='${tabAttrs} ${tab.key}="${tab.value}"'/>
</c:forEach>
この場合、タブID(キー)とURL(値)のハッシュマップがありました。 tabAttrs変数はこれより前に設定されていません。したがって、値をtabAttrsの現在の値(開始するには '')にキー/値式を加えたものに設定するだけです。