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(その本体に対応)を「グローバル」レジストリに格納するだけです。次に、以前に保存されたテンプレートを評価してページに書き込むタグを作成しました。
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;
}
}
ご覧のとおり、レジストリは、evaluateメソッドが呼び出されるたびに適切な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>
これは非常にうまく機能しますが、これが許可されているかどうかわかりませんか?より良いアプローチはありますか?