一、JSTL标签库
1.1、 分类:
核心标签库: c:if; c:forEach
国际化标签: 国际化相关类和原理
数据库标签 (略)
XML标签 (略)
JSTL函数(EL函数)
1.2、 需要的jar包: standard.jar jstl.jar
1.3、 参考核心标签库
二、编写自定义标签的步骤(自定义EL函数,步骤相同)
2.1、 JSP中标签继承体系
2.2、 JSP中常用标签接口
① Tag接口:其中的方法都是由容器调用的。
常量:
SKIP_BODY:忽略标签的主体内容。只为doStartTag方法服务
EVAL_BODY_INCLUDE:不忽略标签的主体内容。只为doStartTag方法服务
SKIP_PAGE:忽略结束标签之后的内容。只为doEndTag方法服务
EVAL_PAGE:不忽略结束标签之后的内容。只为doEndTag方法服务
方法:
int doStartTag():容器调用。遇到自定义标签的开始标签时被调用。
int doEndTag():容器调用。遇到自定义标签的结束时被调用。
void setPageContext(PageContext pc):由容器调用。处理标签之前就会调用。
void setParent(Tag t):由容器调用。处理标签之前就会调用。目标传递进父标签,没有传递null。
void release() :由容器调用,释放标签类占用的资源。
② IterationTag接口:继承Tag接口。增加重复执行主体内容的方法
int doAfterBody():执行完主体后会被容器调用该方法。
该方法的返回值只能是:
Tag.SKIP_BODY,忽略主体,进入结束标签处理。
IterationTag.EVAL_BODY_AGAIN,再执行一次主体内容。
执行流程 :
③ BodyTag接口:继承IterationTag接口。增加了获取主体内容的方法。
常量:
int EVAL_BODY_BUFFERED:给doStartTag()方法用的。只有返回该值,以下2个方法才会被容器调用。
方法:
void doInitBody():初始化主体。容器调用
void setBodyContent(BodyContent b) :设置主体内容。容器调用。BodyContent就代表着主体内容。
执行流程:
④ SimpleTag接口:
void doTag():遇到标签就执行。容器调用。
void setJspBody(JspFragment jspBody):容器调用。传入标签的主体内容。
void setJspContext(JspContext pc):容器调用。传入PageContext对象。
void setParent(JspTag parent):容器调用。传入父标签。
2.3、 应用: 自定义标签步骤 获取访问的客户机的IP地址
--------------------------------------------------------------------------------------------------------------------
①、编写一个类,直接或间接实现javax.servlet.jsp.tagext.Tag接口
//TagSupport实现了Tag接口
public class ShowRemoteIpTag extends TagSupport {
public int doStartTag() throws JspException {
String remoteIp = pageContext.getRequest().getRemoteAddr();
try {
pageContext.getOut().write(remoteIp);
} catch (IOException e) {
e.printStackTrace();
}
return super.doStartTag();
}
}
②、在WEB-INF目录下建立一个扩展名为tld(Tag Libary Definition)的xml文件。
<?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 http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<tlib-version>1.0</tlib-version>
<short-name>itcast</short-name>
<uri>http://www.itcast.cn/jsp/jstl</uri>
<tag><!-- 描述标签 -->
<description>Show Remote Address</description>
<name>showRemoteIp</name>
<tag-class>cn.itcast.tag.ShowRemoteIpTag</tag-class>
<body-content>empty</body-content><!-- 指示标签的主体内容:没有就写empty -->
</tag>
</taglib>
③、(可选的)在web.xml中对tld文件和名称空间进行映射对应。
<jsp-config>
<taglib>
<taglib-uri>http://www.itcast.cn/jsp/jstl</taglib-uri>
<taglib-location>/WEB-INF/itcast.tld</taglib-location>
</taglib>
</jsp-config>
④、在JSP中使用
<%@ taglib uri="http://www.itcast.cn/jsp/jstl" prefix="itcast"%>
<body>
您的IP地址为:<itcast:showRemoteIp/>
</body>
--------------------------------------------------------------------------------------------------------------------
三、标签执行步骤和原理
传统标签
简单标签
四、传统标签实现的附属功能
4.1、 控制jsp页面某一部分内容是否执行。(被标签包围的部分不显示,包括html标签)
--------------------------------------------------------------------------------------------------------------
<%@ taglib uri="http://www.itcast.cn/jsp/jstl" prefix="itcast"%>
<body>
我喜欢你
<itcast:demo2>芙蓉姐姐</itcast:demo2>
</body>
public class Demo2Tag extends TagSupport {
@Override
public int doStartTag() throws JspException {
return Tag.SKIP_BODY;
}
}
<tag>
<name>demo2</name>
<tag-class>cn.itcast.tag.Demo2Tag</tag-class>
<body-content>JSP</body-content><!-- 指示标签的主体内容:有就写JSP,即JSP中能出现什么,标签中就能出现什么 -->
</tag>
--------------------------------------------------------------------------------------------------------------
4.2、 控制结束标签后的JSP内容是否执行
--------------------------------------------------------------------------------------------------------------
<%@ taglib uri="http://www.itcast.cn/jsp/jstl" prefix="itcast"%>
<body>
他喜欢你
<itcast:demo3/>芙蓉姐姐a
</body>
public class Demo3Tag extends TagSupport {
@Override
public int doEndTag() throws JspException {
return Tag.SKIP_PAGE;
}
}
<tag>
<name>demo3</name>
<tag-class>cn.itcast.tag.Demo3Tag</tag-class>
<body-content>empty</body-content>
</tag>
--------------------------------------------------------------------------------------------------------------
4.3、 控制jsp页面内容重复执行。
--------------------------------------------------------------------------------------------------------------
<%@ taglib uri="http://www.itcast.cn/jsp/jstl" prefix="itcast"%>
<body>
<!-- 让标签的主体内容重复执行3次 -->
<itcast:demo4 count="10"><hr/></itcast:demo4>
</body>
public class Demo4Tag extends TagSupport {
private int count;
private int temp;
// 在调用doStartTag之前,容器会把属性的值自动传进来
public void setCount(int count) {
this.count = count;
this.temp = count;
}
@Override
public int doStartTag() throws JspException {
return Tag.EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
count--;
// 如果count>0,再执行一次主体内容
if(count>0){
return IterationTag.EVAL_BODY_AGAIN;
}else{
// 否则,进入结束标签
count = temp; // 重新定为3,防止下次访问时内存中为0
return Tag.SKIP_BODY;
}
}
}
<tag>
<name>demo4</name>
<tag-class>cn.itcast.tag.Demo4Tag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>count</name>
<required>true</required> <!-- 是否为必须的属性 -->
<rtexprvalue>true</rtexprvalue>
<!-- rt:RunTime expr:expression value:值 是否支持表达式: EL或者Java表达式 若为false 只支持直接量 -->
</attribute>
</tag>
--------------------------------------------------------------------------------------------------------------
4.4、 修改页面内容输出
--------------------------------------------------------------------------------------------------------------
<%@ taglib uri="http://www.itcast.cn/jsp/jstl" prefix="itcast"%>
<body>
<!-- 将主体内容改为大写输出 -->
<itcast:demo5>asdafsdf</itcast:demo5>
</body>
public class Demo5Tag extends BodyTagSupport {
// 要保证主体内容被容器传递进来
@Override
public int doStartTag() throws JspException {
return BodyTag.EVAL_BODY_BUFFERED;
}
// 把修改后的主体内容输出到页面上
@Override
public int doEndTag() throws JspException {
// 得到主体内容
String content = bodyContent.getString();
try {
pageContext.getOut().write(content.toUpperCase());
} catch (IOException e) {
e.printStackTrace();
}
return super.doEndTag();
}
}
<tag>
<name>demo5</name>
<tag-class>cn.itcast.tag.Demo5Tag</tag-class>
<body-content>JSP</body-content>
</tag>
--------------------------------------------------------------------------------------------------------------
五、简单标签实现的附属功能
5.0 输出客户机的IP地址
--------------------------------------------------------------------------------------------------------------
<%@ taglib uri="http://www.itcast.cn/jsp/tag/simple" prefix="sitcast" %>
<body>
您的IP地址为:<sitcast:showRemoteIp/>
</body>
public class ShowRemoteIpSimpleTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
// pageContest继承于JspContext,在父类JspContest中通过getJspContext()方法可以获得,需要强转
PageContext pc = (PageContext) getJspContext();
// 再由pageContext获取八大对象
String remoteIp = pc.getRequest().getRemoteAddr();
pc.getOut().write(remoteIp);
}
}
<tag><!-- 描述标签 -->
<description>Show Remote Address</description>
<name>showRemoteIp</name>
<tag-class>cn.itcast.stag.ShowRemoteIpSimpleTag</tag-class>
<body-content>empty</body-content><!-- 指示标签的主体内容:没有就写empty -->
</tag>
--------------------------------------------------------------------------------------------------------------
5.1 控制jsp页面某一部分内容是否执行。(被标签包围的部分不显示,包括html标签)
--------------------------------------------------------------------------------------------------------------
<%@ taglib uri="http://www.itcast.cn/jsp/tag/simple" prefix="sitcast"%>
<body>
我喜欢你
<sitcast:demo2>芙蓉姐姐</sitcast:demo2>
</body>
public class Demo2SimpleTag extends SimpleTagSupport {
// 该方法什么都不做,那么主体内容就不显示
@Override
public void doTag() throws JspException, IOException {}
}
// 若向显示主体内容,则使用该方法
@Override
public void doTag() throws JspException, IOException {}
// 该方法暴力访问设置浏览器显示隐藏的内容,但是源码中仍不显示
// @Override
// public void doTag() throws JspException, IOException {
// // 获取主体内容
// JspFragment jf = getJspBody();
// // 把主体内容输出到指定的流中,输入即可
// PageContext pc = (PageContext) getJspContext();
// JspWriter out = pc.getOut();
// jf.invoke(out);
//该方法与上面被注释的代码作用完全相同
getJspBody().invoke(null);
}
}
<tag>
<name>demo2</name>
<tag-class>cn.itcast.stag.Demo2SimpleTag</tag-class>
<body-content>scriptless</body-content> <!-- 简单标签中如果有主体内容,则写scriptless -->
</tag>
--------------------------------------------------------------------------------------------------------------
5.2 控制结束标签后的JSP内容是否执行
--------------------------------------------------------------------------------------------------------------
<%@ taglib uri="http://www.itcast.cn/jsp/tag/simple" prefix="sitcast"%>
<body>
他喜欢你
芙<sitcast:demo3/>蓉姐姐a
</body>
public class Demo3SimpleTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
// 扔此异常,则结束标签后的JSP内容不执行
throw new SkipPageException();
}
}
<tag>
<name>demo3</name>
<tag-class>cn.itcast.stag.Demo3SimpleTag</tag-class>
<body-content>empty</body-content> <!-- 简单标签中如果没有主体内容,则写empty -->
</tag>
--------------------------------------------------------------------------------------------------------------
5.3、 控制jsp页面内容重复执行。
--------------------------------------------------------------------------------------------------------------
<%@ taglib uri="http://www.itcast.cn/jsp/tag/simple" prefix="sitcast"%>
<body>
<!-- 让标签的主体内容重复执行5次 支持直接量5 EL表达式${1+4} Java表达式<%=1+2 %> -->
<sitcast:demo4 count="${1+3}"><hr/></sitcast:demo4>
</body>
public class Demo4SimpleTag extends SimpleTagSupport {
private int count; // 自动类型转换仅限基本类型
public void setCount(int count) {
this.count = count;
}
@Override
public void doTag() throws JspException, IOException {
for(int i=0;i<count;i++){
// 输出主体内容
getJspBody().invoke(null);
}
}
}
<tag>
<name>demo4</name>
<tag-class>cn.itcast.stag.Demo4SimpleTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>count</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
--------------------------------------------------------------------------------------------------------------
5.4、 修改页面内容输出
--------------------------------------------------------------------------------------------------------------
<%@ taglib uri="http://www.itcast.cn/jsp/tag/simple" prefix="sitcast"%>
<body>
<!-- 将主体内容改为大写输出 -->
<sitcast:demo5>asdafsdf</sitcast:demo5>
</body>
public class Demo5SimpleTag extends SimpleTagSupport {
// 必须拿到要修改的主体内容
@Override
public void doTag() throws JspException, IOException {
// 得到缓冲字符串输出流,用来缓存主体内容
StringWriter sw = new StringWriter();
// 获取主体内容
JspFragment jf = getJspBody();
jf.invoke(sw);
String content = sw.toString();
// 输出
PageContext pc = (PageContext) getJspContext();
pc.getOut().write(content.toUpperCase());
}
}
<tag>
<name>demo5</name>
<tag-class>cn.itcast.stag.Demo5SimpleTag</tag-class>
<body-content>scriptless</body-content>
</tag>
--------------------------------------------------------------------------------------------------------------
六、 标签的配置元素详解
tld文件:
taglib:根元素
tlib-version:版本号
short-name:引用标签时的短名称。一般与tld文件的文件名一致,好找。
uri:标签绑定的名称空间。只是一个名字,没有实际的意义。
tag:定义标签元素
name:标签的名称。
tag-class:标签的实现类的全名称。
body-content:指示标签的主体内容的类型。
可选值:
empty:没有主体内容。适用于传统和简单标签。
JSP:说明JSP文件中能出现啥,标签主体内容中就能出现啥。适用于传统标签。
scriptless:说明标签的主体内容不能是java脚本。适用于简单标签。
tagdependent:说明标签的主体内容是原封不动的传递给标签处理类的。
而不是传递的运算结果
attribute:定义标签的属性
name:属性名。对应标签处理类中的setter方法
required:是否是必须的属性
rtexprvalue:是否支持表达式(EL或java表达式)。默认是false。
七、标签的实用案例:
防盗链的开发
模拟c:if
模拟c:when c:otherwise c:choose
模拟c:forEach 熟悉 java.lang.reflect.Array类的使用
过滤HTML标记的标签
八、JSTL中的剩余核心标签
-------------------------------------------------------------------------------------------------------------------------
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<body>
<!-- c:out:输出内容到页面上 注: 会自动转义HTML标签 escapeXml默认为true(不转义) -->
<%
pageContext.setAttribute("data","hello<hr/>");
%>
<c:out value="hello JSTL"></c:out> <br/><br/>
<c:out value="${data}" ></c:out> <br/><br/>
<c:out value="${data}" escapeXml="false"></c:out> <br/><br/>
<c:out value="${data1}" default="没有值"></c:out>
<hr/>
<!-- c:set: 把某些对象绑定到域中 -->
<c:set var="s" value="hello itcast" scope="page"></c:set>
${s}<br/><br/>
<hr/>
<!-- c:set: 设置JavaBean的属性值 -->
<!-- 注: 创建一个JavaBean Person 字段有name,age,birthday -->
<jsp:useBean id="p1" class="cn.itcast.domain.Person"></jsp:useBean>
${p1.name}
<%--
p1.setName("朱巧玲"); 被<c:set标签>替代
--%>
<c:set value="朱巧玲" property="name" target="${p1}"></c:set>
${p1.name}<br/><br/>
<hr/>
<!-- c:set: 设置map对象的key和value -->
<%
pageContext.setAttribute("map",new HashMap());
%>
<c:set value="i am value1" property="i an key1" target="${map}"></c:set>
<c:set value="i am value2" property="i an key2" target="${map}"></c:set>
<c:forEach items="${map}" var="me">
${me} <br/>
</c:forEach>
<hr/>
<!-- c:remove: 用于删除各种Web域中的属性 略 -->
<!-- c:catch: 用于捕获JSP中的异常 其中参数:var="e": e就是引用异常对象的名称 由${e.message}获取该异常 -->
<c:catch var="e">
<%=1/0 %>
</c:catch>
${e.message}
<hr/>
<!-- c:choose c:when c:otherwise 作用等同于if else-->
<!--
choose无法单独使用,只是作为when和otherwise的父标签而存在,用来传递数据的
when和otherwise必须出现在choose中
choose中可以有多个when,但是不可以只有otherwise
choose中可以有多个when,但只能有一个otherwise或没有。 有otherwise必须出现在when的最后面
-->
<c:set value="F" var="grade" scope="page"></c:set>
<c:choose>
<c:when test="${grade=='A'}">
优秀
</c:when>
<c:when test="${grade=='B'}">
良好
</c:when>
<c:when test="${grade=='C'}">
及格
</c:when>
<c:otherwise>
差
</c:otherwise>
</c:choose>
<hr/>
<!-- c:import: 动态包含,如同jsp:include -->
<!-- c:redirect: 请求重定向 -->
<!--c:url: 组织url字符串,不指定var属性会把value的值直接打到页面上 ;能进行url重写; -->
<c:url value="/example/bbs.jsp" ></c:url><br/><br/>
<%--
pageContext.setAttribute("uu","/example/bbs.jsp");
--%>
<c:url value="/example/bbs.jsp" var="uu" scope="page"></c:url>
<a href="${uu}">BBS论坛</a><br/><br/>
<!-- c:param 传递参数,并自动对不安全的数据进行url编码 -->
<c:url value="/example/result.jsp" var="vv" scope="page">
<c:param name="content" value="hello 你好" ></c:param>
</c:url>
<a href="${vv}">点击</a>
<hr/>
<!-- c:forTokens : 拆分分界符 -->
<c:forTokens items="2015-08/17" delims="-/" var="s">
${s}<br/>
</c:forTokens>
</body>
-------------------------------------------------------------------------------------------------------------------------
九、国际化的JSTL标签库(略)