那些年javaweb自定义标签详解

一、简介

自定义标签的作用主要是用来替换JSP中的Java脚本。属于JSP技术。

二、自定义标签的开发步骤:

1.编写一个实现Tag接口的Java(标签处理器类)

2.编写标签库描述符(tld)文件,在tld文件中把标签处理器类进行描述在tld文件放入应用的web-inf文件中。如输入客户端ip地址的例子具体步骤示例如下:

1>定义一个类,实现javax.servlet.jsp.tagext.Tag接口(通过继承Tag接口的实现类也可)。

  public class ShowRemoteIpTag extends TagSupport {
  	public int doStartTag() throws JspException {
  		String remoteIp = pageContext.getRequest().getRemoteAddr();
  		try {
  			pageContext.getOut().print("您的IP是是:"+remoteIp);
  		} catch (IOException e) {
  			e.printStackTrace();
  		}
  		return super.doStartTag();
  	}
  }

2、在WEB-INF目录下建立一个扩展名为tldXML文件(XML的内容参考Tomcat中的示例)fk.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">
      <description>my taglib study.</description>
      <tlib-version>1.0</tlib-version>
      <short-name>fk</short-name>
      <uri>http://www.test.com/jsp/fk</uri>
      <tag> <!--  可定义标签如<fk: showRemoteIp />  -->
  		<description>Show Remote Ip</description>
          <name>showRemoteIp</name>
  		<tag-class>com.fk.tag.ShowRemoteIpTag</tag-class>
  		<body-content>empty</body-content>
      </tag>
   <tag>
  	<name>forEach</name>
  	<tag-class>com.fk.tag.example.ForEachSimpleTag</tag-class>
  	<body-content>scriptless</body-content>
  	<attribute> <!-- 定义标签属性 -->
  	    <name>items</name>
  	    <required>true</required>
  	    <rtexprvalue>true</rtexprvalue>
  	</attribute>
  	<attribute>
  	    <name>var</name>
  	    <required>true</required>
  	    <rtexprvalue>false</rtexprvalue><!--  var属性是否支持el-->
  	</attribute>
  </tag>
  <function> <!--  也可定义在el中使用的函数如:${fk:contains(users,user)}  -->
  <description>某一List对象是否包含某一Object对象</description>
  <name>contains</name>
  	<function-class>com.fk.util.ListContainsLabel</function-class>
  	<function-signature>java.lang.Boolean contains(java.util.List,java.lang.Object)</function-signature>
  </function>
  </taglib>

3、在web.xml中建立tld文件的存放位置和uri的对应关系。

注:此步骤是可选的,前提是tld文件放在了WEB-INF目录下(建议使用此方式)

  <jsp-config>
  	<taglib>
  		<taglib-uri>http://www.test.com/jsp/fk</taglib-uri>
  		<taglib-location>/WEB-INF/fk.tld</taglib-location>
  	</taglib>
  </jsp-config>

三、Tag接口详解(接口中的方法大部分都是容器调用的,继承了JspTag接口)

int doStartTag():容器调用。遇到开始标签时调用。

返回值可为:

Tag.SKIP_BODY:指示标签主体内容不执行

Tag.EVAL_BODY_INCLUDE:指示标签主体内容执行

int doEndTag():容器调用。遇到结束标签时调用。

返回值可为:

Tag.SKIP_PAGE:忽略结束标签之后的JSP内容

Tag.EVAL_PAGE:结束标签后的JSP内容还要继续执行

Tag getParent():用户调用。得到父标签。没有父标签返回null

void release():容器调用。释放标签类占用的资源。

void setPageContext(PageContext pc):容器调用。传入当前页面的上下文对象

void setParent(Tag t):容器调用。传入当前标签的父标签对象。如果有的话。

四、IterationTag接口:增加了重复执行主体内容的方法。(IterationTag接口继承了Tag接口,TagSupport类实现了IterationTag接口)

int doAfterBody():主体执行后,结束标签执行前,容器调用

返回值:

Tag.SKIP_BODY:指示标签主体内容不执行

IterationTag.EVAL_BODY_AGAIN:再次调用doAfterBody方法

注:成员变量的问题。

