EL自定义标签

  在JSP中,往往需要写Java代码,这样前后端不够分离。EL表达式使得JSP页面只有标签的存在,而标签的逻辑代码写在对应的.java文件中。
  一个EL自定义标签包括.tld配置文件(放在/WebContent/WEB-INF目录下)和标签所对应的.java 文件。
  .tld文件所必需的部分:

<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">

  <description>JSTL 1.1 core library</description>
  <display-name>JSTL core</display-name>
  <tlib-version>1.1</tlib-version>

  <!-- 建议在jsp页面上使用的标签的前缀 -->
  <short-name>test</short-name>
  <!-- 作为tld文件的id,用来标识当前的tld文件 -->
  <uri>http://java.zhang.com/jsp/jstl/core</uri>

    <tag>
    <!-- 标签的名字 -->
    <name>hello</name>
    <!-- 标签所在的全类名 -->
    <tag-class>tag.HelloSipleTag</tag-class>
    <!--标签体类型 -->
    <body-content>empty</body-content>

    <!-- 描述当前标签的属性 -->
    <attribute>
        <!-- 属性名 -->
        <name>value</name>
        <!-- 该属性是否为必须 -->
        <required>true</required>
        <!-- runtime expression value
           当前属性是否可以接收运行时表达式的动态值-->
        <rtexprvalue>true</rtexprvalue>
    </attribute>
  </tag>
</taglib>

1.简单标签

标签需要实现SimpleTag接口或者继承SimpleTagSupport类。
1)当实现SimpleTag接口时,需要实现接口所带的这四个方法

    @Override
    public JspTag getParent() {
        // TODO Auto-generated method stub
        return null;
    }


    //三个get方法由servlet引擎调用,把相应对象传入
    @Override
    public void setJspBody(JspFragment arg0) {
        // TODO Auto-generated method stub  
    }

    //写一个全局变量 用于接收传入的pageContext(可以获取到其他的八个隐含对象)
    private PageContext pageContext;
    @Override
    public void setJspContext(JspContext arg0) {
        // TODO Auto-generated method stub
        this.pageContext=(PageContext)arg0;
    }

    @Override
    public void setParent(JspTag arg0) {
        // TODO Auto-generated method stub

    }

具体标签实现的逻辑由doTag()方法实现:

    //实际的标签体逻辑
    public void doTag() throws JspException, IOException {
        // TODO Auto-generated method stub
        System.out.println("doTag");
        System.out.println(value+","+count);

        HttpServletRequest request=(HttpServletRequest)pageContext.getRequest();
        pageContext.getOut().print("Hello:"+request.getParameter("name"));
    }

如果标签附带属性,需要在.java文件中写属性所对应的setter方法
注意:在.tld文件中声明的属性要和setter方法中名字一致

    //设置标签体的属性
    private String value;
    private String count;


    public void setValue(String value) {
        this.value = value;
    }

    public void setCount(String count) {
        this.count = count;
    }

JSP页面的标签:

<test:hello value="111"/>

运行结果为:
运行结果

简单标签的设计思路:首先在.tld文件中声明所需要的标签,然后在.java文件中写具体的方法,最后在JSP页面调用写好的标签。
注意:在实现SimpleTag接口时,获取PageContext对象需要先写一个全局变量

private PageContext pageContext

然后再强制类型转换

    public void setJspContext(JspContext arg0) {
        // TODO Auto-generated method stub
        this.pageContext=(PageContext)arg0;
    }

通过PageContext对象可以获得其他八个隐含对象。如:pageContext.getOut()
2)继承SimpleTagSupport类(常用)
在SimpleTagSupport类中只需要写doTag方法,获取pageContext对象不需要在setJspContext方法中类型转换获取, SimpleTagSupport类添加了getJspContext()方法获取JspContext对象

    //实际的标签体逻辑
    public void doTag() throws JspException, IOException {
        // TODO Auto-generated method stub
        System.out.println("doTag");
        System.out.println(value+","+count);

        //在SimpleTagSupport类中只需要写doTag方法,获取pageContext对象不需要在setJspContext方法中获取,继承SimpleTag类后有内置的getJspContext方法获取JspContext对象
        PageContext pageContext=(PageContext)getJspContext();
        //通过pageContext对象获得request对象
        HttpServletRequest request=(HttpServletRequest)pageContext.getRequest();
        getJspContext().getOut().print("Hello:"+request.getParameter("name"));
    }

实现原理:
1.在JSP页面中调用标签时,JSP引擎利用setJspContext()和setXXX()将代表当前页面的pageContext对象和属性传给标签处理器类,
2.在.java文件中将pagecontext对象和属性取出,在doTag方法中进行标签的逻辑操作

2.带标签体的标签

/*
 * 1.若一个标签有标签体<test:testJspFragment>Hello</test:testJspFragment>
 *   在自定义标签处理器中使用JSPFragment对象封装标签体信息
 * 2.若配置了标签含有标签体,则JSP 引擎会调用setJspBody()方法,把JSPFragment对象传递给标签处理器类
 *   在SimpleTagSupport中还定义了一个getJspBody()方法,用于返回JspFragment对象,便于直接调用
 * 3.JSPFragment的 invoke(Writer)方法:把标签体内容从Writer中输出
 *  若为invoke(null),则等同于invoke(getJspContext().getOut()),即直接把标签体内容输出到页面上
 * 4. 在.tld文件中使用body-content节点来描述标签体类型:
 *  1)empty:没有标签体
 *  2)(大部分)scriptless:标签体可以包含el表达式(${param.name})和jsp动作元素,但不能包含jsp的脚本元素(<% request.getParameter("name")%>)
 *  3)tagdependent:表示标签体交由标签本身去处理,若指定tagdependent,在标签体中的所有代码都会原封不动的交给标签处理器,而不是将执行结果交给标签处理器
 */
