JavaWeb学习篇之----自定义标签 JSTL标签库详解

本文介绍了JavaWeb中自定义标签的使用,包括编写实现Tag接口的Java类、标签库描述符(tld)文件的创建,以及在JSP页面中的导入和使用。同时,讲解了自定义标签的执行原理,包括doStartTag和doEndTag等方法。此外,文章还详细探讨了JSTL的核心标签库,如c:out、c:set、c:remove等标签的使用方法及其功能。最后,讨论了如何基于自定义标签开发一套类似JSTL的标签库,并给出了if、choose/when/otherwise和forEach标签的实现示例。
摘要由CSDN通过智能技术生成
               

今天来看一下自定义标签的内容,自定义标签是JavaWeb的一部分非常重要的核心功能,我们之前就说过,JSP规范说的很清楚,就是Jsp页面中禁止编写一行Java代码,就是最好不要有Java脚本片段,下面就来看一下自定义标签的简介:

自定义标签主要用于移除Jsp页面中的java代码。
移除jsp页面中的java代码,只需要完成两个步骤:
编写一个实现Tag接口的Java类,并覆盖doStartTag方法,把jsp页面中的java代码写到doStartTag方法中。
编写标签库描述符(tld)文件,在tld文件中对自定义标签进行描述。
完成以上操作,即可在JSP页面中导入和使用自定义标签。
快速入门:使用自定义标签输出客户机IP
查看tag接口api文档,分析自定义标签的执行流程。


下面来看一下一个简单的Demo使用自定义标签打印客户机的IP地址

首先我们自定义标签类:ViewIpTag

