第3章Tag文件与Tag标记

本章导读 
主要内容 
 Tag文件的结构
 Tag标记
 Tag文件中的常用指令

难点
 Tag文件中的attribute指令
 Tag文件中的variable指令

关键实践 
 解析单词

一个Web应用中的许多JSP页面可能需要使用某些相同的信息,如都需要使用相同的导航栏、标题等。如果能将许多页面都需要的共同的信息形成一种特殊文件,而且各个JSP页面都可以使用这种特殊的文件,那么这样的特殊文件就是可复用的代码。代码复用是软件设计的一个重要方面、是衡量软件可维护性的重要指标之一。
第2章学习了include指令标记和include动作标记,使用这两个标记可以实现代码的复用。但是,在某些情况下,使用include指令标记和include动作标记有一定的缺点,比如,如果include指令标记或动作标记要处理的文件是一个JSP文件,那么用户可以在浏览器的地址栏中直接输入该JSP文件所在Web服务目录访问这个JSP文件,这可能不是Web应用所希望发生的,因为该JSP文件也许仅仅是个导航条,仅仅供其他JSP文件使用include指令标记或动作标记来嵌入或动态加载的,而不是让用户直接访问的。另外,include指令标记和include动作标记允许所要处理的文件存放在Web服务目录中的任意子目录中,不仅显得杂乱无章,而且使得include标记和所处理文件的所在目录的结构形成了耦合,不利于Web应用的维护。
本章我们将学习一种特殊的文本文件: Tag文件。Tag文件和JSP文件很类似,可以被JSP页面动态加载调用,实现代码的复用(但用户不能通过该Tag文件所在Web服务目录直接访问Tag文件)。
本章在webapps目录下新建一个Web服务目录ch3,除非特别约定,例子中的JSP页面均保存在ch3目录中。


视频讲解 

3.1Tag文件
3.1.1Tag文件的结构

Tag文件是扩展名为.tag的文本文件,其结构和JSP文件类似。一个Tag文件中可以有普通的HTML标记符、某些特殊的指令标记(见3.4节)、成员变量声明和方法的定义、Java程序片和Java表达式。以下是一个简单的Tag文件oddNumberSum.tag,负责计算100内的全部奇数的代数和。
oddNumberSum.tag


<%@ tag pageEncoding="utf-8"%>

<p style="font-family:宋体;font-size:36">

1~100内的奇数之和: 

<%int sum=0,i=1;

for(i=1;i<=100;i++){

if(i%2==1)

sum=sum+i;

}

out.println(sum);

%>

</p>







3.1.2Tag文件的保存
 Tag文件所在目录

Tag文件可以实现代码的复用,即Tag文件可以被许多JSP页面使用。为了能让一个Web应用中的JSP页面使用某一个Tag文件,必须把这个Tag文件存放到Tomcat服务器指定的目录中,也就是说,如果某个Web服务目录下的JSP页面准备调用一个Tag文件,那么必须在该Web服务目录下,建立如下的目录结构: 


Web服务目录\WEB-INF\tags



例如: 


ch3\WEB-INF\tags



其中的WEBINF(字母大写)和tags都是固定的目录名称,而tags下的子目录的名称可由用户给定。
一个Tag文件必须保存到tags目录或其下的子目录中。这里把3.1.1节中的oddNumberSum.tag保存到
ch3\WEBINF\tags
目录中。
 Tag文件的编码
保存Tag文件时按照Tag文件指定的编码保存,例如Tag文件使用tag指令(见稍后的3.4节): 


<%@ tag pageEncoding="utf-8"%>



指定的编码是UTF8,因此需要按照UTF8编码保存Tag文件。例如,用文本编辑器“记事本”编辑Tag文件,在保存该Tag文件时,将“保存类型(T)”选择为“所有文件(*.*)”,将“编码(E)”选择为“UTF8”。
3.2Tag标记
3.2.1Tag标记与Tag文件



视频讲解

