JSP自定义标签开发+TLD文件元素详解

标 签
<taglib>
<tlib-version>
<jsp-version>
<short-name>
<description>
<display-name>
<icon>
<uri> TLD文件的根元素 此标签库的版本 此标签库依赖的JSP版本。 当在JSP中使用标签时,此标签库首选或者建议的前缀。当然可以完全忽略这个建议 描述信息 图形工具可显示的一个简短名称 图形工具可显示的图标 指定使用该标签库中标签的URI 含 义

<validator>
<listener>
<function>
<tag> 关于该库的TagLibraryValidator信息 指定事件监听器类 定义一个在EL中使用的函数 定义一个标签

标 签
<description>
<display-name>
<icon>
<name>
<tag-class>
<tei-class>
<body-content>
<variable>
<example>
<attribute> 指定针对标签的信息 含 义 开发工具用于显示的一个简短名称 可被开发工具使用的图标 标签名称 Java标签处理器类的名称。注意这是处理器类的全限定名称,比如com.xx.tag.TableTag Javax.servlet.jsp.tagext.TagExtraInfo类的一个可选子类 此标签的主体部分的内容。其值可为scriptless\tagdependent\empty,默认为empty 定义脚本变量信息 使用该标签例子的可选的非正式描述 包含了此标签的一个属性的元数据

标 签
<description>
<name>
<required>
<rtexprvalue>
<type> 有关描述的文本信息 含 义 在jsp标签中使用的属性名称 指定属性是必须的还是可选的,默认为false,表示属性可选。如果该值为true,则jsp页面必须为该属性提供一个值。可能的值true、false、yes、no 指定属性是否能接受请求时表达式的值,默认为false,表示不能接受请求时表达式的值。可能值:true、false、yes、no 属性的数据类型,该元素只能用在当<rtexprvalue>设置为true时。它指定当使用请求时属性表达式(<%= %>)
返回类型。默认string


