JSP标签编程 2


本章目标

JSP标签编程

    定义有属性的标签

本章目标

理解标签中熟悉的设置方法

理解标签配置文件中的属性定义格式

        上面已经清楚的知道了,对于一个标签的开发需要标签的支持了,标签库的描述文件、web.xml文件中进行配置、之后在JSP中进行使用

         但是对于属性:<jsp:forward page=""/>,  现在自己的标签也可以定义属性操作

         下面定义一个可以完成日期格式化显示的操作,希望用户可以输入自己的日期的格式化的模板,根据此模板最终完成标签

package com.demo;
import java.util.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;

public class IteratTag extends TagSupport {
	private String name;
	private String scope; // 这个id用于保存集合中的每一个元素
	private String 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<?>) {  //instanceof测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据
			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;  
		}
		
		
	}
	@Override
	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 String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getScope() {
		return scope;
	}
	public void setScope(String scope) {
		this.scope = scope;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = 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>firsttag</short-name>  
	   
	  <tag>			
	  <name>present</name>				
	  <tag-class>com.demo.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>com.demo.IteratTag</tag-class>
	  <body-content>JSP</body-content>	
	  <attribute>
		<name>name</name>  
		<required>true</required>  
		<rtexprvale>true</rtexprvale>  
	  </attribute>
	  <attribute>
		<name>scope</name>  
		<required>true</required>  
		<rtexprvale>true</rtexprvale>  
	  </attribute>
	  <attribute>
		<name>id</name>  
		<required>true</required>  
		<rtexprvale>true</rtexprvale>  
	  </attribute>
	  </tag> 
</taglib>

	<taglib>
			<taglib-uri>gz</taglib-uri>
			<taglib-location>/WEB-INF/gztag.tld</taglib-location>
		</taglib>
		<taglib>

<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="java.util.*"%>
<%@ taglib prefix="mytag" uri="gz"%>
<html>
<head>
	<title>欢迎光临</title>
</head>
<body>
<%
	List<String> all = new ArrayList<String>();
	all.add("你好吗");
	all.add("天天快乐");
	all.add("神仙日子");
	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代码


小结

迭代标签在实际的开发中使用较多,尤其是在Struts 框架中更被广泛使用

迭代标签需要用户处理标签体中的内容


body-content的值有下面4种:

<xsd:enumeration value="tagdependent"/>

    <xsd:enumeration value="JSP"/>

    <xsd:enumeration value="empty"/>

    <xsd:enumeration value="scriptless"/>

 

 

tagdependent:标签体内容直接被写入BodyContent,由自定义标签类来进行处理,而不被JSP容器解释,

如下:

<test:myList>

select name,age from users

</test:myList>

 

JSP:接受所有JSP语法,如定制的或内部的tag、scripts、静态HTML、脚本元素、JSP指令和动作。如:

<my:test>

    <%=request.getProtocol()%>      // ②

</my:test>

具体可参考后面附源码。

 

empty:空标记,即起始标记和结束标记之间没有内容。

下面几种写法都是有效的,

<test:mytag />

<test:mytag uname="Tom" />

<test:mytag></test:mytag>

 

scriptless:接受文本、EL和JSP动作。如上述②使用<body-content> scriptless </body-content>则报错,具体可参考后面附源码。


第十二章    JSP标签编程    -------BodyTagSupport 类

掌握BodyTagSupport 类的基本操作流程

掌握TagExtraInfo 类和VariableInfo 类的作用

可以使用BodyTagSupport 类完成迭代标签的开发

BodyTagSupport

BodyTagSupport是TagSupport 类的子类,通过继承BodyTagSupport 类实现的标签可以直接处理标签体的数据,BodTagSupport 类的定义如下:

public class BodyTagSupport
   
   
    
    extends 
    
    TagSupport
   
   
   
   
    
    implements 
    
    BodyTag
   
   












TagExtraInfo l类和VariableInfo类

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




           为了更好的说明BodySupport类, 以及与便利相关的两个类的关系,那么下面使用此类修改之前的迭代标签


package com.demo;
import java.util.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;

public class BodyIteratorTag extends BodyTagSupport {
	private String name;
	private String scope; // 这个id用于保存集合中的每一个元素
	private String 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<?>) {  //instanceof测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据
			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;  
		}
		
		
	}
	@Override
	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;
		}
	}

	@Override
	public int doEndTag() throws JspException { //如果此方法没有编写则没有输出
		if(super.bodyContent != null) {
			try {
				super.bodyContent.writeOut(super.getPreviousOut());
			} catch (Exception e) {

			}
		}
		return BodyTagSupport.EVAL_PAGE;	//正常执行完毕
	}

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

}



package com.demo;

import javax.servlet.jsp.tagext.TagData;
import javax.servlet.jsp.tagext.TagExtraInfo;
import javax.servlet.jsp.tagext.VariableInfo;
// 标签变量的处理类
public class BodyIteratorTagExtraInfo extends TagExtraInfo {
	@Override
	public VariableInfo[] getVariableInfo(TagData data) {
		
		return new VariableInfo[] {new VariableInfo(data.getId(),
				"java.lang.String",true,VariableInfo.NESTED)};
		
	}
}

         
<tag>            
      <name>bodyiterate</name>            
      <tag-class>com.demo.BodyIteratorTag</tag-class>
      <tei-class>
          com.demo.BodyIteratorTagExtraInfo
      </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> 



