我想使用JspFragment定义模板。这就是为什么我创建以下Tag类的原因:
public class CreateTemplateTag extends SimpleTagSupport {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public void setJspBody(JspFragment jspBody) {
// Reqister "body" in Template-Registry to use it later on ..
TemplateRegistry.put(getJspContext(), name, jspBody);
}
}
上面的类只是将JspFragment(与其主体相对应)存储在“全局”注册表中。
接下来,我创建了一个Tag,该Tag评估先前存储的模板并将其写入页面:
public class UseTemplateTag extends SimpleTagSupport {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public void doTag() throws JspException, IOException {
JspContext ctx = getJspContext();
ctx.getOut().write(TemplateRegistry.evaluate(ctx, name));
}
}
注册表是一个非常简单的实现:
public class TemplateRegistry {
private static final String REGISTRY_KEY = "__TPL_REG__";
public static void put(JspContext ctx, String name, JspFragment frag) {
HashMap attribute = (HashMap) ctx.getAttribute(REGISTRY_KEY);
if(attribute==null) {
attribute = new HashMap();
ctx.setAttribute(REGISTRY_KEY,attribute);
}
attribute.put(name, frag);
}
public static String evaluate(JspContext ctx, String name) {
HashMap attribute = (HashMap) ctx.getAttribute(REGISTRY_KEY);
if(attribute!=null) {
try {
JspFragment frag = (JspFragment) attribute.get(name);
StringWriter writer = new StringWriter();
StringBuffer sb = writer.getBuffer();
frag.invoke(writer);
writer.flush();
return sb.toString();
} catch(Exception e) {
e.printStackTrace();
}
}
return null;
}
}
如您所见,每次调用评估方法时,注册表都会评估适当的JspFragment。
我使用的JSP代码如下:
...
<util:CreateTemplate name="xxx">
<custom:myTag attr="${var}"/>
This is ${var}
</util:CreateTemplate>
...
<c:forEach var="var" items="${someStringCollection}">
<util:UseTemplate name="xxx"/>
</c:forEach>
这样效果很好,但是我不确定是否允许这样做?
有没有更好的方法?
最佳答案
我不确定您所允许的意思。如果它对您有用,那就很好。它似乎与提供给您的功能非常相似。我认为您的方法的优点是可以将模板片段与其余代码保持在同一页面上。但是,根据文件的大小,这可能很快成为不利条件。
惯用的企业Java会说您应该有很多较小的文件,因此请采用这些小模板中的每一个,并为它们创建一个小的包含文件。如果它们都是2-3行,则最好按照自己的方式进行。如果它们增长到20到30行,则将它们移动到自己的文件中可能会更容易,因此您可以更轻松地查看核心页面逻辑,而不会被所有模板包含的内容分散注意力。