制作tld文件及应用详解
1、开个环境:myeclipse6.5+tomcat6.0.23
所需组件jree5.0
2、index.jsp
顶部添加:<%@ taglib uri="/cmszxm" prefix="cms" %>
<table width="800" border="0" align="center" cellpadding="0" cellspacing="0">
  <tr>
    <td align="center">测试信息</td>
  </tr>
<cms:module_list>
  <tr>
    <td align="center"><%=module_info.getModuleName() %></td>
  </tr>
</cms:module_list>
</table>
3、web.xml中指定你的tld文件
 <jsp-config>
  <taglib>
   <taglib-uri>/cmszxm</taglib-uri>
   <!-- 置自定义标签的uri(不一定存在,但是一定要唯一),为页面的部署做好准备 -->
   <taglib-location>/WEB-INF/tlds/cms.tld</taglib-location>
   <!--定位你的tld文件的相对路径 -->
  </taglib>
 </jsp-config>

4、写自定义Tag的tld文件
<?xml version="1.0" encoding="UTF-8" ?>
<taglib>
    <tlib-version>1.0</tlib-version> <!-- 你自定义标签的版本数 -->
    <jsp-version>2.0</jsp-version> <!-- 标签库依赖的JSP版本 -->
    <short-name>cmsTablib</short-name> <!-- 标签的简写 -->
    <uri></uri> <!-- 指定这个标签库的uri信息 -->
    <small-icon></small-icon> <!-- 被工具使用的小图标 -->
    <description>cms</description> <!-- 本标签的描述 -->

    <tag>

      <name>module_list</name> <!-- 标签名字 -->
      <tag-class>com.ModuleListTag</tag-class> <!-- 指定你的标签的类 -->
      <body-content>JSP</body-content> <!-- 标签主体的内容 -->
      <description>module_list</description> <!-- 标签描述 -->

      <variable>
        <name-given>module_info</name-given>
        <variable-class>com.ModuleVO</variable-class>
        <declare>true</declare>
        <scope>cccc</scope>
      </variable>

    </tag>

</taglib>

5、ModuleListTag.java
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import javax.servlet.ServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import tools.ConnSqlSer;
public class ModuleListTag extends BodyTagSupport {
 private static final long serialVersionUID = 1670679946944899701L;
 ServletRequest request = null;
 private Iterator it;
 ModuleVO vo = new ModuleVO();
 //遇到开始标签执行  
 public int doStartTag() throws JspException {
  request = pageContext.getRequest();
  Collection coll = (Collection) getModule_List();
  // 表示如果未找到指定集合,则不用处理标签体,直接调用doEndTag()方法。  
  if (coll == null || coll.isEmpty())
   return 0;
  it = coll.iterator();
  if (it.hasNext()) {
   vo = (ModuleVO) it.next();
   pageContext.setAttribute("module_info", vo);
   return 1;
  }
  return 0;
 }
 //遇到标签体执行
 public int doAfterBody() {
  if (it.hasNext()) {
   vo = ((ModuleVO) it.next());
   pageContext.setAttribute("module_info", vo);
   return 2;
  }
  return 0;
 }
 //遇到结束标签执行  
 public int doEndTag() throws JspException {
  System.out.println("doEndTag...");
  return EVAL_PAGE;
 }

 public ArrayList getModule_List() {
  Connection conn = ConnSqlSer.init();
  PreparedStatement pstm = null;
  ResultSet rs = null;
  ArrayList<ModuleVO> list = new ArrayList<ModuleVO>();
  String sql = "SELECT ModuleID,ModuleCode,ModuleName,ModuleLinkUrl FROM PermissionControl_Module ORDER BY ModuleCode";
  try {
   pstm = conn.prepareStatement(sql);
   rs = pstm.executeQuery();
   while (rs.next()) {
    ModuleVO module = new ModuleVO();
    module.setModuleID(rs.getString("ModuleID"));
    module.setModuleCode(rs.getString("ModuleCode"));
    module.setModuleName(rs.getString("ModuleName"));
    list.add(module);
   }
  } catch (SQLException e) {
   System.out.println("查询系统模块信息");
  } finally {
   ConnSqlSer.ConnClose(rs, pstm, conn);
  }
  return list;
 }

6、ModuleVO.java
import javax.servlet.jsp.tagext.TagSupport;
public class ModuleVO extends TagSupport {

 String ModuleID;  
 String ModuleCode;
 String ModuleName;

