首页 > 代码库 > EL的函数与标签

EL的函数与标签

1 什么EL函数库

  EL函数库是由第三方对EL的扩展,我们现在学习的EL函数库是由JSTL添加的。下面我们会学习JSTL标签库。

EL函数库就是定义一些有返回值的静态方法。然后通过EL语言来调用它们!当然,不只是JSTL可以定义EL函数库,我们也可以自定义EL函数库。

  EL函数库中包含了很多对字符串的操作方法,以及对集合对象的操作。例如:${fn:length(“abc”)}会输出3,即字符串的长度。

 

2 导入函数库

  因为是第三方的东西,所以需要导入。导入需要使用taglib指令!

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

3 EL函数库介绍

l  String toUpperCase(String input):

l  String toLowerCase(String input):

l  int indexOf(String input, String substring):

l  boolean contains(String input, String substring):

l  boolean containsIgnoreCase(String input, String substring):

l  boolean startsWith(String input, String substring):

l  boolean endsWith(String input, String substring):

l  String substring(String input, int beginIndex, int endIndex):

l  String substringAfter(String input, String substring):

l  substringBefore(String input, String substring):

l  String escapeXml(String input):

l  String trim(String input):

l  String replace(String input, String substringBefore, String substringAfter):

l  String[] split(String input, String delimiters):

l  int length(Object obj):

l  String join(String array[], String separator):

<%@taglib prefix="fn"   uri="http://java.sun.com/jsp/jstl/functions"   %>

String[] strs = {"a", "b","c"};

List list = new ArrayList();

list.add("a");

pageContext.setAttribute("arr", strs);

pageContext.setAttribute("list", list);

%>

${fn:length(arr)   }<br/><!--3-->

${fn:length(list)   }<br/><!--1-->

${fn:toLowerCase("Hello")   }<br/> <!-- hello -->

${fn:toUpperCase("Hello")   }<br/> <!-- HELLO -->

${fn:contains("abc",   "a")}<br/><!-- true -->

${fn:containsIgnoreCase("abc",   "Ab")}<br/><!-- true -->

${fn:contains(arr,   "a")}<br/><!-- true -->

${fn:containsIgnoreCase(list,   "A")}<br/><!-- true -->

${fn:endsWith("Hello.java",   ".java")}<br/><!-- true -->

${fn:startsWith("Hello.java",   "Hell")}<br/><!-- true -->

${fn:indexOf("Hello-World",   "-")}<br/><!-- 5 -->

${fn:join(arr,   ";")}<br/><!-- a;b;c -->

${fn:replace("Hello-World",   "-", "+")}<br/><!-- Hello+World -->

${fn:join(fn:split("a;b;c;",   ";"), "-")}<br/><!-- a-b-c -->

 

${fn:substring("0123456789",   6, 9)}<br/><!-- 678 -->

${fn:substring("0123456789",   5, -1)}<br/><!-- 56789 -->

${fn:substringAfter("Hello-World",   "-")}<br/><!-- World -->

${fn:substringBefore("Hello-World",   "-")}<br/><!-- Hello -->

${fn:trim("     a b c       ")}<br/><!-- a b c -->

${fn:escapeXml("<html></html>")}<br/> <!-- <html></html> -->

 

 

4 自定义EL函数库

l  写一个类,写一个有返回值的静态方法;

l  编写tld文件,可以参数fn.tld文件来写,把tld文件放到classes下(还可以自定义命名空间);

l  在页面中添加taglib指令,导入自定义标签库。

 

ItcastFuncations.java

package cn.itcast.el.funcations;

 

public class ItcastFuncations {

    public static String test() {

       return "传智播客自定义EL函数库测试";

    }

}

 

itcast.tld(放到classes下)

<?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">

   

  <description>ITCAST 1.0 functions library</description>

  <display-name>ITCAST functions</display-name>

  <tlib-version>1.0</tlib-version>

  <short-name>itcast</short-name>

  <uri>http://www.itcast.cn/jsp/functions</uri>

 

  <function>

    <name>test</name>

    <function-class>cn.itcast.el.funcations.ItcastFuncations</function-class>

    <function-signature>String test()</function-signature>

  </function>

</taglib>

 

index.jsp

<%@ page language="java"   import="java.util.*" pageEncoding="UTF-8"%>

