概述
本篇博文中主要探讨以下内容:

  1. JSTL的核心标签库的使用
  2. 开发简单的自定义标签的步骤
  3. 在Web应用中使用标签


JSTL和自定义标签

  • 一、JSTL
  • 1.1 通用目的标签
  • 1.1.1 out标签
  • 1.1.2 set标签
  • 1.1.3 remove标签
  • 1.2条件控制标签
  • 1.2.1 if标签
  • 1.2.2 choose标签
  • 1.3 循环控制标签
  • 1.3.1 forEach标签
  • 二、自定义标签
  • 2.1 创建"Hello"标签
  • 2.2 访问标签体
  • 2.3 自定义标签属性


一、JSTL

  • JSTL(JSP Standard Tag Library):JSP标准标签库

使用JSTL可以提高JSP页面的开发效率,也可以避免重复开发标签库。

  • JSTL包

taglibs-standard-impl-1.2.5.jar
taglibs-standard-spec-1.2.5.jar

下载地址:
http://tomcat.apache.org/download-taglibs.cgi

  • JSTL库及使用的URI与前缀

库名称

使用的URI

前缀

核心标签库

http://java.sun.com/jsp/jstl/core

c

XML标签库

http://java.sun.com/jsp/jstl/xml

x

国际化和格式化库

http://java.sun.com/jsp/jstl/fmt

fmt

SQL标签库

http://java.sun.com/jsp/jstl/sql

sql

函数库

http://java.sun.com/jsp/jstl/functions

fn

  • 核心(core)标签库
  1. 通用目的
<c:out>//在页面中显示内容
<c:set>//定义或者设置一个作用域变量值
<c:remove>//清除一个作用域变量
<c:catch>//捕获异常
  1. 条件控制
<c:if>//根据一个属性等于一个值改变处理
<c:choose>//根据一个属性等于一组值改变处理
<c:when>//用来测试一个条件
<c:otherwise>//当所有when条件都为false时,执行该标签内的内容
  1. 循环控制
<c:forEach>//对集合中的每个对象作迭代处理
<c:forTokens>//对给定字符串中的每个子串执行处理
  1. URL处理
<c:url>//重写URL并对它们的参数编码
<c:import>//访问Web应用程序外部的内容
<c:redirect>//告诉客户浏览器访问另一个URL
<c:param>//用来传递参数

在JSP页面中使用JSTL,必须使用taglib指令来引用标签库

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

1.1 通用目的标签

1.1.1 out标签

<c:out>标签的功能与JSP中脚本表达式(<%= %>)相同,用于向页面输值。

  1. 格式一:不带标签体
<c:out value="$value" [escapeXml ="{true|false}"]
	default = "defaultValue"/>
  1. 格式二:带标签体
<c:out value="$value" [escapeXml ="{true|false}"]>
	default value
</c:out>

标签需要一个value属性,它的值是向页面中输出的值。default表示如果value的值为null或者不存在,则输出该默认值;如果escapeXml的值为true(默认值),表示将value属性值中包含的<,>,’,"或者&等特殊字符转换为相应的实体引用(或者字符编码),如小于号(<)将转换为&lt;大于号(>)转换为&gt;如果escapeXml的值为false将不转换。

<c:out value ="${[pageContext.request.remoteAddr}" />  //输出客户地址
<c:out value ="${number} /> //输出number变量的值
//可以替换JSP的脚本表达式

1.1.2 set标签

尽管EL可以有很多方式管理变量,单不能定义作用域变量和从作用域中删除变量。使用<c:set>和<c:remove>标签,就能完成这些操作哟。
使用<c:set>标签可以:

  1. 定义一个字符串类型的作用域变量,并通过变量名引用它。
  2. 通过变量名引用一个现有的作用域变量。
  3. 重新设置作用域变量的属性值

作用:向域对象中存入值

  • 属性:
    var:key值
    value:值
    scope:作用域(page request session application)
  • 代码:
<h3>set标签</h3>
<%
request.setAttribute("msg", "A");
%>
<c:set var="msg" value="B" scope="request"></c:set>
${ msg }
//页面输出结果:B

另外一种格式

//不带标签体的情况  单标签
<c:set target = "target" property="propertyName" value = "value" />
或者
//带标签体的情况  双标签标签  
<c:set target = "target" property="propertyName">
	value
</c:set>
//其中 target属性是指定对象名
		property属性是指定属性名
		value属性是要设置的值

注意:target属性的值应该是用EL的形式,如target="${book}",不能写成
target="book"