<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="java.util.*"%>
<%@ taglib prefix="mytag" uri="gz"%>
<html>
<head>
	<title>欢迎光临</title>
</head>
<body>
<%
	List<String> all = new ArrayList<String>();
	all.add("你好吗");
	all.add("天天快乐");
	all.add("神仙日子");
	request.setAttribute("all",all);   //将内存保存在标签执行
%>		
<mytag:present name="all" scope="request">
	<mytag:bodyiterate id="url" name="all" scope="request">

		<h3>生活:${url}、<%=url.length()%></h3>
	</mytag:bodyiterate>
</mytag:present>
</body>
</html>
此时的url 已经成为一个变量存在,而这个便利的使用,必须依靠:BodyIteratorTagExtraInfo 支持才可以完成

此时的代码已经明显比以前更加复杂了,所以在世界中基本上使用TagSupport 类比较多的

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

小结

使用BodyTagSupport 类可以完成标签的开发,但是开发的过程要比直接使用TagSupport 类麻烦许多

通过TagExtraInfo 类和VariableInfo 可以直接将标签中定义的属性变为一个变量操作


简单标签

在JSP1.2之前如果要想进行标签库的开发,要么西安站继承TagSupport 类要么就是继承BodyTagSupport 类,而且还要去覆写里面的doStartTag()、doAfterBody()、doEndTag(),而且还要非常清楚这些方法的返回值类型,例如: SKIP_BODY、EVAL_BODY_INCLUDE等,这对于用户的开发而言实战在太麻烦了,所以到了JSP2.0 之后,为了简化标签开发 的复杂度,专门增加了一个制作简单标签库的SimpleTagSupport类,直接覆写里面的doTag() 方法即可完成


SimpleTagSupport 类的定义如下:

public class SimpleTagSupport extends Object implements SimpleTag


          SimpleTagSupport 类一网打尽之前的所有复杂的标签开发,再也不用去区分什么doxxTag()方法了,而直接就是doTag() 方法。



下面开发一个之前的格式化日期的程序

package com.demo;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

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) {
			e.printStackTrace();
		}
		super.doTag();
	}
	public String getFormat() {
		return format;
	}
	public void setFormat(String format) {
		this.format = format;
	}
	
}

 <tag>			
	  <name>simple</name>			
	  <tag-class>com.demo.SimpleDateTag</tag-class>
	  <body-content>empty</body-content>	
	  <attribute>
		<name>format</name>  
		<required>true</required>  
		<rtexprvalue>true</rtexprvalue>  
	  </attribute>
	  </tag> 

<%@ page contentType="text/html; charset=GBK"%>
<%@ taglib prefix="mytag" uri="gz"%>
<html>
<head>
<title>欢迎光临</title>
</head>
<body>
	<h1>
		<mytag:simple format="yyyy-MM-dd HH:mm:ss.SSS"/>
	</h1>
</body>
</html>

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

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


package com.demo;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
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 String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getScope() {
		return scope;
	}

	public void setScope(String scope) {
		this.scope = scope;
	}
	
}

<tag>			
	  <name>simpleiterate</name>			
	  <tag-class>com.demo.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> 

<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="java.util.*"%>
<%@ taglib prefix="mytag" uri="gz"%>
<html>
<head>
	<title>欢迎光临</title>
</head>
<body>
<%
	List<String> all = new ArrayList<String>();
	all.add("你好吗");
	all.add("天天快乐");
	all.add("神仙日子");
	request.setAttribute("all",all);   //将内存保存在标签执行
%>		
<h1>
<mytag:simpleiterate id="url" name="all" scope="request">
	<h2>${url}</h2>
</mytag:simpleiterate>
</h1>
</body>
</html>
         此时的代码功能就已经实现了,可以发现,通过简单标签完成的标签库的开发,再也不用像之前的那样需要处理各个复杂的返回值的操作了

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


小结

通过SimpleTagSupport 类实现的标签库操作要比使用TagSupport 类容易许多,而且也不用再娶处理各个复杂的返回值类型


DynamicAttributes 接口

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

package com.demo;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.DynamicAttributes;
import javax.servlet.jsp.tagext.SimpleTagSupport;

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()));
	}
}

<tag>
	  <name>add</name>			
	  <tag-class>com.demo.DynamicAddTag</tag-class>
	  <body-content>empty</body-content>	
	  <dynamic-attributes>true</dynamic-attributes>
	  </tag>

<%@ page contentType="text/html; charset=GBK"%>
<%@ taglib prefix="mytag" uri="gz"%>
<html>
<head>
<title>欢迎光临</title>
</head>
<body>
	<h3>
		<mytag:add num1="22.2" num2="11.1" num3="33.3"/>
	</h3>
</body>
</html>

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


















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值