1 . 什么是自定义标签
尽管JSP本身,以及第三方提供了很多标签库,但因为业务需要,我们有时还是需要自定义标签。因为JSP页面中不可以存在Java代码,所以我们需要自定义标签!
2 .标签的真身
其实我们现在应该可以了解了,真的是万物皆对象。JSP可以是一个对象,当然标签也可以是一个对象。其实在页面中使用的标签就是对一个对象的方法调用!
标签:
- 标签处理类:都有自己的标签处理类!所有标签处理类都必须去实现Tag或SimpleTag接口;
- TLD(Tag Library Description):一个TLD文件中可以部署多个标签!JSP会通过TLD文件找到标签! (webapps\examples\WEB-INF\jsp2,这里有模板)
3,SimpleTag
1) SimpleTag是什么
标签处理类必须实现JspTag接口,而JspTag接口有两个子接口:Tag和SimpleTag。更加确切的说:标签处理类必须实现Tag或SimpleTag接口。
JSP2.0之后,SUN提供了SimpleTag接口,通过SimpleTag接口来实现标签处理类要比Tag这种传统方式方便很多,所以现在我们可以大声与Tag说再见了。
SimpleTag接口内容如下:
void doTag():标签执行方法;
JspTag getParent():获取父标签;
void setParent(JspTag parent):设置父标签
void setJspContext(JspContext context):设置PageContext
void setJspBody(JspFragment jspBody):设置标签体对象;
4 .自定义标签方式一:实现SimpleTag接口的自定义标签
案例:定义一个Hello SimpleTag的简单标签
标签类的定义:
public class HelloTag implements SimpleTag {
private PageContext pageContext;
public void doTag() throws JspException, IOException {
pageContext.getOut().write("<p>Hello SimpleTag!</p>");
}
public void setJspContext(JspContext pc) {
this.pageContext = (PageContext) pc;
}
public void setParent(JspTag parent) {}
public JspTag getParent() {return null;}
public void setJspBody(JspFragment jspBody) {}
}
TLD文件的定义
注意: [把tld文件放到classes\META-INF\hello.tld路径]
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
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 ">
<tlib-version>1.0</tlib-version>
<short-name>kzkate</short-name>
<uri>http://www.kzkate.cn/kzkate-tags</uri>
<tag>
<name>hello</name>
<tag-class>cn.kzkate.simpletags.HelloTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
jsp中使用
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="kzkate" uri="http://www.kzkate.cn/kzkate-tags" %>
......
<body>
This is my JSP page. <br>
<kzkate:hello/>
</body>
5 .自定义标签方式二:继承SimpleTagSupport的自定义标签
public class HelloTag extends SimpleTagSupport {
public void doTag() throws JspException, IOException {
this.getJspContext().getOut().write("<p>Hello SimpleTag!</p>");
}
}
6 .有标签体的标签
标签类
public class HelloTag extends SimpleTagSupport {
public void doTag() throws JspException, IOException {
PageContext pc = (PageContext) this.getJspContext();
HttpServletRequest req = (HttpServletRequest) pc.getRequest();
String s = req.getParameter("exec");
if(s != null && s.endsWith("true")) {
//[获取当前标签的标签体对象];
JspFragment body = this.getJspBody()
JspWriter out = pc.getOut();
//[执行标签体。如果使用null来调用invoke()方法,那么默认是使用当前页面的输出流!即使用null与当前的效果相同。]
body.invoke(out);
}
}
}
TLD文件
<tag>
<name>hello</name>
<tag-class>cn.kzkate.simpletags.HelloTag</tag-class>
<body-content>scriptless</body-content>
</tag>
jsp中使用
<kzkate:hello>
<h1>哈哈哈~</h1>
</kzkate:hello>
body-content元素的可选值有:
empty:不能有标签体内容。
JSP:标签体内容可以是任何东西:EL、JSTL、<%=%>、<%%>,以及html;但不建议使用Java代码段,SimpleTag已经不再支持使用JSP
scriptless:标签体内容不能是Java代码段,但可以是EL、JSTL等;
tagdependent:标签体内容不做运算,由标签处理类自行处理,无论标签体内容是EL、JSP、JSTL,都不会做运算。
public class HelloTag extends SimpleTagSupport {
public void doTag() throws JspException, IOException {
PageContext pc = (PageContext) this.getJspContext();
HttpServletRequest req = (HttpServletRequest) pc.getRequest();
String s = req.getParameter("exec");
if(s != null && s.endsWith("true")) {
//[获取当前标签的标签体对象];
JspFragment body = this.getJspBody();
JspWriter out = pc.getOut();
//[执行标签体。如果使用null来调用invoke()方法,那么默认是使用当前页面的输出流!即使用null与当前的效果相同。]
body.invoke(out);
}
}
}
<tag>
<name>hello</name>
<tag-class>cn.kzkate.simpletags.HelloTag</tag-class>
<body-content>scriptless</body-content>
</tag>
<kzkate:hello>
<h1>哈哈哈~</h1>
</kzkate:hello>
7,不执行标签下面的页面内容
我们知道,在使用Tag接口来编写标签时,可以跳过标签下面的JSP页面内容。在SimpleTag中也是可以的,这需要在doTag()方法中抛出SkipPageException。
SkipPageException是JspException的子类,当doTag()方法抛出该异常时,JSP真身不会打印异常信息,而是跳转页面内容!
public class SkipTag extends SimpleTagSupport {
public void doTag() throws JspException, IOException {
this.getJspContext().getOut().print("<h1>只能看到我!</h1>");
throw new SkipPageException();
}
}
<tag>
<name>skip</name>
<tag-class>cn.kzkate.simpletags.SkipTag</tag-class>
<body-content>empty</body-content>
</tag>
<kzkate:skip/>
<h1>看不见我!</h1>
8,带有属性的标签
- 在处理类中添加属性,以及getter/setter方法;
- 在TLD中部属相关属性。
public class DemoTag extends SimpleTagSupport {
private String name;
public String getName() {
return name;
}
//[Servlet在执行标签时会先调用setName()方法把值传递给处理类,然后再调用doTag()方法。]
public void setName(String name) {
this.name = name;
}
public void doTag() throws JspException, IOException {
this.getJspContext().getOut().print("hello " + name);
}
}
<tag>
<name>demo</name>
<tag-class>cn.kzkate.simpletags.DemoTag</tag-class>
<body-content>empty</body-content>
<attribute>
//[tag>中可以有0~n个<attribute>元素,每个<attribute>表示一个属性。]
//[定属性名(必须给出<name>),当指定的属性为name时,那么标签处理类必须有setName()方法。getName()可以没
//有。因为Servlet会调用setName()传递值给标签处理类]
<name>name</name>
//[属性是否为必须的。默认值为false,表示属性不是必须的。]
<required>true</required>
//[属性是否可以是表达式。如EL表达式,以及<%=xxx%>。默认值为false,表示不能是表达式。]
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
<%
pageContext.setAttribute("name", "liSi");
String name = "wangWu";
%>
<kzkate:demo name="zhangSan"/><br/>
<kzkate:demo name="${name }"/><br/>
<%--[因为<rtexprvalue>为false,所以属性值为能否是动态表达式,所以${name}和<%=name%>都是非法的。]--%>
<kzkate:demo name="<%=name %>"/>
9,综合案例:自定义分页标签和时间格式化标签
分页标签类
public class PageTag extends SimpleTagSupport {
private int curPage;//当前页
private int pageSize;//每页显示的条数;
private int total;//总页数
private String url;//点击上一页或下一页跳转到哪个请求进行处理数据
private String className = "tres";
public void doTag() throws JspException, IOException {
JspWriter out = this.getJspContext().getOut();
StringBuffer str = new StringBuffer();
str.append("<div align='center' class='"+className+"'>");
if(curPage==1){
str.append("首页 上一页");
}else{
str.append("<a href='"+url+"&curPage=1'>首页 </a>");
str.append("<a href='"+url+"&curPage="+(curPage-1)+"'>上一页</a>");
}
str.append("当前第"+curPage+"页共"+total+"页");
if(curPage!=total){
str.append("<a href='"+url+"&curPage="+(curPage+1)+"'>下一页 </a>");
str.append("<a href='"+url+"&curPage="+total+"'>末页</a>");
}else{
str.append("下一页 末页");
}
str.append("<form action='listAction.do?method=list' method='post'>");
str.append("<input size='3' name='curPage'>");
str.append("<input type='submit' value='Go'>");
str.append("</form>");
str.append("</div>");
/*str.append("<script>");
str.append("function validate(){");
str.append("}");
str.append("</script>");*/
out.println(str);
}
//省略get/set方法
}
日期标签类
public class DateTag extends SimpleTagSupport {
//设定日期的格式
private String parttern = "yyyy-MM-dd E";
//指定日期
private Date value ;
@Override
public void doTag() throws JspException, IOException {
//获取输出流对象
JspWriter out = this.getJspContext().getOut();
SimpleDateFormat sf = new SimpleDateFormat(parttern);
//Date d = new Date();
String str = sf.format(value);
out.println(str);
}
//省略get/set方法
}
分页标签和日期标签TLD
<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
version="2.1">
<description>这是我们自定义的标签</description>
<display-name>My core</display-name>
<tlib-version>1.0</tlib-version>
<short-name>my</short-name>
<uri>/mytag</uri>
<tag>
<description>
这是一个日期标签
</description>
<name>date</name>
<tag-class>com.cshr.tag.DateTag</tag-class>
<body-content>empty</body-content>
<!-- 设置标签的属性 -->
<attribute>
<description>这个属性用来设置日期的格试</description>
<name>parttern</name>
<!-- 是否为必须属性 -->
<required>false</required>
<!-- 是否支持动态表达式 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<description>这个属性用来设置日期的值</description>
<name>value</name>
<!-- 是否为必须属性 -->
<required>true</required>
<!-- 是否支持动态表达式 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<description>
这是一个分页标签
</description>
<name>page</name>
<tag-class>com.cshr.tag.PageTag</tag-class>
<body-content>empty</body-content>
<!-- 设置标签的属性 -->
<attribute>
<description>这个属性用来设置当前页数</description>
<name>curPage</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>这个属性用来设置每页显示多少条数据</description>
<name>pageSize</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>这个属性用来设置总页数</description>
<name>total</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>这个属性用来设置请求的地址</description>
<name>url</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<description>这个属性用来设置CSS</description>
<name>className</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
</taglib>
jsp中测试
......
<%@ taglib uri="/mytag" prefix="my" %>
<%@ taglib uri="/mytag" prefix="my" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%
Date d = new Date(2012-1900,11,12);
request.setAttribute("d",d);
%>
.......
<!-- 自定义日期标签 -->
<my:date value="${d}" parttern="yyyy/MM/dd"/>
<fmt:formatDate value="${d}" pattern="yyyy/MM/dd" />
<!-- 自定义分页标签 -->
<my:page pageSize="${pageSize}" url="listAction.action?method=list" total="${total}" curPage="${curPage}" className="badoo"/>