 public String getModuleID() {
  return ModuleID;
 }
 public void setModuleID(String moduleID) {
  ModuleID = moduleID;
 }
 public String getModuleCode() {
  return ModuleCode;
 }
 public void setModuleCode(String moduleCode) {
  ModuleCode = moduleCode;
 }
 public String getModuleName() {
  return ModuleName;
 }
 public void setModuleName(String moduleName) {
  ModuleName = moduleName;
 }



TLD自定义标签 

TLD配置说明

rtexprvalue的全称是 Run-time Expression Value, 它用于表示是否可以使用JSP表达式.

当在<attribute>标签里指定<rtexprvalue>true</rtexprvalue>时, 表示该自定义标签的某属性的值可以直接指定或者通过动态计算指定,  example as follow:

<sql:query var="result" >
    select * from mytable order by nameid
</sql:query>
<%request.setAttribute("nameid", "2"); %>
<myTag:cupSize cupSize="1" cupSizes="${result}"></myTag:cupSize>
<myTag:cupSize cupSize="${nameid}" cupSizes="${result}"></myTag:cupSize>


当在<attribute>标签里指定<rtexprvalue>false</rtexprvalue>时, 表示该自定义标签的某属性的值只能直接指定,  example as follow:
<myTag:cupSize cupSize="1" cupSizes="${result}"></myTag:cupSize>

...................................................................................................................................................................................................................

TLD文件配置详解(jsp自定义标签)

<tag>
<name>write</name>
<tagclass>org.apache.struts.taglib.bean.WriteTag</tagclass>
<bodycontent>empty</bodycontent>
<attribute>
<name>bundle</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>其中:
<name>write</name>:这个Tag的名字
<tagclass>org.apache.struts.taglib.bean.WriteTag</tagclass>:这个Tag是由那个类实现的(这个class可以在struts.jar包中找到)
<bodycontent>empty</bodycontent>:这个Tag可以直接结尾,不需要填写内容
   这里bodycontent有三个可选值
       jsp        标签体由其他jsp元素组成   
         如果其有jsp元素,那么标签会先解释,然后将元素的实际值传入。比如标签体里含有<%=attributeName%>这样子的jsp元素,此时标签会按attributeName的实际值是什么就传入什么。这个是最常用的一个。
       empty 标签体必须为空   
         在引用这个Tag的时候,可以<bean:write bundle="attributeName" />,而不必<bean:write bundle="attributeName" ></bean:write> 
       tagdependent 由标签解释,不带jsp转换 
<attribute> </attribute>这里标识的是这个Tag的一个参数
<name>bundle</name>这个参数的名字
<required>false</required>这个参数是否是必填相
      如果为true则必须写这个参数,否则会报错
<rtexprvalue>true</rtexprvalue>是说这个标签的值可以写入
       rtexprvalue:"RUN-TIME EXPRESSION VALUE",是否可以动态赋值,在jsp中如value="<%=attributeName%>"

...................................................................................................................................................................................................................

重载BodyTagSupport类的方法:
编写标签对应的实现类时,需要重载BodyTagSupport类几个方法:doStartTag(), setBodyContent(), doInitBody(), doAfterBody(), doEndTag();


他们执行顺序如下:
doStartTag()→doInitBody()→setBodyContent()→doAfterBody()→doEndTag()


doStartTag()方法可返回EVAL_BODY_INCLUDE或SKIP_BODY,
如果返回EVAL_BODY_INCLUDE则继续执行;
如果返回SKIP_BODY则接下来的doInitBody(),setBodyContent(), doAfterBody()三个方法不会被执行,
而直接执行doEndTag()方法。

setBodyContent()方法用于设置标签体内容,如果在此之前要作一些初始化工作,则在doInitBody()方法中完成。
标签体内容执行完后,会调用doAfterBody()方法,此方法可返回EVAL_BODY_TAG, SKIP_BODY, 
EVAL_PAGE或SKIP_PAGE。
如果返回EVAL_BODY_TAG则会再次设置标签体内容,直到返回SKIP_BODY;
如果返回EVAL_PAGE则标签体执行完后会继续执行JSP页面中接下来的部分;
如果返回SKIP_PAGE,则JSP页面的后续内容将不再执行。

标签中静态常量:

EVAL_BODY_INCLUDE:告诉服务器正文的内容,并把这些内容送入输出流
SKIP_BODY:告诉服务器不要处理正文内容
EVAL_PAGE:让服务器继续执行页面
SKIP_PAGE:让服务器不要处理剩余的页面
EVAL_BODY_AGAIN:让服务器继续处理正文内容,只有doAfterBody方法可以返回
EVAL_BODY_BUFFERED:BodyTag接口的字段,在doStartTag()返回
EVAL_BODY_INCLUDE、SKIP_BODY一般由doStartTag()返回,而EVAL_PAPGE、SKIP_PAGE由doEndTag()返回。