一、概述
我们在进行javaweb开发时,jsp页面上经常会用到jstl标签和structs标签,但是有时候这些标签并不能满足我们的要求,这个时候就需要或者可以通过自定义标签的方式来满足我们要实现的功能。
二、自定义标签的组成
自定义标签一般由三部分组成,准确的说是两部分,第三部分是我们在jsp页面中引用我们自定义的标签,然后使用。
- 标签的处理程序(Java类)
- tld文件:标签的描述符文件(.tld文件要放在和web.xml同一级目录下)
- 引用标签,使用taglib引入到jsp中
三、自定义标签的作用
- 使我们的Java代码和JSP页面彻底分离
- 还可以使我们的代码更安全(页面中没有算法、商业业务逻辑等)
- 提供了可重用的功能组件
四、标签处理程序的编写
标签处理程序必须实现接口或者继承类,实现Tag和BodyTag接口可以自定义带有标签体和属性的标签,实现SimpleTag接口只能自定义最简单的标签(没有标签体,也没有属性)。而TagSupport、BodyTagSupport、SimpleTagSupport类正好是Tag、BodyTag、SimpleTag接口的实现类。
五、几个简单的例子
示例1:没有标签体,也没有属性
//标签处理程序
package
com.wangyi.tag;
import
java.io.IOException;
import
javax.servlet.jsp.JspContext;
import
javax.servlet.jsp.JspException;
import
javax.servlet.jsp.JspWriter;
import
javax.servlet.jsp.PageContext;
import
javax.servlet.jsp.tagext.SimpleTagSupport;
/**
* 自定义标签1:没有标签体,也没有属性
*/
public
class
WelcomeTag
extends
SimpleTagSupport {
/*
* 当
jsp
页面执行该标签处理程序所指定的标签的时候,执行该方法
*/
@Override
public
void
doTag()
throws
JspException, IOException {
//获得当前
jsp
页面的上下文对象
JspContext
jc
=
this
.
getJspContext
();
//获得该
jsp
页面上下文对象的输出流
JspWriter
out
=
jc
.getOut();
//获得session中的user属性
Object
obj
=
jc
.
getAttribute
(
"user"
,PageContext.
SESSION_SCOPE
);
if
(
obj
!=
null
){
//如果session中存在user属性
out
.println(
"成功!"
);
}
else
{
//如果不存在
out
.println(
"<a href=''>登录</a>"
);
}
}
}
//标签的描述符文件文件(.tld文件)
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
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
>
welcomeTag
</
description
>
<
display-name
>
welcomeTag
</
display-name
>
<
tlib-version
>
1.0
</
tlib-version
>
<!-- 指定标签库默认的前缀名(prefix) -->
<
short-name
>
wt
</
short-name
>
<!-- 在
jsp
页面中引入该标签的
url
-->
<!-- 一个.tld中可以定义多个tag,一个tag代表一个标签 -->
<
tag
>
<!-- 标签的名称 -->
<
name
>
welcomeTag
</
name
>
<!-- 标签处理程序类 -->
<
tag-class
>
com.wangyi.tag.WelcomeTag
</
tag-class
>
<!-- 设定标签间的主体(body)内容形式
只有三种值:
jsp
:表示标签间可有主体内容
empty:表示标签间不能有主体内容
Tagdependent
:表示标签间主体内容由标签自行处理
-->
<
body-content
>
empty
</
body-content
>
</
tag
>
</
taglib
>
示例2:有标签体,但是没有属性
//标签处理程序
package
com.wangyi.tag;
import
java.io.IOException;
import
javax.servlet.jsp.JspException;
import
javax.servlet.jsp.JspWriter;
import
javax.servlet.jsp.tagext.BodyContent;
import
javax.servlet.jsp.tagext.BodyTagSupport;
/**
* 自定义标签2:有标签体,但没有属性
*/
public
class
TestTag
extends
BodyTagSupport {
/**
* 当
jsp
页面执行到某个标签结束的时候,执行该方法处理标签体的内容
*/
@Override
public
int
doAfterBody()
throws
JspException {
//获得该标签的标签体
BodyContent
bc
=
this
.getBodyContent();
//获得该标签的标签体的输出流
JspWriter
out
=
bc
.getEnclosingWriter();
//获得标签体的内容
String
content
=
bc
.getString();
try
{
out
.println(
content
.toUpperCase());
}
catch
(IOException
e
) {
e
.printStackTrace();
}
return
this
.
EVAL_PAGE
;
//该返回值告诉
jsp
页面,这个标签执行完毕,可以去执行页面中的其他标签了
}
}
//标签的描述符文件文件(.tld文件)
<
tag
>
<
name
>
testTag
</
name
>
<
tag-class
>
com.wangyi.tag.TestTag
</
tag-class
>
<
body-content
>
JSP
</
body-content
>
</
tag
>
//页面:
<%@
page
language
=
"java"
contentType
=
"text/html; charset=UTF-8"
pageEncoding
=
"UTF-8"
%>
<!-- 引入自定义标签 -->
<!
DOCTYPE
html
PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"
http://www.w3.org/TR/html4/loose.dtd"
;
>
<
html
>
<
head
>
<
meta
http-equiv
=
"Content-Type"
content
=
"text/html; charset=UTF-8"
>
<
title
>
自定义标签1
</
title
>
</
head
>
<
body
>
自定义标签1:
<
wt:welcomeTag
/>
<
br
>
自定义标签2:
<
wt:testTag
>
this is second custom tag.
</
wt:testTag
>
</
body
>
</
html
>
示例3:通用的分页标签
//标签处理程序
package
com.wangyi.tag;
import
java.io.IOException;
import
java.text.MessageFormat;
import
javax.servlet.jsp.JspException;
import
javax.servlet.jsp.JspWriter;
import
javax.servlet.jsp.tagext.TagSupport;
/**
* 自定义分页标签
*/
public
class
PageTag
extends
TagSupport {
private
int
nowPage
= 1;
//当前页
private
int
pageSize
= 4;
//分页大小
private
int
count
= 0;
//总记录数
private
String
url
;
//访问
url
public
int
getNowPage() {
return
nowPage
;
}
public
void
setNowPage(
int
nowPage
) {
this
.
nowPage
=
nowPage
;
}
public
int
getPageSize() {
return
pageSize
;
}
public
void
setPageSize(
int
pageSize
) {
this
.
pageSize
=
pageSize
;
}
public
int
getCount() {
return
count
;
}
public
void
setCount(
int
count
) {
this
.
count
=
count
;
}
public
String getUrl() {
return
url
;
}
public
void
setUrl(String
url
) {
this
.
url
=
url
;
}
/**
* 当
jsp
页面遇到了分页标签的时候执行该方法。
* 这个标签一定是有属性的,这些属性就是给我们这个类的属性赋值(通过反射调用setter方法)
*/
@Override
public
int
doStartTag()
throws
JspException {
//总页数的计算
int
allPage
=
count
%
pageSize
== 0 ?
count
/
pageSize
:
count
/
pageSize
+ 1;
//特殊当前页处理
if
(
nowPage
<= 1){
nowPage
= 1;
}
if
(
nowPage
>=
allPage
){
nowPage
=
allPage
;
}
//超链接的模板,第一个占位{0}:访问
url
,第二个占位{1}:当前页,第三个占位{2}:该链接的显示文字
String
link
=
"<a href=''{0}?page={1}''>{2}</a>"
;
//MessageFormat.format()方法:第一个参数是字符串模板,其他参数均为字符串模板中需要填充的占位
//首页
String
first
= MessageFormat.
format
(
link
,
url
,
"1"
,
"首页"
);
//上一页
String
up
=
"上一页"
;
if
(
nowPage
> 1){
up
= MessageFormat.
format
(
link
,
url
,
nowPage
-1+
""
,
"上一页"
);
}
//下一页
String
next
=
"下一页"
;
if
(
nowPage
<
allPage
){
next
= MessageFormat.
format
(
link
,
url
,
nowPage
+1+
""
,
"下一页"
);
}
//尾页
String
last
= MessageFormat.
format
(
link
,
url
,
allPage
+
""
,
"尾页"
);
//htmlString:在
jsp
页面上显示的分页块元素
String
htmlString
=
"{0} {1} {2} {3} 共{4}页,第{5}页,分页单位:{6},共{7}条"
;
htmlString
= MessageFormat.
format
(
htmlString
,
first
,
up
,
next
,
last
,
allPage
+
""
,
nowPage
+
""
,
pageSize
+
""
,
count
);
//将htmlString输出到页面中
JspWriter
out
=
this
.
pageContext
.getOut();
try
{
out
.println(
htmlString
);
}
catch
(IOException
e
) {
e
.printStackTrace();
}
return
this
.
EVAL_PAGE
;
该返回值告诉
jsp
页面,这个标签执行完毕,可以去执行页面中的其他标签了
}
}
//标签的描述符文件文件(.tld文件)
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
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
>
welcomeTag
</
description
>
<
display-name
>
welcomeTag
</
display-name
>
<
tlib-version
>
1.0
</
tlib-version
>
<!-- 指定标签库默认的前缀名(prefix) -->
<
short-name
>
wt
</
short-name
>
<!-- 在
jsp
页面中引入该标签的
url
,也可以不写该元素,然后通过引入该
tld
文件的方式来引入该
tld
里面的标签 -->
<
tag
>
<
name
>
page
</
name
>
<
tag-class
>
com.wangyi.tag.PageTag
</
tag-class
>
<
body-content
>
empty
</
body-content
>
<!-- 定义标签体的属性 -->
<
attribute
>
<
name
>
nowPage
</
name
>
<
required
>
true
</
required
>
<
rtexprvalue
>
true
</
rtexprvalue
>
</
attribute
>
<
attribute
>
<
name
>
pageSize
</
name
>
<
required
>
true
</
required
>
<
rtexprvalue
>
true
</
rtexprvalue
>
</
attribute
>
<
attribute
>
<
name
>
count
</
name
>
<
required
>
true
</
required
>
<
rtexprvalue
>
true
</
rtexprvalue
>
</
attribute
>
<
attribute
>
<
name
>
url
</
name
>
<
required
>
true
</
required
>
<
rtexprvalue
>
true
</
rtexprvalue
>
</
attribute
>
</
tag
>
</
taglib
>
//页面:
<%@
page
language
=
"java"
contentType
=
"text/html; charset=UTF-8"
pageEncoding
=
"UTF-8"
%>
<!-- 引入自定义标签,采用
tld
文件中
url
的方式 -->
<!-- 引入自定义标签,采用直接引入标签描述符文件(.
tld
文件)的方式 -->
<%@
taglib
uri
=
"/WEB-INF/pageTag.tld"
prefix
=
"p"
%>
<!
DOCTYPE
html
PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"
http://www.w3.org/TR/html4/loose.dtd"
;
>
<
html
>
<
head
>
<
meta
http-equiv
=
"Content-Type"
content
=
"text/html; charset=UTF-8"
>
<
title
>
自定义标签1
</
title
>
</
head
>
<
body
>
自定义标签1:
<
wt:welcomeTag
/>
<
br
>
自定义标签2:
<
wt:testTag
>
this is second custom tag.
</
wt:testTag
>
<
br
>
自定义标签3:
<
p:page
pageSize
=
"5"
url
=
"UserServlet"
count
=
"16"
nowPage
=
"1"
/>
</
body
>
</
html
>
示例1、示例2、示例3结果: