jsp的标签技术:在jsp页面中最好不要出现java代码,这时我们可以使用标签技术将java代码替换成标签来表示。JSP的标签技术主要有下面四种:

  1. jsp标签。
  2. EL表达式。
  3. JSTL标签库。
  4. 自定义标签技术。

一、jsp标签

sun原生提供的标签,可以直接在jsp页面中使用。这种标签技术在实际使用中用的不是很多。它有很多标签,下面介绍其中的几种标签:

1、标签

标签用于把另外一个资源的输出内容插入进当前JSP页面的输出内容之中,这种在JSP页面执行时的引入方式称之为动态引入

语法:

<jsp:include page="relativeURL | <%=expression%>" flush="true|false" />

page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来获得。
flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面的已输出的内容刷新到客户端。

与include指令的比较:

标签是动态引入, 标签涉及到的2个JSP页面会被翻译成2个servlet,这2个servlet的内容在执行时进行合并。 而include指令是静态引入,涉及到的2个JSP页面会被翻译成一个servlet,其内容是在源文件级别进行合并。不管是标签,还是include指令,它们都会把两个JSP页面内容合并输出,所以这两个页面不要出现重复的HTML全局架构标签,否则输出给客户端的内容将会是一个格式混乱的HTML文档。

2、标签

标签用于把请求转发给另外一个资源。

语法:

<jsp:forward page="relativeURL | <%=expression%>" />

page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得。

3、标签

当使用和标签引入或将请求转发给其它资源时,可以使用标签向这个资源传递参数。

语法1:

<jsp:include page="relativeURL | <%=expression%>">
        <jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
    </jsp:include>

语法2:

<jsp:forward page="relativeURL | <%=expression%>">
        <jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
    </jsp:include>

标签的name属性用于指定参数名,value属性用于指定参数值。在和标签中可以使用多个标签来传递多个参数。

二、EL表达式

EL 全名为Expression Language。EL表达式最初出现的目的是为了取代jsp页面中的jsp脚本表达式,但是随着el的发展el的功能已经不限于此了。

EL表达式是JSP 2.0(JavaEE1.4)规范中的一门技术 。因此,若想正确解析EL表达式,需使用支持Servlet2.4/JSP2.0技术的WEB服务器。

注意:如果有些Tomcat服务器不能使用EL表达式,可以采取的方法是:

(1)升级成tomcat6

(2)在JSP中加入<%@ page isELIgnored=”false” %>

EL表达式主要有下面四种功能:获取数据、执行运算、获取常用开发对象和调用java方法。

1、获取数据

使用中括号的地方通常都可以使用点号替代,有两种情况除外:中括号中是数字或者中括号中包含特殊字符(-.)的情况。

注意:在中括号中如果不用双引号引起来则是变量,先找变量的值再拿变量的值使用。如果用双引号则是常量,直接使用常量的值。它只能获取数据,不要试图通过EL表达式来设置数据。

(1) 获取常量

字符串/数字/布尔类型,直接写在el表达式中,el直接进行输出。

(2) 获取域中的变量

如果el中写的是一个变量的名,则el会调用pageContext的findAttribute方法。在四大作用域中以给定的名字找对应的属性值,找到后进行输出,如果四个域中都找不到,什么都不输出。

(3) 获取数组中的数据

(4) 获取集合中的数据

(5) 获取Map中的数据

(6) 获取javabean的属性

示例如下:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
        <%@page import="com.itheima.domain.Person"%>
        <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
        <html>
          <head>
          </head>
          <body>
            <h1>获取javabean的属性</h1><hr>
            <%
                Person p = new Person();
                p.setName("Lilei");
                p.setAge(17);
                pageContext.setAttribute("p",p);
             %>
             ${p.name }${p.age } ${p.name }
             <img src="${pageContext.request.contextPath }/1.jpg"/>

            <h1>获取Map中的数据</h1><hr>
            <%
                Map<String,String> map = new HashMap();
                map.put("name","张三");
                map.put("age","17");
                map.put("gender","男");
                map.put("addr","中国");
                pageContext.setAttribute("map",map);
                pageContext.setAttribute("name","age");
             %>
             ${map["name"] }${map["addr"] }
             ${map.gender }${map.age }

            <h1>获取集合中的数据</h1><hr>
            <%
                List<String> list = new ArrayList<String>();
                list.add("甄嬛");
                list.add("安陵容");
                list.add("华妃");
                pageContext.setAttribute("list",list);
             %>
            ${list[2] }

            <h1>获取数组数据</h1><hr>
            <%
                String [] names = {"容嬷嬷","紫薇","金锁","小燕子"};
                pageContext.setAttribute("names",names);
             %>
            ${names[2]}
            <h1>获取域中的变量数据</h1><hr>
            <%
                String name = "李四";
                pageContext.setAttribute("name",name);
            %>
            ${name }
            <h1>获取常量数据</h1><hr>
            ${"阿萨德发射点发" } ${199 } ${true }
          </body>
        </html>

