07Java--JSP自定义标签
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了07Java--JSP自定义标签相关的知识,希望对你有一定的参考价值。
自定义标签
自定义标签
自定义标签主要用于移除Jsp页面中的java代码。
在JSP中使用自定义标签的开发步骤如下:
开发一个对应的Java类。
配置这个Java类,使它成为一个标签。
使用tablib指令引入。
编写一个实现Tag接口的Java类(标签处理类)
public class ViewTag implements Tag {
private PageContext mPageContext;
@Override
public void setPageContext(PageContext pageContext) {
mPageContext = pageContext;
}
@Override
public void setParent(Tag tag) {
}
@Override
public Tag getParent() {
return null;
}
@Override
public int doStartTag() throws JspException {
System.out.println("调用doStartTag()方法");
HttpServletRequest request = (HttpServletRequest) mPageContext.getRequest();
JspWriter out = mPageContext.getOut();
String ip = request.getRemoteAddr();
try {
out.write(ip);
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
@Override
public int doEndTag() throws JspException {
System.out.println("调用doEndTag()方法");
return 0;
}
@Override
public void release() {
System.out.println("调用release()方法");
}
}
在WEB-INF/目录下新建tld文件,在tld文件中对标签处理器类进行描述
legend.tld文件的代码如下:
<?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">
<!-- description用来添加对taglib(标签库)的描述 -->
<description>开发的自定义标签库</description>
<!--taglib(标签库)的版本号 -->
<tlib-version>1.0</tlib-version>
<short-name>GaclTagLibrary</short-name>
<!--
为自定义标签库设置一个uri,uri以/开头,/后面的内容随便写,如这里的/legend ,
在Jsp页面中引用标签库时,需要通过uri找到标签库
在Jsp页面中就要这样引入标签库:<%@taglib uri="/legend" prefix="legend"%>
-->
<uri>/legend</uri>
<!--一个taglib(标签库)中包含多个自定义标签,每一个自定义标签使用一个tag标记来描述 -->
<!-- 一个tag标记对应一个自定义标签 -->
<tag>
<description>这个标签的作用是用来输出客户端的IP地址</description>
<!--
为标签处理器类配一个标签名,在Jsp页面中使用标签时是通过标签名来找到要调用的标签处理器类的
通过viewIP就能找到对应的com.legend.tag.ViewTag类
-->
<name>viewIP</name>
<!-- 标签对应的处理器类-->
<tag-class>com.legend.tag.ViewTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
在Jsp页面中使用自定义标签
使用"<%@taglib uri="标签库的uri" prefix="标签的使用前缀"%>"指令引入要使用的标签库。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="xdp" uri="/legend" %>
<html>
<head>
<title>输出客户端IP</title>
</head>
<body>
使用自定义标签获取IP地址是:<xdp:viewIP/>
</body>
</html>
输出结果:
使用自定义标签获取IP地址是:127.0.0.1
这就是开发和使用自定义标签的好处,可以让我们的Jsp页面上不嵌套java代码,下面我们看下自定义标签的调用过程:
setPageContext(PageContext pc) -> setParent(Tag t) -> doStartTag() -> doEndTag() -> release()
传统标签(暂略)
传统标签在实际开发中由于技术过于落后,所以不再使用,这里待以后补充。
简单标签使用
由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广, SUN公司为降低标签技术的学习难度,在JSP 2.0中
定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。
SimpleTag介绍
实现SimpleTag接口的标签通常称之为简单标签,简单标签共定义5个方法:
方法 | 描述 |
---|---|
setJspContext() | 用于把JSP页面的pageContext对象传递给标签处理器对象。 |
setParent() | 用于把父标签处理器对象传递给当前标签处理器对象。 |
getParent() | 用于获得当前标签的父标签处理器对象。 |
setJspBody() | 用于把代表标签体的JspFragment对象传递给标签处理器对象。 |
doTag() | 重要,用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。 |
其中方法的执行顺序如下:
开发简单标签
SUN公司针对SimpleTag接口提供了一个默认的实现类SimpleTagSupport,SimpleTagSupport类中实现了SimpleTag接口的所有方法,
因此我们可以编写一个类继承SimpleTagSupport类,然后根据业务需要再重写doTag方法。
控制jsp页面某一部分内容执行
SimpleTagDemo.java
public class SimpleTagDemo extends SimpleTagSupport {
/**
* 简单标签使用doTag()方法就可以完成所有业务逻辑
*/
@Override
public void doTag() throws JspException, IOException {
// 得到代表jsp标签提的JspFragment
JspFragment jspFragment = this.getJspBody();
// 得到jsp页面的PageContext对象
PageContext pageContext = (PageContext) jspFragment.getJspContext();
// 调用JspWriter将标签内容输出到浏览器
jspFragment.invoke(pageContext.getOut());
}
}
在WEB-INF目录下新建一个simpletag.tld文件,然后在simpletag.tld文件中添加对该标签处理类的描述,如下:
<?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">
<!-- description用来添加对taglib(标签库)的描述 -->
<description>SimpleTag自定义标签库</description>
<!--taglib(标签库)的版本号 -->
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<!--
为自定义标签库设置一个uri,uri以/开头,/后面的内容随便写,如这里的/simpletag ,
在Jsp页面中引用标签库时,需要通过uri找到标签库
在Jsp页面中就要这样引入标签库:<%@taglib uri="/simpletag" prefix="gacl"%>
-->
<uri>/simpletag</uri>
<!--一个taglib(标签库)中包含多个自定义标签,每一个自定义标签使用一个tag标记来描述 -->
<!-- 一个tag标记对应一个自定义标签 -->
<tag>
<description>SimpleTag(简单标签)</description>
<!--
为标签处理器类配一个标签名,在Jsp页面中使用标签时是通过标签名来找到要调用的标签处理器类的
通过demo1就能找到对应的com.legend.simple.SimpleTagDemo1类
-->
<name>demo</name>
<!-- 标签对应的处理器类-->
<tag-class>com.legend.simple.SimpleTagDemo</tag-class>
<!--
tld文件中有四种标签体类型 :empty JSP scriptless tagdepentend
在简单标签(SampleTag)中标签体body-content的值只允许是empty和scriptless,不允许设置成JSP,如果设置成JSP就会出现异常
在传统标签中标签体body-content的值只允许是empty和JSP。如果标签体body-content的值设置成tagdepentend,那么就表示标签
体里面的内容是给标签处理器类使用的。
-->
<body-content>scriptless</body-content>
</tag>
</taglib>
在jsp页面中导入并使用自定义标签,如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="legend" uri="/simpletag" %>
<html>
<head>
<title>简单标签控制标签体是否执行</title>
</head>
<body>
<legend:demo>
legend
</legend:demo>
</body>
</html>
输出结果:
legend
控制jsp页面内容重复执行
如果要重复输出的话,我们只需要修改上面的例子中的java代码即可,修改SimpleTagDemo1的代码如下:
public class SimpleTagDemo1 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
JspFragment jspFragment = getJspBody();
// 循环输出五次即可
for (int i = 0; i < 5; i++) {
jspFragment.invoke(null);
}
}
}
运行效果如下:
legend legend legend legend legend
修改jsp页面内容输出
public class SimpleTagDemo1 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
JspFragment jspFragment = getJspBody();
StringWriter writer = new StringWriter();
// 将标签体的内容写入到StringWriter流中
jspFragment.invoke(writer);
// 获取StringWriter流的内容,转成字符串,并转换为大写形式
String content = writer.getBuffer().toString();
content = content.toUpperCase();
PageContext context = (PageContext) jspFragment.getJspContext();
// 将修改后的content输出到浏览器
context.getOut().write(content);
}
}
输出结果:
LEGEND
控制整个jsp页面执行
编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法抛出SkipPageException异常即可,jsp收到这个异常,将忽略标签余下jsp页面的执行。
public class SimpleTagDemo4 extends SimpleTagSupport{
@Override
public void doTag() throws JspException, IOException {
// 抛出异常,在此处断开后续执行
throw new SkipPageException();
}
}
修改jsp文件如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="legend" uri="/simpletag" %>
<html>
<head>
<title>简单标签控制标签体是否执行</title>
</head>
<body>
<h1>人生得意须尽欢</h1>
<legend:demo1/>
<h1>莫使金樽空对月</h1>
</body>
</html>
此时执行到自定义标签则会抛出异常,导致后续的内容无法执行,所以输出结果是:
人生得意须尽欢
注意:
如果一个项目中包含多个tld的文件,只需要保证uri不一样即可,如果存在一样的情况,可以在jsp页面使用另外一种引入方式:
<%@taglib uri="/WEB-INF/simpletag.tld" prefix="legend"%>
JspFragment类介绍
javax.servlet.jsp.tagext.JspFragment类是在JSP2.0中定义的,它的实例对象代表JSP页面中的一段符合JSP语法规范的JSP片段,这段JSP片段中不能包含JSP脚本元素。
WEB容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象表示,并调用标签处理器对象的setJspBody方法把JspFragment对象传递给标签处理器对象。
JspFragment类中只定义了两个方法,如下所示:
getJspContext():用于返回代表调用页面的JspContext对象.
invoke(Writer out):用于执行JspFragment对象所代表的JSP代码片段,参数out用于将JspFragment对象的执行结果写入到输出流中,
如果传递参数out的值为null,则将执行结果写入到JspContext.getOut()方法返回的输出流对象中。
spFragment.invoke方法是JspFragment最重要的方法,利用这个方法可以控制是否执行和输出标签体的内容、是否迭代执行标签体的内容或对标签体的执行结果进行修改后再输出。
开发属性标签
自定义标签可以定义一个或多个属性,这样,在JSP页面中应用自定义标签时就可以设置这些属性的值,通过这些属性为标签处理器传递参数信息,从而提高标签的灵活性和复用性。
要想让一个自定义标签具有属性,通常需要完成两个任务:
在标签处理器中编写每个属性对应的setter方法
在TLD文件中描术标签的属性
为自定义标签定义属性时,每个属性都必须按照JavaBean的属性命名方式,在标签处理器中定义属性名对应的setter方法,用来接收 JSP页面调用自定义标签时传递进来的属性值。
在标签处理器中定义相应的set方法后,JSP引擎在解析执行开始标签前,也就是调用doStartTag方法前,会调用set属性方法,为标签设置属性。
tld文件中用于描述标签属性的<attribute>元素说明
<tag>元素的<attribute>子元素用于描述自定义标签的一个属性,自定义标签所具有的每个属性都要对应一个<attribute>元素
<tag>
<!-- 标签名 -->
<name>demo</name>
<!-- 标签处理器类-->
<tag-class>com.legend.simple.SimpleTagDemo</tag-class>
<!-- 标签体允许的内容-->
<body-content>scriptless</body-content>
<!-- 标签的属性描述 -->
<attribute>
<description>描述标签的count属性</description>
<!-- 标签的count属性 -->
<name>count</name>
<required>true</required>
<!-- rtexprvalue用来指示标签的属性值是否可以是一个表达式,
一般设置为true,true就表示允许标签的属性值可以是一个表达式-->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<attribute\\>元素的子元素说明:
属性名 | 是否必须 | 描述 |
---|---|---|
description | 否 | 用于指定属性的描述信息。 |
name | 是 | 用于指定属性的名称。大小写敏感,不能以jsp、_jsp、java和sun开头。 |
required | 否 | 用于指定在JSP页面中调用自定义标签时是否必须设置这个属性。true表示必须设置,false则可以设置或不设置该属性。 |
rtexprvalue | 否 | 用于执行属性值是一个静态值或动态值,true表示可以指定属性值是动态元素,false则表示只能指定属性的值为静态的文本值。 |
type | 否 | 用于指定属性值的Java类型。 |
范例1:通过标签的属性控制标签体的执行次数
CustomAttrTag.java
public class CustomAttrTag extends SimpleTagSupport {
private int count;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
@Override
public void doTag() throws JspException, IOException {
JspFragment jspFragment = getJspBody();
for (int i = 0; i < count; i++) {
jspFragment.invoke(null);
}
}
}
在WEB-INF目录下的tld文件中添加对该标签的描述,如下所示:
<?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">
<description>简单属性标签</description>
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/simpleattr</uri>
<tag>
<!-- 标签名 -->
<name>attrtag</name>
<!-- 标签处理器类-->
<tag-class>com.legend.simple.CustomAttrTag</tag-class>
<!-- 标签体允许的内容-->
<body-content>scriptless</body-content>
<!-- 标签的属性描述 -->
<attribute>
<description>描述标签的count属性</description>
<!-- 标签的count属性 -->
<name>count</name>
<required>true</required>
<!-- rtexprvalue用来指示标签的属性值是否可以是一个表达式,
一般设置为true,true就表示允许标签的属性值可以是一个表达式-->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
在jsp页面引入标签库并使用自定义标签
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="legend" uri="/simpleattr" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--使用自定义属性标签显示结果--%>
<legend:attrtag count="5">
<h1>Hello World</h1>
</legend:attrtag>
</body>
</html>
输出结果:
Hello World
Hello World
Hello World
Hello World
Hello World
注意:如果标签的属性值是8种基本数据类型,那么在JSP页面在传递字符串时,JSP引擎会自动转换成相应的类型,但如果标签的属性值是复合数据类型,那么JSP引擎是无法自动转换的。
范例2:标签属性值是复合数据类型的赋值
CustomAttrTag.java
public class CustomAttrTag extends SimpleTagSupport {
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public void doTag() throws JspException, IOException {
getJspContext().getOut().write(date.toLocaleString());
}
}
在WEB-INF目录下的tld文件中添加对该标签的描述,如下所示:
<?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">
<description>简单属性标签</description>
<tlib-version>1.0</tlib-version>
<short-name>SimpleTagLibrary</short-name>
<uri>/newSimpleAttr</uri>
<tag>
<name>attrtag</name>
<tag-class>com.legend.simple.CustomAttrTag</tag-class>
<body-content>empty</body-content>
<attribute>
<description>描述标签的count属性</description>
<name>date</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
在jsp页面引入标签库并使用自定义标签:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/newSimpleAttr" prefix="legend"%>
<!DOCTYPE HTML>
<html>
<head>
<title>如果标签接收的属性值是一个复合数据类型,该如何给标签的属性赋值</title>
</head>
<body>
<%--
在jsp页面中使用自定义标签,标签有一个date属性 ,是一个复合数据类型
如果标签的属性值是8种基本数据类型,那么在JSP页面在传递字符串时,JSP引擎会自动转换成相应的类型
但如果标签的属性值是复合数据类型,那么JSP引擎是无法自动转换的--%>
<%--如果一定要给标签的复合属性赋值,那么可以采用表达式的方式给复合属性赋值,如下所示: --%>
<%
Date d = new Date();
request.setAttribute("date", d);
%>
<legend:attrtag date="${date}"/>
<hr/>
<legend:attrtag date="<%=new Date()%>"/>
</body>
</html>
输出结果:
2017-7-4 4:25:20
2017-7-4 4:25:20
简单标签实战
开发防盗链标签
编写标签处理器类:RefererTag.java
public class RefererTag extends SimpleTagSupport {
// 网站域名
private String site;
// 要跳转的页面
private String page;
@Override
public void doTag() throws JspException, IOException {
PageContext pageContext = (PageContext) getJspContext();
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
// 获取请求的来路
String referer = request.getHeader("referer");
// 如果来路是空或者不是我们自己的网址则重定向到page页面
if (referer == null || !referer.startsWith(site)){
HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
String webRoot = request.getContextPath();
// 重定向到web页面
if (page.startsWith(webRoot)) {
response.sendRedirect(page);
}else {
response.sendRedirect(webRoot + page);
}
// 重定向后,控制保护的页面不被执行
throw new SkipPageException();
}
}
public void setSite(String netSite) {
this.site = netSite;
}
public void setPage(String page) {
this.page = page;
}
}
在WEB-INF目录下tld文件中添加对该标签的描述
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 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">
<description>防盗链标签</description>
<tlib-version>1.0</tlib-version>
<short-name>TagLib</short-name>
<uri>/legendTagLib</uri>
<tag>
<name>referer</name>
<tag-class>com.legend.simple.RefererTag</tag-class>
<body-content>empty</body-content>
<!--两个自定义标签属性-->
<attribute>
<description>描述标签的site属性</description>
<name>site</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>描述标签的page属性</description>
<name>page</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
在jsp页面中导入标签库并使用防盗链标签
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="legend" uri="/legendTagLib"%>
<%--在Jsp页面使用防盗链标签
当用户尝试通过URL地址访问页面时,防盗链标签的标签处理器就会将其重定向到其他jsp文件--%>
<legend:referer site="http://localhost:8080" page="/index.jsp"/>
<html>
<head>
<title>防盗链标签测试</title>
</head>
<body>
网站内部资料
</body>
</html>
其中跳转到到的index.jsp标签如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>公司网站</title>
</head>
<body>
<h1>网站首页</h1>
<h1><a href="referertag.jsp">查看资料</a></h1>
</body>
</html>
当我们通过 http://localhost:8080/referertag.jsp 去访问时,会自动跳转到index.jsp。如果想查看referertag.jsp的内容可以直接通过index.jsp中的查看网站即可。
开发<c:if>标签
编写标签处理器类:IFTag.java
public class IfTag extends SimpleTagSupport{
private boolean flag;
@Override
public void doTag() throws JspException, IOException {
PageContext pageContext = (PageContext) getJspContext();
if (flag) {
pageContext.getOut().write("您好,世界!");
}
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
在WEB-INF目录下tld文件中添加对该标签的描述
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 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">
<description>if标签</description>
<tlib-version>1.0</tlib-version>
<short-name>TagLib</short-name>
<tag>
<description>if标签</description>
<name>if</name>
<tag-class>com.legend.simple.IfTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<description>描述标签的site属性</description>
<name>flag</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
在jsp页面中导入标签库并使用if标签
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="/WEB-INF/ifTag.tld"%>
<html>
<head>
<title>if标签测试</title>
</head>
<body>
<%--if标签的flag属性值为true ,标签体的内容会输出--%>
<c:if flag="true"/>
<%--if标签的flag属性值为false ,标签体的内容不会输出--%>
<c:if flag="false"/>
</body>
</html>
开发when和otherwise
<c:when>标签和<c:otherwise>标签对应着两个不同的标签处理器类,我们希望做到的效果是,如果<c:when>标签执行了,那么就
<c:otherwise>标签就不要再执行,所需需要建立父标签来让两个标签共享变量。
开发父标签ChooseTag.java
public class OtherWiseTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
// 获取父标签实例
ChooseTag parentTag = (ChooseTag) getParent();
// 如果父标签下的when标签没有执行过
if (parentTag.isExecute() == false) {
getJspBody().invoke(null);
//设置父标签的isExecute属性为true,通知父标签自己已经执行过
parentTag.setExecute(true);
}
}
}
- 开发when标签和otherwise标签
whenTag.java
public class WhenTag extends SimpleTagSupport {
private boolean test;
@Override
public void doTag() throws JspException, IOException {
// 获取标签的父标签
ChooseTag parentTag = (ChooseTag) getParent();
if (test == true && parentTag.isExecute() == false) {
// 输出标签的内容
getJspBody().invoke(null);
// 将父标签的isExecute设置为true,通知父标签自己已经执行过
parentTag.setExecute(true);
}
}
public void setTest(boolean test) {
this.test = test;
}
}
OtherWise.java
public class OtherWiseTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
// 获取父标签实例
ChooseTag parentTag = (ChooseTag) getParent();
// 如果父标签下的when标签没有执行过
if (parentTag.isExecute() == false) {
getJspBody().invoke(null);
//设置父标签的isExecute属性为true,通知父标签自己已经执行过
parentTag.setExecute(true);
}
}
}
在WEB-INF目录下tld文件中添加对ChooseTag、WhenTag、OtherWiseTag这三对标签的描述
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 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">
<description>when和otherwise标签</description>
<tlib-version>1.0</tlib-version>
<short-name>choose</short-name>
<tag>
<description>choose标签</description>
<name>choose</name>
<tag-class>com.legend.simple.ChooseTag</tag-class>
<body-content>scriptless</body-content>
</tag>
<tag>
<description>when标签</description>
<name>when</name>
<tag-class>com.legend.simple.WhenTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<description>when标签的test属性</description>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<description>otherwise标签</description>
<name>otherwise</name>
<tag-class>com.legend.simple.OtherWiseTag</tag-class>
<body-content>scriptless</body-content>
</tag>
</taglib>
在jsp页面中导入标签库并测试when和otherwise标签
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="/WEB-INF/chooseTag.tld"%>
<html>
<head>
<title>when和otherwise标签</title>
</head>
<body>
<c:choose>
<c:when test="${user==null}">
when标签输出的内容:<h3>用户为空</h3>
</c:when>
<c:otherwise>
用户不为空
</c:otherwise>
</c:choose>
<hr/>
<c:choose>
<c:when test="${user!=null}">
用户不为空
</c:when>
<c:otherwise>
otherwise标签标签体输出的内容:<h3>用户为空</h3>
</c:otherwise>
</c:choose>
</body>
</html>
输出结果:
when标签输出的内容:
用户为空
otherwise标签标签体输出的内容:
用户为空
JSTL库
JSTL标签库的使用是为弥补html标签的不足,规范自定义标签的使用而诞生的。使用JSLT标签的目的就是不希望在jsp页面中出现java逻辑代码。
JSTL标签库有很多种分类,如下所示:
核心标签(用得最多)
国际化标签(I18N格式化标签)
数据库标签(SQL标签,很少使用)
XML标签(几乎不用)
JSTL函数(EL函数)
JSTL的核心标签库标签共13个,使用这些标签能够完成JSP页面的基本功能,减少编码工作。从功能上可以分为4类:表达式控制标签、流程控制标签、
循环标签、URL操作标签。
(1)表达式控制标签:out标签、set标签、remove标签、catch标签。
(2)流程控制标签:if标签、choose标签、when标签、otherwise标签。
(3)循环标签:forEach标签、forTokens标签。
(4)URL操作标签:import标签、url标签、redirect标签、param标签。
在JSP页面引入核心标签库的代码为:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
如果使用的idea的话则需要手动去引入JSTL库:
首先下载JSTL的库进行解压,然后拷贝lib下的两个jar包到工程的WEB-INF下的lib文件夹下。
然后选择File -> Setting -> languages&Frameworks -> Schemas and DTDs -> +号,然后在URL输出如下内容:
之后选择explorer找到解压文件的tld目录下的c.tld文件,然后保存即可。
表达式标签
<c:out \\>标签
<c:out \\>标签主要是用来输出数据对象(字符串、表达式)的内容或结果。
<c:out \\>标签的使用有两种语法格式:
【语法1】:<c:out value=”要显示的数据对象” [escapeXml=”true|false”] [default=”默认值”]/>
【语法2】:<c:out value=”要显示的数据对象” [escapeXml=”true|false”]>默认值</c:out>
这两种方式没有本质的区别,只是格式上的差别。[escapeXml=”true|false”] [default=”默认值”]这些使用[]属性表示是不是必须的。
<c:out>标签的属性如下所示:
属性名 | 是否支持EL | 属性类型 | 描述 |
---|---|---|---|
value | true | Object | 指定要输出的内容。 |
escapeXml | true | Boolean | 指定是否将特殊字符进行HTML编码转换后再进行输出。 |
default | true | Object | 当value属性的值为空时,所输出的默认值。 |
范例:<c:count>标签的使用:
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>JSTL--out标签的使用</title>
</head>
<body>
<h3><c:out value="下面的代码演示了c:out的使用,以及在不同属性值状态下的结果。"/></h3>
<hr/>
<ul>
<%--(1)直接输出了一个字符串。 --%>
<li>(1)<c:out value="JSTL的out标签的使用" /></li>
<li>(2)<c:out value="<a href=\'http://www.cnblogs.com/\'>点击链接到博客园</a>" /></li>
<%--escapeXml="false"表示value值中的html标签不进行转义,而是直接输出 --%>
<li>(3)<c:out value="<a href=\'http://www.cnblogs.com/\'>点击链接到博客园</a>" escapeXml="false"/></li>
<%--(4)字符串中有转义字符,但在默认情况下没有转换。 --%>
<li>(4)<c:out value="<未使用字符转义>" /></li>
<%--(5)使用了转义字符<和>分别转换成<和>符号。 --%>
<li>(5)<c:out value="<使用字符转义>" escapeXml="false"></c:out></li>
<%--(6)设定了默认值,从EL表达式${null}得到空值,所以直接输出设定的默认值。 --%>
<li>(6)<c:out value="${null}">使用了默认值</c:out></li>
<%--(7)未设定默认值,输出结果为空。 --%>
<li>(7)<c:out value="${null}"></c:out></li>
<%--(8)设定了默认值,从EL表达式${null}得到空值,所以直接输出设定的默认值。 --%>
<li>(8)<c:out value="${null}" default="默认值"/></li>
<%--(9)未设定默认值,输出结果为空。 --%>
<li>(9)<c:out value="${null}"/></li>
</ul>
</body>
</html>
<c:set>标签
<c:set>标签用于把某一个对象存在指定的域范围内,或者将某一个对象存储到Map或者JavaBean对象中。
<c:set>标签的使用有四种语法格式:
语法1:存值,把一个值放在指定的域范围内。
<c:set value=”值1” var=”name1” [scope=”page|request|session|application”]/>
含义:把一个变量名为name1值为“值1”的变量存储在指定的scope范围内。
语法2:
<c:set var=”name2” [scope=”page|request|session|application”]>
值2
</c:set>
含义:把一个变量名为name2,值为值2的变量存储在指定的scope范围内。
语法3:
<c:set value=”值3” target=”JavaBean对象” property=”属性名”/>
含义:把一个值为“值3”赋值给指定的JavaBean的属性名。相当与setter()方法。
语法4:
<c:set target=”JavaBean对象” property=”属性名”>
值4
</c:set>
含义:把一个值4赋值给指定的JavaBean的属性名。
语法1和语法2是向scope范围内存储一个值,语法3和语法4是给指定的JavaBean赋值。
<c:set>标签的属性如下所示:
属性名 | 是否支持EL | 属性类型 | 描述 |
---|---|---|---|
value | true | Object | 用于指定属性值。 |
var | false | String | 用于指定要设置的Web域属性的名称。 |
scope | false | String | 用于指定属性所在的Web域。 |
target | true | Object | 用于指定要设置属性的对象,这个对象必须是JavaBean或Map。 |
property | true | String | 用于指定当前要为对象设置的属性名称。 |
范例:<c:set>标签的使用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<jsp:useBean id="person" class="com.legend.jstl.Person"/>
<%--负责实例化Bean,id指定实例化后的对象名,可以通过${person}得到person在内存中的值--%>
<!DOCTYPE HTML>
<html>
<head>
<title>JSTL--set标签</title>
</head>
<body>
<h3>代码给出了给指定scope范围赋值的示例。</h3>
<ul>
<%--通过<c:set>标签将data1的值放入page范围中。--%>
<li>把一个值放入page域中:<c:set var="data1" value="legend" scope="page"/></li>
<%--使用EL表达式从pageScope得到data1的值。--%>
<li>从page域中得到值:${pageScope.data1}</li>
<%--通过<c:set>标签将data2的值放入request范围中。--%>
<li>把一个值放入request域中:<c:set var="data2" value="vincent" scope="request"/></li>
<%--使用EL表达式从requestScope得到data2的值。--%>
<li>从request域中得到值:${requestScope.data2}</li>
<%--通过<c:set>标签将值name1的值放入session范围中。--%>
<li>把一个值放入session域中。<c:set var="name1" value="uding" scope="session"></c:set></li>
<%--使用EL表达式从sessionScope得到name1的值。--%>
<li>从session域中得到值:${sessionScope.name1} </li>
<%--把name2放入application范围中。 --%>
<li>把一个值放入application域中。<c:set var="name2" scope="application">kevin</c:set></li>
<%--使用EL表达式从application范围中取值,用<c:out>标签输出使得页面规范化。 --%>
<li>使用out标签和EL表达式嵌套从application域中得到值:
<c:out value="${applicationScope.name2}">未得到name的值</c:out>
</li>
<%--不指定范围使用EL自动查找得到值 --%>
<li>未指定scope的范围,会从不同的范围内查找得到相应的值:${data1}、${data2}、${name1}、${name2}</li>
</ul>
<hr/>
<h3>使用Java脚本实现以上功能</h3>
<ul>
<%--注意:使用<%=%>的方式代替out.println()比较好--%>
<li>把一个值放入page域中。<%pageContext.setAttribute("data1","legend");%></li>
<li>从page域中得到值:<%out.println(pageContext.getAttribute("data1"));%></li>
<li>把一个值放入request域中。<%request.setAttribute("data2","vincent");%></li>
<li>从request域中得到值:<%out.println(request.getAttribute("data2"));%></li>
<li>把一个值放入session域中。<%session.setAttribute("name1","uding");%></li>
<li>从session中域得到值:<%=session.getAttribute("name1") %></li>
<li>把另一个值放入application域中。<%application.setAttribute("name2","kevin");%></li>
<li> 从application域中得到值:<%=application.getAttribute("name2")%>;</li>
<li>未指定scope的范围,会从不同的范围内查找得到相应的值:
<%=pageContext.findAttribute("data1")%>、
<%=pageContext.findAttribute("data2")%>、
<%=pageContext.findAttribute("name1")%>、
<%=pageContext.findAttribute("name2")%>
</li>
</ul>
<hr/>
<h3>操作JavaBean,设置JavaBean的属性值</h3>
<%--设置JavaBean的属性值,等同与setter方法,Target指向实例化后的对象,property指向要插入值的参数名。
注意:使用target时一定要指向实例化后的JavaBean对象,要跟<jsp:useBean>配套使用--%>
<c:set target="${person}" property="name">legend</c:set>
<c:set target="${person}" property="age">25</c:set>
<ul>
<li>使用的目标对象为:${person}</li>
<li>从Bean中获得的name值为:<c:out value="${person.name}"></c:out></li>
<li>从Bean中获得的age值为:<c:out value="${person.age}"></c:out></li>
</ul>
<hr/>
<h3>操作Map</h3>
<%
Map map = new HashMap();
request.setAttribute("map",map);
%>
<%--将data对象的值存储到map集合中 --%>
<c:set property="data" value="legend" target="${map}"/>
${map.data}
</body>
</html>
jsp页面中使用到的javabean.Person类的代码如下:
public class Person {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
输出结果:
代码给出了给指定scope范围赋值的示例。
把一个值放入page域中:
从page域中得到值:legend
把一个值放入request域中:
从request域中得到值:vincent
把一个值放入session域中。
从session域中得到值:uding
把一个值放入application域中。
使用out标签和EL表达式嵌套从application域中得到值: kevin
未指定scope的范围,会从不同的范围内查找得到相应的值:legend、vincent、uding、kevin
使用Java脚本实现以上功能
把一个值放入page域中。
从page域中得到值:legend
把一个值放入request域中。
从request域中得到值:vincent
把一个值放入session域中。
从session中域得到值:uding
把另一个值放入application域中。
从application域中得到值:kevin
kevin
未指定scope的范围,会从不同的范围内查找得到相应的值: legend、 vincent、 uding、 kevin
操作JavaBean,设置JavaBean的属性值
使用的目标对象为:com.legend.jstl.Person@2b03228f
从Bean中获得的name值为:legend
从Bean中获得的age值为:25
操作Map
legend
remove标签
<c:remove>标签主要用来从指定的JSP范围内移除指定的变量。
<c:remove var=”变量名” [scope=”page|request|session|application”]/>
范例:<c:remove>标签的使用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML>
<html>
<head>
<title>JSTL--remove标签</title>
</head>
<body>
<ul>
<c:set var="name" scope="session">legend</c:set>
<c:set var="age" scope="session">25</c:set>
<li><c:out value="${sessionScope.name}"></c:out></li>
<li><c:out value="${sessionScope.age}"></c:out></li>
<%--使用remove标签移除age变量 --%>
<c:remove var="age" />
<li><c:out value="${sessionScope.name}"></c:out></li>
<li><c:out value="${sessionScope.age}"></c:out></li>
</ul>
</body>
</html>
输出结果:
legend
25
legend
<c:catch>标签
<c:catch>标签用于捕获嵌套在标签体中的内容抛出的异常。
<c:catch [var="varName"]>容易产生异常的代码</c:catch>
var属性用于标识<c:catch>标签捕获的异常对象,它将保存在page这个Web域中。
范例:<c:catch>标签的使用
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML>
<html>
<head>
<title>JSTL: --表达式控制标签“catch”标签实例</title>
</head>
<body>
<h4>catch标签实例</h4>
<hr>
<%--把容易产生异常的代码放在<c:catch></c:catch>中,
自定义一个变量errorInfo用于存储异常信息 --%>
<c:catch var="errorInfo">
<%--实现了一段异常代码,向一个不存在的JavaBean中插入一个值--%>
<c:set target="person" property="hao"></c:set>
</c:catch>
<%--用EL表达式得到errorInfo的值,并使用<c:out>标签输出 --%>
异常:<c:out value="${errorInfo}" /><br />
异常 errorInfo.getMessage:<c:out value="${errorInfo.message}" /><br />
异常 errorInfo.getCause:<c:out value="${errorInfo.cause}" /><br />
异常 errorInfo.getStackTrace:<c:out value="${errorInfo.stackTrace}" />
</body>
</html>
运行结果:
catch标签实例
异常:javax.servlet.jsp.JspTagException: Invalid property in <set>: "hao"
异常 errorInfo.getMessage:Invalid property in <set>: "hao"
异常 errorInfo.getCause:
异常 errorInfo.getStackTrace:[Ljava.lang.StackTraceElement;@4afd104f
流程控制标签
<c:if>标签
<c:if>标签和程序中的if语句作用相同,用来实现条件控制。
【语法1】:没有标签体内容(body)
<c:if test="testCondition" var="varName" [scope="{page|request|session|application}"]/>
【语法2】:有标签体内容
<c:if test="testCondition" [var="varName"] [scope="{page|request|session|application}"]>
标签体内容
</c:if>
【参数说明】:
(1)test属性用于存放判断的条件,一般使用EL表达式来编写。
(2)var属性用来存放判断的结果,类型为true或false。
(3)scopes属性用来指定var属性存放的范围。
<c:if>标签的属性如下所示:
属性名 | 是否支持EL | 属性类型 | 描述 |
---|---|---|---|
test | true | boolean | 决定是否处理标签体中的内容的条件表达式 |
var | false | String | 将test属性的执行结果保存到某个Web域中的某个属性的名称。 |
scope | false | String | 指定将test属性的执行结果保存到哪个Web域中。 |
范例:<c:if>标签的使用
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>JSTL--if标签</title>
</head>
<body>
<h4>if标签示例</h4>
<hr>
<form action="index.jsp" method="post">
<input type="text" name="uname" value="${param.uname}">
<input type="submit" value="登录">
</form>
<%--使用if标签进行判断并把检验后的结果赋给adminchock,存储在默认的page范围中。 --%>
<c:if test="${param.uname==\'admin\'}" var="adminchock">
<%--可以把adminchock的属性范围设置为session,这样就可以在其他的页面中得到adminchock的值,
使用<c:if text=”${adminchock}”><c:if>判断,实现不同的权限。 --%>
<c:out value="管理员欢迎您!"/>
</c:if>
<%--使用EL表达式得到adminchock的值,如果输入的用户名为admin将显示true。 --%>
${adminchock}
</body>
</html>
输出结果:
- <c:choose>、<c:when>和<c:otherwise>
<c:choose> <c:when>和<c:otherwise>这3个标签通常情况下是一起使用的,<c:choose>标签作为<c:when>和<c:otherwise>标签的父标签来使用。
使用<c:choose>,<c:when>和<c:otherwise>三个标签,可以构造类似 “if-else if-else” 的复杂条件判断结构。
<c:choose>
<c:when test="条件1">
//业务逻辑1
<c:when>
<c:when test="条件2">
//业务逻辑2
<c:when>
<c:when test="条件n">
//业务逻辑n
<c:when>
<c:otherwise>
//业务逻辑
</c:otherwise>
</c:choose>
范例:<c:choose>及其嵌套标签用法
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%--引入JSTL核心标签库 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML>
<html>
<head>
<title>JSTL-- choose及其嵌套标签</title>
</head>
<body>
<h4>choose及其嵌套标签</h4>
<hr/>
<%--通过set标签设定score的值为85 --%>
<c:set var="score" value="85"/>
<c:choose>
<%--使用<c:when>进行条件判断。
如果大于等于90,输出“您的成绩为优秀”;
如果大于等于70小于90,输出“您的成绩为良好”;
大于等于60小于70,输出“您的成绩为及格”;
其他(otherwise)输出“对不起,您没能通过考试”。
--%>
<c:when test="${score>=90}">
你的成绩为优秀!
</c:when>
<c:when test="${score>70 && score<90}">
您的成绩为良好!
</c:when>
<c:when test="${score>60 && score<70}">
您的成绩为及格
</c:when>
<c:otherwise>
对不起,您没有通过考试!
</c:otherwise>
</c:choose>
</body>
</html>
运行结果:
choose及其嵌套标签示例
您的成绩为良好!
<c:forEach>标签
<c:forEach>标签根据循环条件遍历集合(Collection)中的元素。
<c:forEach
var=”name”
items=”Collection”
varStatus=”StatusName”
begin=”begin”
end=”end”
step=”step”>
本体内容
</c:forEach>
【参数解析】:
(1)var设定变量名用于存储从集合中取出元素。
(2)items指定要遍历的集合。
(3)varStatus设定变量名,该变量用于存放集合中元素的信息。
(4)begin、end用于指定遍历的起始位置和终止位置(可选)。
(5)step指定循环的步长
<c:forEach>包含如下属性:
属性名 | 是否支持EL | 属性类型 | 描述 | |
---|---|---|---|---|
var | NO | String | 必须具备,且无默认值。 | |
items | YES | Arrays Collection Iterator Enumeration Map String[] args | 必须具备,且无默认值。 | |
begin | YES | int | 非必须具备,默认值为0。 | |
end | YES | int | 非必须具备,默认值为集合最后一个元素。 | |
step | YES | int | 非必须具备,默认值为1。 | |
varStatus | NO | String | 非必须具备,且无默认值。 | varStatus包含四个状态: index:当前循环的索引值。 count:循环的次数。 first:是否为第一个位置。 last:是否为最后一个位置。 |
范例:<c:forEach>标签的使用:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page import="java.util.ArrayList"%>
<html>
<head>
<title>JSTL: -- forEach标签实例</title>
</head>
<body>
<h4><c:out value="forEach实例"/></h4>
<%
List<String>list = new ArrayList<String>();
list.add(0, "贝贝");
list.add(1, "晶晶");
list.add(2, "欢欢");
list.add(3, "莹莹");
list.add(4, "妮妮");
request.setAttribute("list", list);
%>
<B><c:out value="不指定begin和end的迭代:" /></B><br>
<%--不使用begin和end的迭代,从集合的第一个元素开始,遍历到最后一个元素。 --%>
<c:forEach var="fuwa" items="${list}">
<c:out value="${fuwa}"/><br/>
</c:forEach>
<B><c:out value="指定begin和end的迭代:" /></B><br>
<%--指定begin的值为1、end的值为3、step的值为2,
从第二个开始首先得到晶晶,每两个遍历一次,
则下一个显示的结果为莹莹,end为3则遍历结束。 --%>
<c:forEach var="fuwa" items="${list}" begin="1" end="3" step="2">
<c:out value="${fuwa}"/><br/>
</c:forEach>
<B><c:out value="输出整个迭代的信息:" /></B><br>
<%--指定varStatus的属性名为s,并取出存储的状态信息 --%>
<c:forEach var="fuwa"
items="${list}"
begin="3"
end="4"
varStatus="s"
step="1">
<c:out value="${fuwa}" />的四种属性:<br>
所在位置,即索引:<c:out value="${s.index}" /><br>
总共已迭代的次数:<c:out value="${s.count}" /><br>
是否为第一个位置:<c:out value="${s.first}" /><br>
是否为最后一个位置:<c:out value="${s.last}" /><br>
</c:forEach>
</body>
</html>
<c:forTokens>标签
<c:forTokens>标签用于浏览字符串,并根据指定的字符将字符串截取。
<c:forTokens items=”strigOfTokens”
delims=”delimiters”
[var=”name”
begin=”begin”
end=”end”
step=”len”
varStatus=”statusName”] >
本体内容
</c:forTokens>
【参数说明】
(1)items指定被迭代的字符串。
(2)delims指定使用的分隔符。
(3)var指定用来存放遍历到的成员。
(4)begin指定遍历的开始位置(int型从取值0开始)。
(5)end指定遍历结束的位置(int型,默认集合中最后一个元素)。
(6)step遍历的步长(大于0的整型)。
(7)varStatus存放遍历到的成员的状态信息。
范例:<c:forTokens>标签的使用
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML>
<html>
<head>
<title>JSTL: -- forTokens标签实例</title>
</head>
<body>
<h4><c:out value="forToken实例"/></h4>
<hr/>
<%--提示:分隔符的作用是根据标识,截取字符串。
如果未设定分隔符或在字符串中没有找到分隔付,将把整个元素作为一个元素截取。
在实际应用中用于在除去某些符号在页面中显示。 --%>
<c:forTokens var="str" items="北、京、欢、迎、您" delims="、">
<c:out value="${str}"></c:out><br/>
</c:forTokens>
<br/>
<c:forTokens items="123-4567-8854" delims="-" var="t">
<c:out value="${t}"></c:out><br/>
</c:forTokens>
<br/>
<c:forTokens items="1*2*3*4*5*6*7"
delims="*"
begin="1"
end="3"
var="n"
varStatus="s">
<c:out value="${n}" />的四种属性:<br>
所在位置,即索引:<c:out value="${s.index}" /><br>
总共已迭代的次数:<c:out value="${s.count}" /><br>
是否为第一个位置:<c:out value="${s.first}" /><br>
&以上是关于07Java--JSP自定义标签的主要内容,如果未能解决你的问题,请参考以下文章