欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义JSP标签02

程序员文章站 2022-05-30 20:53:17
...

12.4开发迭代标签

支持标签的类:

package org.lxh.tagdemo ;
import java.util.* ;
import javax.servlet.jsp.* ;
import javax.servlet.jsp.tagext.* ;

public class IterateTag extends TagSupport {
	private String name ;
	private String scope ;
	private String id ;	// 这个id用于保存集合中的每一个元素
	private Iterator<?> iter = null ;
	public int doStartTag()
               throws JspException{
		Object value = null ;
		if("page".equals(this.scope)){
			value = super.pageContext.getAttribute(this.name,PageContext.PAGE_SCOPE) ;
		}
		if("request".equals(this.scope)){
			value = super.pageContext.getAttribute(this.name,PageContext.REQUEST_SCOPE) ;
		}
		if("session".equals(this.scope)){
			value = super.pageContext.getAttribute(this.name,PageContext.SESSION_SCOPE) ;
		}
		if("application".equals(this.scope)){
			value = super.pageContext.getAttribute(this.name,PageContext.APPLICATION_SCOPE) ;
		}
		if(value!=null && value instanceof List<?>){
			this.iter = ((List<?>)value).iterator() ;
			if(iter.hasNext()){
				// 将属性保存在page属性范围之中
				super.pageContext.setAttribute(this.id,iter.next()) ;
				return TagSupport.EVAL_BODY_INCLUDE ;
			} else {
				return TagSupport.SKIP_BODY ;
			}
		} else {
			return TagSupport.SKIP_BODY ;
		}
	}

	public int doAfterBody()
                throws JspException{
		if(iter.hasNext()){
			// 将属性保存在page属性范围之中
			super.pageContext.setAttribute(this.id,iter.next()) ;
			return TagSupport.EVAL_BODY_AGAIN ;	// 反复执行doAfterBody()方法
		} else {
			return TagSupport.SKIP_BODY ;
		}
	}

	public void setName(String name){
		this.name = name ;
	}
	public void setScope(String scope){
		this.scope = scope ;
	}
	public void setId(String id){
		this.id = id ;
	}
	public String getName(){
		return this.name ;
	}
	public String getScope(){
		return this.scope ;
	}
	public String getId(){
		return this.id ;
	}
}

标签的描述文件:

<?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_1.xsd"
    version="2.1">
    <tlib-version>1.0</tlib-version>
    <short-name>mldntag</short-name>
    <tag>
	<name>present</name>
	<tag-class>org.lxh.tagdemo.AttributeTag</tag-class>
	<body-content>JSP</body-content>
	<attribute>
		<name>name</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<attribute>
		<name>scope</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
    </tag>
    <tag>
	<name>iterate</name>
	<tag-class>org.lxh.tagdemo.IterateTag</tag-class>
	<body-content>JSP</body-content>
	<attribute>
		<name>name</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<attribute>
		<name>scope</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<attribute>
		<name>id</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
    </tag>
</taglib>

使用XML映射tld文件的绝对路径:

<web-app 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-app_2_5.xsd"
   version="2.5">

  <display-name>Welcome to Tomcat</display-name>
  <description>
     Welcome to Tomcat
  </description>
	<jsp-config>
		<taglib>
			<taglib-uri>mldn_date</taglib-uri>
			<taglib-location>/WEB-INF/datetag.tld</taglib-location>
		</taglib>
		<taglib>
			<taglib-uri>mldn</taglib-uri>
			<taglib-location>/WEB-INF/mldntag.tld</taglib-location>
		</taglib>
	</jsp-config>
	<resource-ref>
		<res-ref-name>jdbc/mldn</res-ref-name>
		<res-type>javax.sql.DataSource</res-type>
		<res-auth>Container</res-auth>
	</resource-ref>
</web-app>

开发JSP文件

<%@ page contentType="text/html" pageEncoding="GBK"%>
<%@ page import="java.util.*"%>
<%@ taglib prefix="mytag" uri="mldn"%>
<html>
<head><title>www.mldnjava.cn,MLDN高端Java培训</title></head>
<body>
<%    // 此代码只是为了测试,实际中此部分应该由servlet传递
    List<String> all = new ArrayList<String>() ;
    all.add("www.MLDN.cn") ;
    all.add("www.MLDNJAVA.cn") ;
    all.add("www.JIANGKER.com") ;
    request.setAttribute("all",all) ;    // 将内容保存在标签执行