2、执行运算

EL中支持的运算类型:算术运算、逻辑运算、比较运算、三元运算符、empty运算符。

算术运算:如果有非数字参与算数运算,el表达式会试图将非数字转换为数字后参与运算。

empty运算符:判断一个对象是否为null或字符串是否为空字符串或集合内容是否为空或域中是否没有任何属性。

示例:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
      </head>
      <body>
        <h1>empty 运算符 : </h1><hr>
        <%
            String str = "aaaa";
            pageContext.setAttribute("str",str);
            List list = new ArrayList();
            list.add("");
            pageContext.setAttribute("list",list);
         %>
         ${empty str }
         ${empty list}
         ${empty pageScope }


        <h1>三元运算</h1><hr>
        ${10>9? "yes" : "no" }     

        <h1>逻辑运算</h1><hr>
        && and 
        ||  or
        !   not

        ${not (3>2 and 1<2 or 10>3) }


        <h1>比较运算</h1><hr>
            > gt
            < lt
            >= ge
            <= le
            != ne
            ==eq
        ${1 eq 1 } ${3 ge 2 } ${5+3 lt 3 }
        <h1>算术运算</h1><hr>
        ${1+1 }
        ${1-2 }
        ${1+"2" }
      </body>
    </html>

3、获取常用开发对象

EL中内置了11个内置对象,这些对象EL内置的,不需要提前定义就可以直接在EL中使用。

pageContext -- 有了它可以很方便的获取jsp页面中的9大隐式对象

pageScope -- page域中属性组成的Map
requestScope -- request域中属性组成的Map
sessionScope -- session域中属性组成的Map
applicationScope --application域中属性组成的Map

param -- 所有请求参数组成的Map<String,String>
paramValues -- 所有请求参数组成的Map<String,String[]>

header -- 所有请求头组成的Map<String,String>
headerValues -- 所有请求头组成的Map<String,String[]>

cookie -- 所有cookie信息组成的Map<String,Cookie>

initParam -- 所有web应用的初始化参数组成Map

示例:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
      </head>
      <body>
      <%
        pageContext.setAttribute("name","wang");
        request.setAttribute("name","li");
       %>
        ${requestScope.name}

        ${param.name } ${paramValues.like[2] }${header["Accept-Language"] }
        ${cookie.JSESSIONID.name }${cookie.JSESSIONID.value }
        ${initParam.name2 }

      </body>
    </html>

4、调用java方法

EL表达式允许用户开发自定义EL函数,以在JSP页面中通过EL表达式调用Java类的方法。一般来说,EL自定义函数开发与应用包括以下三个步骤:

  1. 编写一个Java类的静态方法。
  2. 编写标签库描述符(tld)文件,在tld文件中描述自定义函数。
  3. 在JSP页面中导入和使用自定义函数。

编写完标签库描述文件后,需要将它放置到

三、JSTL标签库

JavaServer Pages Standard Tag Library是由JCP(Java Community Process)指定的标准,是提供给 Java Web 开发人员的一个标准通用的标签函数库,和 EL 配合来取代传统直接在页面上嵌入 Java 程序(Scripting)的做法,以提高程序可读性、维护性和方便性。

JSTL标签库主要包括五类:

  1. 核心标签库 (core) — c
  2. 国际化标签 fmt
  3. 数据库标签 sql
  4. XML标签 xml
  5. JSTL函数(EL函数) el

1、核心标签库

(1) <c:out>标签

标签用于输出一段文本内容到pageContext对象当前保存的“out”对象中。

