一、JSP标签介绍,自定义标签
一、JSP标签介绍
1、 标签库有什么作用
自定义标签库是一种优秀的表现层技术,之前介绍的MVC模式,我们使用jsp作为表现层,但是jsp语法嵌套在html页面,美工还是很难直接参与开发,并且jsp脚本和html代码耦合在一起,维护成本较高。我们能不能开发一套和html风格类似并且能完成jsp脚本功能的标签来解决这种低效的协作方式呢?于是标签库就诞生了。
2、 标签的继承体系
3、 相关类的介绍
3.1 Tag
/**
* The interface of a classic tag handler that does not want to manipulate its body.
*.............
*/
public interface Tag extends JspTag {
Tag接口是所有传统标签的父接口,其中定义了两个重要方法(doStartTag、
doEndTag)方法和四个常量(EVAL_BODY_INCLUDE、SKIP_BODY、EVAL_PAGE、
SKIP_PAGE),这两个方法和四个常量的作用如下:
1.WEB容器在解释执行JSP页面的过程中,遇到自定义标签的开始标记就会去调用标签处理器的doStartTag方法,doStartTag方法执行完后可以向WEB容器返回常量EVAL_BODY_INCLUDE或SKIP_BODY。如果doStartTag方法返回EVAL_BODY_INCLUDE,WEB容器就会接着执行自定义标签的标签体;如果doStartTag方法返回SKIP_BODY,WEB容器就会忽略自定义标签的标签体,直接解释执行自定义标签的结束标记。
2.WEB容器解释执行到自定义标签的结束标记时,就会调用标签处理器的doEndTag方法,doEndTag方法执行完后可以向WEB容器返回常量EVAL_PAGE或SKIP_PAGE。如果doEndTag方法返回常量EVAL_PAGE,WEB容器就会接着执行JSP页面中位于结束标记后面的JSP代码;如果doEndTag方法返回SKIP_PAGE,WEB容器就会忽略JSP页面中位于结束标记后面的所有内容。从doStartTag和doEndTag方法的作用和返回值的作用可以看出,开发自定义标签时可以在doStartTag方法和doEndTag方法体内编写合适的Java程序代码来实现具体的功能,通过控制doStartTag方法和doEndTag方法的返回值,还可以告诉WEB容器是否执行自定义标签中的标签体内容和JSP页面中位于自定义标签的结束标记后面的内容。
3.生命周期:setPageContext(可以获得PageContext)‐‐‐>setParent‐‐‐>doStartTag‐‐‐>doEndTag‐‐‐>release
3.2 JspTag
/**
* Serves as a base class for Tag and SimpleTag.
* This is mostly for organizational and type-safety purposes.
*
* @since 2.0
*/
public interface JspTag {
// No methods even through there are some common methods
JspTag接口是所有自定义标签的父接口,它是JSP2.0中新定义的一个标记接口,没有任何属性和方法。JspTag接口有Tag和SimpleTag两个直接子接口,JSP2.0以前的版本 中只有Tag接口,所以把实现Tag接口的自定义标签也叫做传统标签,把实现SimpleTag 接口的自定义标签叫做简单标签。
3.3 IterationTag
/**
* The IterationTag interface extends Tag by defining one additional
* method that controls the reevaluation of its body.
...........
*/
public interface IterationTag extends Tag {
IterationTag接口继承了Tag接口,并在Tag接口的基础上增加了一个doAfterBody方法和一个EVAL_BODY_AGAIN常量。实现IterationTag接口的标签除了可以完成Tag接口
所能完成的功能外,还能够通知WEB容器是否重复执行标签体内容。对于实现了IterationTag接口的自定义标签,WEB容器在执行完自定义标签的标签体后,将调用标签处理器的doAfterBody方法,doAfterBody方法可以向WEB容器返回常量EVAL_BODY_AGAIN或SKIP_BODY。如果doAfterBody方法返回EVAL_BODY_AGAIN,WEB容器就会把标签体内容再重复执行一次,执行完后接着再调用doAfterBody方法,如此往复,直到doAfterBody方法返回常量SKIP_BODY,WEB容器才会开始处理标签的结束标记和调用doEndTag方法。
可见,开发自定义标签时,可以通过控制doAfterBody方法的返回值来告诉WEB容器是否重复执行标签体内容,从而达到循环处理标签体内容的效果。例如,可以通过一个
实现IterationTag接口的标签来迭代输出一个集合中的所有元素,在标签体部分指定元素的输出格式。
在JSP API中也提供了IterationTag接口的默认实现类TagSupport,我们在编写自定义标签的标签处理器类时,可以继承和扩展TagSupport类,这相比实现IterationTag接口将简化开发工作。
3.4 TagSupport
/**
* A base class for defining new tag handlers implementing Tag.
*
* <p> The TagSupport class is a utility class intended to be used as
* the base class for new tag handlers. The TagSupport class
* implements the Tag and IterationTag interfaces and adds additional
* convenience methods including getter methods for the properties in
* Tag. TagSupport has one static method that is included to
* facilitate coordination among cooperating tags.
*
* <p> Many tag handlers will extend TagSupport and only redefine a
* few methods.
*/
public class TagSupport implements IterationTag, Serializable {
3.5 BodyTag
/**
* The BodyTag interface extends IterationTag by defining additional methods
* that let a tag handler manipulate the content of evaluating its body.
.........
*/
public interface BodyTag extends IterationTag {
BodyTag接口继承了IterationTag接口,并在IterationTag接口的基础上增加了两个 方法(setBodyContent、doInitBody)和一个EVAL_BODY_BUFFERED常量。实现 BodyTag接口的标签除了可以完成IterationTag接口所能完成的功能,还可以对标签体内容进行修改。对于实现了BodyTag接口的自定义标签,标签处理器的doStartTag方法 不仅可以返回前面讲解的常量EVAL_BODY_INCLUDE或SKIP_BODY,还可以返回常量 EVAL_BODY_BUFFERED。如果doStartTag方法返回EVAL_BODY_BUFFERED,WEB容器就 会创建一个专用于捕获标签体运行结果的BodyContent对象,然后调用标签处理器的 setBodyContent方法将BodyContent对象的引用传递给标签处理器,WEB容器接着将标 签体的执行结果写入到BodyContent对象中。在标签处理器的后续事件方法中,可以通 过先前保存的BodyContent对象的引用来获取标签体的执行结果,然后调用 BodyContent对象特有的方法对BodyContent对象中的内容(即标签体的执行结果)进 行修改和控制其输出。
在JSP API中也提供了BodyTag接口的实现类BodyTagSupport,我们在编写能够修 改标签体内容的自定义标签的标签处理器类时,可以继承和扩展BodyTagSupport类,这 相比实现BodyTag接口将简化开发工作。
3.6 BodyTagSupport
/**
* A base class for defining tag handlers implementing BodyTag.
* <p>
* The BodyTagSupport class implements the BodyTag interface and adds additional
* convenience methods including getter methods for the bodyContent property and
* methods to get at the previous out JspWriter.
* <p>
* Many tag handlers will extend BodyTagSupport and only redefine a few methods.
*/
public class BodyTagSupport extends TagSupport implements BodyTag {
3.7 传统标签接口中的各个方法可以返回的返回值说明
在现在的jsp标签开发中,很少直接使用传统标签来开发了,目前用得较多的都是简单标签,所以Jsp的传统标签开发了解一下即可。
3.8 SimpleTag
/**
* Interface for defining Simple Tag Handlers.
*
* <p>Simple Tag Handlers differ from Classic Tag Handlers in that instead
* of supporting <code>doStartTag()</code> and <code>doEndTag()</code>,
* the <code>SimpleTag</code> interface provides a simple
* <code>doTag()</code> method, which is called once and only once for any
* given tag invocation. All tag logic, iteration, body evaluations, etc.
* are to be performed in this single method. Thus, simple tag handlers
* have the equivalent power of <code>BodyTag</code>, but with a much
* simpler lifecycle and interface.</p>
..................
* @see SimpleTagSupport
* @since 2.0
*/
public interface SimpleTag extends JspTag {
SimpleTag接口
SimpleTag接口是JSP2.0中新增的一个标签接口。由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广,因此,SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口。SimpleTag接口与传统标签接口最大的区别在于,SimpleTag接口只定义了一个用于处理标签逻辑的doTag方法,该方法在WEB容器执行自定义标签时调用,并且只被调用一次。那些使用传统标签接口所完成的功能,例如是否执行标签体、迭代标签体、对标签体内容进行修改等功能都可以在doTag方法中完成。
在JSP API中也提供了SimpleTag接口的实现类SimpleTagSupport,我们在编写简单标签时,可以继承和扩展SimpleTagSupport类,这相比实现SimpleTag接口将简化开发工作。
3.9 SimpleTagSupport
/**
* A base class for defining tag handlers implementing SimpleTag.
* <p>
* The SimpleTagSupport class is a utility class intended to be used
* as the base class for new simple tag handlers. The SimpleTagSupport
* class implements the SimpleTag interface and adds additional
* convenience methods including getter methods for the properties in
* SimpleTag.
*
* @since 2.0
*/
public class SimpleTagSupport implements SimpleTag {
3.10 JspFragment
/**
* Encapsulates a portion of JSP code in an object that
* can be invoked as many times as needed. JSP Fragments are defined
* using JSP syntax as the body of a tag for an invocation to a SimpleTag
* handler, or as the body of a <jsp:attribute> standard action
* specifying the value of an attribute that is declared as a fragment,
* or to be of type JspFragment in the TLD.
*
*...........
*
* @since 2.0
*/
public abstract class JspFragment {
3.10.1 invoke()方法
/**
* Executes the fragment and directs all output to the given Writer,
* or the JspWriter returned by the getOut() method of the JspContext
* associated with the fragment if out is null.
.....*/
public abstract void invoke( Writer out )
throws JspException, IOException;
<!‐‐
tld文件中有四种标签体类型 :emptyJSPscriptlesstagdepentend
在简单标签(SampleTag)中标签体body‐content的值只允许是empty和scriptless,不允许设置成JSP,如果设置成JSP就会出现异常 在传统标签中标签体body‐content的值只允许是empty和JSP 如果标签体body‐content的值设置成tagdepentend,那么就表示标签体里面的内容是给标签处理器类使用的,例如:开发一个查询用户的sql标签,此时标签体重的SQL语句就是给SQL 标签的标签处理器来使用的<hx:sql>select * from user</hx:sql>在这种情况下,sql标签的<body‐content>就要设置成tagdepentend,tagdepentend用得比较少,了解一下即可
‐‐>
二、自定义标签
自定义标签除了可以移除jsp页面java代码外,它也可以实现以下功能
1、 传统标签开发
1.1 控制jsp页面某一部分内容是否执行
1.1.1 控制标签体的内容是否执行
1.1.1.1 创建一个类继承TagSupport
Tag1 .java
package com.hx.mytag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
public class Tag1 extends TagSupport{
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public int doStartTag() throws JspException {
//return super.doStartTag();//SKIP_BODY 标签体的内容不执行
return EVAL_BODY_INCLUDE;//标签体的内容执行
}
}
1.1.1.2 添加tld文件
这个文件我们没有必要重新写一遍,到Tomcat服务器上的\apache-tomcat-8.0.53\webapps\examples\WEB-INF\jsp2中复制一个过来,修改名字存放到我们的项目中WEB-INF的任意子路径下。删除一些标签成如下内容
tag.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>HxTagLibrary</short-name>
<!--
为自定义标签库设置一个uri,uri以/开头,/后面的内容随便写,如这里的/hx ,
在Jsp页面中引用标签库时,需要通过uri找到标签库
在Jsp页面中就要这样引入标签库:<%@taglib uri="/hx" prefix="hx"%>
-->
<uri>/hx</uri>
<!--一个taglib(标签库)中包含多个自定义标签,每一个自定义标签使用一个tag标记来描述 -->
<!-- 一个tag标记对应一个自定义标签 -->
<tag>
<description>这个标签的作用是用来输出HelloWorld</description>
<!--
为标签处理器类配一个标签名,在Jsp页面中使用标签时是通过标签名来找到要调用的标签处理器类的
通过name就能找到对应的类tag-class
-->
<name>tag1</name>
<!-- 标签对应的处理器类-->
<tag-class>com.hx.mytag.Tag1</tag-class>
<body-content>jsp</body-content>
<!--
<body-content></body-content>标签体
<attribute></attribute>属性
-->
</tag>
</taglib>
1.1.1.3 在jsp页面是如何使用标签
<%@ taglib uri="tld文件中指定的唯一标识" prefix="指定标签前缀"%>
我们看到这个导入标签库的编译指令主要有两个属性,一个是用于定位我们已经写好的标签库,定位的方法就是读取每个tld文件中的URI元素的值,prefix用于指定我们使用标签时的前缀
<刚刚指定的前缀 :标签名 />
tag1.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:tag1>
<h1>Hello World</h1>
</h:tag1>
</body>
</html>
自定义标签类 doStartTag方法 return EVAL_BODY_INCLUDE
自定义标签类 doStartTag方法 return SKIP_BODY
1.1.2 控制标签后的jsp是否执行
那之前的Tag1.java添加doEndTag()方法
package com.hx.mytag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
public class Tag1 extends TagSupport{
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public int doStartTag() throws JspException {
//return super.doStartTag();//SKIP_BODY 标签体的内容不执行
//EVAL_BODY_INCLUDE 标签体的内容执行
return EVAL_BODY_INCLUDE;
}
@Override
public int doEndTag() throws JspException {
//return super.doEndTag();//EVAL_PAGE 标签后面的内容执行
return SKIP_PAGE;
}
}
tld配置不需要改
tag1.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:tag1>
<h1>Hello World</h1>
</h:tag1>
<span>Hello everybody</span>
</body>
</html>
自定义标签类 doEndTag方法 return EVAL_PAGE
自定义标签类 doEndTag方法 return SKIP_PAGE
1.2 控制jsp页面内容重复执行
Tag2 .java
package com.hx.mytag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
public class Tag2 extends TagSupport {
int count = 3;
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public int doStartTag() throws JspException {
// return super.doStartTag();//SKIP_BODY 标签体的内容不执行
// EVAL_BODY_INCLUDE 标签体的内容执行
return EVAL_BODY_INCLUDE;
}
/*
* 控制doAfterBody()方法的返回值, 如果这个方法返回EVAL_BODY_AGAIN, 则web服务器又执行一次标签体,
* 依次类推,一直执行到doAfterBody方法返回SKIP_BODY,则标签体才不会重 复执行。
*
* @see javax.servlet.jsp.tagext.TagSupport#doAfterBody()
*/
@Override
public int doAfterBody() throws JspException {
count--;
if (count > 0) {
return EVAL_BODY_AGAIN;
}
return SKIP_BODY;
// return super.doAfterBody();//SKIP_BODY
}
}
在之前的tld文件中加入下面代码,<tag>元素与<tag>元素同级
<tag>
<description>循环输出标签体的内容</description>
<name>tag2</name>
<tag-class>com.hx.mytag.Tag2</tag-class>
<body-content>JSP</body-content>
</tag>
tag2.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:tag2>
<h1>Hello World</h1>
</h:tag2>
</body>
</html>
1.3 修改jsp页面内容再输出
将标签体里的内容全部小写输出
Tag3 .java
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class Tag3 extends BodyTagSupport {
@Override
public int doStartTag() throws JspException {
return super.doStartTag();//EVAL_BODY_BUFFERED
}
@Override
public int doEndTag() throws JspException {
//获取标签体里的内容
String value=getBodyContent().getString().toLowerCase();
//输出到浏览器
try {
pageContext.getOut().write(value);
} catch (IOException e) {
e.printStackTrace();
}
return super.doEndTag();
}
}
配置tld
<tag>
<description>小写</description>
<name>tag3</name>
<tag-class>com.hx.mytag.Tag3</tag-class>
<body-content>JSP</body-content>
</tag>
tag2.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:tag3>
<h1>Hello World</h1>
</h:tag3>
</body>
</html>
2、 简单标签开发
2.1 控制jsp页面某一部分内容是否执行
2.1.1 控制标签体的内容是否执行
编写标签类
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class SimpleTag1 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
JspFragment jspFragment = getJspBody();
jspFragment.invoke(null);
// 参数为null,代表拿到JspWriter.getOut(),会输出到浏览器
//不调用该方法,内容就不会输出到浏览器
}
}
配置tld
<tag>
<description></description>
<name>tag4</name>
<tag-class>com.hx.mytag.SimpleTag1</tag-class>
<body-content>scriptless</body-content>
</tag>
使用标签
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:tag4>
<h1>Hello World</h1>
</h:tag4>
</body>
</html>
调用invoke
没有调用invoke
配置成 <body-content>JSP</body-content>会报错
2.1.2 控制标签后的jsp代码是否执行
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class SimpleTag2 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
throw new SkipPageException();// 抛出该异常接下来的jsp代码不会执行了
}
}
<tag>
<description></description>
<name>tag5</name>
<tag-class>com.hx.mytag.SimpleTag2</tag-class>
<body-content>JSP</body-content>
</tag>
注释抛的异常
2.2 控标签体的内容重复执行
编写标签类
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class SimpleTag3 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
int count = 3;
JspFragment jspFragment = getJspBody();
for (int i = 0; i < count; i++) {
jspFragment.invoke(null);// 有多少次循环就调用多少次invoke方法
}
}
}
配置tld
<tag>
<description></description>
<name>tag6</name>
<tag-class>com.hx.mytag.SimpleTag2</tag-class>
<body-content>scriptless</body-content>
</tag>
使用标签
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:tag6>
<h1>Hello World</h1>
</h:tag6>
<span>Hello everybody</span>
</body>
</html>
效果
2.3 修改jsp页面内容再输出(标签提的内容小写输出)
编写标签类
package com.hx.mytag;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class SimpleTag4 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
JspFragment jspFragment = getJspBody();
StringWriter out=new StringWriter();
jspFragment.invoke(out);
String lowerCase = out.getBuffer().toString().toLowerCase();
jspFragment.getJspContext().getOut().write(lowerCase);
}
}
配置tld
<tag>
<description></description>
<name>tag7</name>
<tag-class>com.hx.mytag.SimpleTag4</tag-class>
<body-content>scriptless</body-content>
</tag>
使用标签
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:tag1>
<h1>Hello World</h1>
</h:tag1>
<span>Hello everybody</span>
</body>
</html>
效果
2.4 根据标签的属性来控制标签体的内容是否显示
编写标签类
package com.hx.mytag;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class SimpleTag5 extends SimpleTagSupport {
private boolean isShow;
public void setIsShow(boolean isShow) {
this.isShow = isShow;
}
@Override
public void doTag() throws JspException, IOException {
if(isShow) {
getJspBody().invoke(null);
}
}
}
配置tld
<tag>
<description>根据isShow属性的值判断是否显示标签体的内容</description>
<name>tag8</name>
<tag-class>com.hx.mytag.SimpleTag5</tag-class>
<body-content>scriptless</body-content>
<attribute>
<description>Boolean类型</description>
<name>isShow</name><!-- 标签的属性名称 -->
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
使用标签
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:tag8 isShow="${2>1 }"><%--可以使用el表达式,或者直接写字符串 --%>
<h1>hello world</h1>
</h:tag8>
</body>
</html>
可以看到配置中description用于描述标签的信息
效果
效果
2.5 输出格式化后的日期
标签的属性值是8种基本数据类型,那么在JSP页面在传递字符串时,JSP引擎会自动 转换成相应的类型,但如果标签的属性值是复合数据类型,那么JSP引擎是无法自动转换 的
编写标签类
package com.hx.mytag;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class SimpleTag5 extends SimpleTagSupport {
private boolean isShow;
public void setIsShow(boolean isShow) {
this.isShow = isShow;
}
@Override
public void doTag() throws JspException, IOException {
if(isShow) {
getJspBody().invoke(null);
}
}
}
配置tld
<tag>
<description>显示格式化后的时间</description>
<name>tag9</name>
<tag-class>com.hx.mytag.SimpleTag6</tag-class>
<body-content>scriptless</body-content>
<attribute>
<description>Deat类型</description>
<name>date</name><!-- 标签的属性名称 -->
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
使用
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:tag9 date="2008-08-08">
</h:tag9>
</body>
</html>
抛异常
改
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<%@ page import="java.util.*"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
request.setAttribute("date", new Date());
%>
<h:tag9 date="${date }">
</h:tag9>
</body>
</html>
3、 自定义if,for,if else if else标签
3.1 自定义 if标签
编写标签类
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class IfTag extends SimpleTagSupport {
private boolean isTrue;
public boolean getIsTrue() {
return isTrue;
}
public void setIsTrue(boolean isTrue) {
this.isTrue = isTrue;
}
@Override
public void doTag() throws JspException, IOException {
if (isTrue) {
getJspBody().invoke(null);
}
}
}
配置
<tag>
<description>if判断</description>
<name>if</name>
<tag-class>com.hx.mytag.IfTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>isTrue</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
使用
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="hx"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<hx:if isTrue="${1<2 }">
<h1>hello</h1>
</hx:if>
</body>
</html>
效果
3.2 自定义for标签
编写标签类
package com.hx.mytag;
import java.io.IOException;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ForTag extends SimpleTagSupport {
private List items;
private String var;
public void setItems(List items) {
this.items = items;
}
public void setVar(String var) {
this.var = var;
}
public List getItems() {
return items;
}
public String getVar() {
return var;
}
@Override
public void doTag() throws JspException, IOException {
JspFragment jspFragment = getJspBody();
if (items != null) {
for (Object item : items) {
getJspContext().setAttribute(var, item);
jspFragment.invoke(null);
}
}
}
}
配置
<tag>
<description>for循环</description>
<name>for</name>
<tag-class>com.hx.mytag.ForTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<description>List类型</description>
<name>items</name><!-- 标签的属性名称 -->
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>String类型</description>
<name>var</name><!-- 标签的属性名称 -->
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
使用
package com.hx.entity;
public class User {
private int id;
private String name;
private char sex;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public User(int id, String name, char sex, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
}
public User() {
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<%@ page import="java.util.*"%>
<%@ page import="com.hx.entity.*"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
List<User> users = new ArrayList<User>();
User u1 = new User(1, "xiaohei", '男', 16);
User u2 = new User(2, "xiaobai", '女', 16);
users.add(u1);
users.add(u2);
request.setAttribute("users", users);
%>
<h:for items="${users}" var="user">
<h1>${user.name }</h1>
</h:for>
</body>
</html>
3.3 自定义if elseif else 标签
编写标签类
Choose .java
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class Choose extends SimpleTagSupport {
//标记,用于判断子标签是否需要执行,当设为false表示一个条件满足,之后的不需要执行
private boolean falg=true;
public boolean getFalg() {
return falg;
}
public void setFalg(boolean falg) {
this.falg = falg;
}
@Override
public void doTag() throws JspException, IOException {
getJspBody().invoke(null);
}
}
IfTag .java
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import com.hx.mytag.*;
public class IfTag extends SimpleTagSupport {
private boolean isTrue;
public boolean getIsTrue() {
return isTrue;
}
public void setIsTrue(boolean isTrue) {
this.isTrue = isTrue;
}
@Override
public void doTag() throws JspException, IOException {
Choose c=(Choose)this.getParent();
boolean flag=c==null?true:c.getFalg();
if (isTrue && flag) {
getJspBody().invoke(null);
if(c!=null)
c.setFalg(false);
System.out.println("if:"+flag);
}else {
if(c!=null)
c.setFalg(true);
System.out.println("if:"+flag);
}
}
}
ElseIfTag .java
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ElseIfTag extends SimpleTagSupport {
private boolean isTrue;
public boolean getIsTrue() {
return isTrue;
}
public void setIsTrue(boolean isTrue) {
this.isTrue = isTrue;
}
@Override
public void doTag() throws JspException, IOException {
Choose c=(Choose)this.getParent();
boolean flag=c==null?true:c.getFalg();
System.out.println("else:"+flag);
if (flag && isTrue) {
getJspBody().invoke(null);
if(c!=null)
c.setFalg(false);
}
}
}
ElseTag .java
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ElseTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
Choose c=(Choose)this.getParent();
boolean flag=c==null?true:c.getFalg();
System.out.println("else:"+flag);
if (flag) {
getJspBody().invoke(null);
}
}
}
配置
<tag>
<description>choose(选择)</description>
<name>choose</name>
<tag-class>com.hx.mytag.Choose</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>flag</name>
<required>false</required>
</attribute>
</tag>
<tag>
<description>if判断</description>
<name>if</name>
<tag-class>com.hx.mytag.IfTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>isTrue</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<description>else if判断</description>
<name>elsif</name>
<tag-class>com.hx.mytag.ElseIfTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>isTrue</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<description>else判断</description>
<name>else</name>
<tag-class>com.hx.mytag.ElseTag</tag-class>
<body-content>scriptless</body-content>
</tag>
使用
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<%@ page import="java.util.*"%>
<%@ page import="com.hx.entity.*"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:choose>
<h:if isTrue="true"> 123</h:if>
<h:else isTrue="true">456</h:else>
</h:choose>
</body>
</html>
三、其他补充
1、 自定义一个简单的标签(无标签体和属性)
要求hello标签向页面输出hello World
步骤
1.1 创建一个类实现Tag接口
重写doEndTag()[或doStartTag()]方法
(或者继承SimpleTagSupport重写doTag()方法......)
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
public class HelloTag implements Tag {
private PageContext pc;
public void setPageContext(PageContext pc) {
this.pc = pc;
}
public int doEndTag() throws JspException {
try {
pc.getOut().write("hello World");
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
public void setParent(Tag t) {
}
public Tag getParent() {
return null;
}
public int doStartTag() throws JspException {
return 0;
}
public void release() {
}
}
1.2 添加tld文件
这个文件我们没有必要重新写一遍,到Tomcat服务器上的webapps/examples/WEB-INF/jsp2中复制一个过来,修改名字存放到我们的项目中WEB-INF的任意子路径下。删除一些标签成如下内容
<?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>HxTagLibrary</short-name>
<!--
为自定义标签库设置一个uri,uri以/开头,/后面的内容随便写,如这里的/hx ,
在Jsp页面中引用标签库时,需要通过uri找到标签库
在Jsp页面中就要这样引入标签库:<%@taglib uri="/hx" prefix="hx"%>
-->
<uri>/hx</uri>
<!--一个taglib(标签库)中包含多个自定义标签,每一个自定义标签使用一个tag标记来描述 -->
<!-- 一个tag标记对应一个自定义标签 -->
<tag>
<description>这个标签的作用是用来输出HelloWorld</description>
<!--
为标签处理器类配一个标签名,在Jsp页面中使用标签时是通过标签名来找到要调用的标签处理器类的
通过viewIP就能找到对应的类com.hx.tag.ViewIp
-->
<name>Hello</name>
<!-- 标签对应的处理器类-->
<tag-class>com.hx.mytag.HelloTag</tag-class>
<body-content>empty</body-content>
<!--
<body-content></body-content>标签体
<attribute></attribute>属性
-->
</tag>
</taglib>
1.3 在jsp页面是如何使用标签
<%@ taglib uri="tld文件中指定的唯一标识" prefix="指定标签前缀"%>
我们看到这个导入标签库的编译指令主要有两个属性,一个是用于定位我们已经写好的标签库,定位的方法就是读取每个tld文件中的URI元素的值,prefix用于指定我们使用标签时的前缀
<刚刚指定的前缀 :标签名 />
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:Hello/>
</body>
</html>
2、 自定义一个有属性的标签
1. 创建一个类继承SimpleTagSupport
2. 声明标签需要的属性
3. 重写doTag() 方法
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class HelloNameTag extends SimpleTagSupport {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void doTag() throws JspException, IOException {
getJspContext().getOut().write("hello : " + name);
}
}
4. 在之前的tld文件中加入下面代码,<tag>元素与<tag>元素同级
<tag>
<description>这个标签的作用是用来向指定姓名的人问好</description>
<!-- 为标签处理器类配一个标签名,在Jsp页面中使用标签时是通过标签名来找到要调用的标签处理器类的 通过name就能找到对应的类tag-class -->
<name>HelloName</name>
<!-- 标签对应的处理器类 -->
<tag-class>com.hx.mytag.HelloNameTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>name</name><!-- 属性的名称 -->
<required>true</required><!-- 属性是否必填 -->
</attribute>
</tag>
5. 使用<h:HelloName name="xiaohei"/>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:Hello/><br>
<h:HelloName name="xiaohei"/>
</body>
</html>
3、 自定义带标签体的标签
标签类
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class HelloNameTag1 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
getJspBody().invoke(null);
}
}
getJspBody()表示获取整个标签体的所有内容,返回的是一个fragment对象,这个对象的一个方法invoke就是用于输出整个内容到jsp页面,如果参数为null表示直接输出,还可以使用Writer作为参数传入,意思是将标签体的内容全部输入到这个字符流中,然后你可以通过一些操作,再次使用write方法输出到jsp页面。也就是说,如果对于标签体中的数据内容需要做一些判断操作的话,可以传递一个writer流,处理完成之后可以再次输出到页面上
配置
<tag>
<description>这个标签的作用是输出标签体的内容</description>
<name>HelloName1</name>
<tag-class>com.hx.mytag.HelloNameTag1</tag-class>
<body-content>scriptless</body-content>
</tag>
使用
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:Hello/><br>
<h:HelloName name="xiaohei"/><br>
<h:HelloName1>xiaoming</h:HelloName1><br>
</body>
</html>
效果
4、 自定义以页面片段为属性的值标签
jsp引擎是可以为我们自动转换并自动赋值到我们标签处理类的私有属性中,但是对于之外的类型都是不可以直接操作的,我们首先看如何以页面片段作为属性,传递。
标签类
package com.hx.mytag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class MyTag extends SimpleTagSupport {
private JspFragment map;
public JspFragment getMap() {
return this.map;
}
public void setMap(JspFragment map) {
this.map = map;
}
public void doTag() throws JspException, IOException {
map.invoke(null);
}
}
配置
<tag>
<description>Outputs a colored tile</description>
<name>mytag</name>
<tag-class>com.hx.mytag.MyTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>map</name>
<required>false</required>
<fragment>true</fragment>
</attribute>
</tag>
使用
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:mytag>
<jsp:attribute name="map">
<h1>hello</h1>
</jsp:attribute>
</h:mytag>
</body>
</html>
效果
我们传递属性值的时候是在标签名的后面添加属性名和属性值,但那时的属性值只限于字符串,你不能传递别的类型的内容。此处我们为了能够传递页面片段,通过jsp:attribute动作指令来给我们的属性赋值,而这个值的内容就是一个页面片段。上文中我们在介绍自定义标签体的时候,我们说可以使用getJspBody可以获得标签体的内容,其实这个方法返回的也是一个fregment,所以我们可以调用invoke方法输出标签体内容。
5、 自定义动态属性标签
传递的属性个数都是固定的,但是在实际开发中往往又会遇到有些参数必须传入有些选择性的传入,这样每个人传递的属性的个数都是不一样的,服务器端该如何处理呢?我们可以使用动态属性标签,使用此标签之前,我们的标签处理类就必须要继承接口DynamicAttributes,这个接口中就只有一个方法,setDynamicAttribute这个方法就是来完成动态的给我们传递的属性赋值。这是第一点,第二点就是需要在tld文件中配置一条语句,表明这个tag是支持动态属性的
标签类
package com.hx.mytag;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.DynamicAttributes;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ShowLover extends SimpleTagSupport implements DynamicAttributes {
private ArrayList<String> keys = new ArrayList<String>();
private ArrayList<Object> values = new ArrayList<Object>();
private ArrayList<String> uris = new ArrayList<String>();
@Override
public void doTag() throws JspException, IOException {
for (int i = 0; i < keys.size(); i++) {
getJspContext().getOut().write(keys.get(i) + " : " + values.get(i) + "<br>");
}
}
@Override
public void setDynamicAttribute(String uri, String localName, Object value) throws JspException {
// localName标签的属性名称
// value标签的属性的值
//uri - -the namespace of the attribute, or null if in the default namespace.
//这是该属性的命名空间,如果没有显式指定就是null。我们暂时可以不用关心
uris.add(uri);
keys.add(localName);
values.add(value);
}
}
配置
<tag>
<description>Outputs a colored tile</description>
<name>ShowLover</name>
<tag-class>com.hx.mytag.ShowLover</tag-class>
<body-content>scriptless</body-content>
<dynamic-attributes>true</dynamic-attributes>
</tag>
使用
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/hx" prefix="h"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h:ShowLover exercise="run" reder="novel" play="game" work="programme" />
</body>
</html>
效果
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">