%>
<mytag:present name="all" scope="request">
    <mytag:iterate id="url" name="all" scope="request">
        <h3>网站:${url}</h3>
    </mytag:iterate>
</mytag:present>
</body>
</html>

此处操作比较简单,主要是为了演示各个方法之间的操作,以及为了以后讲解Struts提供更加方便的原理操作。

本程序是直接采用了List集合方式完成的,而实际之中可能会传递Map或者对象数组等地的,这些功能的实现过程基本上是一样的

 而且此时一个JSP页面也确实复合了MVC的设计准则,代码非常少,而且不含Scriptlet代码。

12.5BodyTagSupport类

自定义JSP标签02

自定义JSP标签02

 自定义JSP标签02

再本程序中,使用<jsp:useBean>标签定义了一个simple得属性名称,但是这个simple却可以想对象一样,可以直接在Scriptlet之间访问,而用户自己定义标签也想实现同样的效果,那么就需要通过TagExtraInfo类和VariableInfo类来完成。

自定义JSP标签02

自定义JSP标签02

为了更好说明此类,故完成下面定义一个变量的java类

package org.lxh.tagdemo ;
import java.util.* ;
import javax.servlet.jsp.* ;
import javax.servlet.jsp.tagext.* ;

public class BodyIterateTag extends BodyTagSupport {
	private String name ;
	private String scope ;
	private String id ;	// 这个id用于保存集合中的每一个元素
	private Iterator<?> iter = null ;
	public int doStartTag()
               throws JspException{
		Object value = null ;
		if("page".equals(this.scope)){
			value = super.pageContext.getAttribute(this.name,PageContext.PAGE_SCOPE) ;
		}
		if("request".equals(this.scope)){
			value = super.pageContext.getAttribute(this.name,PageContext.REQUEST_SCOPE) ;
		}
		if("session".equals(this.scope)){
			value = super.pageContext.getAttribute(this.name,PageContext.SESSION_SCOPE) ;
		}
		if("application".equals(this.scope)){
			value = super.pageContext.getAttribute(this.name,PageContext.APPLICATION_SCOPE) ;
		}
		if(value!=null && value instanceof List<?>){
			this.iter = ((List<?>)value).iterator() ;
			if(iter.hasNext()){
				// 将属性保存在page属性范围之中
				super.pageContext.setAttribute(this.id,iter.next()) ;
				return BodyTagSupport.EVAL_BODY_BUFFERED ;
			} else {
				return BodyTagSupport.SKIP_BODY ;
			}
		} else {
			return BodyTagSupport.SKIP_BODY ;
		}
	}

	public int doAfterBody()
                throws JspException{
		if(iter.hasNext()){
			// 将属性保存在page属性范围之中
			super.pageContext.setAttribute(this.id,iter.next()) ;
			return BodyTagSupport.EVAL_BODY_AGAIN ;	// 反复执行doAfterBody()方法
		} else {
			return BodyTagSupport.SKIP_BODY ;
		}
	}
	public int doEndTag()
             throws JspException{	// 如果此方法没有编写,则没有输出
		if(super.bodyContent != null){	
			try{
				super.bodyContent.writeOut(super.getPreviousOut()) ;
			}catch(Exception e){
			}
		}
		return BodyTagSupport.EVAL_PAGE ;	// 正常执行完毕
	}

	public void setName(String name){
		this.name = name ;
	}
	public void setScope(String scope){
		this.scope = scope ;
	}
	public void setId(String id){
		this.id = id ;
	}
	public String getName(){
		return this.name ;
	}
	public String getScope(){
		return this.scope ;
	}
	public String getId(){
		return this.id ;
	}
}
package org.lxh.tagdemo ;
import javax.servlet.jsp.tagext.* ;
public class BodyIterateTagExtraInfo extends TagExtraInfo {
	public VariableInfo[] getVariableInfo(TagData data){
		return new VariableInfo[] {new VariableInfo(data.getId(),"java.lang.String",true,VariableInfo.NESTED)} ;
	}
}

该ltd文件如下:

<?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_1.xsd"
    version="2.1">
    <tlib-version>1.0</tlib-version>
    <short-name>mldntag</short-name>
    <tag>
	<name>present</name>
	<tag-class>org.lxh.tagdemo.AttributeTag</tag-class>
	<body-content>JSP</body-content>
	<attribute>
		<name>name</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<attribute>
		<name>scope</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
    </tag>
    <tag>
	<name>iterate</name>
	<tag-class>org.lxh.tagdemo.IterateTag</tag-class>
	<body-content>JSP</body-content>
	<attribute>
		<name>name</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<attribute>
		<name>scope</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<attribute>
		<name>id</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
    </tag>
    <tag>
	<name>bodyiterate</name>
	<tag-class>org.lxh.tagdemo.BodyIterateTag</tag-class>
	<tei-class>
		org.lxh.tagdemo.BodyIterateTagExtraInfo
	</tei-class>
	<body-content>JSP</body-content>
	<attribute>
		<name>name</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<attribute>
		<name>scope</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<attribute>
		<name>id</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
    </tag>
</taglib>

实际的工作中,对于标签的开发没有必要做深入的研究,因为有很多第三方开发的标签可以使用。

自定义JSP标签02

12.5简单标签的开发

为了简化标签开发的复杂度,专门增加了一个制作简单标签库的SimpleTagSupport类,直接覆写里面的doTag()方法即可完成。

自定义JSP标签02

下面开发一个之前开发的时间规格功能:

package org.lxh.tagdemo ;
import java.io.* ;
import java.util.* ;
import java.text.* ;
import javax.servlet.jsp.* ;
import javax.servlet.jsp.tagext.* ;
public class SimpleDateTag extends SimpleTagSupport {
	private String format ;	// 接收格式化
	public void doTag()
           throws JspException,
                  IOException{
		SimpleDateFormat sdf = new SimpleDateFormat(this.format) ;
		try{
			super.getJspContext().getOut().write(sdf.format(new Date())) ;
		}catch(Exception e){}
	}
	public void setFormat(String format){
		this.format = format ;
	}
	public String getFormat(){
		return this.format ;
	}
}

标签操作:

   <tag>
	<name>simpledate</name>
	<tag-class>org.lxh.tagdemo.SimpleDateTag</tag-class>
	<body-content>empty</body-content>
	<attribute>
		<name>format</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>=
    </tag>

XML文件的操作:

		<taglib>
			<taglib-uri>mldn_date</taglib-uri>
			<taglib-location>/WEB-INF/datetag.tld</taglib-location>
		</taglib>
		<taglib>
			<taglib-uri>mldn</taglib-uri>
			<taglib-location>/WEB-INF/mldntag.tld</taglib-location>
		</taglib>

直接编写JSP文件:

<%@ page contentType="text/html" pageEncoding="GBK"%>
<%@ taglib prefix="mytag" uri="mldn"%>
<html>
<head><title>www.mldnjava.cn,MLDN高端Java培训</title></head>
<body>
	<h1>
		<mytag:simpledate format="yyyy-MM-dd HH:mm:ss.SSS"/>
	</h1>
</body>
</html>

此时标签的功能和之前完全一样,但是实现起来不用再处理各种复杂的返回值数据,直接编写即可。

但是也存在一个问题,返回值没有了,该怎么进行循环呢?

再进行迭代输出的时候,之前是通过doStartTag()和doAfterBody()操作的page属性范围,保存一个个的对象属性,但现在的操作中,可以直接通过getJspBody()调用标签体的内容。

package org.lxh.tagdemo ;
import java.io.* ;
import java.util.* ;
import java.text.* ;
import javax.servlet.jsp.* ;
import javax.servlet.jsp.tagext.* ;
public class SimpleIterateTag extends SimpleTagSupport {
	private String id ;
	private String name ;
	private String scope ;
	public void doTag()
           throws JspException,
                  IOException{
		Object value = null ;
		if("page".equals(this.scope)){
			value = super.getJspContext().getAttribute(this.name,PageContext.PAGE_SCOPE) ;
		}
		if("request".equals(this.scope)){
			value = super.getJspContext().getAttribute(this.name,PageContext.REQUEST_SCOPE) ;
		}
		if("session".equals(this.scope)){
			value = super.getJspContext().getAttribute(this.name,PageContext.SESSION_SCOPE) ;
		}
		if("application".equals(this.scope)){
			value = super.getJspContext().getAttribute(this.name,PageContext.APPLICATION_SCOPE) ;
		}
		if(value != null && value instanceof List<?>){
			Iterator<?> iter = ((List<?>) value).iterator() ;
			while(iter.hasNext()){
				super.getJspContext().setAttribute(id,iter.next()) ;
				super.getJspBody().invoke(null) ;
			}
		}
	}
	public void setId(String id){
		this.id = id ;
	}
	public void setName(String name){
		this.name = name ;
	}
	public void setScope(String scope){
		this.scope = scope ;
	}
	public String getId(){
		return this.id ;
	}
	public String getName(){
		return this.name ;
	}
	public String getScope(){
		return this.scope ;
	}
}