示例:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
      </head>
      <body>
        <h1>HTML转义输出</h1><hr>
        <a href="#">xxx</a>
        <c:out value="<a href='#'>xxx</a>" ></c:out>
        ${fn:escapeXml('<a href="#">xxx</a>') }

        <h1>输出默认值</h1><hr>
        <%
            String addr = "西二旗";
            //pageContext.setAttribute("addr",addr);
         %>
        <c:out value="${addr}" default="北京"></c:out>
        ${addr == null?"北京" : addr }

        <h1>输出变量</h1><hr>
        <%
            String name = "无双";
            pageContext.setAttribute("name",name);
         %>
         <c:out value="${name}"></c:out>
         ${name }
        <h1>输出常量</h1><hr>
        <c:out value="阿斯蒂芬"></c:out>
        ${"啦啦啦啦" }
      </body>
    </html>

(2) <c:set>标签

标签用于把某一个对象存在指定的域范围内,或者设置Web域中的java.util.Map类型的属性对象或JavaBean类型的属性对象的属性。

示例:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%@page import="com.itheima.domain.Person"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
      </head>
      <body>
        <h1>修改域中的JavaBean的属性的值</h1><hr>
        <%
            Person p = new Person();
            pageContext.setAttribute("p",p);
         %>
         <c:set target="${p}" property="name" value="克林顿"></c:set>
         ${p.name }


        <h1>设置或修改域中的Map的值</h1><hr>
        <%
            Map map = new HashMap();
            pageContext.setAttribute("map",map);
         %>
        <c:set target="${map}" property="cellphone" value="10010"></c:set>     
        <c:set target="${map}" property="cellphone" value="10086"></c:set>     
        ${map.cellphone }

        <h1>设置或修改域中的属性值</h1><hr>
        <c:set var="name" value="韦小宝"></c:set>
        <c:set var="name" value="阿珂"></c:set>
        ${name }
      </body>
    </html>

(3) <c:remove>标签

标签用于删除各种Web域中的属性。

其语法格式如下:

<c:remove var="varName"     
            [scope="{page|request|session|application}"] />

示例:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
      </head>
      <body>
        <%
            pageContext.setAttribute("name","蓝精灵");
            request.setAttribute("name","小丸子");
            session.setAttribute("name","机器猫");
            application.setAttribute("name","蜡笔小新");
         %>
         <c:remove var="name"/>
        ${name }
      </body>
    </html>

(4) <c:catch>标签

标签用于捕获嵌套在标签体中的内容抛出的异常。

其语法格式如下:

<c:catch [var="varName"]>nested actions</c:catch>
var属性用于标识<c:catch>标签捕获的异常对象,它将保存在page这个Web域中。 

**示例:**

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page contentType="text/html;charset=gb2312" %>
    <c:catch var="myex“ >
        <%
            10/0;
        %>
    </c:catch>
    异常:<c:out value="${myex}" />  ${myex}<br />
    异常 myex.getMessage:<c:out value="${myex.message}" /><br />
    异常 myex.getCause:<c:out value="${myex.cause}" /><br />
    异常 myex.getStackTrace:<c:out value="${myex.stackTrace}" />

(5) <c:if>标签

标签可以构造简单的“if-then”结构的条件表达式,它没有实现else的功能,如果想要实现else只能重新写一遍判断。

示例:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
      </head>
      <body>
        <c:if test="${2>1}">
            确实是这样的....
        </c:if>
        <c:if test="${2<=1}">
            你确定吗?
        </c:if>
      </body>
    </html>

(6) <c:choose>标签

标签用于指定多个条件选择的组合边界,它必须与和标签一起使用。使用,和三个标签,可以构造类似 “if-else if-else” 的复杂条件判断结构。

示例:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page contentType="text/html;charset=gb2312" %>
    <c:set value="${param.count}" var="count“  /> pageContext(count,2)
    <c:choose>
        <c:when test="${count == 0}">
            对不起,没有符合您要求的记录。
        </c:when>
        <c:otherwise>
            符合您要求的记录共有${count}条.
        </c:otherwise>
    </c:choose>

(7) <c:forEach>标签

标签用于对一个集合对象中的元素进行循环迭代操作,或者按指定的次数重复迭代执行标签体中的内容。