1.1.3 remove标签

  • 作用:从域对象中移除值
  • 属性:
    var:移除的key值
  • 代码:
<h3>remove标签</h3>
<c:set var="msg" value="美美"/>
${ msg }

<h3>已经把msg移除了</h3>
<c:remove var="msg"/>
${ msg }

注意:remove标签不能用于删除JavaBeans或Map对象

1.2条件控制标签

1.2.1 if标签

  • 作用:进行语句的判断。注意:只有if,没有else
  • 属性:
    test:必须要出现的,判断的条件
    var:把判断条件的结果(true或者false)保存到var变量中
    scope:作用域
    代码:
<h3>if标签</h3>
<%
int n = 20;
request.setAttribute("n", n);
%>
<c:if test="${ n eq 10 }" var="i">
<font color="red">n=10</font>
</c:if>
<c:if test="${ n ne 10 }">
<font color="blue">n!=10</font>
</c:if>
${ i }

页面输出结果:n!=10 false

1.2.2 choose标签

  • 作用:用来进行判断,但是复合的标签
<c:choose>
<c:when test=""></c:chen>
<c:when test=""></c:chen>
<c:otherwise></c:otherwise>
</c:choose>
  • 属性:
    关注when标签,test属性
  • 代码:
<%
int n = 10;
request.setAttribute("n", n);
%>
<c:choose>
<c:when test="${ n eq 20 }">
n=20
</c:when>
<c:otherwise>
n=其他
</c:otherwise>
</c:choose>

页面输出结果:n=其他

1.3 循环控制标签

1.3.1 forEach标签

  • 作用:用来迭代数据
    forEach当成普通的for循环。for(int i=1; i<=10; i++){}
    forEach当成增强的for循环。for(String key : 集合){}
  • 属性:
    var:声明变量
    begin:从哪开始
    end:到哪结束
    step:步长
    varStatus:在迭代的过程中会产生一些信息,把信息保存在varStatus属性。其中属性有一些值:
    count:代表计数
    index:代表下标
    first:判断是否是第一个元素
    last:判断是否是最后一个元素
    current:代表当前迭代的元素
    items:代表的是要迭代的集合(数组 list set map)
  • 代码:
<%@page import="com.pers.domain.User"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>

<!-- 导入JSTL的标签库 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<%
for(int i=0;i<=10;i++){

}
%>

<h3>普通for循环</h3>
<c:forEach var="j" begin="0" end="10" step="1" varStatus="vs">
${ vs.count }
</c:forEach>

<h3>模拟增强for循环</h3>
<c:forEach var="s" items="${ list }">
${ s }
</c:forEach>


<h3>遍历数据,数据需要存入在域对象中,遍历List集合</h3>
<%
List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
request.setAttribute("list", list);
%>
<c:forEach var="s" items="${ list }">
${ s }
</c:forEach>

<h3>遍历Map集合</h3>
<%
Map<String,String> map = new HashMap<String,String>();
map.put("a", "A");
map.put("b", "B");
map.put("c", "C");
request.setAttribute("map", map);
%>
<c:forEach var="entry" items="${ map }">
${ entry.key } -- ${ entry.value }
</c:forEach>

<h3>List集合中有Java对象</h3>
<%
List<User> ulist = new ArrayList<User>();
ulist.add(new User(1,"张三","zhangsan123","zhangsan@163.com"));
request.setAttribute("ulist", ulist);
%>
<c:forEach var="user" items="${ ulist }">
${ user.username } -- ${ user.email }
</c:forEach>

</body>
</html>

二、自定义标签

自定义标签是用户定义的JSP语言元素。当JSP页面包含一个自定义标签时将被转化为servlet,标签转化为对被 称为tag handler的对象的操作,即当servlet执行时Web container调用那些操作。

JSP标签扩展可以让你创建新的标签并且可以直接插入到一个JSP页面。 JSP 2.0规范中引入Simple Tag Handlers来编写这些自定义标记。

你可以继承SimpleTagSupport类并重写的doTag()方法来开发一个最简单的自定义标签。

开发简单的自定义标签的步骤
(1)创建标签处理类
(2)创建标签库描述文件TLD
(3)在JSP页面中使用标签

2.1 创建"Hello"标签

接下来,我们想创建一个自定义标签叫作

<ltex:Hello>

标签格式为:

<ex:Hello />

要创建自定义的JSP标签,你首先必须创建处理标签的Java类。所以,让我们创建一个HelloTag类,如下所示:

package com.runoob;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {

  public void doTag() throws JspException, IOException {
    JspWriter out = getJspContext().getOut();
    out.println("Hello Custom Tag!");
  }
}