package com.weijia.traditionaltag;import java.io.IOException;import javax.servlet.http.HttpServletRequest;import javax.servlet.jsp.JspException;import javax.servlet.jsp.JspWriter;import javax.servlet.jsp.tagext.TagSupport;/** * 自定义标签,然后将这个标签映射到这个类:mytag:viewIP * 记得将自定义的标签绑定到一个url上面,这个url一般是公司的网址 *  */public class ViewIpTag extends TagSupportprivate static final long serialVersionUID = 1L@Override public int doStartTag() throws JspException {  //内置一个pageContext对象,我们之前说到pageContext对象,它里面是封装了9个隐式对象  HttpServletRequest request = (HttpServletRequest)this.pageContext.getRequest();  JspWriter out = this.pageContext.getOut();  String ip = request.getRemoteAddr();  try {   out.print(ip);  } catch (IOException e) {   throw new RuntimeException(e);  }  return super.doStartTag(); }}

自定义tld文件,mytag.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 web-jsptaglibrary_2_0.xsd"    version="2.0">      <description>JSTL 1.1 core library</description>  <display-name>JSTL core</display-name>  <tlib-version>1.1</tlib-version>  <short-name>weijia</short-name>  <uri>http://www.weijia.cn/mytag</uri>  <!-- 显示IP地址 -->  <tag>    <description>        Catches any Throwable that occurs in its body and optionally        exposes it.    </description>    <name>viewIP</name>    <tag-class>com.weijia.traditionaltag.ViewIpTag</tag-class>    <body-content>empty</body-content>  </tag></taglib>
这里我们将就自定义的标签类就注册好了,下面解释一下这些字段的含义:

首先看一下:

<short-name>这个标签是指定我们定义标签的简称,这个作用不大

<uri>这个标签是给这个标签文件指定一个访问路径,这个路径我们在Jsp页面中引入这个标签的时候需要用到

<tag-class>这个标签就是指定我们自定义的标签类的全称

<body-content>这个标签表明自定义标签是否有标签体内容(empty:没有,JSP:有)


我们注册之后标签类了,下面就在Jsp页面中进行使用了,这时候就要用到我们之前说到的Jsp的指令中的taglib了,格式如下:

<%@ taglib uri="http://www.weijia.cn/mytag" prefix="mytag" %>
这个就将我们定义的标签引入到Jsp页面中了,其中我们uri属性的值就是我们在标签定义文件mytag.tld中指定的那个uri那个标签值,当然这里的uri也可以直接指定mytag.tld文件的路径即: /WEB-INF/mytag.tld 也是可以的,其实我们查看翻译之后的Jsp代码可以看到,不管用那种方式,他其实加载的时候都是去找真是路径中文件:



其中prefix属性的值是标签前缀名,这个名称就是我们在Jsp页面中使用的标签前缀,这个值一般和tld文件的文件名是保持一致的


下面就是在Jsp中使用标签:

客户机的IP地址是:<mytag:viewIP/>
这样就是打印了客户机的IP地址,这里我们在Jsp页面中就没有Java代码了


上面我们介绍了一个简单的例子,下面我们来详细看一下这个自定义标签的执行原理:

JSP引擎将遇到自定义标签时,首先创建标签处理器类的实例对象,然后按照JSP规范定义的通信规则依次调用它的方法。
1、public void setPageContext(PageContext pc), JSP引擎实例化标签处理器后,将调用setPageContext方法将JSP页面的pageContext对象传递给标签处理器,标签处理器以后可以通过这个pageContext对象与JSP页面进行通信。
2、public void setParent(Tag t),setPageContext方法执行完后,WEB容器接着调用的setParent方法将当前标签的父标签传递给当前标签处理器,如果当前标签没有父标签,则传递给setParent方法的参数值为null。
3、public int doStartTag(),调用了setPageContext方法和setParent方法之后,WEB容器执行到自定义标签的开始标记时,就会调用标签处理器的doStartTag方法。
4、public int doEndTag(),WEB容器执行完自定义标签的标签体后,就会接着去执行自定义标签的结束标记,此时,WEB容器会去调用标签处理器的doEndTag方法。
5、public void release(),通常WEB容器执行完自定义标签后,标签处理器会驻留在内存中,为其它请求服务器,直至停止web应用时,web容器才会调用release方法。

我可以查看我们上面的例子翻译后的Jsp代码:

 out.write("<body>  \r\n"); out.write("\t<!-- 显示客户机的IP地址 -->\r\n"); out.write("\t客户机的IP地址是:"); if (_jspx_meth_mytag_005fviewIP_005f0(_jspx_page_context))     return; out.write("\r\n"); out.write("\t\r\n");


再来看一下那个if中的方法的代码:

private boolean _jspx_meth_mytag_005fviewIP_005f0(PageContext _jspx_page_context)          throws Throwable {    PageContext pageContext = _jspx_page_context;    JspWriter out = _jspx_page_context.getOut();    //  mytag:viewIP    com.weijia.traditionaltag.ViewIpTag _jspx_th_mytag_005fviewIP_005f0 = (com.weijia.traditionaltag.ViewIpTag) _005fjspx_005ftagPoo    l_005fmytag_005fviewIP_005fnobody.get(com.weijia.traditionaltag.ViewIpTag.class);    _jspx_th_mytag_005fviewIP_005f0.setPageContext(_jspx_page_context);    _jspx_th_mytag_005fviewIP_005f0.setParent(null);    int _jspx_eval_mytag_005fviewIP_005f0 = _jspx_th_mytag_005fviewIP_005f0.doStartTag();    if (_jspx_th_mytag_005fviewIP_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {      _005fjspx_005ftagPool_005fmytag_005fviewIP_005fnobody.reuse(_jspx_th_mytag_005fviewIP_005f0);      return true;    }    _005fjspx_005ftagPool_005fmytag_005fviewIP_005fnobody.reuse(_jspx_th_mytag_005fviewIP_005f0);    return false;  }
我们可以看到,首先这个方法接收的是一个pageContext变量对象,这个和我们之前说的一样,自定义标签类中有一个pageContext变量对象就可以操作其他对象了,下面来看一下那个方法的代码,首先他会去加载那个标签类,同时注意到首先是执行setPageContext()方法的,将pageContext变量传递到标签类中,然后看setParent()方法传递的是null,因为我们打印IP的标签没有父标签的,接下来执行doStartTag()方法,然后再执行doEndTag()方法,这里我们看到是做个判断,如果doEndTag方法返回的值是Tag.SKIP_PAGE的话,就是说余下的jsp页面不执行了,所以返回一个true,那么我们看到上面的if判断代码中,如果这个方法返回true的话,直接return,下面的代码就不执行了。大体流程就是这样的。


下面我们用自定义标签来实现一些特定需求的功能:

1、不执行标签体内容

自定义标签类:

package com.weijia.traditionaltag;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.TagSupport;/** * 是否输出标签体内容 * @author weijiang204321 * */public class TagDemo1 extends TagSupport@Override public int doStartTag() throws JspException {  return TagSupport.EVAL_BODY_INCLUDE;//输出标签体内容  //return TagSupport.SKIP_BODY;//不输出标签体内容 }}

我们看到只要doStartTag方法返回TagSupport.EVAL_BODY_INCLUDE常量,就会执行标签体内容,如果返回的是TagSupport.SKIP_BODY常量,就不会执行标签体内容,代码很简单。


下面我们再来注册这个标签类:

 <!-- 是否显示标签体 -->  <tag>    <description>        Catches any Throwable that occurs in its body and optionally        exposes it.    </description>    <name>demo1</name>    <tag-class>com.weijia.traditionaltag.TagDemo1</tag-class>    <body-content>JSP</body-content>  </tag>

因为是有标签体内容的,所以<body-content>标签的值是JSP


在Jsp页面中使用:

<!-- 不执行标签体 --><simpletag:demo1> aaaa</simpletag:demo1>


2、控制JSP余下页面的内容不执行

自定义标签类:

package com.weijia.traditionaltag;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.TagSupport;/** * 控制整个JSP是否输出 * @author weijiang204321 * */public class TagDemo2 extends TagSupport@Override public int doStartTag() throws JspException {  return super.doStartTag(); } @Override public int doEndTag() throws JspException {  return TagSupport.EVAL_PAGE;  //return TagSupport.SKIP_PAGE;不执行余下的jsp内容 }}
当doEndTag方法返回的是TagSupport.EVAL_PAGE常量的话就执行jsp余下的内容,如果返回的是TagSupport.SKIP_PAGE常量的话就不执行jsp余下的内容


在tld文件中注册这个自定义标签类:

  <!-- 控制是否显示jsp页面 -->  <tag>    <description>        Catches any Throwable that occurs in its body and optionally        exposes it.    </description>    <name>demo2</name>    <tag-class>com.weijia.traditionaltag.TagDemo2</tag-class>    <body-content>empty</body-content>  </tag>

在JSP页面中使用:

<!-- 不执行余下的页面内容 --><simpletag:demo2/>
这样使用之后,在这个标签之后的内容就不会执行了,我们在上面分析源代码的时候已经解析过了。页面都不会含有余下的内容了,如果我们将这个标签放在页面的第一行,那么这个页面就是一片空白,我们在浏览器中查看页面的源代码,也是发现一片空白的,因为out对象没有进行print了


3、重复执行标签体内容

自定义标签体类:

package com.weijia.traditionaltag;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.TagSupport;/** * 控制标签体重复执行 * @author weijiang204321 * */public class TagDemo3 extends TagSupportprivate int count = 5;  @Override public int doStartTag() throws JspException {  return TagSupport.EVAL_BODY_INCLUDE; }  @Override public int doAfterBody() throws JspException {  count--;  if(count > 0){   return TagSupport.EVAL_BODY_AGAIN;//执行完之后接着执行doAfterBody()方法  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值