Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在JSPEL中连接字符串?_Java_Jsp_El_Taglib - Fatal编程技术网

Java 在JSPEL中连接字符串?

Java 在JSPEL中连接字符串?,java,jsp,el,taglib,Java,Jsp,El,Taglib,我有一个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列表,每个bean都有一个属性,它本身就是一个电子邮件地址列表

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

...
这将为列表中的每个bean呈现一个

对于子列表,我希望能够将列表中的每个条目连接起来,形成一个字符串,显示为
title
属性的一部分。为什么?因为我们正在使用javascript库(mootools)将此
转换为浮动工具提示,并且该库将
标题
转换为工具提示的文本

因此,如果
${conf.subject}
是“subject”,那么我最终希望
标题
是“subject:blah@blah.com, blah2@blah2.com,包含子列表的所有电子邮件地址


如何使用jspel实现这一点?我试图避免将scriptlet块放在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>

...

我只是重复使用
,引用它自己的值来附加/连接字符串。

你能用这个吗?似乎它需要数组而不是列表

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

如果您的子列表是ArrayList,并且您执行以下操作:

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

你几乎得到了你所需要的

唯一的区别是标题将是: “主题:[blah@blah.com, blah2@blah2.com,等等

也许对你来说已经足够好了

执行此操作的“干净”方法是使用函数。由于JSTL
join
函数在
集合上不起作用,因此您可以轻松编写自己的集合,并在所有地方重复使用它,而不是剪切和粘贴大量循环代码

您需要函数实现和TLD,以便让您的web应用程序知道在哪里可以找到它。将它们放在一个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();
  }

}
package com.x.taglib.core;
公共类StringUtil{
公共静态字符串联接(Iterable元素、CharSequence分隔符){
StringBuilder buf=新的StringBuilder();
if(元素!=null){
if(分隔符==null)
分隔符=”;
用于(对象o:元素){
如果(buf.length()>0)
追加(分隔符);
buf.附加(o);
}
}
返回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>

1
x-c
http://dev.x.com/taglib/core/1.0
将Iterable的元素连接到字符串中。
参加
参加
com.x.taglib.core.StringUtil
java.lang.String连接(java.lang.Iterable,java.lang.CharSequence)
虽然TLD有点冗长,但对于任何使用JSP的开发人员来说,了解如何使用TLD是一项很好的技能。而且,由于您选择了JSP这样的标准进行表示,所以您很有可能拥有能够帮助您解决问题的工具

与向基础模型添加更多方法相比,这种方法有许多优点。此函数可以编写一次,并在任何项目中重用。它使用一个封闭源代码的第三方库。在不同的上下文中可以支持不同的分隔符,而不必为每个分隔符使用新方法来污染模型API

最重要的是,它支持视图和模型控制器开发角色的分离。这两个领域的任务通常由不同的人在不同的时间执行。保持这些层之间的松散耦合可将复杂性和维护成本降至最低。即使是在演示文稿中使用不同的分隔符这样的微小更改,也需要程序员修改库,这将是一个非常昂贵且繁琐的系统


无论是否作为EL函数公开,StringUtil类都是相同的。唯一需要的“额外”是TLD,这是微不足道的;一个工具可以很容易地生成它。

我想这就是你想要的:

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


在本例中,我有一个带有tabid(key)和URL(value)的hashmap。在此之前未设置tabAttrs变量。因此,它只是将值设置为tabAttrs的当前值(“”开始)加上键/值表达式。

只需将字符串放在服务器的var旁边,如下所示:

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

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

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

...

太晚了

自从这个答案最初发布以来,标签库的实现方式似乎已经有了很大的进步,所以我最终做了一些重大的改变以使事情正常运行。我的最终结果是:

标记库文件:

<?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>
要使用它:

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

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

[新日期(${row.key}),],

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

<div>${stringList.stream().reduce(",", (n,p)->p.concat(n))}</div>
${stringList.stream().reduce(“,”,(n,p)->p.concat(n))}
如果您有一个ex.Person对象列表(firstName,lastName),并且您希望只包含其中一个属性(ex-firstName),则可以使用map

<div>${personList.stream().map(p->p.getFirstName()).reduce(",", (n,p)->p.concat(n))}</div>
${personList.stream().map(p->p.getFirstName()).reduce(“,”,(n,p)->p.concat(n))}
在你的情况下,你可以使用类似的东西(删除最后的“,”也)


...

小心在API发布之前就已经完成了,与之不同。它们不能同时sunc两个API,因为这会破坏向后兼容性。

我认为这是最好的方法,而不必按照fn:join的思路编写自己的函数(这并不太难),如果底层列表是ArrayList,但是我不想冒险说它是其他列表实现,而没有相同的toString()实现。为什么您认为编写一个自定义jstl函数比在支持bean中多编写一个方法更好?这不是一个挑衅性的问题。在这种情况下,我会在bean中编写一个方法来处理这个问题,比如getinvitesasstring()。这有什么不对?我对我的回答加了一个回应。我会向你提出同样的问题:
<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>