Using JSP-Fragments outside of the tag where it was defined
I want to define a template using a JspFragment. That's why I created the following Tag class:
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);
}
}
The above class simply stores the JspFragment (which corresponds to its body) in a "global" registry. Next, I created a Tag, which evaluates a previously stored template and writes it to the page:
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));
}
}
The registry is a very simple implementation:
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;
}
}
As you can see, the registry evaluates the appropriate JspFragment each time the evaluate method is called.
The JSP code I used follows:
...
<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>
This works quite well, but I'm not sure whether or not this is allowed? Is there a better app开发者_开发百科roach?
I'm not sure what you mean by allowed. If it works for you it's fine. It seems very similar to the functionality given to you by <%@include file="yourfile" %>. I think the advantage to your approach is that you can keep the template snippets on the same page as the rest of the code. Depending on the size of the files, this can quickly become a disadvantage however.
Idiomatic enterprise java would say you should have lots of smaller files, so take each of those little templates and make a small include file for them. If they are all 2-3 lines each, you're better off doing it your way. If they grow to be 20-30 lines, it will probably easier to move them into their own files so you can more easily see the core page logic without being distracted by all the template includes.
精彩评论