public class TestJspFragment extends SimpleTagSupport {

    @Override
    public void doTag() throws JspException, IOException {
        JspFragment jspFragment = getJspBody();
        //JspFragment.invoke(Writer):Writer即为标签体内容输出的字符流,若为null,则输出到getJspContext().getOut(),即输出到页面上
        //标签的属性可以通过getJspContext().getOut().print(xxx)输出到页面上
        //而标签体的内容通过jspFragment.invoke(null)输出到页面上
        jspFragment.invoke(null);
    }
}

3.带父标签的标签

父标签:

/*
 * 1.父标签无法获取子标签的引用,父标签把子标签作为标签体来引用
 * 2.子标签可以通过getParent()方法获取父标签的引用。
 * 若此标签确实具有父标签,JSP引擎会把代表父标签的引用通过setParent(JspTag parent)方法赋给标签处理器,然后通过getParent()取出
 * 3.父标签是JspTag类型,该接口是一个空接口,是用来统一SimpleTag和Tag的,实际使用需要类型转换
 * 4.在.tld文件中,无需为父标签配额外的配置,子标签是以标签体形式存在
 * 
 */
import java.io.IOException;

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

public class ParentTag extends SimpleTagSupport {

    private String name="ParentTag";
    public String getName() {
        return name;
    }

    @Override
    public void doTag() throws JspException, IOException {
        System.out.println("父标签的标签处理器类name:" + name);
        getJspBody().invoke(null);
    }
}

子标签:

import java.io.IOException;

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

public class SonTag extends SimpleTagSupport {

    @Override
    public void doTag() throws JspException, IOException {
        //1.得到父标签的引用
        JspTag parent = getParent();

        //2.获取父标签的name属性
        ParentTag parentTag = (ParentTag)parent;
        String name = parentTag.getName();

        //3.把 name 值打印到JSP页面上
        getJspContext().getOut().print("子标签输出name:"+name);
    }
}

4.foreach标签

import java.io.IOException;
import java.util.Collection;

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

public class ForEachTag extends SimpleTagSupport {
    private Collection<?> items;
    public void setItems(Collection<?> items) {
        this.items = items;
    }

    private String var;
    public void setVar(String var) {
        this.var = var;
    }

    @Override
    /*
     * 1.将标签体的属性利用setXXX方法传入到.java中,并准备遍历item集合    此时键(var)是l
     * 2.把正在遍历的对象和var形成键值对放入到pageContext中 ,利用setAttribute方法  (getJspContext().setAttribute(var, obj);) 键:var 值:正在遍历的对象
     *   在JSP页面使用el表达式利用键取出setAttribute设置好的值 (${l} 等同于 <% pageContent.getAttribute("l") %>
     * 3.遍历集合,把标签体的el表达式获取到的内容输出到页面上
     */
    public void doTag() throws JspException, IOException {
        if(items != null) {
            for(Object obj : items) {
                //把正在遍历的对象以键值对的形式放入到pageContext中
                getJspContext().setAttribute(var, obj);
                /*
                不能通过getJspContext().getOut()方法直接输出集合对象,因为集合的对象可能包含多个属性,只能先放入PageContext域中,在Jsp页面上的foreach标签体中利用EL表达式获取到对象的每个属性,然后利用getJspBody().invoke(null)输出标签体中获取的内容
                */
                getJspBody().invoke(null);
            }
        }
    }
}
    <%
        List<String> list = new ArrayList();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        request.setAttribute("list", list);
    %>
    <!-- var是setAttribute和getAttribute的键 ,通过var,把遍历的集合对象存入pageContext并在JSP中利用var取出(即标签体的内容就是每个的集合对象的内容),并把标签体的内容输出到页面上-->
    <test:forEach items="${requestScope.list }" var="l">
        ${pageScope.l};
        <br>
        ${l};
        <br>
    </test:forEach>

5.choose标签

import java.io.IOException;

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

public class ChooseTag extends SimpleTagSupport {

    private boolean flag = true;

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public boolean isFlag() {
        return flag;
    }

    @Override
    public void doTag() throws JspException, IOException {
        getJspBody().invoke(null);
    }
}
import java.io.IOException;

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

public class WhenTag extends SimpleTagSupport {
    private boolean test;

    public void setTest(boolean test) {
        this.test = test;
    }

    @Override
    public void doTag() throws JspException, IOException {
        if(test) {

            ChooseTag chooseTag = (ChooseTag)getParent();
            boolean flag = chooseTag.isFlag();

            if(flag) {
                getJspBody().invoke(null);
                chooseTag.setFlag(false);
            }
        }
    }
}
import java.io.IOException;

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

public class OtherwiseTag extends SimpleTagSupport {


    @Override
    public void doTag() throws JspException, IOException {
        ChooseTag chooseTag = (ChooseTag)getParent();

        if(chooseTag.isFlag())
            getJspBody().invoke(null);
    }

}
    <test:choose>
        <test:when test="${param.age>24 }">大学毕业</test:when>
        <test:when test="${param.age>20 }">高中毕业</test:when>
        <test:otherwise>高中</test:otherwise>
    </test:choose>
    <br>

choose标签的思路是 在choose标签中设置一个flag 根据flag来判断语句是否执行,执行了语句flag就变为false,不再继续执行别的语句。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值