tld文件的设置一样的:

<tag>
	<name>simpleiterate</name>
	<tag-class>org.lxh.tagdemo.SimpleIterateTag</tag-class>
	<body-content>scriptless</body-content>
	<attribute>
		<name>name</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<attribute>
		<name>scope</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<attribute>
		<name>id</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
    </tag>

xml也是,不做重复。

再JSP文件中:

<%@ page contentType="text/html" pageEncoding="GBK"%>
<%@ page import="java.util.*"%>
<%@ taglib prefix="mytag" uri="mldn"%>
<html>
<head><title>www.mldnjava.cn,MLDN高端Java培训</title></head>
<body>
	<%
		List<String> all = new ArrayList<String>() ;
		all.add("www.MLDN.cn") ;
		all.add("www.MLDNJAVA.cn") ;
		all.add("www.JIANGKER.com") ;
		request.setAttribute("all",all) ;
	%>
	<h1>
		<mytag:simpleiterate id="url" name="all" scope="request">
			<h2>网站:${url}</h2>
		</mytag:simpleiterate>
	</h1>
</body>
</html>

此时代码功能已经实现了,可以发现,通过简单标签的标签库的开发,再也不用像之前那样处理各个复炸的返回值操作了。

技术这样的简单,但是标签库本身也是一个不常用的内容,所以掌握标签的使用的操作原理即可,而开发的使用建议不要使用。

12.6DynamicAttributes接口

之前的所有属性如果需要,则必须在<tag>文件中使用<attribute>的节点进行定义,但是如果现在属性是不固定的,可以由用户自己任意设置的话,就可以使用DynamicAttributes接口实现。

下面通过观察一个简单程序的实现来观察结果:

package org.lxh.tagdemo ;
import java.io.* ;
import java.util.* ;
import javax.servlet.jsp.* ;
import javax.servlet.jsp.tagext.* ;
public class DynamicAddTag extends SimpleTagSupport implements DynamicAttributes {
		private Map<String,Float> num = new HashMap<String,Float>() ;
		public void doTag()
           throws JspException,
                  IOException{
			Float sum = 0.0f ;
			Iterator<Map.Entry<String,Float>> iter = this.num.entrySet().iterator() ;
			while(iter.hasNext()){
				Map.Entry<String,Float> value = iter.next() ;
				sum += value.getValue() ;	// 取出每一个内容
			}
			super.getJspContext().getOut().write(sum + "") ;
		}
		public void setDynamicAttribute(String uri,
                         String localName,
                         Object value)
                         throws JspException{
			// 取出设置的每一个动态属性,都保存在Map集合里
			num.put(localName,Float.parseFloat(value.toString())) ;
		}
}

tld文件的设置:

  <tag>
	<name>add</name>
	<tag-class>org.lxh.tagdemo.DynamicAddTag</tag-class>
	<body-content>empty</body-content>
	<dynamic-attributes>true</dynamic-attributes>
    </tag>

xml文件设置:

	<jsp-config>
		<taglib>
			<taglib-uri>mldn_date</taglib-uri>
			<taglib-location>/WEB-INF/datetag.tld</taglib-location>
		</taglib>
		<taglib>
			<taglib-uri>mldn</taglib-uri>
			<taglib-location>/WEB-INF/mldntag.tld</taglib-location>
		</taglib>
	</jsp-config>

JSP文件:

<%@ page contentType="text/html" pageEncoding="GBK"%>
<%@ taglib prefix="mytag" uri="mldn"%>
<html>
<head><title>www.mldnjava.cn,MLDN高端Java培训</title></head>
<body>
	<h2>计算结果:
		<mytag:add num1="11.2" num2="12.3" num3="13.5"/> 
	</h2>
</body>
</html>

使用动态属性,在进行标签调用的时候非常方便,但是如果是动态实现,则实现标签的难度也很大。

标签掌握的原理即可,因为下一章将讲解一些免费的标签组件。

 

                                                                                                                                                              2018 07 18