zoukankan      html  css  js  c++  java
  • JSP自定义标签(1)


    一、引入标签


    其实在JSP中我们已经使用过了几个标签,比如<jsp:forward>、<jsp:include>等;这些标签都是预先定义好的,如果我们需要自定义标签,就需要学习标签编程。

    标签编程的优点就是灵活性+封装性。

    灵活性体现在属性的赋值上,可以赋任意值。比如<jsp:forward page="A">   //A处可以赋任意的URL;

    封装性体现在内部的行为的封装,因为标签是用一个类实现的,因此类的方法中能够包含任意复杂的动作。

    因此标签是为了能够在JSP中使用尽可能少的Scriptlet;

    比如:

     <table>
     <%
     	for(int i=0;i<10;i++){
     %>
     	<tr>
     <%
      		for(int j=0;j<10;j++){
     %>
      		<td><%=i*j%></td>
     <%
      		}
     %>
      	</tr>
     <%
     	}
     %>
     </table>

    这个代码非常混乱,但是如果通过标签,从这段代码都封装在一个标签里,则代码就清晰了很多。


    接下来是我通过标签封装后的JSP页面效果;

    <%@ page contentType="text/html" pageEncoding="GBK"%>
    <%@ taglib prefix="xiazdong" uri="xiazdong"%>
    <html>
    	<head>
    		<title></title>
    	</head>
    	<body>
    		<xiazdong:table row="5" col="3"/>
    	</body>
    </html>

    是不是大大缩短了呢??再来看看我在背后干了什么。。。。

    TableTagSupport.java

    package org.tagext;
    import javax.servlet.jsp.tagext.*;
    import javax.servlet.jsp.*;
    public class TableTagSupport extends TagSupport{
    	private String row;
    	private String col;
    	public String getRow(){
    		return row;
    	}
    	public String getCol(){
    		return col;
    	}
    	public void setRow(String row){
    		this.row = row;
    	}
    	public void setCol(String col){
    		this.col = col;
    	}
    	public int doStartTag()throws JspException{
    		JspWriter out = super.pageContext.getOut();
    		try{
    			out.println("<table border=\"3\"> ");
    			for(int i=0;i<Integer.parseInt(row);i++){
    				out.println("<tr>");
    				for(int j=0;j<Integer.parseInt(col);j++){
    					out.println("<td>"+i*j+"</td>");
    				}
    				out.println("</tr>");
    			}
    			out.println("</table>");
    		}
    		catch(Exception e){}
    		return TagSupport.SKIP_BODY;
    	}
    }

    是不是很神奇。。。那接下来就看看实现的过程吧。

    注意,在编写标签之前,必须把tomcat\lib中的jsp-api.jar文件配置在CLASSPATH中才可以;


    二、基本标签编写


    1、TagSupport类


    如果要编写一个标签类,则必须继承javax.servlet.jsp.tagext.TagSupport

    TagSupport中提供了很多常用方法:

    (1)    public int doStartTag()throws JspException;    //    标签开始时调用

    能够返回SKIP_BODY(跳过标签体)、EVAL_BODY_INCLUDE(执行标签体)

    (2)    public int doEndTag()throws JspException;    //     标签结束时调用

    能够返回SKIP_PAGE(立刻停止执行)、EVAL_PAGE(JSP正常运行完毕);

    (3)    int SKIP_BODY;        // 跳过标签体

    (4)    int EVAL_BODY_INCLUDE;    //执行标签体

    (5)    int EVAL_BODY_AGAIN;    //  重复执行标签体,主要是因为集合迭代输出,只能在doAfterBody中使用;

    (6)    public int doAfterBody()throws JspException;    //   执行完一次标签体后调用的函数;

    能够返回SKIP_BODY(结束标签体)、EVAL_BODY_AGAIN(重复执行标签体)

    (7)  JspWriter out = super.pageContext.getOut();//获取向网页输出的输出流;

    举例讲述这些函数和常量代表什么意思:

    <xiazdong:hello>                                <!--标签头 -->
            <h3><%="xiazdong"%></h3>            <!--    标签体-->
    </xiazdong:hello>                                <!-- 标签尾-->

    执行流程如下:

    (1)doStartTag();   <xiazdong:hello>时调用,如果是EVAL_BODY_INCLUDE,则继续;如果是SKIP_BODY,则执行(4)

    (2)执行标签体;

    (3)如果实现了doAfterBody,则执行;如果返回SKIP_BODY,则执行(4) ; 如果返回EVAL_BODY_AGAIN,则重复执行doAfterBody;

    (4)doEndTag():标签尾调用;


     2.制作无属性标签


    为了清晰,我们以例子说明。

    代码举例1:实现显示Hello world;


    1.编写HelloTag.java


    package org.tagext;
    import javax.servlet.jsp.tagext.*;
    import javax.servlet.jsp.*;
    
    public class HelloTag extends TagSupport{
    	public int doStartTag()throws JspException{
    		JspWriter out = super.pageContext.getOut();
    		try{
    			out.println("<h3>Hello world!!!</h3>");
    		}
    		catch(Exception e){}
    		return TagSupport.SKIP_BODY;
    	}
    }

    注意点:

    (1)javax.servlet.jsp.tagext.TagSupport,必须记住;

    (2)JspWriter out = super.pageContext.getOut();

    (3)public int doStartTag()throws JspException;必须记住;


    2.编写xiazdong.tld 


    tld文件是标签描述文件,是整个标签编程的核心,用来描述自定义的标签的名字、标签的实现类、是否有标签体、描述属性等;

    一个tld文件其实类似于一个标签库,里面能够描述很多标签;每个标签都以

    <tag>
    	<name>hello</name>		<!--表示标签的名字 类似于<jsp:forward>中的forward-->
    	<tag-class>org.tagext.HelloTag</tag-class>	<!--标签所在类 -->
    	<body-content>empty</body-content>		<!--是否存在标签体-->
    </tag>

    的形式描述;

    *.tld文件的模版如下:(因为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">
    	<tlib-version>1.0</tlib-version>
    	//插入tag描述
    </taglib>


    3.在web.xml中编写映射


    编写映射的目的类似于给一个网页配置一个映射地址,为了方便访问;

    比如本来需要访问/a/b/c/d/e/f/g/1.tld,这个路径非常麻烦,但是如果通过映射,我们可以只需要用"a"表示一长串的文件路径及名称;

    <jsp-config>
    	<taglib>
    		<taglib-uri>xiazdong</taglib-uri>
    		<taglib-location>/WEB-INF/classes/xiazdong.tld</taglib-location>
    	</taglib>
    </jsp-config>


    4.编写JSP页面并使用自定义的标签


    <%@ taglib prefix=""   uri=""%>        prefix类似于<jsp:forward>中的jsp,uri中使用前面所说的映射;

    <%@ page contentType="text/html" pageEncoding="GBK"%>
    <%@ taglib prefix="xiazdong" uri="xiazdong"%>
    <html>
    	<head>
    		<title></title>
    	</head>
    	<body>
    		<h1><xiazdong:hello/></h1>
    	</body>
    </html>


     3.制作有属性标签


    其实制作有属性和制作无属性没有太大区别,


    1.需要在原来的HelloTag.java 中加入属性.


    如果做形如:<xiazdong:hello id="" format="" />的属性,则需要在HelloTag.java中添加两个属性,id属性和format属性;

    形如:

    class HelloTag extends TagSupport
    {
    	private String id;
    	private String format;
    	//setter和getter
    	public int doStartTag()throws JspException{}
    }
    

    在用户使用标签,并为id和format属性赋值时,会自动调用setter方法,将HelloTag类中的id和format赋值;


    2.在tld文件中添加属性描述:


    属性描述形如:

    <body-content>empty</body-content>后面加上
    <attribute>
    	<name>name</name>		<!--属性姓名 -->
    	<required>true</required>	<!--属性是否必要 -->
    	<rtexprvalue>empty</rtexprvalue>	<!--是否支持表达式语言 -->
    </attribute>


    代码实例:


    HelloTag.java

    package org.tagext;
    import javax.servlet.jsp.tagext.*;
    import javax.servlet.jsp.*;
    
    public class HelloTag extends TagSupport{
    	private String name;
    	private String age;
    	public String getName(){
    		return name;
    	}
    	public String getAge(){
    		return age;
    	}
    	public void setName(String name){
    		this.name = name;
    	}
    	public void setAge(String age){
    		this.age = age;
    	}
    	public int doStartTag()throws JspException{
    		JspWriter out = super.pageContext.getOut();
    		try{
    			out.println("<h3>姓名:"+name+"</h3>");
    			out.println("<h3>年龄:"+age+"</h3>");
    		}
    		catch(Exception e){}
    		return TagSupport.SKIP_BODY;
    	}
    }


    xiazdong.tld
    需要加上attribute的描述:名字、是否必须、是否支持表达式语言

    <?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">
      <tlib-version>1.0</tlib-version>
      <short-name>x</short-name>
      <tag>
    	<name>hello</name>
    	<tag-class>org.tagext.HelloTag</tag-class>
    	<body-content>empty</body-content>
    	<attribute>
    		<name>name</name>
    		<required>true</required>
    		<rtexprvalue>empty</rtexprvalue>
    	</attribute>
    	<attribute>
    		<name>age</name>
    		<required>true</required>
    		<rtexprvalue>empty</rtexprvalue>
    	</attribute>
      </tag>
    </taglib>

    HelloTag.jsp

    <%@ page contentType="text/html" pageEncoding="GBK"%>
    <%@ taglib prefix="xiazdong" uri="xiazdong"%>
    <html>
    	<head>
    		<title></title>
    	</head>
    	<body>
    		<h1><xiazdong:hello name="xiazdong" age="20"/></h1>
    	</body>
    </html>

    三、IterationTag和Tag接口的区别


    Tag接口只有一些最基本的标签编程方法,而IterationTag接口是用于迭代输出,比如EVAL_BODY_AGAIN等;




    作者:xiazdong
    出处:http://blog.xiazdong.info
    本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
  • 相关阅读:
    异常-ERROR yarn.ApplicationMaster: User class threw exception: java.sql.SQLException: Communications link failure
    异常-Data truncation: Truncated incorrect DOUBLE value: '-9370.3530-'
    算法中的时间复杂度分析
    MySQL开启binlog无法启动ct 10 21:27:31 postfix/pickup[4801]: warning: 6BD991A0039: message has been queue
    【异常】ERROR main:com.cloudera.enterprise.dbutil.SqlFileRunner: Exception while executing ddl scripts. com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'ROLES' already exists
    CDH5.16.1的agent启动报错:ERROR Error, CM server guid updated, expected d9bcadb4-f983-41b8-a667-66760f47bc91, received a67f5efa-8473-4f6a-94d6-231d1f432ef0
    MySQL无法启动:ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
    [Ubuntu] Ubuntu13.04, the desktop freezed after login
    [ubuntu] ubuntu13.04安装rabbitcvs管理svn
    [javascript] ajaxfileupload.js 跨域上传文件
  • 原文地址:https://www.cnblogs.com/xiazdong/p/3058121.html
Copyright © 2011-2022 走看看