zoukankan      html  css  js  c++  java
  • javaweb回顾第八篇如何创建自定义标签

     前言:在javaweb开发中自定义标签的用处还是挺多的。今天和大家一起看自定义标签是如何实现的。

    1:什么是标签

    标签是一种XML元素,通过标签可以使JSP页面变得简介易用,而且标签具有很好的复用性。

    2:自定义标签的标签库主要的接口以及类的继承实现关系图

    3:一步步实现自定义标签

    3.1:Tag接口

    我们先看一个标签<td></td>这个标签有开始标签和结束标签,而且还有<tr>这样的父标签,那么实现一个简单的标签需要什么呢

    第一:开始标签  第二:结束标签第三:资源释放3个方法,而且还有父标签,如果我们要得到这个JSP上的内容我们还需要一个PageContext那么现在我们应该清晰了实现一个标签需要的元素。ok我们来看看Tag接口都有哪些内容

    3.1.1:int doStartTag() throws JspException;这个是开始执行的起始方法

    3.1.2:int doEndTag() throws JspException;这个是即将结束的结束方法

    3.1.3:void release();释放对象的资源

    3.1.4:void setPageContext(PageContext pc);设置当前页的上下文对象

    3.1.5: void setParent(Tag t);设置父标签

    3.1.6:Tag getParent();获取父标签

    通过上面的介绍我们现在应该知道怎么去写一个标签了,我们小试牛刀一下

    public class HelloTag implements Tag{
    
        private PageContext pageContext;
        private Tag parent;
        public void setPageContext(PageContext pc) {        
            this.pageContext=pc;//这个方法由jsp页面的实现对象调用
        }
        public void setParent(Tag t) {    
            this.parent=t;
        }
        public Tag getParent() {
    
            return parent;
        }
        public int doStartTag() throws JspException {
    
            return SKIP_BODY;
        }
        public int doEndTag() throws JspException {
    
            //利用pageContext来获取jspWriter对象
            JspWriter out=pageContext.getOut();
            try {
                //利用JSPWriter向客户端输入信息
                out.print("Hello Tag");
            } catch (IOException e) {
                e.printStackTrace();
            }
            return SKIP_PAGE;
        }
        public void release() {
        }

    其中SKIP_BODY表示忽略标签体内容,下面我们会说到。既然写完了一个标签体我们就开始配置了

    首先在WEB-INFO创建一个tlds文件夹然后创建一个tld文件然后设置如下

           <tag>
            <name>hello</name>
            <tag-class>com.lp.tags.HelloTag</tag-class>
            <body-content>empty</body-content>//表示标签没有内容
          </tag>

    然后我们在创建一个jsp文件然后在jsp文件头部加上Taglib指令元素<%@ taglib uri="/WEB-INF/tlds/CustomTaglib.tld" prefix="hello"%>

    在jsp页面就可以直接引用HelloTag标签了比喻我的是<hello:hello></hello:hello>

    启动运行结果如下

    有人又问了如果<td>这样的标签都有属性啊,如果有属性我怎么办呢,这个也简单没有属性我们就加入属性。我们来实现一个加法的自定义标签。这个我使用TagSupport类,从上面图中我们可以看出这个类实现了Tag接口,它会使我们写标签更加简单

    public class AddTag extends TagSupport{
        private int num1;
        private int num2;
        public int getNum2() {
            return num2;
        }
        public void setNum2(int num2) {
            this.num2 = num2;
        }
        public int getNum1() {
            return num1;
        }
        public void setNum1(int num1) {
            this.num1 = num1;
        }
        public int doEndTag() throws JspException
        {
            JspWriter out=pageContext.getOut();
            int num=num1+num2;
            try {
                out.print(num);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return EVAL_PAGE;
        }

    有人又问你为什么没有写doStartTag方法啊,其实TagSupport类已经帮我们实现了,它默认情况是忽略标签中的内容的。现在我们在此配置tld文件

    <tag>
            <name>add</name>
            <tag-class>com.lp.tags.AddTag</tag-class>
            <attribute>//表示属性
                <name>num1</name>属性命名
                <required>true</required>是否必须输入
                <rtexprvalue>true</rtexprvalue>是否是可运行的表达式
            </attribute>
            <attribute>
                <name>num2</name>
                <required>true</required>
                <rtexprvalue>true</rtexprvalue>
            </attribute>
        </tag>

    现在我们在jsp中加入以下代码

    <%@ taglib uri="/WEB-INF/tlds/CustomTaglib.tld" prefix="addtaglib"%>
    <body> 自定义的标签: <% int num1 = Integer.parseInt(request.getParameter("num1")); int num2 = Integer.parseInt(request.getParameter("num2"));%> 算法: <addtaglib:add num2="<%=num1 %>" num1="<%=num2 %>"></addtaglib:add> </body>

    再次运行我们看看结果

    有人又说了,你这写的标签都没有标签内容,你能不能实现一个标签带有内容的呢,ok这个没问题,刚刚我们说了SKIP_BODY表示忽略标签内容那么有个相反的EVAL_BODY_INCLUDE表示带有标签中的内容,在这里我们一起实现一个Switch case default三个标签体联用的简单功能

    我们先看SwitchTag标签

    public class SwitchTag extends TagSupport{
        private static final long serialVersionUID = 1L;
        //用于判断子标签是否已执行
        private boolean childTagExec;
        public SwitchTag()
        {
            childTagExec=false;
        }
        public int doStartTag() throws JspException
        {
            //当遇到switch的起始标签的时候子标签还没执行
            childTagExec=false;
            return EVAL_BODY_INCLUDE;//此时开始执行Switch内部的Case标签了
        }
        /**
         * 由子标签处理器对象调用,用于判断是否可以执行自身的标签体
         * @return
         */
        public synchronized boolean isExec()
        {
            return (!childTagExec);
        }
        /**
         * 如果子标签任何一个满足条件就调用这个方法 通知父标签
         * 这样其他子标签就忽略他们自身标签体,从而实现Switch case
         */
        public synchronized void childTagSucceeded()
        {
            childTagExec=true;
        }
        public void release()
        {
            childTagExec=false;
        }

    CaseTag

    public class CaseTag extends TagSupport{
        private static final long serialVersionUID = 1L;
        private boolean cond;//表示条件(比喻case:1此类)
        public CaseTag()
        {
            cond=false;
        }
        public void setCond(boolean cond)
        {
            this.cond=cond;
        }
        public int doStartTag() throws JspException
        {
            Tag parent=getParent();//获取父标签
            //判断是否可以执行自身标签
            if(!((SwitchTag)parent).isExec())
            {
                return SKIP_BODY;
            }
            //如果条件为true,则通知父标签有一个子标签满足条件
            //否则忽略标签体
            if(cond)
            {
                ((SwitchTag)parent).childTagSucceeded();
                return EVAL_BODY_INCLUDE;
            }
            else {
                return SKIP_BODY;
            }
        }
        public void release()
        {
            cond=false;
        }

     DefaultTag

    public class DefaultTag extends TagSupport{
        private static final long serialVersionUID = 1L;
        public int doStartTag() throws JspException
        {
            Tag parent=getParent();
            if (!((SwitchTag)parent).isExec()) {
                return SKIP_BODY;
            }
            ((SwitchTag)parent).childTagSucceeded();//如果所有Case都不满足则执行Default标签
            return EVAL_BODY_INCLUDE;
        }
    }

    我们在次配置tld文件

    <tag>
            <name>switch</name>
            <tag-class>com.lp.tags.SwitchTag</tag-class>
            <body-content>jsp</body-content>
        </tag>
        <tag>
            <name>case</name>
            <tag-class>com.lp.tags.CaseTag</tag-class>
            <body-content>jsp</body-content>
            <attribute>
                <name>cond</name>
                <required>true</required>
                <rtexprvalue>true</rtexprvalue>
            </attribute>
        </tag>
        <tag>
            <name>default</name>
            <tag-class>com.lp.tags.DefaultTag</tag-class>
            <body-content>jsp</body-content>
        </tag>

    其中<body-content>jsp</body-content>中jsp表示支持jsp具有的一切功能(比喻jsp9种内置对象)

    <body>
        <%
            String userName = request.getParameter("userName");
        %>
        <mytag:switch>
            <mytag:case cond='<%=userName.equals("zhangsan")%>'>
                <%out.print("张三");%>
            </mytag:case>
            <mytag:case cond='<%=userName.equals("lisi")%>'>
                <%out.print("李四");%>
            </mytag:case>
            <mytag:case cond='<%=userName.equals("wangwu")%>'>
                <%out.print("王五");%>
            </mytag:case>
            <mytag:default>
                <%out.print("无");%>
            </mytag:default>
        </mytag:switch>
    </body>

    现在开始执行效果如下

    3.1:IterationTag接口

    上面我们都一直说的标签内容都一次性完成,但是如果是循环标题体内容怎么办,那么就用到了IterationTag接口,此接口增加了一个方法

    public int doAfterBody() throws JspException该方法表示每次对标签体处理之后被调用也就是说在doStartTag方法之后doEndTag方法之前被调用,如果没有的话就不执行。

    新增加了一个常量EVAL_BODY_AGAIN表示再次执行标签体。现在我们实现一个获取多条用户信息展示的功能

    public class UserBean implements Serializable{
    
        private static final long serialVersionUID = 1L;
    
        public UserBean(){}
    
        public UserBean(String userName,int age,String email)
        {
            this.age=age;
            this.email=email;
            this.userName=userName;
        }
        private String userName;
        private int age;
        private String email;
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getEmail() {
            return email;
        }
        public void setEmail(String email) {
            this.email = email;
        }
    }
    public class IterateTag extends TagSupport{
        private static final long serialVersionUID = 1L;
        
        private Iterator items;//获取集合
        private String itemId;//对象的标识
        private Object item;//迭代对象中的每一个对象
        public IterateTag()
        {
            items=null;
        }
        public void release()
        {
            items=null;
        }
        /**
         * 得到集合的迭代对象
         */
        public void setItems(Collection cl)
        {
            if(cl.size()>0)
                items=cl.iterator();
        }
        public void setVar(String var)
        {
            this.itemId=var;
        }
        public int doStartTag()throws JspException
        {
            if(items.hasNext())//首先被执行
            {
                item=items.next();
            }
            else{
                return SKIP_BODY;
            }
            saveItems();//把迭代的对象保存在pageContext中
            return EVAL_BODY_INCLUDE;
        }
        public int doAfterBody() throws JspException
        {
            if(items.hasNext())//直到把迭代对象中的每一项都放进pageContext中
            {
                item=items.next();
            }
            else{
                return SKIP_BODY;
            }
            saveItems();
            return EVAL_BODY_AGAIN;
        }
        public void saveItems()
        {
            if(item==null)
            {
                pageContext.removeAttribute(itemId,pageContext.PAGE_SCOPE);
            }
            else{
                pageContext.setAttribute(itemId, item);//如果加入相同的id会进行覆盖
            }
        }
    }
    <tag>
            <name>iterate</name>
            <tag-class>com.lp.tags.IterateTag</tag-class>
            <body-content>JSP</body-content>
            <attribute>
                <name>items</name>
                <required>true</required>
                <rtexprvalue>true</rtexprvalue>
            </attribute>
            <attribute>
                <name>var</name>
                <required>true</required>
                <rtexprvalue>false</rtexprvalue>
            </attribute>
        </tag>
    <body>
        <%
            ArrayList al = new ArrayList();
            UserBean user1 = new UserBean("zhangsan", 25, "7808@outlook.com");
            UserBean user2 = new UserBean("lisi", 15, "16455@qq.com");
            UserBean user3 = new UserBean("wangwu", 35, "7808@outlook.com");
            al.add(user1);
            al.add(user2);
            al.add(user3);
        %>
        <table>
            <tr>
                <td>用户名</td>
                <td>年龄</td>
                <td>邮箱</td>
            </tr>
            <iterator:iterate items="<%=al%>" var="user">
            <jsp:useBean id="user" class="com.lp.beans.UserBean"></jsp:useBean>
                <tr>        
                    <td><jsp:getProperty property="userName" name="user" /></td>
                    <td>${user.age}</td>
                    <td>${user["email"]}</td>
                </tr>
            </iterator:iterate>
        </table>
    </body>

    效果如下

    4:简单标签开发

    为了简化自定义标签开发,JSP2.0加入了简单标签的开发实现的接口是SimpleTag,我们一起看下SimpleTag的主要方法

    4.1: public void setJspContext( JspContext pc )该方法被容器调用,设置JspContext,JspContext 是PageContext的基类

    4.2:public void setParent( JspTag parent );设置父标签

    4.3:public JspTag getParent();获取父标签

    4.4:public void setJspBody( JspFragment jspBody );该方法用于设置标签体标签体,标签体由JspFragment对象提供,可以把JspFragment看做是一个对象封装一段JSP代码,可以被多次执行。

    4.5:public void doTag(),主要处理标签和标签体的业务逻辑

    public class WelcomeSimpleTag extends SimpleTagSupport{
      private JspFragment jspFragment;
      private String name;
      public void setJspBody(JspFragment jspBody)
      {
          this.jspFragment=jspBody;
      }
      public void setName(String name)
      {
          this.name=name;
      }
      public void doTag() throws JspException, IOException
      {
          JspContext jspContext=getJspContext();
          JspWriter out=jspContext.getOut();
          out.print(name);
          jspFragment.invoke(null);
      }

    然后在jsp页面之间调用即可。关于简单标签的开发,大家可以自行实践。

  • 相关阅读:
    解决url传递过程中加号变空格的问题<转>
    windows下CEF3的关闭流程《转》
    mfc封装cef浏览器 关闭整个窗口程序得时候又重启mfc 应用的程序
    雷神免费资源
    LCA的 RMQ解法模版
    最新的js焦点图库
    whereis+whatis+man
    Anroid 手机助手 详细解析 概述(二)
    <c:forEach varStatus="status">中 varStatus的属性简介
    JBoss 系列四十九:JBoss 7/WildFly 中端口使用列表
  • 原文地址:https://www.cnblogs.com/LipeiNet/p/5744129.html
Copyright © 2011-2022 走看看