简单易懂的JSP自定义标签

1.在JSP页面中,我们可以嵌入java代码来执行逻辑操作。但是一旦当页面复杂,java代码的大量嵌入势必会导致页面结构混乱,难以维护。但是我们的确需要需要这样的逻辑处理模块来完成页面的逻辑处理,JSP为了解决这一难题,使得页面与代码最大程度上的分离,开发了自定义标签。

2.首先标签我们再熟悉不过了,在Html中,我们使用各种各样的标签在页面中嵌入相应的内容。但是我们使用的都是一套规范好的标签,比如说超链接a,我们是不是可以自己做一个标签b,也让具有a同样的功能。当然是可以的,JSP提供了这样的机制。我们把这个叫做JSP自定义标签,当然了,使用自定义标签不是为了解决我们前边提出的做一个超链接b这种没有什么意义的问题,他是为了我们简化JSP页面,在最大程度上使得java代码与页面分离。我们首先看一下如何实现自定义标签然后再讨论这其中的原理。

3.我们知道标签一般分为两种,即有标签体和无标签体的。我们这里实现的都是没有标签体的,原理是一样的,既然是入门嘛,我们挑一个简单的来。

4.实现一个简单的无标签体的标签,功能是调用这个标签就可以输出一句话。首先给出自定义标签的三个步骤。

一:建立一个java类,继承TagSupport方法(或者实现Tag接口)。复写其中的doEndTag()方法。

二:在tld文件中配置这个标签

三:jsp页面中调用这个标签。在这里面步骤而可能是新手最容易出错的。我们重点的看一下这一点。

(1)首先建立一个MyTag类,我们先简单一点,采用继承TagSupport的方式。代码如下:

package Tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;
/*TagSupport的写法相对来说比较简单,
 * 直接继承一个TagSupport然后再复写doEndTag()方法
 *
 *
 */
public class MyTag2 extends TagSupport{
    public int doEndTag() throws JspException
    {
        //直接复写方法
        String str="Hello JSP Tag";
        try {
            pageContext.getOut().print(str);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return super.doEndTag();
    }
}

这个很简洁,解释一个地方,就是pageContext,这是一个内建对象,我们可以直接获取到它,然后调用对应的方法输出。这里就算是完成了。接下来是配置这个标签。

(2)建立tld文件,这个tld文件是自定义标签的配置文件,我们在这里面要定义标签的各种属性。新建xml文件,将后缀名改为.tld。然后看代码:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.1</jsp-version>
<short-name>myTag</short-name>
<uri>http://myTag</uri>
<tag>
<name>MyTag2</name>
<tag-class>Tag.MyTag2</tag-class>
<body-content>empty</body-content>
</tag>
<tag>

</taglib>

解释一下这个文件的格式:首先前两行自动生成的,不用管,如果你的没有自动生成可以把这两行拷贝一下,这个通用的。

接下来是taglib,也就是标签库,我们可以在这里配置很多的标签。接下来的三行都无关大雅,我们重点看一下uri,这是你的标签的地址,这个地址可以随意的写,但是一般还是要按照格式来,写成http的格式(因为我们接下来学到的标准标签库就是这种格式,这样可以让我们的自定义标签更加专业,可读性更高)。接下来很重要<tag></tag>标签体内就是这个标签的配置,名字可以随意,但是class需要写包名加类名,最后一个body-content,指的是标签体的内容,由于我们这里的标签都是不带标签体的标签,所以这个属性是empty。OK,如果你顺利的完成了这些,那么已经成功90%了,接下来就很简单了

(3)JSP页面中使用自定义的标签。

在JSP页面中导入标签的uri(就是我们刚才在配置文件中写的uri),指定前缀(prefix),然后就可以使用了。实例代码如下:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://myTag" prefix="h" %><!--导入对应的标签库以及指定前缀-->
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
  <h:MyTag/>
  </br>
  <h:MyTag2/>
  </br>
  <h:MyTag4/>
  <h:MyTag5 count="5"/>
</body>
</html>

OK,到这里我们的任务已经完成了,到在Tomcat上部署一下在浏览器调用JSP就可以看到输出的Hello了。

5.什么?这个标签也太low了吧,没错,他就是很low,我们来做一个有趣的。做一个下拉的列表。什么?杀鸡焉用宰牛刀?做个列表我还用的着自定义吗?这不是自找代码写嘛,别急我还没说完,我们做一个动态的下拉列表。列表项可以根据后台的数据库的数据的数量增加,数据从数据库获取。当然了,我们只是演示一下原理,数据的获取我就不做了,有兴趣的可以再做一下。

假设我们这里有一个这样的需求:一个公司需要招聘员工,在网站上发布自己的需求,求职者可以在投递自己的简历的时候选择自己感兴趣的职位,但是随着时间的流逝有的职位已经招满了,就不需要出现在选项中。所以我们需要做一个下拉列表,这个列表可以动态的修改,如果这个职位已经满了,那么就从数据库中移除(或者关闭这个接口)。下拉列表中不再显示。面对这个需求,我们需要怎么实现呢?不能每一次更新就重新在做一个页面吧,那样工作量太大。我们可以使用自定义标签来完成这个需求。

(1)首先我们建立一个人员类,这和类有id与position两个属性,对应的数据库中建立这个表。我们在这里为了简便就不从数据库获取数据了,只是演示原理。建立一个people的java bean,代码如下:

package Tag;

public class People {
 int id;
 String name;
public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
 
}


(2)建立标签的后台处理类,代码如下:

package Tag;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

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

public class MyTag4 extends TagSupport {
 