以下代码重写了doTag()方法,方法中使用了getJspContext()方法来获取当前的JspContext对象,并将"Hello Custom Tag!"传递给JspWriter对象。

编译以上类,并将其复制到环境变量CLASSPATH目录中。最后创建如下标签库:<Tomcat安装目录>webapps\ROOT\WEB-INF\custom.tld。

<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>2.0</jsp-version>
  <short-name>Example TLD</short-name>
  <tag>
    <name>Hello</name>
    <tag-class>com.runoob.HelloTag</tag-class>
    <body-content>empty</body-content>
  </tag>
</taglib>

接下来,我们就可以在JSP文件中使用Hello标签:

<%@ taglib prefix="ex" uri="WEB-INF/custom.tld"%>
<html>
  <head>
    <title>A sample custom tag</title>
  </head>
  <body>
    <ex:Hello/>
  </body>
</html>

以上程序输出结果为:

Hello Custom Tag!

2.2 访问标签体

你可以像标准标签库一样在标签中包含消息内容。如我们要在我们自定义的Hello中包含内容,格式如下:

<ex:Hello>
   This is message body
</ex:Hello>

我们可以修改标签处理类文件,代码如下:

package com.runoob;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {

   StringWriter sw = new StringWriter();
   public void doTag()
      throws JspException, IOException
    {
       getJspBody().invoke(sw);
       getJspContext().getOut().println(sw.toString());
    }

}

接下来我们需要修改TLD文件,如下所示:

<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>2.0</jsp-version>
  <short-name>Example TLD with Body</short-name>
  <tag>
    <name>Hello</name>
    <tag-class>com.runoob.HelloTag</tag-class>
    <body-content>scriptless</body-content>
  </tag>
</taglib>

现在我们可以在JSP使用修改后的标签,如下所示:

<%@ taglib prefix="ex" uri="WEB-INF/custom.tld"%>
<html>
  <head>
    <title>A sample custom tag</title>
  </head>
  <body>
    <ex:Hello>
        This is message body
    </ex:Hello>
  </body>
</html>

以上程序输出结果如下所示:

This is message body

2.3 自定义标签属性

你可以在自定义标准中设置各种属性,要接收属性,值自定义标签类必须实现setter方法, JavaBean 中的setter方法如下所示:

package com.runoob;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {

   private String message;

   public void setMessage(String msg) {
      this.message = msg;
   }

   StringWriter sw = new StringWriter();

   public void doTag()
      throws JspException, IOException
    {
       if (message != null) {
          /* 从属性中使用消息 */
          JspWriter out = getJspContext().getOut();
          out.println( message );
       }
       else {
          /* 从内容体中使用消息 */
          getJspBody().invoke(sw);
          getJspContext().getOut().println(sw.toString());
       }
   }

}

属性的名称是"message",所以setter方法是的setMessage()。现在让我们在TLD文件中使用的元素添加此属性:

<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>2.0</jsp-version>
  <short-name>Example TLD with Body</short-name>
  <tag>
    <name>Hello</name>
    <tag-class>com.runoob.HelloTag</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
       <name>message</name>
    </attribute>
  </tag>
</taglib>

现在我们就可以在JSP文件中使用message属性了,如下所示:

<%@ taglib prefix="ex" uri="WEB-INF/custom.tld"%>
<html>
  <head>
    <title>A sample custom tag</title>
  </head>
  <body>
    <ex:Hello message="This is custom tag" />
  </body>
</html>

以上实例数据输出结果为:

This is custom tag

你还可以包含以下属性:

属性

描述

name

定义属性的名称。每个标签的是属性名称必须是唯一的。

required

指定属性是否是必须的或者可选的,如果设置为false为可选。

rtexprvalue

声明在运行表达式时,标签属性是否有效。

type

定义该属性的Java类类型 。默认指定为 String

description

描述信息

fragment

如果声明了该属性,属性值将被视为一个 JspFragment。

以下是指定相关的属性实例:

.....
    <attribute>
      <name>attribute_name</name>
      <required>false</required>
      <type>java.util.Date</type>
      <fragment>false</fragment>
    </attribute>
.....

如果你使用了两个属性,修改TLD文件,如下所示:

.....
    <attribute>
      <name>attribute_name1</name>
      <required>false</required>
      <type>java.util.Boolean</type>
      <fragment>false</fragment>
    </attribute>
    <attribute>
      <name>attribute_name2</name>
      <required>true</required>
      <type>java.util.Date</type>
    </attribute>
.....