<%@ taglib prefix="itcast"   uri="/WEB-INF/classes/itcast.tld" %>

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD   HTML 4.01 Transitional//EN">

<html>

  <body>

    <h1>${itcast:test() }</h1>

  </body>

</html>

 

如果把itcast.tld文件放到classes\META-INF\itcast.tld,那么就可以把

<%@ taglib prefix="itcast" uri="/WEB-INF/classes/itcast.tld" %>

修改为

<%@ taglib prefix="itcast" uri="http://www.itcast.cn/jsp/functions" %>

对应itcast.tld文件中的<uri>元素内容。

一般这种方式都是打包成Jar时,在Jar中的META-INF目录中存放TLD文件。

 

自定义标签

Tag

 

1 什么是自定义标签

  尽管JSP本身,以及第三方提供了很多标签库,但因为业务需要,我们有时还是需要自定义标签。因为JSP页面中不可以存在Java代码,所以我们需要自定义标签!

 2 标签的真身

其实我们现在应该可以了解了,真的是万物皆对象。JSP可以是一个对象,当然标签也可以是一个对象。其实在页面中使用的标签就是对一个对象的方法调用!

l  标签处理类:都有自己的标签处理类!所有标签处理类都必须去实现Tag或SimpleTag接口;

l  TLD(Tag Library Description):一个TLD文件中可以部署多个标签!JSP会通过TLD文件找到标签! (webapps\examples\WEB-INF\jsp2,这里有模板)

3 Hello Tag!

写一个类:MyTag,实现Tag接口。Tag接口中一共6个方法!我们只需要去实现两个方法即可,其他的方法当它不存在!

l  setPageContext(PageContext):为本类添加PageContext属性,在本方法中把参数赋给本类属性。没错,就是用来保存PageContext中,因为doStartTag()方法中要用PageContext;

l  int doStartTag():使用pageContext获取out对象,然后使用out向页面打印:“Hello Tag!”。本方法还有一个返回值,返回0就行了(先不用管返回值是干什么的)!

l  TLD:TLD文件中的一个<tag>对应一个标签的部署信息!现在中需要照猫画虎就OK了!没错,TLD是一个XML文件!(可以到webapps\examples\WEB-INF\jsp2中查找TLD文件)

 

MyTag.java

package cn.itcast.tags;

 

import java.io.IOException;

 

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.PageContext;

import javax.servlet.jsp.tagext.Tag;

 

public class MyTag implements Tag  {

    private PageContext pageContext ;

    public void setPageContext(PageContext   pageContext) {

       this.pageContext = pageContext;

    }

    public int doStartTag() throws JspException {

       try {

           this.pageContext.getOut().write("Hello   Tag!"); 

       } catch (IOException e) {

           throw new JspException(e);

       }

       return 0 ;

    }

    public void setParent(Tag t) {}

    public Tag getParent() {return null;}

    public int doEndTag() throws JspException {return 0;}

    public void release() {  }

}

 mytld.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   web-jsptaglibrary_2_0.xsd"

    version="2.0">

 

    <description>xixi</description>

    <tlib-version>1.0</tlib-version>

    <jsp-version>2.0</jsp-version>

    <short-name>hello tag</short-name>

    <uri></uri>

    <small-icon></small-icon>

 

    <tag>

      <name>helloTag</name> 

      <tag-class>cn.itcast.tags.MyTag</tag-class>

      <body-content>empty </body-content>

    </tag>

</taglib>

 把mytld.tld文件放到/WEB-INF/classes/mytld.tld路径。

index.jsp

<%@taglib prefix="it"   uri="/WEB-INF/classes/mytld.tld" %>

……

<body>

    <h1><it:helloTag/> </h1>

</body>

4 标签的生命周期

  在开始聊标签的生命周期之前,我们先来看看TLD的加载过程。

首次加载TLD文件

当index.jsp第一次被执行时,Tomcat会把index.jsp编译成index_jsp.java。在这个过程中,Tomcat会根据“<%@ taglib uir=”/WEB-INF/classes/mytld.tld”…%>”去加载mytld.tld文件。这个加载TLD文件的过程只执行一次,以后就不会再执行了。

 

实例化标签处理器对象

通过TLD找到标签的处理器类,然后实例化处理器对象,并把处理器对象放到“标签池”中。也就是说,每个标签的处理器类只会有一个实例!因为下一次访问这个标签就直接从池中获取处理器对象,而不需要再去创建了。

 