某个Web服务目录下的Tag文件只能由该Web服务目录中的JSP页面调用,JSP页面必须通过Tag标记来调用一个Tag文件。

Tag标记的名字和Tag文件的名字一致,也就是说,当我们编写了一个Tag文件并保存到特定目录中后(见3.1.2节),也就给出了一个Tag标记,该标记的格式为: 


<Tag文件的名字 />



或


<Tag 文件的名字 > 其他内容(称为标体内容)</Tag文件的名字>



一个Tag文件对应着一个Tag标记,把全体Tag标记称之为一个自定义标记库或简称为标记库。
 3.2.2Tag标记的使用
一个JSP页面通过使用Tag标记来调用一个Tag文件。Web服务目录下的一个JSP页面在使用Tag标记来调用一个Tag文件之前,必须首先使用taglib指令标记引入该Web服务目录下的标记库,只有这样,JSP页面才可以使用Tag标记调用相应的Tag文件。
taglib指令的格式如下: 


<%@ taglib tagdir="标记库的位置" prefix="前缀">



例如: 


<%@ taglib tagdir="/WEB-INF/tags" prefix="computer"%>



引入标记库后,JSP页面就可以使用带前缀的Tag标记调用相应的Tag文件,其中的前缀由<taglib>指令中的prefix属性指定。例如JSP如下使用Tag标记调用相应的Tag文件: 


<computer:oddNumberSum />



taglib指令中的prefix给出的前缀由用户自定义,其好处是,通过前缀可以有效地区分不同标记库中具有相同名字的标记文件。

注:  
JSP页面使用Tag标记时,冒号:的左右不要有空格。



例3_1中的JSP页面使用Tag标记调用oddNumberSum.tag(该Tag文件见3.1.1节)计算100之内的奇数和。
例3_1
example3_1.jsp(效果如图3.1所示)


<%@ page contentType="text/html"%>





<%@ page pageEncoding="utf-8"%>

<%@ taglib tagdir="/WEB-INF/tags" prefix="computer"%>

<HTML><body bgcolor=cyan>

<h1>调用Tag文件计算100内奇数和: </h1>

<computer:oddNumberSum /> <%-- 使用Tag标记 --%>

</body></HTML>





图3.1使用Tag标记



如果把3.1.1节中的oddNumberSum.tag保存在
ch3\WEBINF\tags\example1
目录中,那么只要将上述JSP页面的taglib指令修改为: 


<%@ taglib tagdir="/WEB-INF/tags/example1"  prefix="computer"%>



即可。
 3.2.3Tag标记的运行原理
Tomcat服务器处理JSP页面中的Tag标记的原理如下: 
 如果该Tag标记对应的Tag文件是首次被JSP页面调用,那么Tomcat服务器会将Tag文件转译成一个Java文件,并编译这个Java文件生成字节码文件,然后执行这个字节码文件(这和执行JSP页面的原理类似)。
 如果该Tag文件已经被转编译为字节码文件,Tomcat服务器将直接执行这个字节码文件。
 如果对Tag文件进行了修改,那么Tomcat服务器会重新将Tag文件转译成一个Java文件,并编译这个Java文件生成字节码文件,然后执行这个字节码文件。
3.3Tag文件中的常用指令


视频讲解

与JSP文件类似,Tag文件中也有一些常用指令,这些指令将影响Tag文件的行为。Tag文件中经常使用的指令有tag、taglib、include、attribute、variable。
以下将分别讲述上述指令在Tag文件中的作用和用法。
 3.3.1tag指令
Tag文件中的tag指令类似于JSP文件中的page指令。Tag文件通过使用tag指令可以指定某些属性的值,以便从总体上影响Tag文件的处理和表示。tag指令的语法如下: 


<%@ tag属性1="属性值" 属性2="属性值" …属性n="属性值"%>



在一个Tag文件中可以使用多个tag指令,因此我们经常使用多个tag指令为属性指定需要的值: 


<%@ tag属性1="属性值"%>

<%@ tag属性2="属性值"%>

