关于这块的资料网上都比较零散,俺整理了下,并附上一个demo希望对大家有帮助。
一、什么是自定义标签?
1,用户自定义的Java 语言元素, 实质是运行一个或者两个接口的JavaBean;
2,可以非常紧密地和JSP的表示逻辑联系在一起,又具有和普通JavaBean相同的业务逻辑处理能力;
3,当一个JSP页面转变为servlet时,其间的用户自定义标签转化为操作一个称为标签hander的对象;
4,可操作默认对象(JSP内置对象),处理表单数据,访问数据库以及其它企业服务;
二、JSP自定义标签的优缺点
优点:
1.JSP自定义标签可以将开发 模块化 , 定义好的标签可以在多个JSP页面使用;
2.JSP自定义标签可以封装复杂的业务逻辑 ,使得WEB工程师不需要过多的关注内部实现;
3.JSP自定义标签可以美化 前台页面内嵌的JAVA代码;
缺点:
由于JAVA的开源性,使得目前的WEB标签很多。从而导致WEB开发的过程当中为免有些让人眼花缭乱,不过配以相应的文档开发说明变可以解决这个问 题。
三、自定义标签库的特点
1,通过调用页面传递参数实现定制;
2,访问所有对JSP页面可能的对象;
3,修改调用页面生成的响应;
4,自定义标签间可相互通信;
5,在同一个JSP页面中通过标签嵌套,可实现复杂交互。
以上是一些概要,方便对这块没有概念的同学们理解下。接下来的东西偏应用一些。
那么要如何使用自定义标签库呢,首先要在JSP页面中通过taglib的指令进行声明,语法是<%@taglib uri="URI" prefix="pre" %>
例子:
<%@taglib uri="/WEB-INF/template.tld" prefix="test" %>
<%@taglib uri="http://java.sun.com/jstl/core" prefix="core" %>
上面的uri对应一个tld约束文件,因为自定义标签在表现形式上是xml的,所以是需要一个外部文件来对其格式进行约束的。下面来通过一个例子了解 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"><!-- tld最新版本是2.0 --> <description>Black开发的超级牛的标签</description><!-- 可以在ide中提示的内容 --> <display-name>black</display-name><!-- just a name --> <tlib-version>1.0</tlib-version><!-- just a version --> <short-name>black</short-name><!-- 无视之 --> <tag><!-- 一个tag标签表示了标签组中的一个标签因此在此文件中可以有多个 --> <description>根据分隔符循环字符串</description><!-- 可以在ide中提示的内容 --> <name>loopString</name><!-- 标签名字,在JSP页面中使用改标签时会用的到,是很重要的节点哦 --> <tag-class>com.mison.tag.LoopStringTag</tag-class><!-- 标签对应的JAVA类 --> <body-content>JSP</body-content><!-- JSP表示该标签内部可以包含其他标签,即可以有子节点,如果这里写empty就不能有子节点了 --> <attribute><!-- 该标签所具有的属性,因此在一个tag节点中可以有多个attribute节点 --> <description>分隔符</description><!-- 可以在ide中提示的内容 --> <name>sep</name><!-- 属性名 --> <required>true</required><!-- 是否必须 --> <rtexprvalue>false</rtexprvalue><!-- 是否允许使用el表达式或者JSP脚本 --> <type>string</type><!-- 类型,可以有int或者string,默认是string --> </attribute> <attribute> <description>循环字符串</description> <name>content</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>string</type> </attribute> <attribute> <description>每次循环时的变量名</description> <name>id</name> <required>true</required> <rtexprvalue>false</rtexprvalue> <type>string</type> </attribute> </tag> <tag> <description>输出Page作用域中的值</description> <name>outPage</name> <tag-class>com.mison.tag.OutPageTag</tag-class> <body-content>empty</body-content> <attribute> <description>变量名</description> <name>var</name> <required>true</required> <rtexprvalue>false</rtexprvalue> <type>string</type> </attribute> </tag> </taglib>
通过上面的例子和注释,我们可以知道我在tld中定义了两个标签loopString和outPage,他们各自具有一些属性。
现在开始写自定义标签对应的JAVA类,首先要先了解下J2EE标签这块的类,接口图。
简单的标签处理程序类
1,必须实现Tag接口的doStartTag()和doEndTag()方法;
2,因为不存在Body,doStartTag()方法必须返回SKIP_BODY;
3,如其余页面要执行,doEndTag()方法返回EVAL_PAGE, 否则返回SKIP_PAGE;
4,对于每一个标签属性,你必须在标签处理程序类里定义一个特性以及get和set方法以一致于JavaBeans 体系惯例
带Body的自定义标签
1,必须实现Tag接口的doStartTag()和doEndTag()方法;
2,可以实现IterationTag接口的doAfterBody()方法;
3,可以实现BodyTag接口的doInitBody和setBodyContent方法;
4,doStartTag方法可以返回SKIP_BODY、EVAL_BODY_INCLUDE、或者EVAL_BODY_BUFFERED(当你想使 用 BodyContent);
5,doEndTag方法可以返回SKIP_PAGE或EVAL_PAGE;
6,doAfterBody方法可以返回EVAL_BODY_AGAIN, SKIP_BODY;
上面看到了一些常量如SKIP_BODY,SKIP_PAGE,在自定义标签中方法return 这些相应的常量来表示接下来的代码流程,在看下面这张图
各常量的含义
看代码,理解上面的那些类,方法,以及常量。
package com.mison.tag; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTagSupport; import javax.servlet.jsp.tagext.IterationTag; import javax.servlet.jsp.tagext.Tag; public class LoopStringTag extends BodyTagSupport { private String sep; private String content; private String id; private String[] strs; private int index; @Override public int doAfterBody() throws JspException { System.out.println("after"); if (index < strs.length) { pageContext.setAttribute(id, strs[index]); System.out.println("本次内容:" + strs[index]); index++; return IterationTag.EVAL_BODY_AGAIN; } else { pageContext.removeAttribute(id); return Tag.EVAL_PAGE; } } @Override public int doEndTag() throws JspException { System.out.println("end"); return Tag.EVAL_PAGE; } @Override public void doInitBody() throws JspException { System.out.println("init"); super.doInitBody(); } @Override public int doStartTag() throws JspException { System.out.println("start"); strs = content.split(sep); System.out.println("本次数组长度为:" + strs.length); index = 0; pageContext.setAttribute(id, strs[index]); index++; return Tag.EVAL_BODY_INCLUDE; } public String getSep() { return sep; } public void setSep(String sep) { this.sep = sep; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getId() { return id; } public void setId(String id) { this.id = id; } }
package com.mison.tag; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.TagSupport; public class OutPageTag extends TagSupport{ private String var; @Override public int doStartTag() throws JspException { try { pageContext.getOut().print(pageContext.getAttribute(var)); } catch (IOException e) { e.printStackTrace(); } return Tag.SKIP_BODY; } @Override public int doAfterBody() throws JspException { // TODO Auto-generated method stub return super.doAfterBody(); } @Override public int doEndTag() throws JspException { // TODO Auto-generated method stub return super.doEndTag(); } public String getVar() { return var; } public void setVar(String var) { this.var = var; } }
不知道大家有没有注意到,在JAVA文件中为了要能够和页面做交互,很重要的一个对象是pageContext,通过这个对象,我们可以获取到所有的 JSP内置对象,这个是不管是取作用域中的值或者是向页面输出都不是难事了。
上面的loopString标签作用是做循环,而outPage则是输出page域中的值到页面上。
来看看JSP页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri="/WEB-INF/black.tld" prefix="black" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Test JSP Tag</title> </head> <body> <ul> <black:loopString sep="," content="a,b,c,d" id="a"> <li><black:outPage var="a"/></li> </black:loopString> </ul> <% pageContext.setAttribute("name","black"); %> <black:outPage var="name"/> </body> </html>
最后就可以在页面上看到一个列表啦。
工程目录结构也给大家看下。