@jianhua.cheng

编写定制标签

March 24, 2016

定制标签的目的是分离表现逻辑和业务逻辑,可以在 JSP 页面编写中尽量不出现scriptlet,而且可以根据自己想要的功能定制属于自己想要的标签,完成特定的功能。

这里只讲在 JSP2.0 之后添加的一个用于编写定制标签的接口—— SimpleTag ,这个接口实现简单,效果也不错。

SimpleTag接口位于javax.servlet.jsp.tagext中,实现了该接口的标签处理器称作简单的标签处理器。SimpleTag接口中只有一个方法:doTag(),并且在标签调用时只执行一次。业务逻辑及主题操作代码都要在这里编写。


一个简单的标签处处理器的生命周期如下:

JSP 容器通过调用其无参构造函数,创建一个简单标签处理器实例。因此,简单的处理器必须有一个无参构造器。

JSP 容器调用setJspCOntext方法,同时传递一个JspContext对象。JspContext最重要的方法是getOut,它返回一个JspWriter,用于将响应发送到客户端。setJspContext方法的签名如下:

public void setJspContext (JspContext jspContext)

大多数时候,需要将传进来的JspContext对象赋给一个类级变量,便于后续使用。

如果表示标签处理器的定制标签是嵌套在另一个标签中的,JSP 容器就会调用setParent方法。该方法的签名如下:

public void setParent(JspTag parent)

JSP 容器为该标签定义的每个属性都调用设置方法(Setters)

如果标签中有主体内容,JSP 将调用SimpleTag接口中的setJspBody方法,将主体内容作为JspFragment传递。如果没有主体内容,JSP 容器将不会调用这个方法。

JSP 容器调用doTag方法。所有变量在doTag方法返回时同步。


注:javax.servlet.jsp.tagext包中也含有SimpleTag接口的一个支持类:SimpleTagSupportSimpleTagSupportSimpleTag接口中的所有方法都提供了默认实现(类似于适配器),我们可以继承它来编写一个简单的标签处理器。当 JSP 容器调用SimpleTag接口的setJspContext方法时,SimpleTagSupport类中的getJspContext方法将返回 JSP 容器传递的JspContext实例。


编写处理器

为了编译标签处理器,需要在构建路径中包含Servlet APIJSP API类包。例如Tomcatservlet-api.jar文件和jsp-api.jar文件。

import java.io.IOException;

import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;

public class MyFirstTag implements SimpleTag {

	JspContext jspContext;

	@Override
	public void doTag() throws JspException, IOException {
		System.out.println("doTag");
		jspContext.getOut().print("This is my first tag.");
	}

	@Override
	public JspTag getParent() {
		System.out.println("getParent");
		return null;
	}

	@Override
	public void setJspBody(JspFragment body) {
		System.out.println("setJspBody");
	}

	@Override
	public void setJspContext(JspContext jspContext) {
		System.out.println("getJspContext");
		this.jspContext = jspContext;
	}

	@Override
	public void setParent(JspTag parent) {
		System.out.println("setParent");
	}

}

MyFIrstTag类有一个类型为JspContextjspContext变量。setJspContext方法将它从 JSP 容器接收到的JspContext赋给这个变量。doTag方法利用JspContext获得一个JspWriter。然后调用JspWriterprint方法,输出This is my first tag.

注册标签

用一个以.tld为扩展名的 XML 文件描述标签处理器。以下示例mytags.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 web-jsptaglibrary_2_1.xsd"
    version="2.1">

    <description>
         Simple tag examples
    </description>
    <tlib-version>1.0</tlib-version>
    <short-name>My First Taglib Example</short-name>
    <tag>
        <name>firstTag</name>
        <tag-class>customtag.MyFirstTag</tag-class>
		<body-content>empty</body-content>
    </tag>

    <tag>
        <name>dataFormatter</name>
        <tag-class>customtag.DataFormatterTag</tag-class>
        <body-content>empty</body-content>
        <attribute>
            <name>header</name>
            <required>true</required>
        </attribute>
        <attribute>
            <name>items</name>
            <required>true</required>
        </attribute>
    </tag>


    <tag>
        <name>select</name>
        <tag-class>customtag.SelectElementTag</tag-class>
        <body-content>scriptless</body-content>
    </tag>

</taglib>

标签类库描述符中的主要元素是tag,它用来描述标签,其中包含一个name元素和一个tag--class元素。name用于给该标签命名。tag-class用于指定标签处理器的全类名。一个.tld文件中可以包含多个tag元素。 description用于描述tag元素。short-name为标签的简称。tlib-version元素设置定制标签的版本。

使用标签

<%@ taglib uri="WEB-INF/mytags.tld" prefix="easy">
<html>
<head>
	<title>测试我的第一个标签</title>
</head>

<body>
Hello!<br/>
<easy:firstTag></easy:firstTag>
</body>
</html>

在控制台上将显示:

setJspContext

doTag


Jianhua Cheng

Written by Jianhua Cheng who lives and works in Shanghai. Try to build something more attractive and interesting. You can follow him on Twitter, Github