关于这块的资料网上都比较零散,俺整理了下,并附上一个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" %>
- uri 表示唯一标识标签库描述符(TLD)的URI,在标签库描述符中描述了uri。这个URI可以是直接或者非直接的。
- prefix 定义了区分指定标签库所定义的标签与其他标签库提供的标签的前缀。
例子:
<%@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 这些相应的常量来表示接下来的代码流程,在看下面这张图
各常量的含义
- EVAL_BODY_INCLUDE 把Body读入存在的输出流中,doStartTag()函数可用
- EVAL_PAGE 继续处理页面,doEndTag()函数可用
- SKIP_BODY 忽略对Body的处理,doStartTag()和doAfterBody()函数可用
- SKIP_PAGE 忽略对余下页面的处理,doEndTag()函数可用
- EVAL_BODY_TAG 已经废止,由EVAL_BODY_BUFFERED取代
- EVAL_BODY_BUFFERED 申请缓冲区,由setBodyContent()函数得到的BodyContent对象来处理tag的body,如果类实现了BodyTag,那么 doStartTag()可用,否则非法
- EVAL_BODY_AGAIN 请求继续处理body,返回自doAfterBody(),这个返回值在你制作循环tag的时候是很有用的
看代码,理解上面的那些类,方法,以及常量。
- 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>
最后就可以在页面上看到一个列表啦。
- a
- b
- c
- d
工程目录结构也给大家看下。
这里貌似不能上传附件。可以到俺混迹的迈胜JAVA论坛下载工程的源代码bbs.misonsoft.com/thread-2904-1-1.html