示例:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
      </head>
      <body>
        <h1>实验:遍历10到100的偶数,如果数字所在的位置是3的倍数,显示成红色</h1><hr>
        <c:forEach begin="10" end="100" step="2" var="i" varStatus="stat">
            <c:if test="${stat.count % 3 == 0}">
                <font color="red">
                    ${i }
                </font>
            </c:if>
            <c:if test="${stat.count % 3 != 0}">
                <font color="blue">
                    ${i }
                </font>
            </c:if>
        </c:forEach>

        <h1>循环执行指定的内容若干次</h1><hr>
        <c:forEach begin="0" end="10" step="2" var="i" >
            ${i },
        </c:forEach>
        <h1>遍历Map中的数据</h1><hr>
        <%
            Map map = new LinkedHashMap();
            map.put("name","曹操");
            map.put("age","59");
            map.put("wife","小乔");
            map.put("gender","男");
            pageContext.setAttribute("map",map);
         %>
        <c:forEach items="${map}" var="entry" >
            ${entry.key }:${entry.value }<br>
        </c:forEach>

        <h1>遍历集合中的数据</h1><hr>
        <%
            List list = new ArrayList();
            list.add("美国");
            list.add("中国");
            list.add("俄罗斯");
            list.add("印度");
            list.add("巴西");
            pageContext.setAttribute("list",list);
         %>
         <c:forEach items="${list}" var="c">
         ${c }<br>
         </c:forEach>

        <h1>遍历数组中的数据</h1><hr>
        <%
            String []  city = {"北京","上海","广州","铁岭","葫芦岛"};
            pageContext.setAttribute("city",city);
         %>
         <c:forEach items="${city}" var="c">
            ${c }<br>
         </c:forEach>
      </body>
    </html>

(8) <c:forTokens>标签

用来浏览一字符串中所有的成员,其成员是由定义符号所分隔的。

示例:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
      </head>
      <body>
        <c:forTokens items="www.baidu.com" delims="." var="str">
            ${str }<br>
        </c:forTokens>
      </body>
    </html>

(9) <c:redirect>标签

标签用于实现请求重定向。

示例:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
      </head>
      <body>
        <c:redirect url="/index.jsp" context="${pageContext.request.contextPath}">
            <c:param name="name" value="zhang"></c:param>
        </c:redirect>
      </body>
    </html>

(10) <c:import>标签

示例:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
      </head>
      <body>
        from xxxxx....
        <c:import url="/index.jsp" var="p" scope="page"></c:import>
        xxxx
        yyyy
        ${p }
        zzzz
      </body>
    </html>

(11) <c:url>标签

标签用于在JSP页面中构造一个URL地址,其主要目的是实现URL重写。URL重写就是将会话标识号以参数形式附加在URL地址后面 。

示例:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
      </head>
      <body>
      <%
        String url = response.encodeURL(request.getContextPath()+"/index.jsp");
       %>
        <a href="<%= url %>">hhhh</a>

        <c:url value="/index.jsp" context="${pageContext.request.contextPath}" var="url" scope="page"></c:url>
        <a href="${url }">xxx</a>

      </body>
    </html>

(12) <c:param>标签

在JSP页面进行URL的相关操作时,经常要在URL地址后面附加一些参数。标签可以嵌套在、或标签内,为这些标签所使用的URL地址附加参数。
标签在为一个URL地址附加参数时,将自动对参数值进行URL编码,例如,如果传递的参数值为“中国”,则将其转换为“%d6%d0%b9%fa”后再附加到URL地址后面,这也就是使用标签的最大好处。

示例:

<c:param name="name" value="value" />

四、自定义标签技术

自定义标签技术分为传统标签和简单标签两种。

1、传统标签

(1)创建自定义标签的步骤

使用自定义标签移除jsp页面中的java代码,只需要完成以下两个步骤:

  1. 编写一个实现Tag接口的Java类(标签处理器类)。
  2. 编写标签库描述符(tld)文件,在tld文件中对标签处理器类描述成一个标签。
  3. 在JSP页面中引入tld文件,就可以在jsp页面中使用自定义标签了。

(2)Tag接口的执行流程

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方法。

doStartTag 和 doEndTag方法来分别处理发现开始标签和发现结束标签时的代码。在doStartTag可以通过返回值来控制标签体是否允许执行,在doEndTag方法里可以通过返回值控制标签之后的剩余页面是否允许执行。

传统标签的这种开发方式,需要我们分析发现开始标签和发现结束标签时都需要执行什么代码,还需要分析到底要返回什么样的标签体控制程序执行,相对来说相当的繁琐,因此有了下面的简单标签。

