1. Introduction
Principle: User-defined jsp tags.When a jsp page with a custom tag is compiled into a servlet by the jsp engine, the tag tag is converted into an operation on an object of a tag processor class.
Tag Library API: Defined in javax.servlet.jsp.tagext
2. Lifecycle of label processor class implementing SimpleTag interface
1) setJspContext: Jsp engine passes pageContext object representing JSP page to label processor object
2) setParent:Jsp engine passes the parent label processor object to the current label processor object.The Jsp engine only calls methods if a parent tag exists
3) setXxx: Set label properties.This method is called only if a property is defined.
4) setJspBody: If a tag body exists, the Jsp engine encapsulates the tag body into a JspFragment object and calls the setJspBody method to pass the JSPFragment object to the tag processor object.If the label body is empty, this setJspBody will not be called by the Jsp engine.
5) doTag: The container invokes the doTag method of the label processor object to execute the label logic
3. Steps to develop and apply custom labels
- Use Java classes for tagging (fields and attributes in classes are attributes when using tags).Like the href attribute of the a tag)
- Describe the name, type, and java class associated with the tag using a TLD file
1. Write Java classes (label processors) that complete the label function
HelloSimpleTag (implements SimpleTag interface): count s the value output through
public class HelloSimpleTag implements SimpleTag { private String value; private String count; public void setValue(String value) { this.value = value; } public void setCount(String count) { this.count = count; } //Tag body logic should actually be written into this method. @Override public void doTag() throws JspException, IOException { // System.out.println("value: " + value + ", count: " + count); // // HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); // pageContext.getOut().print("Hello: " + request.getParameter("name")); JspWriter out = pageContext.getOut(); int c = 0; c = Integer.parseInt(count); for(int i = 0; i < c; i++){ out.print((i + 1) + ": " + value); out.print("<br>"); } } @Override public JspTag getParent() { System.out.println("getParent"); return null; } @Override public void setJspBody(JspFragment arg0) { System.out.println("setJspBody"); } private PageContext pageContext; //JSP Engine Call, Represent JSP Page PageContext Object incoming //PageContext Available JSP Eight other implicit objects on the page. //So everything is JSP Label processors that pages can do can do. @Override public void setJspContext(JspContext arg0) { System.out.println(arg0 instanceof PageContext); this.pageContext = (PageContext) arg0; } @Override public void setParent(JspTag arg0) { System.out.println("setParent"); } }
ReadFileTag (inherits SimpleTagSupport class): Gives a text path and outputs the contents of the text
public class ReadFileTag extends SimpleTagSupport{ //Relative to current WEB File name of applied root path private String src; public void setSrc(String src) { this.src = src; } @Override public void doTag() throws JspException, IOException { PageContext pageContext = (PageContext) getJspContext(); InputStream in = pageContext.getServletContext().getResourceAsStream(src); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String str = null; while((str = reader.readLine()) != null){ str = Pattern.compile("<").matcher(str).replaceAll("<"); str = Pattern.compile(">").matcher(str).replaceAll(">"); pageContext.getOut().println(str); pageContext.getOut().println("<br>"); } } }
2. Write tag library description (tld) files to describe customizations in TLD files
<?xml version="1.0" encoding="UTF-8" ?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"> <!-- describe TLD file --> <description>MyTag 1.0 core library</description> <display-name>MyTag core</display-name> <tlib-version>1.0</tlib-version> <!-- Recommended in JSP Prefix for labels used on pages --> <short-name>mytag</short-name> <!-- As tld File id, Used to uniquely identify the current TLD file, Multiple tld File URI Cannot Repeat. adopt JSP Page taglib Labeled uri Attribute to reference. --> <uri>http://www.xxx.com/mytag/core</uri> <!-- Describe Custom HelloSimpleTag Label --> <tag> <!-- Name of label: stay JSP Name when labeling a page --> <name>hello</name> <!-- The full class name of the label --> <tag-class>com.zhang.javaweb.tag.HelloSimpleTag</tag-class> <!-- Type of label body --> <body-content>empty</body-content> <!-- Describes the properties of the current label --> <attribute> <!-- Property Name --> <name>value</name> <!-- Is this property required --> <required>true</required> <!-- rtexprvalue: runtime expression value Whether the current property can accept the dynamic value of a runtime expression --> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>count</name> <required>false</required> <rtexprvalue>false</rtexprvalue> </attribute> </tag>
<tag> <name>readerFile</name> <tag-class>com.zhang.javaweb.tag.ReadFileTag</tag-class> <body-content>empty</body-content> <attribute> <name>src</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
3. Import and use custom tags in JSP pages
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!-- Import Label Library(Description File) --> <%@taglib uri="http://www.xxx.com/mytag/core" prefix="mytag" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <mytag:readerFile src="/WEB-INF/note.txt" />
<!-- count Runtime expression cannot be received, so it cannot be used el Expression --> <mytag:hello value="${param.name }" count="10" /> </body> </html>
3. Summary of usage methods
1. Custom labels with labels
1). If a label has a label body
<mytag:testJspFragment>abcdefg</mytag:testJspFragment>
Use JspFragment objects to encapsulate tag body information in a tag processor for custom tags.
2). If a label is configured to contain a label body
The JSP engine then calls the setJspBody() method to pass the JspFragment to the label processor class
A getJspBody() method is also defined in SimpleTagSupport to return a JspFragment object.
3). invoke(Writer) method of JspFragment
Output label contents from Writer, if null,
Is equivalent to invoke(getJspContext().getOut()), which outputs the contents of the label body directly to the page.
Sometimes, with the help of StringWriter, you can get the contents of the label body first in the label processor class:
//1. Use StringWriter to get the contents of the label body.
StringWriter sw = new StringWriter();
bodyContent.invoke(sw);
//2. Change the contents of the label body to uppercase
String content = sw.toString().toUpperCase();
4). Use the body-content node in the tld file to describe the type of tag body
<body-content>: Specifies the type of label body, which in most cases is scriptless.There are three possible values:
- empty: no label body)
- scriptless: The tag body can contain el expressions and JSP action elements, but cannot contain script elements of JSP
- Tagdependent: Indicates that the label body is left to the label itself for parsing.If tagdependent is specified, all code in the body of the tag will be left intact to the tag processor, rather than passing execution results to the tag processor
<body-content>tagdependent</body-content>
5). Define a custom label
<mytag:printUpper time="10">abcdefg</mytag>Convert the contents of the tag body to uppercase and output time to the browser the next time.
6). Implement forEach Tags
>Two properties: items (Collection type), var(String type)
> doTag:
* Walk through the collection corresponding to the items
* Place the traversing object in the pageContext, key: var, value: traversing object.
* Export the contents of the label body directly to the page.
<c:forEach items="${requestScope.customers }" var="cust2">
${pageScope.cust2.id } -- ${cust2.name } <br>
</c:forEach>
2. Develop tags with parent Tags
@Override public void doTag() throws JspException, IOException { //1. Get a reference to the parent tag JspTag parent = getParent(); //2. Gets the parent tag's name attribute ParentTag parentTag = (ParentTag) parent; String name = parentTag.getName(); //3. hold name Print values to JSP On Page. getJspContext().getOut().print("Sublabel Output name: " + name); }
1). The parent tag cannot get a reference to the child tag
Parent tags only use child tags as tag bodies
2). Subtags can obtain a reference to the parent tag through the getParent() method (this method inherits SimpleTagSupport or implements the SimpleTag interface itself)
If a child tag does have a parent tag, the JSP engine assigns a reference representing the parent tag to the tag processor via setParent(JspTag parent)
3). The type of parent tag is JspTag
The interface is an empty interface, but it unifies SimpleTag with Tag.Actual use requires a type of cast.
4). Parent tag <body-content></body-content>needs to be set to scriptless
There is no need to have additional configuration for the parent tag in the tld configuration file.However, child tags exist as tag bodies, so the parent tag's <body-content></body-content> needs to be set to scriptless.
5). Implementation
<c:choose>
<c:when test="${param.age > 24}">University graduation</c:when>
<c:when test="${param.age > 20}">High school graduation</c:when>
</c:otherwise>Under High School...</c:otherwise>
</c:choose>
Develop 3 tags: choose, when, otherwise
Where the when tag has a boolean type attribute: test
> Choose is the parent label of when and otherwise
When used before otherwise
Define a "global" boolean type flag in the parent label choose: used to determine whether a child label is executed when a condition is met.
* If the test of when is true and the flag of when's parent tag is also true, execute when's tag body (normal output of the contents of the tag body).
Also set flag to false
* If when the test is true and when the flag of the parent tag is false, the tag body is not executed.
* If flag is true, otherwise executes the label body.