自定义标签库
文章目录
客户化JSP标签
- 客户化JSP标签技术是在JSP 1.1版本中才出现的,它支持用户在JSP文件中自定义标签,这样可以使JSP代码更加简洁。
- 这些可重用的标签能处理复杂的逻辑运算和事务,或者定义JSP网页的输出内容和格式。
创建客户化JSP标签的步骤
• (1)创建标签的处理类
• (2)创建标签库描述文件,标签库描述文件的额后缀名是:.tld
• (3)在JSP文件中引入标签库,然后插入标签,例如:mm:hello/
JSP Tag API
- Servlet容器编译JSP网页时,如果遇到自定义标签,就会调用这个标签的处理类。
- 标签处理类必须扩展以下两个类之一:
– javax.servlet.jsp. tagext .TagSupport
– javax.servlet.jsp. tagext . BodyTagSupport
TagSupport类的主要方法
- doStartTag
Servlet容器遇到自定义标签的起始标志时调用该方法 - doEndTag
Servlet容器遇到自定义标签的结束标志时调用该方法 - setValue(String k,Object o)
在标签处理类中设置key/value - getValue(String k)
在标签处理类中根据参数key返回匹配的value - removeValue(String k)
在标签处理类中删除key/value - setPageContext(PageContext pc)
设置PageContext对象,该方法由Servlet容器在调用doStartTag或doEndTag方法前调用 - setParent(Tag t)
设置嵌套了当前标签的上层标签的处理类,该方法由Servlet容器在调用doStartTag或doEndTag方法前调用 - getParent()
返回嵌套了当前标签的上层标签的处理类
TagSupport类的两个重要属性
• parent:代表嵌套了当前标签的上层标签的处理类
• pageContext : 代 表 Web 应 用 中 的javax.servlet.jsp.PageContext对象
• JSP容器在调用doStartTag或doEndTag方法前 , 会 先 调 用 setPageContext 和setParent 方 法 , 设 置 pageContext 和parent。
• 在doStartTag或doEndTag方法中可以通过getParent方法获取上层标签的处理类;在TagSupport类中定义了protected类型的pageContext成员变量,因此在标签处理类中可以直接访问pageContext变量。
PageContext类
PageContext类提供了保存和访问Web应用的共享数据的方法:
– public void setAttribute(String name, Object value, intscope)
– public Object getAttribute(String name, int scope)
• 其中,scope参数用来指定属性存在的范围,它的可选值包括:
– PageContext.PAGE_SCOPE
– PageContext.REQUEST_SCOPE
– PageContext.SESSION_SCOPE
– PageContext.APPLICATION_SCOPE
• 例如:
pageContext.setAttribute(“username”,”zhangsan”,PageContext.SESSION_SCOPE);
TagSupport类的处理标签的方法
• public int doStartTag() throws JspException
• public int doEndTag() throws JspException
doStartTag()方法
• 当Servlet容器遇到自定义标签的起始标志,就会调用doStartTag()方法。
• doStartTag()方法返回一个整数值,用来决定程序的后续流程。它有两个可选值:
– Tag.SKIP_BODY
– Tag.EVAL_BODY_INCLUDE
• Tag.SKIP_BODY表示标签之间的内容被忽略。
• Tag.EVAL_BODY_INCLUDE表示标签之间的内容被正常执行。例如
对于以下代码:
<prefix: Mytag>
Hello
……
……
</prefix:Mytag>
假若的doStartTag()方法返回Tag.SKIP_BODY,”Hello”字符串不会显示在网页上;若返回Tag.EVAL_BODY_INCLUDE,“Hello” 字符串将显示在网页上。
doEndTag()方法
当Servlet容器遇到自定义标签的结束标志,就会调用doEndTag()方法。
• doEndTag()方法也返回一个整数值,用来决定程序后续流程。它有两个可选值:
– Tag.SKIP_PAGE
– Tag.EVAL_PAGE
• Tag.SKIP_PAGE表示立刻停止执行JSP网页,网页上未处理的静态内容和JSP程序均被忽略,任何已有的输出内容立刻返回到客户的浏览器上。
• Tag.EVAL_PAGE表示按正常的流程继续执行JSP网页。
用户自定义的标签属性
在标签中还能包含自定义的属性,例如:
<prefix:mytag username=“zhangsan">
……
……
</prefix:mytag>
• 在标签处理类中应该将这个属性作为成员变量,并且分别提供设置和读取属性的方法,假定以上username为String类型,可以定义如下方法:
private String username;
public void setUsername(String value){
this.username=value;
}
public String getUsername(){
return username;
}
范例1:创建hello标签
定义一个名为mytaglib的标签库,它包含一个简单的hello标签,这个标签能够将JSP页面中所有的mm:hello/解析为字符串“hello”。
hello标签的处理类HelloTag
package learn.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
public class MyTag extends TagSupport {
@Override
public int doStartTag() throws JspException {
try {
//向页面输出文本字符串
this.pageContext.getOut().print("hello world ");
} catch (IOException e) {
e.printStackTrace();
}
return EVAL_BODY_INCLUDE;
}
@Override
public int doEndTag() throws JspException {
try {
//向页面输出文本字符串
this.pageContext.getOut().print("welcome");
} catch (IOException e) {
e.printStackTrace();
}
return EVAL_PAGE;
}
}
创建hello标签的标签库的描述文件
创建Tag Library的描述文件mytaglib.tld文件,在这个文件中定义mytaglib标签库和hello标签。这个文件存放位置为/WEB-INF/mytaglib.tld。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.1</jsp-version>
<short-name>myTag</short-name>
<uri>/myTag</uri>
<tag>
<name>firstTag</name>
<tag-class>learn.tag.MyTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
在JSP中加入hello标签
在 hellowithtag1.jsp 中 加 入 引 用mytaglib的taglib指令:<%@ taglib uri="/mytaglib" prefix=“mm” %>以上taglib指令中,prefix属性用来指定引用mytaglib标签库时的前缀。
在 hellowithtag1.jsp 文件中插入hello标签:mm:hello/ :
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/myTag" prefix="hello"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%=basePath%>">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<p><font color="blue"><hello:firstTag/></font></p>
</body>
</html>
结果是:
查看页面源代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="http://localhost:8080/JavaWeb/">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<p><font color="blue">hello world welcome</font></p>
</body>
</html>
范例2:创建message标签
创建一个能替换test应用中JSP网页的静态文本的标签,这个标签名为message,它放在mytaglib标签库中。
创建包含JSP网页静态文本的文件
首先将创建包含JSP网页静态文本的文件,这些文本以key/value的形式存放,这个文件名为message.properties:
title=hello world
body=welcome
在Web应用启动时装在静态文本
尽管装载静态文本的任务可以直接由标签处理类来完成,但是把初始化的操作安排在Web应用启动时完成,这更符合Web编程的规范。
在本例中,由DispatcherServlet类的init方法负责从静态文本文件中读取静态文本,然后把它们装载到Properties对象中,最后再把这个Properties对象作为属性保存到ServletContext中。
DispatcherServlet类的init方法
package learn.servlet;
import java.io.InputStream;
import java.util.Properties;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
public class InitServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
public void init(ServletConfig config) throws ServletException {
Properties ps = new Properties();
try {
ServletContext context = config.getServletContext();
InputStream inputStream = context.getResourceAsStream("/WEB-INF/message.properties");
ps.load(inputStream);
inputStream.close();
//将properties对象放置到application范围内供其他组件使用
context.setAttribute("ps", ps);
} catch (Exception e) {
e.printStackTrace();
}
}
}
为 了 保 证 在 Web 应 用 启 动 时 就 加 载DispatcherServlet,应该在web.xml中配置这个Servlet时设置load-on-startup属性:
<servlet>
<display-name>InitServlet2</display-name>
<servlet-name>InitServlet2</servlet-name>
<servlet-class>learn.servlet.InitServlet2</servlet-class>
<load-on-startup>10</load-on-startup>
</servlet>
创建MessageTag标签处理类
MessageTag包含一个成员变量key,它与message标签的属性key对应。在MessageTag中定义了getKey和setKey方法在MessageTag的doEndTag方法中,首先从pageContext中读取包含静态文本的Properties对象然后从Properties对象中读取key对应的静态文本,最后输出该文本
package learn.tag;
import java.util.Properties;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;
public class MyTag2 extends TagSupport {
private String key;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
@Override
public int doEndTag() throws JspException {
try {
Properties properties = (Properties)this.pageContext.getAttribute("ps", PageContext.APPLICATION_SCOPE);
String message = properties.getProperty(key);
this.pageContext.getOut().println(message);
} catch (Exception e) {
e.printStackTrace();
}
return EVAL_PAGE;
}
}
在mytaglib库中定义message标签
<tag>
<name>message</name>
<tag-class>learn.tag.MyTag2</tag-class>
<body-content>empty</body-content>
<attribute>
<name>key</name>
<required>true</required>
</attribute>
</tag>
最后jsp页面输出:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/myTag" prefix="hello" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%=basePath%>">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<hello:message key="title"/>
<hello:message key="body"/>
</body>
</html>
练习
-
问题:在标签处理类中,如何访问session范围内的共享数据?
• 选项:
(A) 在 TagSupport 类 中 定 义 了 session 成 员 变 量 , 直 接 调 用 它 的getAttribute()方法即可。
**(B)**在标签处理类TagSupport类中定义了pageContext成员变量,先通过它的 getSession() 方 法 获 得 当 前 的HttpSession 对 象 , 再调用HttpSession对象的getAttribute()方法。
© pageContext.getAttribute(“attributename”,PageContext.SESSION_SCOPE) -
问 题 : 在 下 面 的 选 项 中 , 哪 些 是TagSupport类的doStartTag()方法的有效返回值?
• 选项:
(A) Tag.SKIP_BODY
(B) Tag.SKIY_PAGE
© Tag.EVAL_BODY_INCLUDE
(D) Tag.EVAL_PAGE