EL函数以及自定义标签的应用

来源:互联网 发布:青铜卡尺 知乎 编辑:程序博客网 时间:2024/06/07 12:40

一、EL函数(调用普通类的静态方法)


编写步骤(自定义EL函数的编写步骤即自定义标签的编写步骤):

 

①编写一个普通的java类,提供一个静态方法,功能自定,例如下:

package cn.wzbrilliant.el;public class ElFunction {    public static String toUpperCase(String str){        return str.toUpperCase();    }}


②在JavaWeb应用的WEB-INF目录下建立一个扩展名是tld(taglib definition)的XML文件。内容如下:

<?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">    <tlib-version>1.0</tlib-version>    <short-name>myfn</short-name>    <uri>/WEB-INF/myfn.tld</uri>        <function><!-- 定义函数 -->        <name>toUpper</name> <!-- 调用名称 -->        <function-class>cn.wzbrilliant.el.ElFunction</function-class> <!-- 类全名 -->        <function-signature>java.lang.String toUpperCase( java.lang.String )</function-signature>    </function>    </taglib>

<tlib-version>值随意

<short-name>一般与文件名、前缀名称相同,方便查找,不相同也可。

<uri>值随意,只要与web.xml中的uri想对应即可


③(可选步骤)前提是把tld文件放到了WEB-INF目录下。
告知应用,tld文件和tld中的uri的对应。修改web.xml,增加以下内容:

<jsp-config>        <taglib>            <taglib-uri>/WEB-INF/myfn.tld</taglib-uri>            <taglib-location>/WEB-INF/myfn.tld</taglib-location>        </taglib></jsp-config>

<taglib> 代表一个标签库,可以多个

<taglib-location> tld文件的位置

 


④ 在JSP中使用

用taglib指令,引入自定义的EL函数库: <%@ taglib uri="/WEB-INF/myfn.tld" prefix="myfn"%> 

使用方式如下:

<%        pageContext.setAttribute("p", "abcdef");%>${myfn:toUpper(h) } <br/>${myfn:toUpper("abcdef") }

代码第五行和第六行都可输出"ABCDEF"。

 

二、EL自定义标签开发

 

自定义标签属于JSP技术

 

1、标签的作用

移除掉JSP中的Java脚本(<%%>)

 

2、编写自定义标签的步骤(自定义EL函数,步骤相同)

 

自定义标签分为两种,传统标签简单标签

 

这里只介绍简单标签的开发:

 

①编写一个类,直接或间接实现javax.servlet.jsp.tagext.Tag接口

 

这里继承SimpleTagSupport类,例子如下: 

