• 第六章_编写定制标签


    6.1、定制标签概述

    利用jsp标准动作指令訪问和操作javaBeans,是首次尝试将表现代码和业务逻辑实现分离。可是,标准动作指令的功能不够强大。单独使用时,开发人员常常要使用jsp页面中的java代码。

    比如,标准动作指令无法像jstlforEach标签那样迭代集合。

    认识到了用javabean分离表现逻辑和业务逻辑的不足之处之后,jsp1.1就定义了定制标签。定制标签具有javaBeans所没有的优势。比如,定制标签能够訪问jsp隐式对象,能够带有属性等。

    6.2、简单的标签处理器

    jsp2.0中,他们在javax.servlet.jsp.tagext包中加入了新的接口:simpleTag。实现SimpleTag接口的标签处理器称作简单的标签处理器,实现TagIterationBodyTag接口的标签处理器称作典型的标签处理器。

    简单的标签处理器的声明周期更加简单。而且更easy。SimpleTag接口中仅仅有一个方法:doTag。而且在标签调用时仅仅运行一次。业务逻辑、迭代及主体操作代码都要在这里编写。简单的标签处理器中的主体是用一个JspFragment类实例表示的。


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

    1、jsp容器通过调用其无參构造器,创建一个简单标签处理器实例。

    因此。简单的标签处理器必须有一个无參构造器。

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

    Public void setJspContext(JspContext jspContext)

    大多数时候,会须要将传进的JspContext赋给一个类变量。以便供兴许使用。

    3、假设表示标签处理器的定制标签是嵌套在还有一个标签中的,jsp容器就会调用setParent方法。该方法具有下面签名:

    Public void setParent(JspTag parent)

    4、JSP容器为给该标签定义的每一个属性都调用设置方法。(setter

    5、假设标签中有主体内容,JSP将调用SimpleTag接口的setJspBody方法,将主体内容作为JspFragment传递。

    假设没有主体内容。JSP容器则不会调用这种方法。

    6、JSP容器调用doTag方法。全部变量在doTag方法返回时进行同步。

    6.3SimpleTag实例

    以下是我的測试代码的项目结构。


    以下是我的代码:

    package customtag;
    
    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 ;
    	public void doTag() throws JspException, IOException {
    		// TODO Auto-generated method stub
    		System.out.println("doTag");
    		jspContext.getOut().print("This is my first tag.") ;
    	}
    
    	public JspTag getParent() {
    		// TODO Auto-generated method stub
    		System.out.println("getParent");
    		return null;
    	}
    
    	public void setJspBody(JspFragment arg0) {
    		// TODO Auto-generated method stub
    		System.out.println("set JspBody");
    	}
    
    	public void setJspContext(JspContext arg0) {
    		// TODO Auto-generated method stub
    		System.out.println("setJspContext");
    		this.jspContext = arg0 ;
    	}
    
    	public void setParent(JspTag arg0) {
    		// TODO Auto-generated method stub
    		System.out.println("set parent");
    	}
    	
    }
    

    <?xml version="1.0" encoding="utf-8"?

    > <taglib xmlnx="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-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> </taglib>


    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@ taglib prefix="easy" uri="/WEB-INF/mytags.tld" %>
    <html>
      <head>
        <title>Testing my first tag</title>
      </head>
      
      <body>
        Hello!!!
        <br />
        <easy:firstTag/>
      </body>
    </html>
    

    6.4、处理属性

    实现SimpleTag接口或者继承SImpleTagSupport的标签处理器能够带有属性。

    以下是项目结构图:


    以下是程序代码:

    package customtag;
    
    import java.io.IOException;
    import java.util.StringTokenizer;
    
    import javax.servlet.jsp.JspContext;
    import javax.servlet.jsp.JspException;
    import javax.servlet.jsp.JspWriter;
    import javax.servlet.jsp.tagext.SimpleTagSupport;
    
    public class DataFormatterTag extends SimpleTagSupport{
    	private String header ;
    	private String items ;
    	
    	public void setHeader(String header) {
    		this.header = header;
    	}
    
    	public void setItems(String items) {
    		this.items = items;
    	}
    
    	@Override
    	public void doTag() throws JspException, IOException {
    		JspContext jspContext = getJspContext() ;
    		JspWriter out = jspContext.getOut() ;
    		out.print("<table style='border:1px solid green'>
    "
    				+"<tr><td><span style='font-wright:bold'>"
    				+ header + "</span></td></tr>
    ") ;
    		StringTokenizer tokenizer = new StringTokenizer(items, ",") ;
    		while(tokenizer.hasMoreTokens()){
    			String token = tokenizer.nextToken() ;
    			out.print("<tr><td>" + token + "</td></tr>
    ") ;
    		}
    		out.print("</table>") ;
    	}
    	
    }
    

    <?xml version="1.0" encoding="utf-8"?

    > <taglib xmlnx="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_1.xsd" version="2.1"> <tlibversion>2.1</tlibversion> <jspversion>2.1</jspversion> <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> </taglib>


    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@ taglib uri="/WEB-INF/mytags.tld" prefix="easy"%>
    <html>
      <head>
        <title>Testing DataFormatterTag</title>
      </head>
      
      <body>
        <easy:dataFormatter items="Alabama,Alaska,Georgia,Florida" header="States"/>
        <br/>
        <easy:dataFormatter header="Countries">
        	<jsp:attribute name="items">
        		US,UK,Canada,Korea
        	</jsp:attribute>
        </easy:dataFormatter>
      </body>
    </html>
    

    执行结果图:



    6.5、管理标签主体

    有了SImpleTag,就能够通过JSP闯过来的JspFragment管理标签主体了。

    JspFragment类表示一段JSP代码。能够不调用。也能够调用多次。JSP片段的定义中不能包括Scriplet或者Scriptlet表达式,它仅仅能包括模版文本和JSP动作指令元素。

    JspFragment类有两个方法:getJspContextinvoke。其方法签名例如以下:

    Public abstract JspContext getJspContext()

    Public abstract void invoke(java.io.Writer writer)throws JspException, java.io.IOException

    getJspContext方法返回与这个JspFragment相关的JspContext。我们能够调用invoke方法来运行片段(标签主体),并将全部输出内容导到指定的Writer

    假设传给invoke方法的值为null,那么输出的结果将会被导到与该片段相关的JspContextgetOut方法所返回的JspWriter

    以下是代码段:

    package customtag;
    
    import java.io.IOException;
    
    import javax.servlet.jsp.JspContext;
    import javax.servlet.jsp.JspException;
    import javax.servlet.jsp.JspWriter;
    import javax.servlet.jsp.tagext.SimpleTagSupport;
    
    public class SelectElementTag extends SimpleTagSupport{
    	private String[] countries = {"Australia", "Brazil", "China"} ;
    	@Override
    	public void doTag() throws JspException, IOException {
    		// TODO Auto-generated method stub
    		JspContext jspContext = getJspContext() ;
    		JspWriter out = jspContext.getOut() ;
    		out.print("<select>
    ") ;
    		for(int i=0;i<3; i++){
    			getJspContext().setAttribute("value", countries[i]) ;
    			getJspContext().setAttribute("text", countries[i]) ;
    			getJspBody().invoke(null) ;
    		}
    		out.print("</select>
    ") ;
    	}
    }
    

    <?xml version="1.0" encoding="utf-8"?

    > <taglib xmlnx="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_1.xsd" version="2.1"> <tlibversion>2.1</tlibversion> <jspversion>2.1</jspversion> <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>


    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@ taglib uri="/WEB-INF/mytags.tld" prefix="easy" %>
    <html>
      <head>
        <title>My JSP 'selectElementTagTest.jsp' starting page</title>
      </head>
      
      <body>
        <easy:select>
        	<option value="${value }">${text }</option>
        </easy:select>
      </body>
    </html>
    

    输出结果显示:



    6.6、编写EL函数

    一般来说。编写一个EL函数要遵循下面两个步骤:

    1、创建一个包括讲台方法的public类。每一个静态方法表示一个函数。这个类不须要实现接口或者继承类。你能够依据须要。像对待其它不论什么类一样部署这个类。这个类必须保存到WEB-INF/classes文件夹或其以下的某个文件夹中。

    2、利用function元素在标签类库描写叙述符中注冊函数。

    Function元素必须直接放在taglib元素下,而且能够带有下面子元素:

    description

    这是一条特定于标签的可选信息。

    display-nameXML工具显示的简称。

    iconXML工具能够使用的可选图标元素。

    name

    该函数独特的名称。

    function-class。实现该函数的java类的全类名。

    function-signature。表示该函数的静态java方法签名。

    example

    使用该函数的一个example的可选信息描写叙述。

    function-extension。通过XML工具使用,没有扩展名,或者有多个扩展名,提供关于该函数的其它信息。

    使用函数时,需利用taglib指令及其uri属性。它指向标签类库描写叙述符。以及要使用的前缀。然后在jsp页面中利用下面语法调用函数:

    ${prefix:functionName(parameterList)}

    以下是关于EL函数的样例:

    package function;
    
    public class StringFunctions {
    	public static String reverseString(String s){
    		return new StringBuffer(s).reverse().toString() ;
    	}
    }
    

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@ taglib uri="/WEB-INF/functions.tld" prefix="f" %>
    <html>
      <head>
        <title>My JSP 'reverseStringFunctionTest.jsp' starting page</title>
      </head>
      
      <body>
      	${f:reverseString("Hello World")}
      </body>
    </html>
    

    <?

    xml version="1.0" encoding="utf-8"?> <taglib xmlnx="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_1.xsd" version="2.1"> <tlibversion>2.1</tlibversion> <jspversion>2.1</jspversion> <function> <description> Reverse a String </description> <name> reverseString </name> <function-class> function.StringFunctions </function-class> <function-signature> java.lang.String reverseString(java.lang.String) </function-signature> </function> </taglib>


    在浏览器输入:http://localhost:8089/servlet/reverseStringFunctionTest.jsp



    6.7、公布定制标签

    我们能够将定制标签处理器和标签类库描写叙述符打包成一个jar文件。以便发给其它人使用,像jstl一样。

    在这样的情况下,就须要包括全部的标签处理器。以及描写叙述它们的tld文件。

    此外。还须要在描写叙述符的uri元素中指定一个绝对的URL

    比如,我就打包成一个cc.jar文件。

    Jar文件内容如图所看到的。


    能够直接利用cmd的jar命令打包,如图:




    这样我们就能够把jar包拷贝到项目的lib文件夹下。而且jsp中引用刚才的uri地址。




    项目执行截图:



  • 相关阅读:
    Spring基础——小的知识点
    Spring总结—— IOC 和 Bean 的总结
    UML 类图
    Spring基础—— 泛型依赖注入
    Spring重点—— IOC 容器中 Bean 的生命周期
    Spring基础—— SpEL
    《大话设计模式》学习笔记13:适配器模式
    《大话设计模式》学习笔记12:状态模式
    《大话设计模式》学习笔记11:抽象工厂模式
    《大话设计模式》学习笔记10:观察者模式
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/6866031.html
Copyright © 2020-2023  润新知