JSP: Make reusable code (tag, macro) and use it on one page

Is there a way to make some kind of parameterized macro on the same JSP page and reuse it several times on the same page. You can use JSP tags, but I would have to make one file for each tag.

+1
source share
2 answers

I have long wanted this functionality, and after I started working again, I wrote my own. I think the / jsp tag files and custom tag classes are great, but often overflowing with simple one-time files, as you describe.

This is how my new macro tag works (used here to simply display html 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()); } } 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 quite simple. If the tag has a body, we assume that we define the macro, and we save this JspFragment. Otherwise, we assume that we call the macro, so we look at it and copy any dynamic attributes into its context so that it is correctly parameterized and maps it to the calling output stream.

Crazy, this is not built into the JSP.

+3
source

I tried the solution from Johnny and found that if you use the macro several times, an error appears.

you need to remove the attributes from the page context after retrieving

 jspFragment.invoke(getJspContext().getOut()); for (String key : attributes.keySet()) { ctx.removeAttribute(key); } 
+1
source

Source: https://habr.com/ru/post/1300605/


All Articles