五、BodyTag:增加了获取主体内容的方法

void doInitBody() :容器调用

void setBodyContent(BodyContent b):容器调用,传递标签的主体内容

注意:以上2个方法都是由容器调用。要求doStartTag()方法必须返回BodyTag.EVAL_BODY_BUFFERED

六、传统标签返回值图、标签类继承及传统标签的执行流程

那些年javaweb自定义标签详解_第1张图片

那些年javaweb自定义标签详解_第2张图片

那些年javaweb自定义标签详解_第3张图片

七、简单标签

SimpleTag接口详解

void setJspContext(JspContext pc) :设置当前JSP的上下文件。容器调用

void setParent(JspTag parent) :设置父标签对象。如果有的话。容器调用

void setJspBody(JspFragment jspBody) :设置主体内容。容器调用

若实现此接口类,有相关的setter属性,容器会自动调用自定义的setter方法。 

void doTag():遇到标签就执行。容器调用。---------处理自定义标签功能的方法

用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。doTag方法中可以 抛出javax.servlet.jsp.SkipPageException异常,用于通知WEB容器不再执行JSP页面中 位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回 Tag.SKIP_PAGE常量的情况。 

JspTag getParent():自己调用。得到父标签。没有返回null

注意:每次调用都会重新实例化,简单标签不会驻留内存,而传统标签会驻留内存(Servlet一样,第一次访问时容器创建实例化后就驻留了)

那些年javaweb自定义标签详解_第4张图片

//url地址过滤,若不是本站过来的url将被传到toPage值的文件中去。
public void doTag() throws JspException, IOException {
		PageContext pc = (PageContext)getJspContext();
		HttpServletRequest request = (HttpServletRequest)pc.getRequest();
		String referer = request.getHeader("Referer");//Referer
		HttpServletResponse response = (HttpServletResponse)pc.getResponse();
		if(null == referer ||!referer.startsWith(siteUrl)){ //若不是指定的url开头地址则转过去,否则继续浏览呢,siteUrl为标签另一属性本站的基地址。
			if(toPage.startsWith("/")){
				response.sendRedirect(toPage);
			}else{
				String path = request.getRequestURL().toString();
				String prePath = path.substring(0, path.lastIndexOf("/"));
				response.sendRedirect(prePath+"/"+toPage);
			}
		}
	}

显示类如下,模拟foreach功能:

public class ForEachSimpleTag extends SimpleTagSupport {
	private Object items;
	private String var;
	private Collection collection ;
	public void setItems(Object items) {
		if(items instanceof List){
			collection = (List)items;
		}
		if(items instanceof Set){
			collection = (Set)items;
		}
		if(items instanceof Map){
			collection = ((Map)items).entrySet();
		}
		if(items.getClass().isArray()){
			int len = Array.getLength(items);//获取数组的长度
			for(int i=0;i<len;i++)
				collection.add(Array.get(items, i));
		}
	}
	public void setVar(String var) {//setter方法容器自动将属性设置进去。
		this.var = var;
	}
	public void doTag() throws JspException, IOException {
		PageContext pc = (PageContext)getJspContext();
		if(null==collection) return;
		for(Object o:collection){
			pc.setAttribute(var, o);
			getJspBody().invoke(null);
		}
	}	
}

八、tld文件的主要元素

taglib:根元素

tlib-version:版本号

short-name:短名称

uri:名称空间

function:可定义函数

name:标签的名称如contains

function-class:标签的处理类如com.fk.util.ListContainsLabel

function-signature:标签的静态处理方法

如:java.lang.Boolean contains(java.util.List,java.lang.Object)

tag:定义一个标签

name:标签的名称

tag-class:标签的处理类。全名称

body-content:标签的主体内容类型。

可选值:

JSP:主体内容可以是任意内容。服务传统标签

scriptless:主体内容一般是非java脚本内容。服务简单标签

empty:没有主体内容

tagdepentend:指示主体内容当做普通字符串对待

attribute:定义标签的属性

name:属性名称

required:是否是必须属性

rtexprvalue:是否支持表达式(EL表达式或Java表达式)

runtime expression value



你可能感兴趣的:(java,jsp,String,object,null,setter)