示例(利用传统标签显示IP地址):

import java.io.IOException;

    import javax.servlet.jsp.JspException;
    import javax.servlet.jsp.PageContext;
    import javax.servlet.jsp.tagext.Tag;

    public class ShowIpTag implements Tag {
        private PageContext pc = null;

        public int doEndTag() throws JspException {
            //EVAL_PAGE -- 结束标签之后的剩余页面需要去执行
            //SKIP_PAGE -- 结束标签之后的剩余页面不要去执行
            return 0;
        }

        public int doStartTag() throws JspException {
            try {
                String ip = pc.getRequest().getRemoteAddr();
                pc.getOut().write(ip);
            } catch (IOException e) {
                e.printStackTrace();
            }
            //Eval_Body_Include -- 开始标签之后的标签体需要执行
            //Skip_Body -- 开始标签之后的标签体不需要执行
            return 0;
        }

        public Tag getParent() {
            return null;
        }

        public void release() {

        }

        public void setPageContext(PageContext pc) {
            this.pc = pc;
        }

        public void setParent(Tag t) {

        }

    }

(3)自定义标签应该具有的功能

  1. 控制jsp页面某一部分内容是否执行。
  2. 控制整个jsp页面是否执行。
  3. 控制jsp页面内容重复执行。
  4. 修改jsp页面内容输出。 HTML转义
例一:控制标签体内容是否执行
        doStartTag
        EVAL_BODY_INCLUDE  执行标签内容
        SKIP_BODY  跳过标签内容

        Tld配置
         <tag>
          <name>demo1</name>
          <tag-class>mytag.MyTag1</tag-class>
          <body-content>JSP</body-content>
         </tag>
        例二:控制标签后的jsp页面是否执行
        doEndTag
        EVAL_PAGE  执行标签后的页面内容
        SKIP_PAGE  跳过标签后的页面内容

        Tld配置
         <tag>
          <name>demo2</name>
          <tag-class>mytag.MyTag2</tag-class>
          <body-content>empty</body-content>
         </tag>

        例三:控制jsp页面内容重复执行
        doStartTag
        EVAL_BODY_INCLUDE  执行标签内容
        doAfterBody
        EVAL_BODY_AGAIN  重复执行标签内容
        SKIP_BODY  跳过标签内容

        doAfterBody代码
        times--;
        if (times > 0) {
            return EVAL_BODY_AGAIN;
        } else {
            return SKIP_BODY;
        }

        例四:修改标签体内容输出
        将标签体内容大写输出
        MyTag4 extends BodyTagSupport
        doStartTag
        EVAL_BODY_BUFFERED
        doEndTag
        String content = getBodyContent().getString();
        pageContext.getOut().write(…);

(4)添加标签属性

自定义标签可以定义一个或多个属性,这样,在JSP页面中应用自定义标签时就可以设置这些属性的值,通过这些属性为标签处理器传递参数信息,从而提高标签的灵活性和复用性。

要想让一个自定义标签具有属性,通常需要完成两个任务:

  1. 在标签处理器中编写每个属性对应的setter方法。
  2. 在TLD文件中描术标签的属性。

为自定义标签定义属性时,每个属性都必须按照JavaBean的属性命名方式,在标签处理器中定义属性名对应的setter方法,用来接收JSP页面调用自定义标签时传递进来的属性值。 例如属性url,在标签处理器类中就要定义相应的setUrl(String url)方法。在标签处理器中定义相应的set方法后,JSP引擎在解析执行开始标签前,也就是调用doStartTag方法前,会调用set属性方法,为标签设置属性。

通过成员变量 和 setter方法设置属性  times
    Tld配置
    <tag>
    … ...
    <attribute>
     <name>times</name>
     <required>true</required>
     <rtexprvalue>true</rtexprvalue>
     </attribute>
    </tag>

2、简单标签

由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广, SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。实现SimpleTag接口的标签通常称为简单标签。简单标签共定义了5个方法:

  1. setJspContext方法
  2. setParent
  3. getParent方法
  4. setJspBody方法
  5. doTag方法