实例(继承SimpleTagSupport类方式):
编写一个DateTag标签,输出系统时间。<c1:date/>,输出的格式:2011年11月9日
step1: 写一个java类,继承SimpleTagSupport类
step2: override doTag()方法,在该方法里,实现相应的处理逻辑 package mytag;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class DateTag extends SimpleTagSupport{
@Override
public void doTag() throws JspException, IOException {
");
out.println(sdf.format(new Date())); PageContext ctx = (PageContext)getJspContext(); JspWriter out = ctx.getOut(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日


}
step3: 在.tld文件当中,描述该标签
<?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">
<tlib-version>1.1</tlib-version>
<short-name>c1</short-name>
<uri>http://www.tarena.com.cn/mytag1</uri>
<tag>
<name>date</name> <tag-class>mytag.DateTag</tag-class> <body-content>empty</body-content>
</tag>
</taglib>
step4: 使用taglib导入标签(jsp中)
<%@taglib prefix="c1" uri="http://www.tarena.com.cn/mytag1" %> <c1:date/>

1.在WEB-INF/tags/select.tag
<%@ tag body-content="empty" %>
<%@ tag dynamic-attributes="tagAttrs" %>
<%@ attribute name="optionsList" type="java.util.List" required="true" rtexprvalue="true"%>
<%@ attribute name="name" required="true"%>
<%@ attribute name="size" required="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>

<select name="${name }" size="${size }"
   <c:forEach var="attrEntry" items="${tagAttrs }">
     ${attrEntry.key}="${attrEntry.value }"
   </c:forEach>
>
   <c:forEach var="option" items="${optionsList}">
     <option value="${option }">${option}</option>
    </c:forEach>
 </select>
这里要注意tag文件只能放在如下位置:
1.WEB-INF/tags
2.WEB-INF/tags的子目录
3.WEB-INF/lib中jar包的META-INF/tags
4.WEB-INF/lib中jar包的META-INF/tags下的子目录
5.jar包中的tag文件需要tld
添加jstl.jar与standard.jar到WEB-INF/lib目录,还有一点就是上面标红的部分:不要使用http://java.sun.com/jstl/core这个url,否则会报foreach中的item属性有问题
2.在jsp中的使用
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.*" %>
<%@ taglib prefix="formTag" tagdir="/WEB-INF/tags" %>
<!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>
<%
 List<String> colorList = new ArrayList<String>();
    colorList.add("red");
    colorList.add("blue");
    colorList.add("white");
    request.setAttribute("colorList",colorList);
%>
<form action="" method="post">
 <formTag:select name="color" size="1" optionsList="${requestScope.colorList}"  style="width:140px"/>
</form>
</body>
</html>
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
 
jsp 自定义标签
 
jsp标签有两组api
JspTag ->SimpleTag ->SimpleTagSupport
JspTag ->Tag ->IterationTag->BodyTag
第二组是classic的,比较早的使用方式,doStartTag(),doEndTag()有N多返回值的那种,使用起来也确实不方便,今天学到了另一个使用第一组api方式的,让人大快人心,贴码
例子是一个Select的标签,支持动态属性设置
1.编写标签类
public class SelectTagHandler extends SimpleTagSupport implements DynamicAttributes {
 private static final String ATTR_TEMPLATE = "%s='%s'";
 private static final String OPTION_TEMPLATE = "<option value='%1$s'>%1$s</option>";
 private List optionsList;
 private String name;
 private String size;
 private Map<String, Object> tagAttrs = new HashMap<String, Object>();
 public void setName(String name) {
  this.name = name;
 }
 public void setSize(String size) {
  this.size = size;
 }
 public void setOptionsList(List optionsList) {
  this.optionsList = optionsList;
 }
 @Override
 public void doTag() throws JspException, IOException {
  PageContext pageContext = (PageContext) getJspContext();
  JspWriter out = pageContext.getOut();
  out.print("<select ");
  out.print(String.format(ATTR_TEMPLATE, "name", this.name));
  out.print(String.format(ATTR_TEMPLATE, "size", this.size));
  for (String attrName : tagAttrs.keySet()) {
   String attrDefinition = String.format(ATTR_TEMPLATE, attrName, tagAttrs.get(attrName));
   out.print(attrDefinition);
  }
  out.print(">");
  for (Object option : this.optionsList) {
   String optionTag = String.format(OPTION_TEMPLATE, option.toString());
   out.println(optionTag);
  }
  out.println("</select>");
 }
 @Override
 public void setDynamicAttribute(String uri, String name, Object value) throws JspException {
  tagAttrs.put(name, value);
 }
}
看到没,代码如此的简洁,动态属性配置也十分的方便,不用写N多个setter与getter方法.
2.编写tld文件WebRoot/tld/select.tld
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3g.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd"
version="2.0">
 <tlib-version>1.2</tlib-version>
 <jsp-version>1.2</jsp-version>
 <short-name>Forms Taglib</short-name>
 <uri>http://hi.baidu.com/tags/forms</uri>
 <description>
  An example tab library of replacements for the html form tags.
 </description>
 
 <tag>
  <name>select</name>
  <tag-class>com.baidu.hi.tag.SelectTagHandler</tag-class>
  <body-content>empty</body-content>
  
  <attribute>
   <name>optionsList</name>
   <required>true</required>
   <rtexprvalue>true</rtexprvalue>
   <type>java.util.List</type>
  </attribute>
  
  <attribute>
   <name>name</name>
   <required>true</required>
  </attribute>
  
  <attribute>
   <name>size</name>
   <required>true</required>
  </attribute>
  
  <dynamic-attributes>true</dynamic-attributes>
 </tag>
</taglib>

3.在jsp中的使用
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ page import="java.util.*" %>
<%@ taglib  prefix="formTags"  uri="/tld/select.tld"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@page import="java.util.ArrayList"%><html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
 List<String> colorList = new ArrayList<String>();
    colorList.add("red");
    colorList.add("blue");
    colorList.add("white");
    request.setAttribute("colorList",colorList);
%>
<form action="" method="post">
 <formTags:select name="color" size="1" optionsList="${requestScope.colorList}" style="width:140px"/>
</form>
</body>
</html>

需要做三件事:

一、编写标签处理器(java文件)

二、在标签库描述符文件中描述该标签 (TLD文件)

三、在jsp文件中引用该标签

具体步骤:

step1:编写一个扩展SimpleTagSupport的类


package foo;

import javax.servlet.jsp.tagext.SimpleTagSupport;
//mort import...

public class SimpleTagTest1 extands SimpleTagSupport{
      //这里放标记处理代码 
}

step2: 实现doTag()方法

public void doTag() throws JspException, IOException {
   
     //在response中打印 "This is xxxxxx"
     getJspContext().getOut().print("This is xxxxxx");

}
step3: 为标记创建一个TLD (taglib description, 标签库描述符)


<?xml version="1.0" encoding="ISO-8859-1" ?>

<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/jsee/web-jsptagLibrary_2_0.xsd"
    version="2.0">
    <tlib-version>1.2</tlib-version>
    <uri>simpleTags</uri>
    <tag>
        <name>simple1</name>
        <description>xxxxxxxx</description>
        <tag-class>foo.SimpleTagTest1</tag-class>
        <body-content>empty</body-content>
    </tag>
</taglib>

step4: 部署标记处理器和TLD

把TLD文件放在WEB-INF下,并把标记处理器放在WEB-INF/classes下,这里当然还要遵循包目录结构。换句话说,标记处理器类要与所有其他web应用Java类放在同一个位置上。

step5: 编写一个使用标记的JSP


<%@ taglib prefix="myTags" uri="simpleTags" %>
<html>
       <body>
                <myTags:simple1 %>
       </body>
</html>

uri中的名称要与TLD文件中的uri的名称一致。

至此,就建立了一个简单的自定义标签。

自定义标签还有几种常见的情况,分别为:

一、有体的标记 (如,<x:label>...</x:label>,"..."为标签的body)

二、标记体中使用了表达式 (如,<x:label> ${movie} </x:label>, "${movie}"为标签的体中出现的EL表达式)

三、循环执行标签体

四、含有属性的简单标签 (如,<x:label movie="${movie}" />)

以下,将分别介绍这几种情况:

情况一:编写的是有体(body)的标记,如:

<myTags:simple2>
    This is the body //这个就是标记的body
</myTags:simple2>
那么在这种情况下,为了执行body内的语句就需要加入这样一句话到doTag()方法中:

getJspBody().invoke(null);
invoke的意思是“处理标记的body,并把它打印到响应(response)中”。

null的意思是把内容输出到响应(response),而不是输出到什么别的书写器(Writer)上。

除此以外,TLD中的 “<body-content>empty</body-content>” 一栏也需要改动,要改为:

<body-content>scriptless</body-content>
之后会介绍四种不同的body-content的参数。

情况二、如果标记体使用了表达式,如:

<myTags:simple3>
    Message is : ${message}
</myTags:simple3>
那么这个表达式的赋值需要在标签处理器的doTag()中完成,如:

getJspContext().setAttribute("message","wear sunscreen");
getJspBody().invoke(null);//一定要记得写这句,否则标签体不会执行
情况三、若想要循环输出一个集合的数据,应该如何实现?如:

<table>
<myTags:simple3>
       <tr><td>${movie}</td></tr>
</myTags:simple3>
</table>
显然,希望通过循环输出不同的movie来形成 一个表格。那么标记处理器的doTag()方法应该改为:


String[] movies = {"Monsoon Wedding", "Saved!", ".. ..."};

public void doTag() throws JspException, IOException {
    for(int i = 0; i < movies.length; i++){
        getJspContext().setAttribute("movie",movies[i]);
        getJspBody().invoke(null);//每次invoke,都会执行一次标签body
    }
}

情况四、如果这个简单标记是有属性的,怎么办?如:


<table>
<myTags:simple5 movieList="${movieCollection}">
       <tr>
             <td>${movie.name}</td>
             <td>${movie.genre}</td>
        </tr>
</myTags:simple5>
</table>

由于标记中出现了属性,所以TLD中的描述必须反映这一情况,因此TLD应调整为:


<?xml version="1.0" encoding="ISO-8859-1" ?>

<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/jsee/web-jsptagLibrary_2_0.xsd"
    version="2.0">
    <tlib-version>1.2</tlib-version>
    <uri>simpleTags</uri>
    <tag>
        <name>simple1</name>
        <description>xxxxxxxx</description>
        <tag-class>foo.SimpleTagTest1</tag-class>
        <body-content>empty</body-content>
        <attribute>
            <name>movieList</name>
            <required>true</required><!-- 说明movieList属性是必需的 -->
            <rtexprvalue>true</rtexprvalue><!-- 说明movieList属性可以是一个运行时表达式(不用非得是一个常量String) -->
     </attribute>
    </tag>
</taglib>

另外,在标记处理器类中,也要对这一属性有相应的体现:


public class SimpleTagTest5 extends SimpleTagSupport{
  
    private List movieList;

    public void setMovieList(List movieList){
        this.movieList = movieList;
    }

    public void doTag() ....
}

 

补充:

<body-content></body-content>中可以写入的参数有四种:

① empty

即标记体为空

② scriptless

这个标记不能有脚本元素,但可以有模板文本和EL, 还可以是定制和标准动作

③ tagdependent

标记体要看做是纯文本,所以不会计算EL,也不会出发标记/动作

④ JSP

能放在JSP中的东西都能放在这个标记体中

猜你喜欢

转载自zhyp29.iteye.com/blog/2293898