…

<%@ tag属性n="属性值"%>



 language属性

language属性的值指定Tag文件使用的脚本语言,目前只能取值Java,其默认值就是Java,因此在编写Tag文件时,没有必要使用tag指令指定language属性的值。
 import属性
import属性的作用是为Tag文件引入包中的类,这样就可以在Tag文件的程序片部分、变量及方法定义部分、表达式部分使用包中的类。import属性可以取多个值,import属性默认已经有如下值: "java.lang.*""javax.servlet.*""javax.servlet.jsp.*""javax.servlet.http.*"。
 pageEncoding
该属性指定Tag文件的字符编码,其默认值是ISO88591。目前,为了避免显示信息出现乱码现象,Tag文件需要将该属性值设置为UTF8。
 3.3.2include指令 
在Tag文件中也有和JSP文件类似的include指令标记,其使用方法和作用与JSP文件中的include指令标记类似。
 3.3.3attribute指令 

Tag文件充当着可复用代码的角色,如果一个Tag文件允许使用它的JSP页面向该Tag文件传递数据,就使得Tag文件的功能更为强大。在Tag文件中通过使用attribute指令让使用它的JSP页面向该Tag文件传递需要的数据。attribute指令的格式如下: 


<%@ attribute name="对象名字" required="true"|"false" type="对象的类型"%>



例如Tag文件myTag.tag中有如下attribute指令:


<%@ attribute name="result" required="true" type="java.lang.Double"%>



那么就相当于Tag文件中有了一个名字是result的对象,但Tag文件不需要创建该对象result,而是等待JSP页面将一个Double型的对象的引用传递给result。

attribute指令中的name属性是必需的,该属性的值是一个对象的名字。JSP页面在调用Tag文件时,可向name属性指定的对象传递一个引用。需要特别注意的是,type在指定对象类型时,必须使用包名,比如,不可以将java.lang.Double简写为Double。如果attribute指令中没有使用type指定对象的类型,那对象的类型默认是java.lang.String类型。

JSP页面使用Tag标记向所调用的Tag文件中name指定的对象传递一个引用,方式如下: 


<前缀: Tag文件名字 对象名字="对象的引用" />



比如,JSP页面使用Tag标记(假设标记的前缀为computer)调用myTag.tag: 


<computer:myTag  result="new Double(3.1415926)" />



就向myTag.tag中attribute指令给出的对象result对象传递了一个Double对象的引用。

attribute指令中的required属性也是可选的,如果省略required属性,那么required的默认值是false。当指定required的值是true时,调用该Tag文件的JSP页面必须向该Tag文件中attribute指令中的name属性给出的对象传递一个引用,当指定required的值是false时,调用该Tag文件的JSP可以向该Tag文件中attribute指令中的name属性给出的对象传递或不传递对象的引用。


注:  在Tag文件中不可以再定义和attribute指令中的name属性给出的对象具有相同名字的变量,否则将隐藏attribute指令中给出的对象,使其失效。



在下面的例3_2中,triangle.tag存放在ch3\WEBINF\tags\example2目录中,该Tag文件负责计算、显示三角形的面积。example3_2.jsp页面保存在ch3中,使用Tag标记调用triangle.tag文件,并且向triangle.tag传递三角形三边的长度。
例3_2
example3_2.jsp(效果如图3.2所示)


<%@ page contentType="text/html"%>

<%@ page pageEncoding="utf-8"%>

<%@ taglib tagdir="/WEB-INF/tags/example2" prefix="getTriangleArea"%>

<HTML><body bgcolor=yellow >

<p style="font-family:宋体;font-size:36;color:blue">

<%--使用Tag标记:  --%>

<getTriangleArea:triangle sideA="15" sideB="16" sideC="20"/>

</p>

</body></HTML>




triangle.tag


<%@ tag pageEncoding="utf-8"%>

<%@ attribute name="sideA" required="true"%>

<%@ attribute name="sideB" required="true"%>

<%@ attribute name="sideC" required="true"%>