    public int doEndTag() throws JspException
    {
        try {
        ArrayList list=(ArrayList)this.list();
        String str="<select>";
        for(int i=0;i<list.size();i++)
        {
            People p=(People)list.get(i);
            int id=p.getId();
            String name=p.getName();
            str+="<option value="+id+">"+name+"</option>";
        }
        str+="</select>";
    
            pageContext.getOut().print(str);
        } catch (Exception e) {
            System.out.println(e);
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return super.doEndTag();
    }
    private ArrayList list()
    {
        ArrayList list=new ArrayList();
        People p1=new People();
        p1.setId(1);
        p1.setName("CEO");
        People p2=new People();
        p2.setId(2);
        p2.setName("CFO");
        People p3=new People();
        p3.setId(3);
        p3.setName("CMO");
        People p4=new People();
        p4.setId(4);
        p4.setName("HR");
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);
        return list;
    }
}


(3)在tid文件中配置:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.1</jsp-version>
<short-name>myTag</short-name>
<uri>http://myTag</uri>
<tag>
<name>MyTag</name>
<tag>
<name>MyTag4</name>
<tag-class>Tag.MyTag4</tag-class>
<body-content>empty</body-content>
</tag>

</taglib>

(4)在JSP中调用即可。

6.上边我们模拟了一下创建一个动态的下拉列表,这个在实际的项目中很实用。但是,我们知道,很多标签都是具有属性的,比如img标签我们可以指定宽度,指定资源的路径等等,接下来我们也来创建一个具有属性的标签。首先我们需要知道,所有的属性在标签的后台处理是属于什么位置:其实标签的所有属性在对应的java后台处理类是该类的私有的成员变量知道了这些,我们来尝试一下自己建立一个具有属性的标签,我们定义这个属性控制的就是输出语句循环地次数,例如,我们定义属性count,这个标签的作用就是输出一句话:Hello,输出的数量更具属性的值变化:例如,属性值为5的时候我们就连续输出五次。

(1)好了,实现一下,我们在java类中添加成员变量:private int cout=1;(默认值为1).給它添加对应的set方法,注意这里是必须的,有的时候甚至不需要定义成员变量但是依然是需要添加对应的set方法。这是核心,之后就比较简单了。代码如下:

package Tag;

import java.io.IOException;

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

public class MyTag5 extends TagSupport{
    private int count =0;
    public void setCount(int count)
    {
        this.count=count;
    }
  public int doEndTag() throws JspException
  {
      for(int i=0;i<this.count;i++)
      {
          try
          {
            pageContext.getOut().print("Hello");
        } catch (IOException e) {
            System.out.println(e);
            e.printStackTrace();
        }
      }
      return super.doEndTag();

  }
}


(2)在tld文件中配置:注意这里的配置有一点小小的区别,我们需要给属性单独的配置,其他的配置方式不变:具体代码如下

我写了注释,就不在解释每个配置的相关的属性。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.1</jsp-version>
<short-name>myTag</short-name>
<uri>http://myTag</uri>
<tag>
<name>MyTag5</name>
<tag-class>Tag.MyTag5</tag-class>
<body-content>empty</body-content>
<!-- 处理属性 -->
<attribute>
<name>count</name>
<required>true</required><!-- 这个属性表示当前的属性是否必填-->
<rtexprvalue>true</rtexprvalue><!-- 这个属性表示当前属性是否可以被外界赋值 -->
</attribute>
</tag>
</taglib>

(3)在JSP里面调用对应的标签。

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://myTag" prefix="h" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
  <h:MyTag5 count="5"/><!--在使用这个标签的时候,对应到的属性就是自动跳出来(如果这个属性是必须的)-->
</body>
</html>

7.在上边我们实现了不带标签体的自定义标签,我们可以感受到这种方式的便捷,这样一来我们的java代码就可以最大程度上放在后台而不用直接写在页面上。当然喽,大牛们其实1还是很体贴的,就像是c++的stl一样,经常使用的东西其实有人给我们做好了,封装好了,我们拿来直接用就可以了。在JSP标签中也是这样,大牛们已经将常用的标签给我们写好了:JSTL。我们下一节再讨论如何使用这个东东,这里的结尾我们还是要回答一下文章开头提出来的问题:JSP标签的实现底层。我们知道:JSP嵌入java代码实际上就是被转给化成了servlet,三种不同的<%!%><=%%><%%>嵌入的代码在servlet中对应生成的的代码的位置不同,其实这里的原理也是如此,

 当浏览器发来请求后,会将这个请求交给JSP翻译成的servlet来处理,自定义标签对应servlet中一个方法的调用,这个方法主要步骤如下

1,产生标签处理类的实例对象

2,将pageContext传入给标签处理类对象

3,看标签是否有父标签,如果有则将父标签传递给标签处理器类。如果没有的话则传入null。

4,调用标签处理类的doStartTag()方法来对应开始标签

5,执行一段标签体

6,执行doEndTag(),对应的是结束标签。

7,一般调用标签处理器类的release()方法来回收标签工作时的相关资源。


 

猜你喜欢

转载自blog.csdn.net/weixin_41863129/article/details/82024325