package cn.wzbrilliant.el;import java.io.IOException;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.SimpleTagSupport;public class SimpleTag extends SimpleTagSupport {    @Override    public void doTag() throws JspException, IOException {//        JspFragment jf=getJspBody();//        jf.invoke(getJspContext().getOut());                getJspBody().invoke(null);            }    }

JspFragment对象的invoke方法将标签内容输入到给定的流中,如果为null,例如上面代码,则其作用与注释部分代码相同。

下面以一个获取远程IP地址的代码为例:

package cn.wzbrilliant.el;import java.io.IOException;import javax.servlet.jsp.JspException;import javax.servlet.jsp.PageContext;import javax.servlet.jsp.tagext.SimpleTagSupport;public class SimpleTag extends SimpleTagSupport {    @Override    public void doTag() throws JspException, IOException {        PageContext pageContext=(PageContext)getJspContext();        String ip=pageContext.getRequest().getRemoteAddr();        pageContext.getOut().write(ip);    }    }


在WEB-INF目录下建立一个扩展名为tld(Tag Libary Definition)的xml文件。
<?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">    <tlib-version>1.0</tlib-version>    <short-name>mytag</short-name>    <uri>/WEB-INF/mytag.tld</uri>    <tag><!-- 描述标签 -->        <description>Show Remote Address</description>        <name>remoteIp</name><!-- 标签名称 -->        <tag-class>cn.wzbrilliant.el.SimpleTag</tag-class>        <body-content>empty</body-content><!-- 指示标签的主体内容:没有就写empty -->    </tag></taglib>

标签内容与EL函数中tld文件中相似。可以添加多个标签。具体如下:

taglib:根元素

    tlib-version:版本号
    short-name:引用标签时的短名称。一般与tld文件的文件名一致,好找。
    uri:标签绑定的名称空间。只是一个名字,没有实际的意义。

    tag:定义标签元素

        name:标签的名称。

        tag-class:标签的实现类的全名称。

        body-content:指示标签的主体内容的类型。

                可选值:empty:没有主体内容。适用于传统和简单标签。

                    JSP:说明JSP文件中能出现什么,标签主体内容中就能出现什么。适用于传统标签。

                    scriptless:说明标签的主体内容不能是java脚本。适用于简单标签。

                    tagdependent:说明标签的主体内容是原封不动的传递给标签处理类的,而不是传递的运算结果


        attribute:定义标签的属性

        name:属性名。对应标签处理类中的setter方法

        required:是否是必须的属性

        rtexprvalue:是否支持表达式(EL或java表达式)。默认是false。


③(可选的)在web.xml中对tld文件和名称空间进行映射对应。

<jsp-config>        <taglib>            <taglib-uri>/WEB-INF/mytag.tld</taglib-uri>            <taglib-location>/WEB-INF/mytag.tld</taglib-location>        </taglib></jsp-config>

此处配置与EL函数相同

 

⑤ 在JSP中使用

首先引入: <%@ taglib uri="/WEB-INF/mytag.tld" prefix="mytag"%> 

使用方法:在jsp页面中使用: <mytag:remoteIp />  即可输出访问服务器的远程的ip地址

 


3.简单标签的原理:

三、自定义标签实例:

 

①实现JSTL中forEach标签的功能

类代码如下:

package cn.wzbrilliant.el;import java.io.IOException;import java.lang.reflect.Array;import java.util.ArrayList;import java.util.Collection;import java.util.List;import java.util.Map;import java.util.Set;import javax.servlet.jsp.JspException;import javax.servlet.jsp.PageContext;import javax.servlet.jsp.tagext.SimpleTagSupport;public class ForEachTag extends SimpleTagSupport {    private String var;    private Collection items;        public void setItems(Object items) {        if(items instanceof List){            this.items=(List)items;        }else if(items instanceof Set){            this.items=(Set)items;        }else if(items instanceof Map){            this.items=((Map)items).entrySet();        }else if(items.getClass().isArray()){            this.items=new ArrayList();            int length=Array.getLength(items);            for(int i=0;i<length;i++){                this.items.add(Array.get(items, i));            }        }else{            throw new RuntimeException("对不起,不支持的类型");        }    }    public void setVar(String var) {        this.var = var;    }    @Override    public void doTag() throws JspException, IOException {        PageContext pageContext=(PageContext) getJspContext();        for(Object obj:items){            pageContext.setAttribute(var, obj);            getJspBody().invoke(null);        }    }    }


mytag.tld文件中添加如下内容:

<tag><!-- forEach标签 -->        <description>for each</description>        <name>forEach</name>        <tag-class>cn.wzbrilliant.el.ForEachTag</tag-class>        <body-content>scriptless</body-content>        <attribute>            <name>items</name>            <required>true</required>            <rtexprvalue>true</rtexprvalue>        </attribute>        <attribute>            <name>var</name>            <required>true</required>            <rtexprvalue>true</rtexprvalue>        </attribute></tag>


使用方法:

<%    int[] arr = new int[] {1,2,3,4};    pageContext.setAttribute("p", arr); %>         <mytag:forEach items="${p}" var="v">            ${v}<br> </mytag:forEach>


②实现JSTL中when  otherwise功能(与if-else结构相似)

 

实现用到了父标签。父标签的作用:用于子标签之间数据的传递。

该例使用了三个标签,分别为choose(父标签),when,otherwise,用三个类实现。

父标签choose实现类:

package cn.wzbrilliant.el;import java.io.IOException;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.SimpleTagSupport;public class ChooseTag extends SimpleTagSupport {    private boolean flag=false;        protected boolean isFlag(){        return flag;    }        protected void setFlag(boolean flag){        this.flag=flag;    }    @Override    public void doTag() throws JspException, IOException {        getJspBody().invoke(null);    }        }


子标签when实现类:

package cn.wzbrilliant.el;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 parent=(ChooseTag)getParent();            parent.setFlag(true);            getJspBody().invoke(null);        }    }        }


子标签otherwise实现类:
package cn.wzbrilliant.el;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 parent=(ChooseTag)getParent();        if(!parent.isFlag()){            getJspBody().invoke(null);        }    }    }


mytag.tld中添加如下内容:
<tag><!-- choose标签 -->        <description>when otherwise</description>        <name>choose</name>        <tag-class>cn.wzbrilliant.el.ChooseTag</tag-class>        <body-content>scriptless</body-content></tag>    <tag><!-- when标签 -->        <description>when otherwise</description>        <name>when</name>        <tag-class>cn.wzbrilliant.el.WhenTag</tag-class>        <body-content>scriptless</body-content>                <attribute>            <name>test</name>            <required>true</required>            <rtexprvalue>true</rtexprvalue>        </attribute></tag>    <tag><!-- otherwise标签 -->        <description>when otherwise</description>        <name>otherwise</name>        <tag-class>cn.wzbrilliant.el.OtherwiseTag</tag-class>        <body-content>scriptless</body-content></tag>