<%! public String getArea(double a,double b,double c) {

if(a+b>c&&a+c>b&&c+b>a) {

double p=(a+b+c)/2.0;

double area=Math.sqrt(p*(p-a)*(p-b)*(p-c)) ;

String result=String.format("%.2f",area);

return "<br>三角形面积(小数点保留2位):"+result;

}

else

return("<br>"+a+","+b+","+c+"不能构成一个三角形,无法计算面积");

}

%>

<%out.println("<BR>三边: "+sideA+","+sideB+","+sideC);

double a=Double.parseDouble(sideA);







double b=Double.parseDouble(sideB);

double c=Double.parseDouble(sideC);

out.println(getArea(a,b,c));

%>





图3.2调用Tag文件计算面积


下面的例3_3中,JSP页面example3_3.jsp只负责将一组随机数据存放到链表(java.util.LinkedList类型对象)中,然后将链表传递给sort.tag,sort.tag负责按低到高顺序显示链表中的数据。sort.tag存放在ch3\WEBINF\tags\example3目录中,example3_3.jsp保存在ch3目录中。

例3_3
example3_3.jsp(效果如图3.3所示)


<%@ page contentType="text/html"%>

<%@ page pageEncoding="utf-8"%>

<%@ page import="java.util.LinkedList"%>

<%@ page import="java.util.Random"%>

<%@ taglib tagdir="/WEB-INF/tags/example3" prefix="sortNumber"%>

<HTML><body bgcolor=#CCCCCC>

<%LinkedList<Double> listNumber=new LinkedList<Double>();

Random random=new Random();

for(int i =0;i<3;i++) {

double d=random.nextDouble(); //[0,1)之间的随机数

listNumber.add(d);

}

%>

<p style="font-family:宋体;font-size:36;color:blue">

排序数据

<sortNumber:sort list="<%= listNumber %>"/><%-- 使用Tag标记 --%>

</body></HTML> 



sort.tag


<%@ attribute name="list" required="true" type="java.util.LinkedList"%>

<%@ tag import="java.util.Collections"%>

<%@ tag import="java.util.Iterator"%>

<%Collections.sort(list);    //排序链表

Iterator<Double> ite=list.iterator(); //得到迭代器

while(ite.hasNext()) {//遍历链表

out.print("<br>"+ite.next());

}

%> 





图3.3调用Tag文件排序数据


 3.3.4variable指令
Tag文件通过使用attribute指令,可以使得调用该Tag文件的JSP页面动态地向其传递数据。在某些Web应用中,JSP页面不仅希望向Tag文件传递数据,而且希望Tag文件能返回数据给JSP页面。比如,许多JSP页面可能都需要调用某个Tag文件对某些数据进行基本的处理,但不希望Tag文件做进一步的特殊处理以及显示数据,因为各个JSP页面对数据的进一步处理或显示格式的要求是不同的。因此,JSP页面希望Tag文件将数据的基本处理结果存放在某些对象中,将这些对象返回给当前JSP页面即可。

Tag文件通过使用variable指令可以将Tag文件中的对象返回给调用该Tag文件的JSP页面。

 variable指令的格式
variable指令的格式如下: 


<%@ variable name-given="对象名" variable-class="对象类型" scope="有效范围"%>



variable指令中属性namegiven的值就是Tag文件返回给JSP页面的对象。该对象的名字必须符合标识符规定,即名字可以由字母、下画线、美元符号和数字组成,并且第一个字符不能是数字字符。variable指令中属性variableclass的值是返回的对象的类型,对象的类型必须带有包名,比如java.lang.Double、java.time. LocalDate等类型。如果variable指令中没有使用variableclass给出对象的类型,那么对象的类型是java.lang.String类型。

