第5章〓JSTL标签库
JSTL(Jakarta Server Pages Standard Tag Library)是JSP标准标签库的简称。
在早期的JSP开发中,JSP与Servlet的职责定位模糊,开发人员习惯上在JSP中做很多的逻辑工作,HTML代码与Java代码混杂,逻辑功能、控制功能、视图功能都混淆在了一起。这种开发模式给代码的开发、阅读、维护都带来很大的麻烦。
随着MVC架构的出现,Jakarta EE中增加了JSTL标准。JSTL的目标是提供给Jakarta Web开发人员一个标准的、通用的标签库,开发人员可以利用这些标签取代JSP页面上的Java代码,从而提高程序的可读性,降低程序的维护难度。
JSTL在本质上是提前定义好的一组标签,这些标签封装了不同的功能,在页面上调用JSTL,可以大幅减少JSP文件中的Java代码。这使Java代码与HTML代码明显分离,因此使用JSTL标签库更符合MVC设计理念。使用JSTL后,JSP可以专注于视图功能,为Jakarta Web开发带来非常大的好处。
Eclipse集成Tomcat进行Jakarta Web开发时,需要单独导入JSTL相关包。下载jstlimpl3.0.jar和jstlapi3.0.jar,复制到WEBINF/lib文件夹下即可使用JSTL。
JSTL 3.0包含的标签库内容见表51。
表51JSTL 3.0包含的标签库内容
功能URI前缀
核心库jakarta.tags.corec
XML处理jakarta.tags.xmlx
I18N格式化jakarta.tags.fmtfmt
关系型数据库访问SQLjakarta.tags.sqlsql
函数jakarta.tags.functionsfn
注意,Jakarta EE 10中包含的JSTL是3.0版。Jakarta EE 10对应的JSP版本是3.1。JSTL 3.0需要JSP 3.1及以上的Web容器支持。EL表达式是JSP规范的一部分,在JSTL操作中会大量使用EL,而EL是从JSP 2.0规范开始的。
本章只着重介绍几个常用标签的使用,其他内容参见Jakarta JSTL规范。
视频讲解
5.1自定义标签库
标签库由标签库描述文件tld(taglibrary descriptors)和标签实现类两部分组成。JSTL标签库中的所有标签与自定义标签定义方法相同。下面自定义一个作者标签,显示作者的名字和性别,通过这个案例了解JSTL标签库的定义过程。
(1) 定义标签类。
新建Web项目ETCTag,创建包com.icss.tag,定义标签类AuthorTag继承Jakarta.servlet.jsp.tagext.TagSupport。一般会重写doEndTag()方法。
public class AuthorTag extends TagSupport{
private String name;
private String sex;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int doEndTag() throws JspException {
JspWriter out = pageContext.getOut();
try{
out.println("
");
out.println("");
if(sex != null)
out.println(" 作者:" + name
+ ",性别: " + sex + ",welcome you!!! | ");
else
out.println(" 作者:" + name
+ ",welcome you!!! | ");
out.println("
");
out.println("
");
}catch(Exception ex){
ex.printStackTrace();
}
return this.EVAL_PAGE;
}
}
(2) 定义标签库描述文件etc.tld。
的子元素为标签库前缀。一个下可以定义多个标签。
标签的子元素为标签名,为标签实现类,为标签的属性。
属性的子元素是属性名,表示属性是否为必须设置,false表示可选,true表示必须设置值; 表示是否可以动态赋值,false表示只能设置静态值,true表示可以动态赋值,如可以使用Java表达式、EL表达式或赋值。
etc our library
etc library
3.0
etc
http://com.icss.tag/core
show file author
author
com.icss.tag.AuthorTag
JSP
author name
name
true
true
author sex
sex
false
true
(3) 在JSP项目TagUse中调用自定义标签。
把AuthorTag编译成lib文件,导入JSP项目中。
把etc.tld复制到JSP项目的WEBINF下。
在JSP文件中调用自定义标签。
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ taglib uri="http://com.icss.tag/core" prefix="etc"%>
This is author tag use sample page.
5.2核心标签库
核心标签库前缀统一使用标识,这个标签库作用最大、用途最广。
参见jstlimpl3.0.jar/METAINF/c.tld中核心标签描述:
JSTL core library
JSTL core
3.0
c
jakarta.tags.core
使用标签库时,需要在JSP页面的头部用taglib指令声明,表示标签前缀,在标签声明时需要指明。
<%@ taglib prefix="c" uri="jakarta.tags.core"%>
5.2.1一般用途标签
视频讲解
本节介绍几个一般用途的常用标签,分别为、、。标签不常用,本节不作介绍。
1.
标签与<%=脚本表达式 %> 或 ${el表达式}的功能基本一致,用于在页面输出静态或动态信息。
基本语法如下,属性信息见表52。
表52属性信息
属性名动态支持属性类型描述
valuetrueObject要输出的表达式值
escapeXmltrueBoolean决定字符<,>、&、’,”在结果串中是否需要转义成对应的字符实体代码,默认为true。HTML转义符见表14
defaulttrueObject输出结果为null时,显示默认值
示例51
你有 个选项
示例52
当EL表达式输出为null时,可以使用输出默认值。
所属城市:
2.
基本语法如下,属性信息见表53。
表53属性信息
属性名动 态 支 持属 性 类 型描述
valuetrueObject要设置的表达式值
vartrueString存储在域对象中的变量名
scopefalseString与var对应的域对象
示例53
使用Java脚本计算一个随机数,然后用标签把随机数存储到request域对象中,最后用EL表达式提取request对象中的变量r,用输出随机数。
<%
int rand = (int)(Math.random()*100);
%>
获取随机数:
3.
基本语法如下,属性信息见表54。
表54属性信息
属性名动 态 支 持属 性 类 型描述
varfalseString存储在域对象中的变量名
scopefalseString与var对应的域对象
示例54
使用移除request域中存储的随机数rand。
<%
int rand = (int)(Math.random()*100);
request.setAttribute("rand", rand);
%>
获取随机数:
移除后随机数:
5.2.2条件判断标签
视频讲解
Java脚本中,条件判断语句有if…else、if…else if…else if…else等。JSTL的目的是简化Java脚本,因此条件判断标签必不可少。
示例55
This is your first visit. Welcome to the site!
1.
条件判断标签,如果测试条件为true,显示标签体内容。标签定义如下:
if
org.apache.taglibs.standard.tag.rt.core.IfTag
JSP
test
true
true
boolean
var
false
false
scope
false
false
基本语法如下,属性信息见表55,test为必选属性,var和scope为可选属性。
内容体
表55属性信息
属性名动 态 支 持属 性 类 型描述
testtrueBoolean测试条件返回为真,处理内容体信息,否则不处理
varfalseString把测试条件返回的布尔值结果,存储到scope对象中
scopefalseStringpage、request、session、application中的某个域对象
示例56
JSTL与EL标签配合使用,判断图书价格是否小于或等于100(符合预算),如是,则显示图书名称。
The book ${book.title} fits your budget!
示例57
测试请求参数中是否有一个名字为name的参数,如果参数为空,则提示。
Please specify your name.
示例58
判断随机数是否大于50,并用EL表达式输出测试结果。
<%
int rand = (int)(Math.random()*100);
pageContext.setAttribute("rand", rand);
%>
welcome you!
测试结果为: ${aa}
总结
JSTL中只有判断,没有else判断。如果需要if…else判断结构,可以用标签判断两次,如和同时使用。
2.
标签配合使用,执行效果等同于Java脚本中的条件判断语句。
(1) 基本语法。
内容体 ( 和 子标签)
中可以放1~n个标签,即至少要包含一个子标签,可以同时存在多个子标签。
中可以放0~1个子标签,即可以没有子标签,最多只能有一个子标签。
(2) 基本语法。
内容体
test属性返回boolean值,决定内容体是否被处理。
不能单独使用,必须要有父标签。
必须要出现在标签的前面。
(3) 基本语法。
条件块
在标签体内,如果没有就返回真,则JSP容器处理中的条件块。
不能单独使用,必须要有父标签。
在体内,必须出现在最后。
示例59
示例效果等同于if…else if…else if…else,只要任何一个test返回真,就不再向下判断,执行内容体后,立即跳出。
...
...
...
...
示例510
示例效果等同于if…else。
No records matched your selection.
${count} records matched your selection.
视频讲解
视频讲解
5.2.3迭代标签
标签在JSP页面迭代输出集合中的数据,与Java脚本中的for()循环功能类似,基本语法如下,属性信息见表56。
内容体
表56属性信息
属性名动 态 支 持属 性 类 型描述
varfalseString迭代变量名
itemstrue参见集合说明迭代的集合对象
varStatusfalseString显示迭代状态,参见LoopTagStatus接口
begintrueint迭代操作时,集合的起始索引
endtrueint迭代操作时,集合的结束索引
steptrueint迭代操作的步长值
说明信息:
begin索引必须大于或等于0。
如果end指定的索引值小于begin,则迭代不会执行。
步长值step必须大于或等于1。
如果items集合为null,不会抛出异常,按照空集合处理,即迭代不会执行。
items支持如下集合类型:
基本类型的静态数组(迭代时会自动使用包装类)。
java.util.Collection接口的实现类(会调用iterator()方法迭代集合)。
java.util.Iterator接口的实现类。
java.util.Enumeration接口的实现类。
java.util.Map接口实现类,var变量的类型为java.util.Map.Entry。
通用分隔符隔开的一个字符串。
1. 集合迭代
迭代静态数组、java.util.Collection、java.util.Iterator等集合对象。
示例511
迭代输出产品集合中的产品信息。
产品名: ${product.name} 价格: ${product.price}
示例512
迭代输出顾客信息,并在中显示。
2. Map迭代
当items类型为java.util.Map时,每个item的类型是java.util.Map.Entry。它有两个属性: key 和 value。
示例513
元素key是: ${entry.key}
元素value是: ${entry.value}
示例514
如下代码中的${entry.value}表示User对象,${entry.value.uname}表示用户名。
<%
Map map = new HashMap();
map.put("tom", new User("tom"));
map.put("jack", new User("jack"));
map.put("rose", new User("rose"));
request.setAttribute("map",map);
%>
${entry.key} |
${entry.value.uname} |
示例515
使用嵌套读取Map数据,${aParam.value}是集合对象。
参数名: ${aParam.key}
参数值:
${aValue}
3. 迭代状态
使用varStatus显示当前迭代状态。迭代状态的操作依赖接口jakarta.servlet.jsp.jstl.core.LoopTagStatus,接口定义如下:
public interface LoopTagStatus {
java.lang.IntegergetBegin();
intgetCount();
java.lang.ObjectgetCurrent();
java.lang.IntegergetEnd();
intgetIndex();
java.lang.IntegergetStep();
booleanisFirst();
booleanisLast();
}
getBegin: 返回迭代的begin属性值,如果begin属性不存在,就返回null。
getCount: 返回环绕迭代集合的当前数量。count是个相对值,从1开始。例如迭代某个集合,begin=5,end=15,step=5,则 counts 值分别为1、2、3。
getCurrent: 返回当前正在迭代的对象。
getEnd: 返回迭代的end属性值,如果end属性不存在,则返回null。
getIndex: 返回环绕迭代集合的当前索引值,索引从0开始。
getStep: 返回迭代的step属性值,如果step属性不存在,则返回null。
isFirst:如果当前的迭代项是集合的第一项,则返回true。
isLast:如何当前的迭代项是集合的最后一项,则返回true。
示例516
<%
int[] sz = new int[]{10,12,35,24,65};
request.setAttribute("sz",sz);
%>
${st.count} |
${st.index} |
${item} |
输出结果如下:
1010
21
3235
43
5465
4. 范围属性
使用属性begin、end、step,可以在迭代集合时选择部分内容处理。
示例517
<%
int[] sz = new int[]{10,12,35,24,65,78,102,205,12,31,20,309};
request.setAttribute("sz",sz);
%>
${st.count} |
${st.index} |
${item} |
输出结果如下:
1235
2465
36102
4812
51020
5.2.4URL相关标签
在JSP页面链接、导入、重定向到其他URL资源,在JSTL中统称为URL相关标签。
1.
基本语法如下,属性信息见表57。
表57属性信息
属性名动 态 支 持属 性 类 型描述
valuetrueString要处理的URL
contexttrueString相对路径的URL依赖的外部Context名字
varfalseString输出到scope对象的变量名
scopefalseString域对象
与锚点不同,它用于生成访问资源的URL,但是并不会产生超链接。value属性值可以使用绝对地址,也可使用相对地址。绝对地址不会重写,而相对地址在解析时会重写,会自动增加context前缀。如,假设Web站点context为: /foo,则输出结果: /foo/ads/logo.html。
示例518
重写
图片的相对路径,当前站点是/Hello,则图片链接为/Hello/pic/flex.png。
等效于
等效于
flex图片
示例519
设置URL资源后,将它存储在域对象中,然后通过EL表达式读取。
示例520
url设置context属性后,强制指向外部context,图片指向/Center/pic/flex.png。
2.
用于导入基于URL的资源,基本语法如下,属性信息见表58。
可选内容体 子标签
表58属性信息
属性名动态支持属性类型描述
urltrueString待导入资源的URL,可以是相对路径,也可以是绝对路径
contexttrueString当使用相对路径访问外部context资源时,指明外部context的名字
varfalseString用于存储所引入文本的变量
scopefalseStringvar属性存储在哪个域对象
charEncodingtrueString引入资源的字符编码
说明:
如果url为null、空串或无效,JspException异常被抛出;
如果charEncoding为null或空串,这个配置会被忽略;
与的功能相似,但是只能嵌入当前Web应用的资源,而还可以导入外部资源。
示例521
嵌入头文件。
(1) 编写头文件head.jsp。
welcome ${user.uname}
(2) 在hello.jsp中嵌入head.jsp。
hello!
示例522
使用绝对地址,导入外部资源文件。
3.
表示发送HTTP的redirect到客户端,与调用HttpServletResponse.sendRedirect()相同,基本语法如下,属性见表59。
表59属性信息
属性名动态支持属性类型描述
urltrueString重定向的目标URL,绝对地址和相对地址都可以
contexttrueString当使用相对路径访问外部context资源时,指明外部context的名字
示例523
用户登录后,根据身份不同,跳转到不同的页面。
4.
表示添加请求参数给URL,在、、中都可以使用,基本语法如下,属性信息见表510。
表510属性信息
属性名动 态 支 持属 性 类 型描述
nametrueStringHTTP请求参数名
valuetrueStringHTTP请求参数值
示例524
使用与URL中直接绑定参数的效果相同:
5.3格式化标签库
在JSP页面显示数字、货币、百分比、日期、时间等数据时,需要按照本地敏感或定制格式显示,这时使用格式化标签库非常方便。
5.3.1格式化数字、货币、百分比
标签可以格式化数字、货币、百分比,基本语法如下:
示例525
<%@ taglib prefix="fmt" uri="jakarta.tags.fmt"%>
输出结果(自动按本地的货币格式显示): ¥9,876,543.21。
如果设置本地化环境为en_US,则输出结果为美国货币格式: $9,876,543.21。
示例526
<%
int rand = (int)(Math.random()*100);
request.setAttribute("rand", rand);
%>
输出结果(保留两位小数):
25.33
12.30
5.3.2格式化日期和时间
使用标签可以在JSP页面格式化日期和时间,基本语法如下:
示例527
<%@ taglib prefix="fmt" uri="jakarta.tags.fmt"%>
输出结果:
28/02/2020
2020-02-2820:46
5.4本章习题
(1) 下列不属于核心库标签的是()。
A. chooseB. ifC. fmtD. otherwise
(2) 下面不属于JSTL标签的是()。
A. 核心标签库B. 国际化/格式化标签库
C. HTML标签库D. SQL标签库
E. 函数标签库
(3) 以下代码配置了一个自定义标签,这段代码应该位于()。
Spring Framework JSP Tag Library
4.0
spring
http://www.springframework.org/tags
A. Tomcat的conf/server.xml文件中
B. Jakarta Web应用的WEBINF/web.xml文件中
C. 一个tld文件中
D. Jakarta Web应用的METAINF/context.xml文件中
(4) 以下不属于标签属性的是()。
A. varB. valueC. itemsD. varStatus
(5) 如下数据类型中,标签不能迭代的是()。
A. java.util.CollectionB. 静态数组
C. java.util.Map D. org.w3c.dom.Node
E. java.util.Iterator
(6) 以下不属于标签属性的是()。
A. varB. valueC. escapeXmlD. default
(7) 标签与<%=脚本表达式 %> 或 ${el表达式}的功能基本一致。(对/错)
(8) 使用标签,可以把指定的值存储到pageContext域对象中。(对/错)
(9) 中至少要包含一个子标签和一个 。(对/错)
(10) 导入资源,url可以是绝对路径也可以是相对路径。(对/错)