(1)简单标签的方法介绍

  1. setJspContext方法
    用于把JSP页面的pageContext对象传递给标签处理器对象。
  2. setParent方法
    用于把父标签处理器对象传递给当前标签处理器对象。
  3. getParent方法
    用于获得当前标签的父标签处理器对象。
  4. setJspBody方法
    用于把代表标签体的JspFragment对象传递给标签处理器对象。
  5. doTag方法
    用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。在doTag方法中可以抛出。
    javax.servlet.jsp.SkipPageException异常,用于通知WEB容器不再执行JSP页面中位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回Tag.SKIP_PAGE常量的情况。

(2)SimpleTag接口方法的执行顺序

当web容器开始执行标签时,会调用如下方法完成标签的初始化:

  1. WEB容器调用标签处理器对象的setJspContext方法,将代表JSP页面的pageContext对象传递给标签处理器对象。
  2. WEB容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给这个标签处理器对象。注意,只有在标签存在父标签的情况下,WEB容器才会调用这个方法。
  3. 如果调用标签时设置了属性,容器将调用每个属性对应的setter方法把属性值传递给标签处理器对象。如果标签的属性值是EL表达式或脚本表达式,则WEB容器首先计算表达式的值,然后把值传递给标签处理器对象。
  4. 如果简单标签有标签体,容器将调用setJspBody方法把代表标签体的JspFragment对象传递进来。

执行标签时:

容器调用标签处理器的doTag()方法,开发人员在方法体内通过操作JspFragment对象,就可以实现是否执行、迭代、修改标签体的目的。

(3)JspFragment类

javax.servlet.jsp.tagext.JspFragment类是在JSP2.0中定义的,它的实例对象代表JSP页面中的一段符合JSP语法规范的JSP片段,这段JSP片段中不能包含JSP脚本元素。WEB容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象表示,并调用标签处理器对象的setJspBody方法把JspFragment对象传递给标签处理器对象。JspFragment类中只定义了两个方法,如下所示:

  1. getJspContext方法
    用于返回代表调用页面的JspContext对象. —- pageContext
  2. public abstract void invoke(java.io.Writer out) – 输出标签体内容
    用于执行JspFragment对象所代表的JSP代码片段。参数out用于指定将JspFragment对象的执行结果写入到哪个输出流对象中,如果传递给参数out的值为null,则将执行结果写入到JspContext.getOut()方法返回的输出流对象中。(简而言之,可以理解为写给浏览器)。
    JspFragment.invoke方法是JspFragment最重要的方法,利用这个方法可以控制是否执行和输出标签体的内容、是否迭代执行标签体的内容或对标签体的执行结果进行修改后再输出。例如:
    在标签处理器中如果没有调用JspFragment.invoke方法,其结果就相当于忽略标签体内容;
    在标签处理器中重复调用JspFragment.invoke方法,则标签体内容将会被重复执行;
    若想在标签处理器中修改标签体内容,只需在调用invoke方法时指定一个可取出结果数据的输出流对象(例如StringWriter),让标签体的执行结果输出到该输出流对象中,然后从该输出流对象中取出数据进行修改后再输出到目标设备,即可达到修改标签体的目的。

(4)简单标签的四个功能示例

例一:控制标签体内容是否执行
        doTag
        JspFragment jspFragment = getJspBody();

        jspFragment.invoke(getJspContext().getOut());
        jspFragment.invoke(null);

        Tld配置
         <tag>
          <name>demo1</name>
          <tag-class>simple.MyTag1</tag-class>
          <body-content>scriptless</body-content>
         </tag>

        例二:控制标签后的jsp页面是否执行
        doTag
        throw new SkipPageException()

        Tld配置
         <tag>
          <name>demo2</name>
          <tag-class>simple.MyTag2</tag-class>
          <body-content>empty</body-content>
         </tag>

        例三:控制jsp页面内容重复执行
        doTag
        JspFragment fragment = getJspBody();
        for (int i = 0; i < times; i++) {
            fragment.invoke(null);
        }

        Tld配置
         <tag>
          <name>demo3</name>
          <tag-class>simple.MyTag3</tag-class>
          <body-content>scriptless</body-content>
         </tag>

        例四:修改jsp页面内容输出
        将标签体内容大写输出
        doTag
        JspFragment fragment = getJspBody();
        StringWriter writer = new StringWriter();
        fragment.invoke(writer);
        getJspContext().getOut().println(
            writer.getBuffer().toString().toUpperCase());

3、 tag接口的继承结构

标签中心 技术架构 标签技术是什么_JSTL标签库