variable指令中scope属性的值指定对象的有效范围,scope的值可以取AT_BEGIN、NESTED和AT_END。当scope的值是AT_BEGIN时,JSP页面一旦开始使用Tag标记,就得到了variable指令返回给JSP页面的对象,JSP页面就可以在Tag标记的标记体中或Tag标记结束后的各个部分中使用variable指令返回给JSP页面的对象。当scope的值是NESTED时,JSP页面只可以在Tag标记的标记体中使用variable指令返回给JSP页面的对象。当scope的值是AT_END时,JSP页面只可以在Tag标记结束后。才可以使用variable指令返回给JSP页面的对象。

下面的variable指令给出的对象的名字是time,类型为java.time.LocalDate,有效范围是AT_END: 


<%@ variable name-given="time"  

variable-class="java.time.LocalDate"  scope="AT_END"%>



 对象的返回
Tag文件为了给JSP页面返回一个对象,就必须将返回的对象的名字以及该对象的引用存储到Tomcat服务器提供的内置对象jspContext中。Tag文件只有将对象的名字及其引用存储到jspContext中,JSP页面才可以使用该对象。比如,Tag文件的variable指令: 


<%@ variable name-given="time"

variable-class="java.time.LocalDate" scope="AT_END"%>



为JSP页面返回名字是time的LocalDate对象。那么Tag文件中必须让jspContext调用


setAttribute("对象名",对象的引用);



方法存储名字是time的对象以及该对象的引用,例如: 


jspContext.setAttribute("time",LocalDate .now());



将名字是time的LocalDate对象存储到jspContext中。
下面的例3_4中,JSP页面example3_4.jsp将String对象交给Tag文件handleData.tag,handleData.tag解析出String对象的字符序列中的全部数字,并计算出数字总和,将数字总和放在Double对象price中,然后返回给JSP页面example3_4.jsp。example3_4.jsp输出price对象中的数字总和。handleData.tag.tag存放在ch3\WEBINF\tags\example4目录中,example3_4.jsp保存在ch3目录中。
例3_4
example3_4.jsp(效果如图3.4所示)


<%@ page contentType="text/html"%>

<%@ page pageEncoding="utf-8"%>

<%@ taglib tagdir="/WEB-INF/tags/example4" prefix="getPrice"%>

<HTML><body bgcolor=#FFCCFF>

<% String str="麻辣豆腐:20.6元,红烧肉:68.9元,烤鸭:199元";

%>

<getPrice:handleData mess="<%= str %>"/><%--使用Tag标记 --%>

<p style="font-family:宋体;font-size:36">

菜单: <br>"<%= str %>"<br>价格总和: 

<%= price %><%--使用Tag标记返回的Double对象price --%>

</p>

<% str="毛巾:2.6元,香皂:6.9元,牙刷:12.3元";

%>

<getPrice:handleData mess="<%= str %>"/>

<p style="font-family:黑体;font-size:36;color:blue">

购物小票: <br>"<%= str %>"<br>价格总和: 

<%= price %>

</p>

</body></HTML> 



handleData.tag


<%@ attribute name="mess" required="true" type="java.lang.String"%>

<%@ tag import="java.util.regex.Pattern"%>

<%@ tag import="java.util.regex.Matcher"%>

<%@ variable name-given="price" variable-class="java.lang.Double"

scope="AT_BEGIN"%>

<%!

public Double getPriceSum(String input){//定义方法

Pattern pattern;//模式对象





Matcher matcher;//匹配对象

String regex="-?[0-9][0-9]*[.]?[0-9]*" ;  //匹配数字的正则表达式

pattern=Pattern.compile(regex);//初始化模式对象

matcher=pattern.matcher(input);//初始化匹配对象,用于检索input

double sum=0;

while(matcher.find()) {

String str=matcher.group();

sum += Double.parseDouble(str);

}

return new Double(sum);

}

%>

<%//将返回的Double对象放在jspContext中,用名字price返回给JSP页面

jspContext.setAttribute("price",getPriceSum(mess));

%>





图3.4向JSP页面返回对象



