
什么是标记
使用HTML语言我们可以这样去编辑我们的网页:
<HTML>
<HEAD>
<TITLE>
HELLO WORLD
</TITLE>
</HEAD>
<BODY>
HELLO WORLD
</BODY>
</HTML>
在这里我们把</HEAD>,<TITLE>,<BODY>称为标记。HTML 标记( HTML Markup)是HTML文档的控制语言,用于指定浏览器显示和打印文档的方式.它是用小于号"<"和大于号">"括起来的短语和符号,如 <Html>、</Body>等。许多HTMl标记以成对的方式出现,如<TITLE></TITLE>、<Body></Body>等。在JSP中我们也可以定制自己的标记,以供JSP页面使用,如下例所示:
<!—login.jsp-->
<%@ taglib uri="/tlds/taglib.tld" prefix="tagclass" %>
<html>
<head>
<title>login</title>
</head>
<body>
<tagclass:login width="200" height= "100" >
</tagclass:login>
</body>
</html>
在上例中</tagclass:login>就是一个JSP定制标记符。widtht、height是这个标记的属性。<%@ taglib uri="/tlds/taglib.tld" prefix="tagclass" %>是一个标记库定义指令,在稍后我们将会讨论。在JSP中定制标记符,实质上就是以标记的形式封装了一个俱有独立功能的Java类。标记的使用减少了直接嵌入JSP页面的Java代码,方便了页面的布局,并且有利于代码的复用,提高了开发的效率。
JSP服务器解析标记的过程
那么当一个标记被嵌入JSP页面后,JSP服务器是如何对这个标记进行解析的呢?各对象的含义如下所示:
Client: 表示客户端。
JSP-Server:JSP服务器。
JSP-Page:JSP页面。
TLD: 标记库描述文件,定义标记和标记的各种属性和处理文件等。
TagClass 标记处理程序
当一个用户访问一个JSP页面时,这个请求被发送到JSP服务器,JSP服务器会根据这个请求去调用相应的页面,如果这个页面中有自定义的标记, JSP服务就会根据页面指令<%@ taglib>去访问TLD得到处理程序的相关信息,接着调用该处理程序的构造器方法,启动标记符处理程序,并读取标记符的属性和相应值。对每个没有设置属性的,调用相应的set方法。当标记符第一次使用时,它的任何属性都不会做过设置,因此对每个属性都调用set方法。属性设置完以后,JSP服务器调用处理程序的doStartTag(),然后再调用doEndTag()方法。最后JSP服务器会继续处理剩下的页面,在页面结尾调用release ()方法,清理占用的所有资源。
TLD文件
TLD(TLD:Tag Library Descriptor标记库描述符)文件,标准的XML格式的标记定义文件,被用来存放标记符的信息,下面就是一个典型的TLD文件。
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!—XML的版本及其字符集-->
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
" http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<!—文档类型定义-->
<taglib>
<!—此标记说明我们开始描述一个标记库-->
<tlibversion>1.0</tlibversion>
<!—标记库的版本-->
<jspversion>1.1</jspversion>
<!—所使用的JSP的版本-->
<shortname>tagclass</shortname>
<!—缺省的名称-->
<tag>
<name>login</name>
<!—标记的名称-->
<tagclass>
tagclass.login.login
<!—处理这个Tag的相应的类的名称-->
</tagclass>
<info>
<!—对本标记符的描述-->
</info>
<attribute>
<!—开始定义标记的属性-->
<name>height</name>
<!—属性的名称-->
<required>true</required>
<!—表示这个属性是不是必须的-->
<rtexprvalue>true</rtexprvalue>
<!—表示这个属性是否可以用JSP的程序段的结果输出-->
</attribute>
<attribute>
<name>width</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
在这个TLD文件中定义了只有一个标记符的标记符库,这个名为login的标记符会调用一个Applet以验证用户的合法性。处理这个标记的类就是 tagclass.login.login。width、height是这个标记的两个属性。属性是在使用标记符时作为参数发送的值。我们可以在上面的示例中增加几个标记,也可以为每个标记添加几个属性。我们开发标记符库时不一定非要从头开始,自己编写一个全新TLD。我们可以使用某个集成的开发的环境,也可以修改上面的例子。
TagLib指令
那么当JSP服务器在解析一个标记符时,它是如何定义一个标记库的呢?这就是TagLib指令的主要责任。
Taglib 指令
定义一个标记库以及其自定义标记的前缀.
JSP 语法
复制代码 代码如下:
<%@ taglib uri="URIToTagLibrary" prefix="tagPrefix" %>
例子
<%@ taglib uri="/tlds/taglib.tld" prefix="tagclass" %>
<html>
<head>
<title>login</title>
</head>
<body>
<tagclass:login width="200" height= "100" >
</tagclass:login>
</body>
</html>
描述
<% @ taglib %>指令声明此JSP文件使用了自定义的标记,同时引用标记库,
也指定了他们的标记的前缀。 你必须在使用自定义标记之前使用<% @ taglib %>指令。
属性
uri="URIToTagLibrary" :Uniform Resource Identifier (URI)根据标记的前缀对自定义的标记进行唯一的命名,URI可以是一个相对或绝对的路径。
prefix="tagPrefix":在自定义标记之前的前缀。如上例中的</tagclass:login>
标记符的处理程序(Tag handle)
我们还是以一个例子来看下如何实现一个Tag handle。首先是看一下它的类图:
让我们再看一下它的代码:
package tagclass.login
import javax.servlet.jsp.tagext.TagSupport
import javax.servlet.jsp.*
import java.io.*
public class login extends TagSupport
{
public login()
{
super()
}
public int doStartTag() throws JspTagException
{
JspWriter out = pageContext.getOut()
try
{
out.println("<APPLET CODEBASE=applet/login/ CODE=login.class width=200 height=100 ></APPLET>")
}
catch(Exception e)
{
}
return SKIP_BODY
}
publicc int doEndTag()throws JsptagException
{
return EVAL_PAGE
}
public void release()
{
super.release()
}
public void setWidth(String language)
{
this.width = width
}
public String getWidth()
{
return this.width
}
public void setHeight(String height)
{
this.height=height
}
public String getHeight()
{
return this.height
}
private String width
private String height
}
从以上我们可以看出,实现一个简单的标记符处理程序有几个要求:①增加一个类,使之继承 java.Servlet.jsp.tagext.TagSupport类。这个类提供了java.Servlet.jsp.tagext.Tag接口所要求的所有的方法。另外,还需要使用一些基本的API,使JSP容器能够调用我们自己提供的标记符处理程序。②必须为每个标记符属性分别创建一个 get<attribute>和set<attribute>方法,JSP容器需要使用这些方法处理程序传递参数。③要为标记符处理程序创建一个构造器和自毁器。JSP需要使用构造器启动处理程序。自毁器是在realease()方法中定义的。在处理程序的生命周期结束时,需要调用自毁器释放所占用的资源。④创建两个名为doStartTag()和doEndTag()的方法,执行具体的处理和输出动作。这两个方法是在处理自定义标记符的起始位置和结束位置调用的。它们的返回值是在Tag Interface里定义的静态int,这几个静态值分别是:
SKIP_BODY隐含0 :跳过了开始和结束标签之间的代码。
EVAL_BODY_INCLUDE隐含1:将body的内容输出到存在的输出流中
SKIP_PAGE隐含5 : 忽略剩下的页面。
EVAL_PAGE隐含6:继续执行下面的页
当然标记符也有它自己的缺点。很不方便的封装过程,有限的功能。对于一些不太复杂和功能单一的逻辑描述,需要传递的参数要求不高时,使用JSP标记,要方便的多。对于大多数的商业逻辑应用,还是使用bean要好的多,也宜于servlet控制。
附:文章中所用示例的完整代码
JSP代码:login.jsp
<%@ taglib uri="/tlds/taglib.tld" prefix="tagclass" %>
<html>
<head>
<title></title>
</head>
<body>
<tagclass:login width="200" height= "100" >
</tagclass:login>
</body>
</html>
标记符描述库:taglib.tld
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
" http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>tagclass</shortname>
<tag>
<name>login</name>
<tagclass>
tagclass.login.login
</tagclass>
<info>
</info>
<attribute>
<name>height</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>width</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
标记符处理程序:login.java
package tagclass.login
import javax.servlet.jsp.tagext.TagSupport
import javax.servlet.jsp.*
import java.io.*
public class login extends TagSupport
{
public login()
{
super()
}
public int doStartTag() throws JspTagException
{
JspWriter out = pageContext.getOut()
try
{
out.println("<APPLET CODEBASE=applet/login/ CODE=login.class width=200 height=100 ></APPLET>")
}
catch(Exception e)
{
}
return SKIP_BODY
}
publicc int doEndTag()throws JsptagException
{
return EVAL_PAGE
}
public void release()
{
super.release()
}
public void setWidth(String language)
{
this.width = width
}
public String getWidth()
{
return this.width
}
public void setHeight(String height)
{
this.height=height
}
public String getHeight()
{
return this.height
}
private String width
private String height
}
标记符处理程序中所使用的Applet : login.java
import java.awt.*
import java.awt.event.*
import java.applet.*
public class login extends Applet implements ActionListener
{
private String s_username
private String s_userpassword
private Button b_ok
private Button b_register
private Label l_username
private Label l_userpassword
private TextField t_username
private TextField t_userpassword
private GridLayout g_gridlayout
public void init()
{
b_ok=new Button("ok")
b_register=new Button("register")
l_username= new Label("name")
l_userpassword=new Label("password")
t_username=new TextField()
t_userpassword=new TextField()
b_ok.addActionListener(this)
b_register.addActionListener(this)
g_gridlayout=new GridLayout(3,2,10,10)
this.setLayout(g_gridlayout)
//this.setBackground(Color.blue)
add(l_username)
add(t_username)
add(l_userpassword)
add(t_userpassword)
add(b_ok)
add(b_register)
}
public void actionPerformed(ActionEvent ev)
{
String s_label=ev.getActionCommand()
if (s_label.equals("ok"))
{
t_username.setText("name")
}
if (s_label.equals("register"))
{
t_userpassword.setText("password")
}
}
public void paint(Graphics g)
{
}
}
我觉得上楼回答的不完全对,自定义标签,不一定就是tomcat给封装好了的,自己也可以实现接口,编写*.tld(标签库描述文件),然后标签创建成功,便可引入页面使用了。下面截一段API与大家讨论:javax.servlet.jsp.tagext
Interface JspTag
All Known Subinterfaces:
BodyTag, IterationTag, LoopTag, SimpleTag, Tag
从上一段API内容中可以看出JspTag接口下又有BodyTag, IterationTag, LoopTag, SimpleTag, Tag几个子接口。
然后以SimpleTag接口为例,分享set_等方法之用意:
Method Summary(方法概要)
void doTag()
Called by the container to invoke this tag.
当容器调用该方法时,唤醒该标签
JspTag getParent()
Returns the parent of this tag, for collaboration purposes.
返回该标签的父标签
void setJspBody(JspFragment jspBody)
Provides the body of this tag as a JspFragment object, able to be invoked zero or more times by the tag handler.
把JspFragment对象作为body提供给这个标签,能够被tag管理器调用0或多次。
void setJspContext(JspContext pc)
Called by the container to provide this tag handler with the JspContext for this invocation.
设置上下文
void setParent(JspTag parent)
Sets the parent of this tag, for collaboration purposes.
设置该标签的父标签
最后,一系列set方法,我觉得可以说成是对标签属性的设置
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)