我有一个JSP需要打印一些文本,这是通过获取循环迭代器并将其提供给另一个对象(Spring bean)生成的,类似于:
<c:forEach var="myVar" items="${myVars}">
<c:out value="anotherObject.getFoo(myVar)"/>
</c:forEach>
Run Code Online (Sandbox Code Playgroud)
显然,上面的代码无效,因为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>
Run Code Online (Sandbox Code Playgroud)
这里显而易见的是JSP代码污染和普遍的丑陋.
2)编写一个标记来执行在scriptlet中完成的任何操作.过度工程的典型例子,哎呀!
3)分解的集合myVars
,并替换每个myVar
与动态代理,InvocationHandler
这会增加额外的参数少的方法来使所有getFoo()
通过电话anotherObject
.所有这些都将在控制器中完成,因此JSP将保持干净并myVar
保持不变.但是以什么价格?
我无法添加.getFoo()
方法,myVar
因为它不适合那里,并会打破关注点的分离.
看起来在JSP/EL 2.2中可以传递参数,但我使用的是Tomcat 6.0.29,它只捆绑了EL 2.1 API.
问题:有人能为这种情况建议最干净的方法吗?
在旧的JSTL版本中也可以使用的简单的Java"技巧修复",并且不需要额外的taglibs/config/dependencies/frameworks等,是在一个类中"包装"你想从JSTL调用的函数.从Map
类扩展,并覆盖其get()
方法.
作为一个最小的例子,如果您想要Math.sin()
从JSTL 调用该函数,您将定义一个类:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在Action execute()方法中执行:
...
request.setAttribute("sine", new Sine());
...
Run Code Online (Sandbox Code Playgroud)
然后在jsp中你可以说:
${sine[0.75]}
Run Code Online (Sandbox Code Playgroud)
计算价值 Math.sin(0.75)
JSTL会将变量sine视为a Map
,但您可以从get()方法计算并返回任何您喜欢的内容.
如果你的函数有多个参数,我想它会涉及更多,但是应该有相同的解决方法:)
这就是我最后的做法。
我传递的不是实例集合SomeType
,而是地图。映射键是相同的SomeType
,值是特定于控制器的内部类的实例,我们称之为SomeTypeSupplement
。
SomeTypeSupplement
添加必要的无参数吸气剂并将所有内容连接在一起。JSP 现在迭代映射条目并能够通过 JSTL 检索数据。
通过这种方式,我可以避免Proxy
神奇的、不必要的 TLD,保持 JSP 的整洁和相当的类型安全。
归档时间: |
|
查看次数: |
16196 次 |
最近记录: |