标签生命周期方法

l  调用setPageContext()方法,把当前页面的PageContext传递给标签处理器类;

l  调用setParent()方法,给标签器传递父标签。如果没有父标签就传递null;

l  在执行到开始标签时,调用doStartTag()方法,doStartTag()方法返回值:

  • 0(Tag.SKIP_BODY):表示忽略标签体内容;
  • 1(Tag.EVAL_BODY_INCLUDE):表示显示标签体内容;

l  在执行到标签标签时,调用doEndTag()方法,doEndTag()方法返回值:

  • 5(Tag.SKIP_PAGE):表示忽略标签后面的页面东西;
  • 6(Tag.EVAL_PAGE)表示显示标签后面的页面东西。

l  release()方法会在重启Tomcat时被执行,即Tomcat从标签器池中移除标签时会调用这个方法。


必须实现Tag接口

添加PageContext属性

保存参数pageContext,在doStartTag()方法中方便使用。

使用pageContext获取输出流,然后使用流对象向浏览器打印Hello Tag!字符串。注意:如果没有在setPageContext()方法中保存参数,那么在doStartTag()方法中就会抛出空指针异常。

返回0表示不执行标签体。现在不用理会它!

这一部分是对当前标签库的声明!都是一些无需关心的东西。

l  当前标签库的描述;

l  当前标签库的版本;

l  支持JSP的版本;

l  标签库的名称(用于在工具上显示标签);

l  uri:这个东西是有用的,后面再讲;

l  小图标也是为了在工具上显示用的;

标签的名称

标签处理类

标签体是空类型

it与taglib指令中的prefix对应;helloTag与tld文件中的<name>对应!

技术分享

SimpleTag

 1 SimpleTag是什么

标签处理类必须实现JspTag接口,而JspTag接口有两个子接口:Tag和SimpleTag。更加确切的说:标签处理类必须实现Tag或SimpleTag接口。

JSP2.0之后,SUN提供了SimpleTag接口,通过SimpleTag接口来实现标签处理类要比Tag这种传统方式方便很多,所以现在我们可以大声与Tag说再见了。

SimpleTag接口内容如下:

l  void doTag():标签执行方法;

l  JspTag getParent():获取父标签;

l  void setParent(JspTag parent):设置父标签

l  void setJspContext(JspContext context):设置PageContext

l  void setJspBody(JspFragment jspBody):设置标签体对象;

2 继承SimpleTagSupport

public class HelloTag extends SimpleTagSupport {

    public void doTag() throws   JspException, IOException {

       this.getJspContext().getOut().write("<p>Hello   SimpleTag!</p>")[向页面输出!注意,不能向页面输出<%%>东西!] ;

    }

}

3 <body-content>

<body-content>元素的可选值有:

l  empty:不能有标签体内容。

l  JSP:标签体内容可以是任何东西:EL、JSTL、<%=%>、<%%>,以及html;但不建议使用Java代码段,SimpleTag已经不再支持使用<body-content>JSP</body-content>;

l  scriptless:标签体内容不能是Java代码段,但可以是EL、JSTL等;

l  tagdependent:标签体内容不做运算,由标签处理类自行处理,无论标签体内容是EL、JSP、JSTL,都不会做运算。

4 不执行标签下面的页面内容

我们知道,在使用Tag接口来编写标签时,可以跳过标签下面的JSP页面内容。在SimpleTag中也是可以的,这需要在doTag()方法中抛出SkipPageException。

SkipPageException是JspException的子类,当doTag()方法抛出该异常时,JSP真身不会打印异常信息,而是跳转页面内容!

5 带有属性的标签

l  在处理类中添加属性,以及getter/setter方法;

l  在TLD中部属相关属性。

 forEach

功能:模仿JSTL中的<c:forEach>标签。

forEach标签属性:

l  items:Object类型,可以是Collection、Map,或者数组(用到了数组反射);

l  begin:Integer类型,表示从哪个下标位置开始遍历;

l  end:Integer类型,表示遍历到哪个下标位置结束;

l  var:String类型,使用var指定的值来保存当前项到PageContext中;

l  step:Integer类型,表示步长;

l  varStatus:String类型,使用varStatus的值来保存当前循环的循环状态。