注:  在JSP页面中不可以再定义与Tag文件返回的对象具有相同名字的变量,否则Tag文件无法将variable指令给出的对象返回给JSP页面(并将出现编译错误)。如果Tag文件同时使用variable指令和attribute指令,那么variable指令中namegiven和attribute指令中name给出的对象不能相同(否则将出现编译错误)。



 3.3.5taglib指令 
JSP页面或Tag文件都可以使用taglib指令引入标记库(如前面各个例子所示)。taglib指令格式如下: 


<%@ taglib tagdir="自定义标记库的位置" prefix="前缀">



一个Tag文件也可以使用几个taglib指令标记引入若干个标记库,例如: 


<%@ taglib tagdir="/WEB-INF/tags" prefix="beijing"%>

<%@ taglib tagdir="/WEB-INF/tags/tagsTwo" prefix="dalian"%>





视频讲解

3.4上机实验

提供了详细的实验步骤要求,按步骤完成,提升学习效果,积累经验,不断提高Web设计能力。
3.4.1实验1解析单词
 实验目的

掌握JSP页面中使用Tag文件,向Tag文件传递对象,Tag文件负责处理对象中的数据。
 实验要求
(1) JSP页面giveText.jsp负责将String对象,比如String str ="how are you",传递给所调用的Tag文件backWords.tag。
(2) backWords.tag文件负责解析出String对象中的单词,并将这些单词返回给JSP页面giveText.jsp。
(3) JSP页面giveText.jsp负责显示backWords.tag返回给它的单词。
(4) 在Tomcat服务器的webapps目录下(比如,D:\apachetomcat9.0.26\webapps)新建一个名字是ch3_practice_one的Web服务目录。把giveText.jsp文件保存到ch3_practice_one目录中。在ch3_practice_one目录下再建立目录结构: \WEBINF\tags\ practice1,将backWords.tag保存在practice1目录中。
(5) 用浏览器访问JSP页面giveText.jsp。
 参考代码
参考代码运行效果如图3.5所示。


图3.5解析单词


giveText.jsp


<%@ page contentType="text/html"%>

<%@ page pageEncoding="utf-8"%>

<%@ page import="java.util.Iterator"%>

<%@ taglib tagdir="/WEB-INF/tags/practice1" prefix="getWords"%>

<HTML><body bgcolor=#CCCCFF>

<% String str="How are you,are you student? where are you from? ";

%>

<getWords:backWords okString ="<%= str %>" /> <%--使用Tag标记 --%>

<p style="font-family:宋体;font-size:26">

<%= str %><br>

<%

Iterator<String> ite=words.iterator();  //使用Tag标记返回的对象words


out.print("使用了"+ words.size()+"个单词:<br>");

while(ite.hasNext()) {//遍历集合

out.print(" "+ite.next());

}

%>

</p></body></HTML>





backWords.tag


<%@ tag import="java.util.HashSet"%>

<%@ tag import="java.util.regex.Pattern"%>

<%@ tag import="java.util.regex.Matcher"%>

<%@ attribute name="okString" required="true" type="java.lang.String"%>

<%@ variable name-given="words" variable-class="java.util.HashSet "

scope="AT_BEGIN"%>

<%

HashSet<String>set=new HashSet<String>(); //集合不允许有相同的元素

Pattern pattern;//模式对象

Matcher matcher;//匹配对象

String regex="[a-zA-Z]+" ;//匹配英文单词

pattern=Pattern.compile(regex);//初始化模式对象

matcher=pattern.matcher(okString);//初始化匹配对象,用于检索okString

while(matcher.find()) {

String str=matcher.group();

set.add(str);

}

//将返回的set对象放在jspContext中,用名字words返回给JSP页面

jspContext.setAttribute("words",set);

%>




3.4.2实验2显示日历
 实验目的

和实验1的目的相同,进一步强化掌握JSP页面使用Tag文件,即向Tag文件传递对象,Tag文件负责处理数据。
 实验要求
