在JSTL循环内调用带参数的方法

时间:2011-07-20 10:37:49

标签: java jsp jstl

我有一个JSP需要打印一些文本,这些文本是通过获取循环迭代器并将其提供给另一个对象(Spring bean)生成的,类似于:

<c:forEach var="myVar" items="${myVars}">
   <c:out value="anotherObject.getFoo(myVar)"/>
</c:forEach>

显然上面的代码无效,因为JSTL .运算符只允许无参数调用。我可以看到以下问题的解决方案:

1)Scriptlets

<c:forEach var="myVar" items="${myVars}">
  <%
    SomeType myVar = (SomeType) pageContext.getAttribute("myVar");
    SomeOtherType anotherObject = (SomeOtherType) pageContext.getAttribute("anotherObject");
    YetAnotherType result = anotherObject.getFoo(myVar);
    pageContext.setAttribute("result", result);
  %>
  <c:out value="${result}"/>
</c:forEach>

这里显而易见的是JSP代码污染和普遍的丑陋。

2)编写一个标记来执行在scriptlet中完成的任何操作。过度工程的典型例子,哎呀!

3)分解myVars的集合,并用dynamic proxy myVar替换每个InvocationHandler,其中getFoo()将添加额外的无参数方法以使所有{{1}通过anotherObject调用。所有这些都将在控制器中完成,因此JSP将保持干净并且myVar保持不变。但是以什么价格?

我无法将.getFoo()方法添加到myVar,因为它不适合那里,会打破关注点的分离。

看起来在JSP / EL 2.2中可以传递参数,但我使用的是仅捆绑EL 2.1 API的Tomcat 6.0.29。

问题:有人能为这种情况建议最干净的方法吗?

6 个答案:

答案 0 :(得分:7)

一个简单的仅限Java的“技巧修复”,也适用于较旧的JSTL版本, 并且不需要额外的taglibs / config / dependencies / frameworks等。 是“包装”您要从JSTL调用的函数 在从Map类扩展的类中,并覆盖其get()方法。

作为一个最小的例子,如果你是想从JSTL调用Math.sin()函数, 你会定义一个类:

public class Sine extends HashMap<Double, Double> {
    private static final long serialVersionUID = 1L; // Avoids compiler-warning

    @Override
    public Double get(Object arg) {
        Double x = (Double) arg;
        return Math.sin(x);
    }
}

然后在Action execute()方法中执行:

...
request.setAttribute("sine", new Sine());
...

然后在jsp中你可以说:

  ${sine[0.75]}

计算值Math.sin(0.75)

JSTL会将变量sine视为Map,但您可以从get()方法计算并返回任何您喜欢的内容。

如果你的函数有多个参数,我想它会更复杂一些, 但也应该有解决办法:)

答案 1 :(得分:2)

这就是我最后如何做到的。

我没有传递SomeType个实例的集合,而是传递了一张地图。映射键是相同的SomeType,值是控制器特定内部类的实例,我们称之为SomeTypeSupplement

SomeTypeSupplement添加必要的无参数getter并将所有内容连接在一起。 JSP现在迭代映射条目,并能够通过JSTL检索数据。

这样我就可以避免Proxy魔法,不必要的TLD,保持JSP整洁,合理安全。

答案 2 :(得分:1)

如果您不能遵守scriptlet(替代方案1),我会为它(您的备选方案2)或自定义EL函数创建自定义标记。我不同意它是“过度工程”,它使用可用的工具用于其预期目的。

你的另类3,但我不喜欢。如果有的话,那么过度工程加上它将使你的系统变得不必要地复杂,并且让其他人更难以遵循。坚持您正在使用的规范和标准的意图。不要为了它而使事情变得更难或更复杂。

答案 3 :(得分:1)

为什么不在后端Java代码中编写对象列表,然后只使用JSP来显示它?

答案 4 :(得分:1)

想要在Rop的最后(按时间)回答中添加评论,但缺少“声望”,所以我在这里得到答案。

我很快就对这样的地图有了同样的想法,但试图让它更普遍可用,有一个“DynamicMap”,DynamicMapCalculator接口,让你将任何方法调用包装到这样的地图中(无需制作新的每次都执行map实现,只使用匿名类实例化。)

如果您有兴趣,这将成为主题: A qu. of style: dynamic map JSTL hack to work around missing parameter function calls

我会对那里的意见感兴趣:这是否可以在没有良心的情况下做到?

答案 5 :(得分:0)

另一种选择是使用Velocity。它比jstl好得多。