使用方法,在jsp中:
<%    pageContext.setAttribute("p", arr);%>        <mytag:choose>    <mytag:when test="${empty p }">            there is empty    </mytag:when>    <mytag:otherwise>            <mytag:forEach items="${p }" var="v">                    <br>${v}            </mytag:forEach>    </mytag:otherwise></mytag:choose>


html显示文本中html代码的过滤 

 

例如留言板中,有时候需要将html代码原样输出,而不解析。

实现类代码如下:

package cn.wzbrilliant.el;import java.io.IOException;import java.io.StringWriter;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.SimpleTagSupport;public class HtmlTextFilterTag extends SimpleTagSupport {    @Override    public void doTag() throws JspException, IOException {        StringWriter sw=new StringWriter();        getJspBody().invoke(sw);        String content=sw.toString();        content = filter(content);        getJspContext().getOut().write(content);    }    private String filter(String message) {        if (message == null)            return (null);        char content[] = new char[message.length()];        message.getChars(0, message.length(), content, 0);        StringBuffer result = new StringBuffer(content.length + 50);        for (int i = 0; i < content.length; i++) {            switch (content[i]) {            case '<':                result.append("<");                break;            case '>':                result.append(">");                break;            case '&':                result.append("&");                break;            case '"':                result.append(""");                break;            default:                result.append(content[i]);            }        }        return (result.toString());    }}


mytag.tld中添加如下内容:
<tag><!-- 文本中Html代码过滤标签 -->        <description>htmlfilter</description>        <name>htmlfilter</name>        <tag-class>cn.wzbrilliant.el.HtmlTextFilterTag</tag-class>        <body-content>scriptless</body-content></tag>


使用方式:在jsp页面中输出文本数据时添加此标签便可将文本中html代码原样输出,而不解析。

 

④防盗链标签

防止别的网站、应用盗链,可以利用EL自定义标签,将请求转向其他URI(自定义的广告等等)

实现代码如下:

package cn.wzbrilliant.el;import java.io.IOException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.jsp.JspException;import javax.servlet.jsp.PageContext;import javax.servlet.jsp.tagext.SimpleTagSupport;public class RefererTag extends SimpleTagSupport {    private String site;    private String redirectPath;    public void setSite(String site) {        this.site = site;    }    public void setRedirectPath(String redirectPath) {        this.redirectPath = redirectPath;    }    @Override    public void doTag() throws JspException, IOException {        PageContext pageContext = (PageContext) getJspContext();        HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();        HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();        String referer = request.getHeader("referer");        if (referer != null && !referer.startsWith(site)) {            String path;            if (redirectPath.startsWith("/")) {                path = request.getContextPath() + redirectPath;            } else {                String uri=request.getRequestURI();                path=uri.substring(0, uri.lastIndexOf("/")+1)+redirectPath;            }            response.sendRedirect(path);        }    }}


mytag.tld中添加如下内容:
<tag><!-- 防盗链 -->        <description>referer</description>        <name>referer</name>        <tag-class>cn.wzbrilliant.el.RefererTag</tag-class>        <body-content>empty</body-content>        <attribute>            <name>site</name>            <required>true</required>            <rtexprvalue>true</rtexprvalue>        </attribute>        <attribute>            <name>redirectPath</name>            <required>true</required>            <rtexprvalue>true</rtexprvalue>        </attribute></tag>


使用方法:在防盗链的页面头部添加: <mytag:referer site="http://localhost:8080/JavaWeb" redirectPath="error.jsp"/> ,其中site值为本应用的URI,redirectPath是将外部应用的请求转发的目标地址,可以是相对路径,也可以是绝对路径。



四、JSTL中的核心标签库(替换掉JSP中的Java脚本)


① c:if

作用:判断是否为true,如果为true,那么标签的主体内容就会显示。
属性:test:必须的。要求必须是boolean的。支持表达式(EL或Java表达式)
   var:保存test运算结果的变量
   scope: 保存的域范围。默认是page

c:forEach

遍历:数组、List、Set、Map
属性:items:要遍历的目标对象。支持表达式
   var:变量名。指向当前遍历的集合中的一个元素
   begin:开始的索引(含)
   end:结束的索引(含)
   step:步长。默认是1
   varStatus:取一个名字,引用了一个对象。该对象有以下方法:
        int getIndex():当前记录的索引号。从0开始
        int getCount():当前记录的顺序。从1开始
        boolean isFirst():是否是第一条记录
        boolean isLast():是否是最后一条记录



博客园博客:欠扁的小篮子


1 0
原创粉丝点击