JSP: Make a reusable code (tag, macro) and use it on the same page

南笙酒味 提交于 2019-12-02 02:23:40

问题


Is there any way to make some sort of parametrized macro on one JSP page and reuse it few times on the same page. JSP tags could be used but I would have to make one file per tag.


回答1:


I've been wanting this functionality for years, and after googling yet again, I wrote my own. I think tag / jsp files & custom tag classes are great, but are often overkill for simple one-offs like you describe.

This is how my new "macro" tag now works (here used for simple html rendering of sortable table headers):

<%@ taglib prefix="tt" uri="/WEB-INF/tld/tags.tld" %>

<!-- define a macro to render a sortable header -->
<tt:macro id="sortable">
    <th class="sortable">${headerName}
        <span class="asc" >&uarr;</span>
        <span class="desc">&darr;</span>
    </th>
</tt:macro>

<table><thead><tr>
    <!-- use the macro for named headers -->
    <tt:macro id="sortable" headerName="Name (this is sortable)" />
    <tt:macro id="sortable" headerName="Age (this is sortable)" />
    <th>Sex (not sortable)</th>
    <!-- etc, etc -->

In /WEB-INF/tld/tags.tld, I added:

<tag>
    <name>macro</name>
    <tag-class>com.acme.web.taglib.MacroTag</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
        <description>ID of macro to call or define</description>
        <name>id</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
    <dynamic-attributes>true</dynamic-attributes>
</tag>

And, finally, the Java tag class:

public class MacroTag
    extends SimpleTagSupport implements DynamicAttributes
{
    public static final String PREFIX = "MacroTag_";
    private boolean bodyless = true;
    private String id;
    private Map<String, Object> attributes = new HashMap<String, Object>();

    @Override public void setJspBody(JspFragment jspFragment) {
        super.setJspBody(jspFragment);
        getJspContext().setAttribute(PREFIX + id, jspFragment, PageContext.REQUEST_SCOPE);
        bodyless = false;
    }

    @Override public void doTag() throws JspException, IOException {
        if (bodyless) {
            JspFragment jspFragment = (JspFragment) getJspContext().getAttribute(PREFIX + id, PageContext.REQUEST_SCOPE);
            JspContext ctx = jspFragment.getJspContext();
            for (String key : attributes.keySet())
                ctx.setAttribute(key, attributes.get(key));
            jspFragment.invoke(getJspContext().getOut());
            for (String key : attributes.keySet()) {
                ctx.removeAttribute(key);
            }
        }
    }

    public void setId(String id) {
        this.id = id;
    }
    @Override public void setDynamicAttribute(String uri, String key, Object val) throws JspException {
        attributes.put(key, val);
    }
}

The implementation is pretty basic. If the tag has a body, we assume we're defining a macro, and we store that JspFragment. Otherwise, we assume we're calling a macro, so we look it up, and copy any dynamic attributes into its context so it be properly parameterized, and render it into the calling output stream.

Crazy this isn't built into JSP.




回答2:


I tried the solution from Johnny and found, that if you use the macro multiple times, there is a bug.

you have to remove the attributes from the page context after renering

jspFragment.invoke(getJspContext().getOut());

for (String key : attributes.keySet()) {
    ctx.removeAttribute(key);
}


来源:https://stackoverflow.com/questions/20817230/jsp-make-a-reusable-code-tag-macro-and-use-it-on-the-same-page

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!