Tag Files
Allow creation of reusable content
Better than jsp:include and c:import– Don’t require adding request parameters to
pass information around
Easier to read than jsp:include or c:import
Tag Files<!-- Header.tag file - placed in WEB-INF/tags directory --><img src="images/Web-Services.jpg"><br>
<!-- Home.jsp --><%@ taglib prefix="myTags" tagDir="/WEB-INF/tags" %>
<html><body>
<!-- This used to be <jsp:include page="Header.jsp"/> --><myTags:Header/>
Welcome to our site.</body></head>
Passing Parameters<!-- The old way --><!-- Header.jsp file --><img src="images/Web-Services.jpg"><br><em><strong>${param.subTitle}</em></strong><br>
<!-- Main.jsp file --><html><body>
<jsp:include page="Header.jsp"> <jsp:param name="subTitle" value="We take the string out of SOAP." /></jsp:include>
<br>Contact us at: ${initParam.mainEmail}</body></html>
Passing Parameters<!-- The better way --><!-- Header.tag file --><%@ attribute name="subTitle" required="true" rtexprvalue="true" %>
<img src="images/Web-Services.jpg"><br><em><strong>${subTitle}</em></strong><br>
<!-- Main.jsp file --><html><body>
<!-- This is easier to read, and the parameters only have tag scope, too! -->
<myTags:Header subTitle="We take the string out of SOAP." />
<br>Contact us at: ${initParam.mainEmail}</body></html>
Passing Parameters<!-- Use jsp:doBody for long values --><!-- Header.tag file --><%@ tag body-content="tagdependent" %>
<img src="images/Web-Services.jpg"><br><em><strong><jsp:doBody></em></strong><br>
<!-- Main.jsp file --><html><body><myTags:Header> We take the sting out of SOAP. OK, so it's not Jini,<br> but we'll help you get through it with the least<br> frustration and hair loss.</myTags:Header>
<br>Contact us at: ${initParam.mainEmail}</body></html>
Finding Tag Files
The container looks for tag files in: WEB-INF/tags Subdirectories of WEB-INF/tags META-INF/tags in library JAR files Subdirectories of META-INF/tags in library
JAR files
If the tag file is in a JAR, there must be a TLD file for it!
Sharpen Your Pencil
What do you put in the Tag File to declare that the tag has one required attribute called title, that can use an EL expression as its value?
What do you put in the Tag File to declare that the tag must NOT have a body?
Draw a Tag File in each of the locations where the Container will look for Tag Files.
WEB-INF
classes foo
lib JAR META-INF
tags myTags
TLDstags moreTags
Sharpen Your Pencil
What do you put in the Tag File to declare that the tag has one required attribute called title, that can use an EL expression as its value?
<%@ attribute name=“title” required=“true” rtexprvalue=“true” %>
What do you put in the Tag File to declare that the tag must NOT have a body?
<%@ tag body-content=“empty” %>
Sharpen Your Pencil
Draw a Tag File in each of the locations where the Container will look for Tag Files.
WEB-INF
classes foo
lib JAR META-INF
tagsfoo.tag
myTags foo.tag
TLDs bar.tld
tagsmoreTags foo.tag
foo.tag
Custom Tag Handlers
Allow much more flexibility than Custom Tag Files
Written in Java
Come in two flavors Classic Simple (JSP 2.0 and above)
Creating a Simple Tag Handler
1. Write a class that extends SimpleTagSupport
2. Override the doTag() method
3. Create a TLD for the tag
4. Deploy the tag handler and TLD
5. Write a JSP that uses the tag
Simple Tag Handlerspublic class SimpleTagTest1 extends SimpleTagSupport { public void doTag() throws JspException, IOException { getJspContext().getOut().write("Lamest tag EVAR!"); }}
<tag> <!-- In TLD --> <description>worst use of a custom tag</description> <name>simple1</name> <tag-class>foo.SimpleTagTest1<tag-class> <body-content>empty</body-content></tag>
<!-- In JSP --><%@ taglib prefix="myTags" uri="simpleTags" %><html><body><myTags:simple1/></body></head>
Simple Tag Handlerspublic class SimpleTagTest2 extends SimpleTagSupport { public void doTag() throws JspException, IOException { getJspBody().invoke(null); }}
<tag> <!-- In TLD --> <description>slightly better use of a custom tag</description> <name>simple2</name> <tag-class>foo.SimpleTagTest2<tag-class> <body-content>scriptless</body-content></tag>
<!-- In JSP --><myTags:simple2> This is the body</myTags:simple2>
Tag Handler Lifecycle
1. Load and instantiate class
2. Call setJspContext(JspContext)3. If tag is nested, call
setParent(JspTag)4. If tag has attributes, call setters
5. If tag has a body, call setJspBody(JspFragment)
6. Call doTag()
Tags and Expressions<!-- In JSP --><myTags:simple3> <!-- What if message isn't defined yet? --> This is the message: ${message}</myTags:simple2>
public class SimpleTagTest3 extends SimpleTagSupport { public void doTag() throws JspException, IOException { getJspContext().setAttribute("message", "Wear sunscreen."); getJspBody().invoke(null); }}
Tags with Attributes<tag> <!-- In TLD --> <description>takes an attribute and iterates over body</description> <name>simple5</name> <tag-class>foo.SimpleTagTest5<tag-class> <body-content>scriptless</body-content> <attribute> <name>movieList</attribute> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute></tag>
Tags with Attributes<table> <myTags:simple5 movieList="${movieCollection}"> <tr> <td>${movie.name}</td> <td>${movie.genre}</td> </tr> </myTags:simple5></table>
public void setMovieList(List<Movie> movieList) { this.movieList = movieList; }
public void doTag() throws JspException, IOException { for(Movie movie : movieList) { getJspContext().setAttribute("movie", movie); getJspBody().invoke(null); }}
Sharpen Your Pencil
SkipPageException allows tag evaluation to be aborted without killing the rest of the page. What is the output of the tag below?
public void doTag() throws JspException, IOException { getJspContext().getOut().print("Message from within
doTag().<br>"); getJspContext().getOut().print("About to throw a
SkipPageException"); throw new SkipPageException();}
<%@ taglib prefix="myTags" uri="simpleTags" %><html><body>About to invoke a tag that throws SkipPageException <br><myTags:simply6/><br>Back in the page after invoking the tag.</body></html>
Sharpen Your Pencilpublic void doTag() throws JspException, IOException { getJspContext().getOut().print("Message from within doTag().<br>"); getJspContext().getOut().print("About to throw a SkipPageException"); throw new SkipPageException();}
<%@ taglib prefix="myTags" uri="simpleTags" %><html><body>About to invoke a tag that throws SkipPageException <br><myTags:simply6/><br>Back in the page after invoking the tag.</body></html>
Result:About to invoke a tag that throws SkipPageExceptionMessage from within doTag().About to throw a SkipPageException
Sharpen Your Pencilpublic void doTag() throws JspException, IOException { getJspContext().getOut().print("Message from within doTag().<br>"); getJspContext().getOut().print("About to throw a SkipPageException"); throw new SkipPageException();}
<html><body>This is page (A) that includes another page (B).<br>Doing the include now:<br><jsp:include page="badTagInclude.jsp" /><br>Back in page A after the include...</body></html>
<%@ taglib prefix="myTags" uri="simpleTags" %>This is page B that invokes the tag that throws SkipPageException.Invoking the tag now:<br><myTags:simply6/><br>Still in page B after the tag invocation…
Sharpen Your PencilOutput:
This is page (A) that includes another page (B).Doing the include now:
This is page B that invokes the tag that throws SkipPageException.Invoking the tag now:
Message from within doTag().About to throw a SkipPageException
Back in page A after the include…
Classic Tag Handlers<!-- No changes in JSP or TLD public class Classic1 extends TagSupport {
public int doStartTag() throws JspException { JspWriter out = pageContext.getOut();
try { out.println("classic tag output"); } catch(IOException e) { throw new JspException("IOException-" + e.toString()); }
return SKIP_BODY; }}
Classic Tag Handlers// Simple tag with a bodypublic class SimpleTag extends SimpleTagSupport { public void doTag() throws JspException, IOException { getJspContext().getOut().print("Before body."); getJspBody().invoke(null); getJspContext().getOut().print("After body."); }}
Classic Tag Handlerspublic int doStartTag() throws JspException { out = pageContext.getOut(); try { out.println("Before body."); } catch (IOException e) { throw new JspException("IOException-" + e.toString()); } return EVAL_BODY_INCLUDE;}
public int doEndTag() throws JspException { try { out.println("After body."); } catch (IOException e) { throw new JspException("IOException-" + e.toString()); } return EVAL_PAGE;}
Classic Tag Handlerspublic int doStartTag() throws JspException { out = pageContext.getOut(); try { out.println("Before body."); } catch (IOException e) { throw new JspException("IOException-" + e.toString()); } return EVAL_BODY_INCLUDE;}
public int doEndTag() throws JspException { try { out.println("After body."); } catch (IOException e) { throw new JspException("IOException-" + e.toString()); } return EVAL_PAGE;}
How can we make the tag body repeat?
Classic Tag Handlers
doStartTag()
Evaluate BODY
doAfterBody()
doEndTag()
Evaluate PAGE
Done
return EVAL_BODY_INCLUDE
return SKIP_BODYreturn EVAL_BODY_AGAIN
return SKIP_BODY
return EVAL_PAGE
return SKIP_PAGE
Sharpen Your Pencil// Write the classic tag handler that is the equivalent of this simple
handlerpublic void doTag() throws JspException, IOException { String [] movies = {"Spiderman", "Saved!", "Amelie"}; for (String movie : movies) { getJspContext().setAttribute("movie", movie); getJspBody().invoke(null); }}
public class MyIteratorTag extends TagSupport { public int doStartTag() throws JspException {} public int doAfterBody() throws JspException {} public int doEndTag() throws JspException {}}
Sharpen Your Pencilpublic class MyIteratorTag extends TagSupport { String [] movies = {"Spiderman", "Saved!", "Amelie"}; int movieCounter;
public int doStartTag() throws JspException { movieCounter = 0;
pageContext.setAttribute("movie", movies[movieCounter]); movieCounter++;
return EVAL_BODY_INCLUDE; }
Sharpen Your Pencil public int doAfterBody() throws JspException { if (movieCounter < movies.length) { pageContext.setAttribute("movie", movies[movieCounter]); movieCounter++; return EVAL_BODY_AGAIN; }
return SKIP_BODY; }
public int doEndTag() throws JspException { return EVAL_PAGE; }}
Dynamic Attributes<!-- remember our beer selection page? --><form method="POST" action="SelectBeer.do"> <p>Select beer color:</p> <select name="color" size="1"> <option value="light">light</option> ... </select> <input type="submit"></form>
<!-- We would like to do this instead --><form method="POST" action="SelectBeer.do"> <p>Select beer color:</p> <formTags:select name="color" size="1" optionsList="${applicationScope.colorList"/> <input type="submit"></form>
Dynamic Attributes
<select> supports the following attributes Core Attributes: id, class, style, title I18N Attributes: lang, dir Event Attributes: onclick, ondblclick, onmouseup, onmouseover, onmousemove, onmouseout, onkeypress, onkeyup, onkeydown
Form Attributes: name, disabled, multiple, size, tabindex, onfocus, onblur, onchange
Dynamic Attributespublic class SelectTagHandler extends SimpleTagSupport
implements DynamicAttributes { private String name; private List optionsList; private Map<String, Object> tagAttrs = new HashMap<String, Object>();
public void setName(String name) { this.name = name; } public void setOptionsList(List value) { this.optionsList = value; }
@Override public void setDynamicAttribute(String uri, String name, Object value)
throws JspException { tagAttrs.put(name, value); }
Dynamic Attributes public void doTag() throws JspException, IOException { JspWriter out = ((PageContext)getJspContext()).getOut();
out.print("<select "); out.print(String.format(ATTR, "name", name));
for(String attrName : tagAttrs.keySet()) { out.print(String.format(ATTR, attrName, tagAttrs.get(attrName))); }
out.println('>');
// Generate options from optionList here
out.println("</select>"); }
private static final String ATTR = "%s='%s' ";}
Dynamic Attributes<tag> <!-- In TLD --> <description>Builds select tag</description> <name>select</name> <tag-class>foo.SelectTagHandler<tag-class> <body-content>empty</body-content> <attribute> <name>name</attribute> <required>true</required> </attribute> <attribute> <name>optionsList</attribute> <type>java.util.List</type> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <dynamic-attributes>true<dynamic-attributes></tag>
WAR Files
Pack your web application in one file
Allow library dependencies to be declared and checked at deployment time
Have the same structure as your webapp, except for adding META-INF/MANIFEST.MF
Accessing Static Content
Static HTML and JSPs can only be accessed if they are not inside WEB-INFThis allows pages to be hidden from direct access, but they can still be forwarded to or included in other pages
Servlet Mapping<web-app ...>
<servlet> <servlet-name>Beer</servlet-name> <servlet-class>com.example.BeerSelect</servlet-class> </servlet>
<servlet-mapping> <servlet-name>Beer</servlet-name> <!-- This has NOTHING to do with the actual layout of your files --> <url-pattern>/Beer/SelectBeer.do</url-pattern> </servlet-mapping>
</web-app>
Servlet Mapping - Three Types of url-pattern
Exact match: /Beer/SelectBeer.doDirectory match: /Beer/*Extension match: *.doContainer looks for matches in the above order
If more than one pattern matches, the longest (most-specific) is used
Welcome Files
A list of welcome files can be specified in the DD
When none of the servlet mappings match, the container looks for the specified files in order
<welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>default.jsp</welcome-file></welcome-file-list>
Welcome Files - Example
1. Client requests www.wickedlysmart.com/MyTestApp/search
2. Container checks for a servlet mapping
3. Container checks for MyTestApp/search/index.html
4. Container checks for MyTestApp/search/default.jsp