jsp页面  设置一个集合

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="http://www.itzl.com/myjstl/mytagTest" prefix="mytag"%><<html>  <head></head>  <body>     <%    /* List list = new ArrayList();    list.add("aaa");    list.add("bbb");    list.add("ccc");    request.setAttribute("list", list); */    /* Map map=new HashMap();    map.put("a1", "qwe");    map.put("a2", "asd");    map.put("a3", "zxc");    request.setAttribute("map", map);    */     int arr[]={1,2,3};    request.setAttribute("arr", arr);    %>    <mytag:ForEach items="${arr}" var="v">    ${v}    </mytag:ForEach>  </body></html>

实现

package cn.zl.web.el;import java.io.IOException;import java.lang.reflect.Array;import java.util.ArrayList;import java.util.Collection;import java.util.Map;import javax.servlet.jsp.JspException;import javax.servlet.jsp.PageContext;import javax.servlet.jsp.tagext.JspFragment;import javax.servlet.jsp.tagext.SimpleTagSupport;import cn.zl.web.jsp.VarStatuts;public class ForEachSimpleTag extends SimpleTagSupport {        private Integer begin;        private Integer end;        private Integer step;        private Object items;        private String var;        private String varStatus;        private Collection collection = new ArrayList();         public void setBegin(Integer begin) {            this.begin = begin;        }        public void setEnd(Integer end) {            this.end = end;        }        public void setStep(Integer step) {            this.step = step;        }        public void setItems(Object items) {            this.items = items;        }        public void setVar(String var) {            this.var = var;        }        public void setVarStatus(String varStatus) {            this.varStatus = varStatus;        }        private Object[] toArray (Object items) throws JspException {            if(items == null ) {                throw new NullPointerException("items不存在!");            }            if(items instanceof Collection) {                return ((Collection)items).toArray() ;            } else if(items instanceof Map) {                return ((Map)items).entrySet().toArray() ;            } else if(items.getClass().isArray()) {                //return (Object[])items ;                int length = Array.getLength(items);//得到数组长度                for (int i = 0; i < length; i++) {                    //取数组中的每个元素                    Object obj = Array.get(items, i);// 取第i个元素                    collection.add(obj);//将数组中的元素加入到集合中                                }                return collection.toArray();            }                        throw new JspException("items不是数组,不是集合!") ;        }        public void doTag() throws JspException, IOException {            Object[] objs = this.toArray(items) ;            if(begin == null) {                begin = 0;            }             if(end == null) {                end = objs.length - 1;            }             if(step == null) {                step = 1;            }             PageContext pageContext = (PageContext) this.getJspContext();            JspFragment body = this.getJspBody();            for(int i = begin; i <= end; i+=step ) {                Object item = objs[i];                if(varStatus != null ) {                    VarStatuts vs = new VarStatuts();                    vs.setFirst(i == begin);                    vs.setLast(i == end);                    vs.setIndex(i);                    vs.setCount(i+1);                    vs.setCurrent(objs[i]) ;                    pageContext.setAttribute(varStatus, vs) ;                }                if(var != null) {                    pageContext.setAttribute(var, item);                 }                body.invoke(null);             }            if(var != null) {                pageContext.removeAttribute(var);            }            if(varStatus != null) {                pageContext.removeAttribute(varStatus);            }         }    }

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">    <description>A tag library exercising SimpleTag handlers.</description>    <tlib-version>1.0</tlib-version>    <short-name>mytag</short-name>    <!--命名空间   (别名)-->    <uri>http://www.itzl.com/myjstl/mytagTest</uri>    <!-- el 自定义函数       -->     <tag><!-- 配置文件 -->        <name>ForEach</name>        <tag-class>cn.zl.web.el.ForEachSimpleTag</tag-class>        <body-content>scriptless</body-content>        <attribute>            <name>items</name><!-- 属性名称 -->            <required>true</required><!-- 改属性是否必须,true代表必须 -->            <rtexprvalue>true</rtexprvalue><!-- 是否支持表达式 -->        </attribute>        <attribute>            <name>var</name><!-- 属性名称 -->            <required>false</required><!-- 改属性是否必须,true代表必须 -->            <rtexprvalue>false</rtexprvalue><!-- 是否支持表达式 -->        </attribute>    </tag>   </taglib>

 

 

 

EL的函数与标签