JavaEE jsp自定义标签
来源:互联网 发布:机蜜租机划算么 知乎 编辑:程序博客网 时间:2024/06/10 01:42
通过使用jsp的自定义标签,可以在简单的标签中封装复杂的功能,可以用以取代jsp脚本。
开发jsp2自定义标签的步骤如下:
- 定义标签处理类;
- 定义*.tld
文件;
- 在jsp页面中使用自定义标签。
简单标签定义
说到标签,可以联想到标签的属性和标签体。为了重点展示自定义标签的编写,我们先定义一个最简单的标签,即无属性无标签体的标签。这个简单标签将显示当前的日期和时间。
定义标签处理类
就像一开始所说的那样,我们需要先定义标签处理类,这个类需要继承自javax.servlet.jsp.tagext.SimpleTagSupport
,并重写doTag
方法:
// DateTimeTag.javapublic class DateTimeTag extends SimpleTagSupport { private static final SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public void doTag() throws JspException, IOException { super.doTag(); getJspContext().getOut().write(sdf.format(new Date())); }}
DateTimeTag类很简单,它继承自SimpleTagSupport,并重写了doTag
方法。doTag
方法中获取了jsp页面上下文的输出流来输出当前的日期和时间。
定义TLD文件
接着,我们需要定义*.tld
文件。TLD是Tag Library Definition
的缩写,即标签库定义。每个TLD文件对应一个标签库,标签库中可以定义多个标签。TLD文件需要放在WEB-INF
目录或其任意子目录下,这里我们将其放在WEB-INF/jsp2
目录下。
下面我们在eclipse中创建一个TLD文件。先在WEB-INF
目录下创建jsp2
目录,再右击jsp2
目录选择New
-Other
-XML
-XML File
,输入文件名(我们输入mytaglib.tld),Next
,选择Creat XML file from a DTD file
,Next
,选择Select XML Catalog entry
,在出现的XML文本选择下拉框中选择-//Sun Microsystems,Inc.//DTD JSP Tag Library 1.2//EN
,Next
,Finish
。
在新创建的TLD文件中可以看到,它的根元素是taglib
,里面可以包含多个tag
子元素,我们就是通过tag
元素来定义标签的。下面我们在mytaglib.tld
文件中定义第一个标签:
<!-- mytaglib.tld --><!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>tlib-version</tlib-version> <jsp-version>jsp-version</jsp-version> <short-name>short-name</short-name> <uri>http://zzw.com/mytaglib</uri> <tag> <name>datetime</name> <tag-class>com.zzw.DateTimeTag</tag-class> <body-content>empty</body-content> </tag></taglib>
在taglib
元素中有一个uri
元素,这个元素指定标签库的URI,我们在使用标签库时就依赖于此元素。在tag
元素中,name
元素指定标签的名字,我们在使用标签时需要指定标签名;tag-class
元素指定标签的处理类;body-content
元素和标签体有关,它可以是下面几个值:
- empty:表示没有标签体;
- JSP:表示标签体可以包含JSP代码;
- scriptless:表示标签体可以包含EL表达式和JSP动作元素,但不能包含JSP的脚本元素;
- tagdependent:表示标签体交由标签本身去解析处理,即在标签体中所写的任何代码都会原封不动地传给标签处理器;
- dynamic-attributes:指定该标签是否支持动态属性,只有当定义动态属性标签时才需要指定该值,关于动态属性标签将在后面介绍。
这里我们只需要指定body-content>
元素值为empty
即可。
在jsp页面中使用自定义标签
接下来我们就可以在jsp页面中使用自定义标签了:
<!-- mytag.jsp --><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><%@ page language="java" contentType="text/html; charset=GBK" pageEncoding="UTF-8"%><%@ taglib uri="http://zzw.com/mytaglib" prefix="mytag"%><meta http-equiv="Content-Type" content="text/html; charset=GBK"><title>自定义标签</title></head><body> 当前时间<mytag:datetime/><hr></body></html>
可以看到,要使用自定义标签,需要先导入自定义标签库,这可以借助jsp编译指令taglib
完成。在taglib
中需要指定自定义标签库的URI和标签库前缀,URI即在TLD文件中的taglib
元素的子元素uri
,前缀指定在此标签库中定义的所有标签的前缀。
使用自定义标签的语法格式为:
<prefix:tagname attribute="expression" ...> <tag-body></prefix:tagname>
由于datetime
标签没有属性,也不需要标签体,我们可以简单写成<mytag:datetime/>
,前缀mytag
表示此标签属于URI为"http://zzw.com/mytaglib"
的标签库。
运行效果如下:
看,我们只在jsp页面中使用了一个简单的标签,就可以显示出当前时间,是不是要比jsp脚本方便多了。看到这,相信你也基本了解了自定义标签的开发,不过这只是最简单的标签,下面我们将介绍自定义标签的更多内容。
带属性的标签
上面我们介绍的简单标签没有任何属性,但通常情况下大多数标签都有一个或多个属性,现在我们就介绍带属性标签的开发。
基本步骤和之前一样,我们先编写标签处理类:
// EmailTag.javapublic class EmailTag extends SimpleTagSupport { private String from; private String to; private Date date; private String message; private static final SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public String getFrom() { return from; } public String getTo() { return to; } public Date getDate() { return date; } public String getMessage() { return message; } public void setFrom(String f) { from=f; } public void setTo(String t) { to=t; } public void setDate(Date d) { date=d; } public void setMessage(String m) { message=m; } public void doTag() throws JspException, IOException { super.doTag(); JspWriter out=getJspContext().getOut(); out.write("<div style=\"padding:10px;border:1px solid;border-color:#ff7f00;color:#ff7f00\">"); out.write("<b>FROM</b>: "+from+"<br>"); out.write("<b>TO</b>  : "+to+"<br>"); out.write("<b>DATE</b>: "+sdf.format(date)+"<br>"); out.write("<p>"+message+"</p>"); out.write("</div>"); }}
EmailTag类和DatetimeTag类的不同之处在于,它多了几个“属性”,而且这些“属性”都有对应的get和set方法。实际上jsp页面正是通过get/set方法来获取/设置标签的属性的。
我们在mytaglib.tld
文件中添加这个新标签:
<!-- mytaglib.tld --> <tag> <name>email</name> <tag-class>com.zzw.EmailTag</tag-class> <body-content>empty</body-content> <attribute> <name>from</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.lang.String</type> </attribute> <attribute> <name>to</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.lang.String</type> </attribute> <attribute> <name>date</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.util.Date</type> </attribute> <attribute> <name>message</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.lang.String</type> </attribute> </tag>
可以看到,这个新的tag
元素多了几个attribute
子元素,我们正是通过attribute
元素来设置标签的属性的。attribute
元素又有如下几个子元素:
- name:指定属性名;
- required:指定此属性是否是必要的;
- rtexprvalue:全称是Run-time Expression Value
,它表示是否可以使用JSP表达式;
- type:指定此属性的类型。
现在我们就可以使用这个新标签了:
<!-- mytag.jsp -->发送邮件<mytag:email date="<%=new Date()%>" message="hello, client" to="client" from="server"/>
注意,由于我们之前已经通过taglib
指令导入了标签库,因此才能直接使用此标签;否则需要先导入标签库。
运行一下,发现出现了一个异常:
大致是说jsp-version
在转换成double
类型时发生转换错误。检查我们的代码,发现只有在mytaglib.tld
文件的taglib
元素中出现了jsp-version
:
<jsp-version>jsp-version</jsp-version>
把jsp-version
修改为2.0
,再次运行时可以正常显示:
如果修改jsp-version
后还是不能正常运行,可以将%TOMCAT_HOME%\webapps\examples\WEB-INF\jsp2
目录下的任意TLD文件中的taglib
元素拷贝到自己的TLD文件中,如果使用eclipse则会报TLD文件有语法错误,不过不用管它,照样可以成功运行。
带标签体的标签
有些标签除了具有属性外,还有标签体,我们也可以开发具有标签体的标签。
我们定义一个迭代器标签,它会依次输出容器中的元素。还是先定义标签处理类:
// IteratorTag.javapublic class IteratorTag extends SimpleTagSupport { private String collection; private String item; public String getCollection() { return collection; } public String getItem() { return item; } public void setCollection(String c) { collection=c; } public void setItem(String i) { item=i; } public void doTag() throws JspException, IOException { super.doTag(); // 从当前jsp页面上下文获取属性 Collection<?> items=(Collection<?>) getJspContext().getAttribute(collection); for(Object i : items) { // 给当前jsp页面上下文设置属性 getJspContext().setAttribute(item, i); // 输出标签体 getJspBody().invoke(null); } }}
在doTag
方法中有一句getIspBody().invoke(null);
,它负责输出标签体。通常标签体是一系列EL表达式或jsp动作指令,我们不打算在这里详细介绍EL表达式,有关EL表达式的内容可以参考这两篇文章:《EL表达式(详解)》和《EL表达式简介》。
然后在TLD文件中定义标签:
<!-- mytaglib.tld --> <tag> <name>iterator</name> <tag-class>com.zzw.IteratorTag</tag-class> <body-content>scriptless</body-content> <attribute> <name>collection</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.lang.String</type> </attribute> <attribute> <name>item</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.lang.String</type> </attribute> </tag>
注意这里的body-content
元素值为scriptless
,表示标签体可以包含EL表达式和JSP动作元素,但不能包含JSP的脚本元素。
最后在jsp页面中使用此标签:
<!-- mytag.jsp --><% ArrayList<String> list=new ArrayList<String>(); for(int i=0; i<10; i++) list.add("item "+i); pageContext.setAttribute("list", list);%> 迭代器<br><mytag:iterator item="item" collection="list"> ${pageScope.item}<br> </mytag:iterator>
我们先用jsp脚本将容器对象添加到page作用域中,IteratorTag类才能取得此容器对象,然后在doTag
方法中又将此容器对象中的元素添加到page作用域中,然后标签体${pageScope.item}
(这是一个EL表达式)负责取得元素对象引用,最后getJspBody().invoke(null);
语句输出此元素对象。
结果如下:
说到这,我们已经介绍了简单标签、带属性标签和带标签体标签的开发,下面我们再介绍几种特殊的自定义标签。
属性为页面片段的标签
之前我们已经介绍了带属性标签的开发,其实标签的属性也可以是一个页面片段。这种标签的处理类中必须有一个类型为javax.servlet.jsp.tagext.JspFragment
的属性,我们将一开始的datetime标签作为片段来进行带属性标签的开发。
定义标签处理类:
// FragmentTag.javapublic class FragmentTag extends SimpleTagSupport { private JspFragment fragment; public JspFragment getFragment() { return fragment; } public void setFragment(JspFragment f) { fragment=f; } public void doTag() throws JspException, IOException { super.doTag(); JspWriter out=getJspContext().getOut(); out.println("<div style=\"padding:10px;border:1px solid;border-color:#000000\">"); fragment.invoke(null); out.println("</div>"); }}
FragmentTag类也遵循带属性标签处理类的编写规范,只不过它的“属性”类型为JspFragment
。在doTag
方法中fragment.invoke(null);
语句负责输出包含的页面片段。
然后在TLD文件中定义此标签:
<!-- mytaglib.tld --> <tag> <name>fragment</name> <tag-class>com.zzw.FragmentTag</tag-class> <body-content>empty</body-content> <attribute> <name>fragment</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <fragment>true</fragment> </attribute> </tag>
注意到,attribute
元素中多了一条子元素fragment
,如果使用eclipse则会报错,我们依然不用管它。如果不设置fragment
元素或设置fragment
元素为false
,则运行时会发生异常:
我们在jsp页面中使用此标签:
<!-- mytag.jsp --> 页面片段<mytag:fragment> <jsp:attribute name="fragment"> <mytag:datetime/> </jsp:attribute> </mytag:fragment>
我们在标签体中使用jsp:attribute
动作指定了fragment标签的属性,注意在TLD文件中fragment标签的body-content
元素值为empty
。
运行结果如下:
动态属性标签
有时,我们不能确定标签有多少个属性或者我们不知道属性的名字,这种情况下可以使用动态属性标签。动态属性标签的处理类必须实现javax.servlet.jsp.tagext.DynamicAttributes
接口,并重写setDynamicAttribute
方法。
我们定义一个简单的动态属性标签,并在jsp页面中显示此标签的属性。
标签处理类:
// DynamicTag.javapublic class DynamicTag extends SimpleTagSupport implements DynamicAttributes { private HashMap<String, Object> attrs=new HashMap<String, Object>(); public void doTag() throws JspException, IOException { super.doTag(); if(attrs!=null && !attrs.isEmpty()) { JspWriter out=getJspContext().getOut(); out.println("<ol>"); Set<String> keys=attrs.keySet(); Iterator<String> iter=keys.iterator(); while(iter.hasNext()) { String key=iter.next(); out.println("<li>"+key+"="+attrs.get(key)+"</li>"); } out.println("</ol>"); } } @Override public void setDynamicAttribute(String uri, String localName, Object value) throws JspException { attrs.put(localName, value); }}
可以看到,我们通过setDynamicAttribute
方法来动态添加标签的属性。
在TLD文件中定义此标签:
<!-- mytaglib.tld --> <tag> <name>dynamic</name> <tag-class>com.zzw.DynamicTag</tag-class> <body-content>empty</body-content> <dynamic-attributes>true</dynamic-attributes> </tag>
此标签多了一个dynamic-attributes
元素,它指定此标签是否是动态属性标签。同样的,在eclipse中设置此元素会报错,但我们同样忽略它。如果不设置此元素或设置此元素值为false
,则在运行时会发生异常:
在jsp页面中使用此标签:
<!-- mytag.jsp -->动态属性<mytag:dynamic user="zzw" password="******" action="signin"/>
运行结果如下:
Tag File
Tag File是自定义标签的简化用法,使用Tag File无需定义标签处理类和TLD文件,但仍然可以在jsp页面中使用自定义标签。下面我们创建一个Tag File,实现对图的迭代。
创建Tag File
Tag File的命名必须以.tag
结尾,文件名就是此标签的标签名。该文件需要放在web应用的某个目录下,通常放在WEB-INF/tags
目录中,这个路径相当于标签库的URI,在jsp页面的taglib
指令中用tagdir
属性指定。
在eclipse中,先在WEB-INF
目录下创建tags
目录,再右击tags
目录选择New
-Other
-Web
-JSP Tag
,输入文件名(我们输入iterator.tag),在出现的模板选择框中选择New Tag File
,Finish
。
<!-- iterator.tag --><%@ tag language='java' pageEncoding='GBK' body-content="scriptless"%><%@ tag import="java.util.*" %><%@ attribute name="bgcolor" required="true"%><%@ attribute name="cellcolor" required="true"%><%@ attribute name="collection" required="true" type="java.util.HashMap"%><%@ variable name-given="end" variable-class="java.util.Date" scope="AT_END"%><% Set<?> keys=collection.keySet(); Iterator<?> iter=keys.iterator();%>开始迭代 <%=new Date()%><br><jsp:doBody/><table bgcolor="${bgcolor}" border="1"><% while(iter.hasNext()) { String key=(String) iter.next();%> <tr bgcolor="${cellcolor}"> <td><%=key%></td> <td><%=collection.get(key)%></td> </tr><%}%></table><% jspContext.setAttribute("end", new Date());%>
Tag File的语法和jsp很相似,它具有以下编译指令:
- taglib:作用类似于jsp页面中的taglib指令,用于导入其他标签库;
- include:作用类似于jsp页面中的include指令,用于包含其他jsp页面或静态页面;
- tag:作用类似于jsp页面中的page指令,用于设置语言、编码等;
- attribute:用于设置标签属性,对应于TLD文件中tag
元素的attribute
子元素;
- variable:用于设置标签变量,这些变量将传给jsp页面使用。
在Tag File中也可以使用jsp动作指令和编写静态文本,我们使用了jsp:doBody
动作指令来输出标签体。
在Tag File中还可以定义变量供jsp页面使用,此功能可借助variable
指令完成。variable
指令有如下属性:
- name-given:指定变量名;
- variable-class:指定变量类型,默认是java.lang.String
;
- scope:指定变量的作用域,有如下3个值:
- AT_BEGIN
:在标签开始使用后的任何地方都可以使用此变量;
- NESTED
:只能在标签体中使用此变量;
- AT_END
:只能在标签结束后使用此变量。
下面在jsp页面中使用此tag:
<!-- mytag.jsp --><%@ taglib tagdir="/WEB-INF/tags" prefix="tags"%><% HashMap<String, Object> map=new HashMap<String, Object>(); map.put("name", "张三"); map.put("old", 22); map.put("sex", "male"); map.put("date", new Date());%> TAG迭代器<br> <tags:iterator bgcolor="#7f00ff" cellcolor="#ffff00" collection="<%=map%>"> 键值对为: </tags:iterator> 结束迭代 <%=end%>
在mytag.jsp
文件中,使用taglib
指令导入了Tag File,tagdir
属性指定了Tag File的路径,prefix
和导入自定义标签库时具有相同的意义。另外在使用tag时,prefix后跟着的是Tag File的名字。
运行效果如下:
Tag File的实质
就如同jsp的实质是Servlet一样,Tag File的实质就是标签处理类,它最后会被处理成一个xxx_tag.java
文件,并被编译成一个xxx_tag.class
文件。
%ECLIPSE_WORKSPACE%\.metadata\.plugins\org.eclipse.wst.server.core\tmpX\work\Catalina\localhost\<PROJECT-NAME>\org\apache\jsp\tag\web
目录下可以找到若干xxx_tag.java
和相应的CLASS文件。查看上述Tag File对应的iterator_tag.java
文件:
// iterator_tag.javapublic final class iterator_tag extends javax.servlet.jsp.tagext.SimpleTagSupport implements org.apache.jasper.runtime.JspSourceDependent, org.apache.jasper.runtime.JspSourceImports { // jsp页面上下文 private javax.servlet.jsp.JspContext jspContext; // 在Tag File中定义的属性 private java.lang.String bgcolor; private java.lang.String cellcolor; private java.util.HashMap collection; // bgcolor、cellcolor和collection的get/set方法类似 public java.lang.String getBgcolor() { return this.bgcolor; } public void setBgcolor(java.lang.String bgcolor) { this.bgcolor = bgcolor; jspContext.setAttribute("bgcolor", bgcolor); } // 在Tag File中的jsp脚本都会在doTag()方法中被转换为静态文本输出 public void doTag() throws javax.servlet.jsp.JspException, java.io.IOException { javax.servlet.jsp.PageContext _jspx_page_context = (javax.servlet.jsp.PageContext)jspContext; javax.servlet.http.HttpServletRequest request = (javax.servlet.http.HttpServletRequest) _jspx_page_context.getRequest(); javax.servlet.http.HttpServletResponse response = (javax.servlet.http.HttpServletResponse) _jspx_page_context.getResponse(); javax.servlet.http.HttpSession session = _jspx_page_context.getSession(); javax.servlet.ServletContext application = _jspx_page_context.getServletContext(); javax.servlet.ServletConfig config = _jspx_page_context.getServletConfig(); javax.servlet.jsp.JspWriter out = jspContext.getOut(); // ... try { // 和带标签体标签一样,都是在doTag()方法中调用getJspBody().invoke(null); _jspx_sout = null; if (getJspBody() != null) getJspBody().invoke(_jspx_sout); // ... } catch( java.lang.Throwable t ) { // ... } finally { // ... } }}
我们在iterator_tag类中找到了三个数据成员bgcolor
、cellcolor
和collection
,它们都有get/set方法。实际上这三个数据成员就是我们在Tag File中定义的属性,可见我们在Tag File中定义的属性都会成为相应标签处理类的数据成员。
我们还发现,和jsp转换成Servlet一样,在doTag
方法中也定义了一系列内置对象,它们和tag类的数据成员jspContext
都能在Tag File中直接使用:
关于这几个对象的使用可以参考我的另一篇文章:《JavaEE jsp的内置对象及其在Servlet中的表示》。
源代码
上述所有代码已经上传到github:
https://github.com/jzyhywxz/WebDemo.git
- javaEE jsp自定义标签
- [javaEE]JSP自定义标签
- JavaEE jsp自定义标签
- javaee学习之路(十六)JSP自定义标签
- JavaEE——JSP标签
- JavaEE自定义tag标签详解
- 疯狂javaee jsp自定义带属性标签访问数据库java.lang.NullPointerException
- JavaEE自定义tag标签详细解释
- [个人博客搬运]JavaEE自定义标签技术
- JSP----自定义标签---简单标签
- jsp自定义标签-----嵌套标签
- JSP标签编程----自定义标签
- JSP 自定义标签:简单标签
- JSP标签-JSTL-自定义标签
- JSP自定义标签-Select标签
- jsp 自定义标签---标签文件
- JSP自定义标签
- JSP自定义标签学习心得
- AOP注解异常: Pointcut is not well-formed: expecting '(' at character position 0 pointCut ^ 1
- Spring Session+Spring Data Redis 解决分布式系统架构中 Session 共享问题
- 构造图像,线段,矩形,椭圆,圆角矩形
- 浅析Android动画(一) View动画高级实例探究
- (2)Hadoop重新格式化HDFS的方法
- JavaEE jsp自定义标签
- CSS3的content属性详解
- Python发送http请求(json格式)
- 对View的一些理解和认识
- (昨天的)codevs天梯 石子归并
- POj 2406 Power Strings
- 进阶之路:MVP+Retrofit+RxJava组合使用
- Redis集群部署文档(centos6系统)
- Redis (五 php与redis的结合使用)