(1) Tag文件calendar.tag负责显示日历。
(2)  编写JSP页面useCalendar.jsp,要求useCalendar.jsp使用Tag标记使用calendar.tag,并将日期的年份和月份传递给calendar.tag。
(3) 在Tomcat服务器的webapps目录下(比如,D:\apachetomcat9.0.26\webapps)新建一个名字是ch3_practice_two的Web服务目录。把useCalendar.jsp文件保存到ch3_practice_two目录中。在ch3_practice_two目录下再建立目录结构: \WEBINF\tags\ practice2,将calendar.tag保存在practice2目录中。
(4) 用浏览器访问JSP页面useCalendar.jsp。
 参考代码
参考代码运行效果如图3.6所示。


图3.6显示日历


useCalendar.jsp


<%@ page contentType="text/html"%>

<%@ page pageEncoding="utf-8"%>

<%@ taglib tagdir="/WEB-INF/tags/practice2" prefix="getCalendar"%>

<HTML><body bgcolor=#CCCCFF>

<getCalendar:calendar year ="2025" month="2" /> <%-- 使用Tag标记 --%>

</body></HTML>



calendar.tag


<%@ tag import="java.time.LocalDate"%>

<%@ tag import="java.time.DayOfWeek"%>

<%@ attribute name="year" required="true" type="java.lang.String"%>

<%@ attribute name="month" required="true" type="java.lang.String"%>

<%

int y=Integer.parseInt(year);

int m=Integer.parseInt(month);

LocalDate date=LocalDate.of(y,m,1);

int days=date.lengthOfMonth(); //得到该月有多少天

int space=0;//存放空白字符的个数

DayOfWeek dayOfWeek=date.getDayOfWeek(); //得到1号是星期几

switch(dayOfWeek) {

case SUNDAY:space=0;

break;

case MONDAY:space=1;

break;

case TUESDAY:space=2;

break;

case WEDNESDAY: space=3;

break;

case THURSDAY:space=4;

break;

case FRIDAY:space=5;

break;

case SATURDAY:space=6;

break;

}

String [] calendar=new String[space+days]; //用于存放日期和1号前面的空白

for(int i=0;i<space;i++)

calendar[i]="--";

for(int i=space,n=1;i<calendar.length;i++){

calendar[i]=String.valueOf(n) ;

n++;

}

%>

<h3> <%=year %>年<%=month %>月的日历:</h3>

<table border=0>

<tr><th>星期日</th><th>星期一</th><th>星期二</th><th>星期三</th>

<th>星期四</th><th>星期五</th><th>星期六</th>

</tr>

<%





int n=0;

while(n<calendar.length){

out.print("<tr>");

int increment=Math.min(7,calendar.length-n);

for(int i=n;i<n+increment;i++) {

out.print("<td>"+calendar[i]+"</td>");

}

out.print("</tr>");

n=n+increment;

}

%>

</table>




习 题 3
1. 用户可以使用浏览器直接访问一个Tag文件吗?
2.  Tag文件应当存放在怎样的目录中?
3. Tag文件中的tag指令可以设置哪些属性的值?
4. Tag文件中的attribute指令有怎样的作用?
5. Tag文件中的variable指令有怎样的作用?
6. 编写两个Tag文件Rect.tag和Circle.tag。Rect.tag负责计算并显示矩形的面积,Circle.tag负责计算并显示圆的面积。编写一个JSP页面lianxi6.jsp,该JSP页面使用Tag标记调用Rect.tag和Circle.tag。调用Rect.tag时,向其传递矩形的两个边的长度; 调用Circle.tag时,向其传递圆的半径。
7. 编写一个Tag文件: GetArea.tag负责求出三角形的面积,并使用variable指令返回三角形的面积给调用该Tag文件的JSP页面。JSP页面负责显示Tag文件返回的三角形的面积。JSP在调用Tag文件时,使用attribute指令将三角形三边的长度传递给Tag文件。one.jsp和two.jsp都使用Tag标记调用GetArea.tag。one.jsp返回的三角形的面积保留最多3位小数,two.jsp返回的三角形的面积保留最多6位小数。