你的位置:首页 > Java教程

[Java教程]EL函数以及自定义标签的应用


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


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

 

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

1 package cn.wzbrilliant.el;2 3 public class ElFunction {4   public static String toUpperCase(String str){5     return str.toUpperCase();6   }7 }

 

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

 1 <??> 2 <taglib ="http://java.sun.com/ ="http://www.w3.org/2001/ 3   xsi:schemaLocation="http://java.sun.com/ 4   version="2.0"> 5   <tlib-version>1.0</tlib-version> 6   <short-name>myfn</short-name> 7   <uri>/WEB-INF/myfn.tld</uri> 8    9   <function><!-- 定义函数 -->10     <name>toUpper</name> <!-- 调用名称 -->11     <function-class>cn.wzbrilliant.el.ElFunction</function-class> <!-- 类全名 -->12     <function-signature>java.lang.String toUpperCase( java.lang.String )</function-signature>13   </function>14   15 </taglib>

<tlib-version>值随意

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

<uri>值随意,只要与web.


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

1 <jsp-config>2     <taglib>3       <taglib-uri>/WEB-INF/myfn.tld</taglib-uri>4       <taglib-location>/WEB-INF/myfn.tld</taglib-location>5     </taglib>6 </jsp-config>

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

<taglib-location> tld文件的位置

 


④ 在JSP中使用

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

使用方式如下:

1 <%2     pageContext.setAttribute("p", "abcdef");3 %>4 5 ${myfn:toUpper(h) } <br/>6 ${myfn:toUpper("abcdef") }

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

 

二、EL自定义标签开发

 

自定义标签属于JSP技术

 

1、标签的作用

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

 

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

 

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

 

 

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

 

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

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

 

 1 package cn.wzbrilliant.el; 2  3 import java.io.IOException; 4  5 import javax.servlet.jsp.JspException; 6 import javax.servlet.jsp.tagext.SimpleTagSupport; 7  8 public class SimpleTag extends SimpleTagSupport { 9 10   @Override11   public void doTag() throws JspException, IOException {12 //    JspFragment jf=getJspBody();13 //    jf.invoke(getJspContext().getOut());14     15     getJspBody().invoke(null);16     17   }18   19 }

 

 

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

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

 1 package cn.wzbrilliant.el; 2  3 import java.io.IOException; 4  5 import javax.servlet.jsp.JspException; 6 import javax.servlet.jsp.PageContext; 7 import javax.servlet.jsp.tagext.SimpleTagSupport; 8  9 public class SimpleTag extends SimpleTagSupport {10 11   @Override12   public void doTag() throws JspException, IOException {13     PageContext pageContext=(PageContext)getJspContext();14     String ip=pageContext.getRequest().getRemoteAddr();15     pageContext.getOut().write(ip);16   }17   18 }

 

②在WEB-INF目录下建立一个扩展名为tld(Tag Libary Definition)的

 1 <??> 2 <taglib ="http://java.sun.com/ ="http://www.w3.org/2001/ 3   xsi:schemaLocation="http://java.sun.com/ 4   version="2.0"> 5  6   <tlib-version>1.0</tlib-version> 7   <short-name>mytag</short-name> 8   <uri>/WEB-INF/mytag.tld</uri> 9 10   <tag><!-- 描述标签 -->11     <description>Show Remote Address</description>12     <name>remoteIp</name><!-- 标签名称 -->13     <tag-class>cn.wzbrilliant.el.SimpleTag</tag-class>14     <body-content>empty</body-content><!-- 指示标签的主体内容:没有就写empty -->15   </tag>16 17 </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.

1 <jsp-config>2     <taglib>3       <taglib-uri>/WEB-INF/mytag.tld</taglib-uri>4       <taglib-location>/WEB-INF/mytag.tld</taglib-location>5     </taglib>6 </jsp-config>

此处配置与EL函数相同

 

⑤ 在JSP中使用

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

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

 

3.简单标签的原理:

 

三、自定义标签实例:

 

①实现JSTL中forEach标签的功能

类代码如下:

 1 package cn.wzbrilliant.el; 2  3 import java.io.IOException; 4 import java.lang.reflect.Array; 5 import java.util.ArrayList; 6 import java.util.Collection; 7 import java.util.List; 8 import java.util.Map; 9 import java.util.Set;10 11 import javax.servlet.jsp.JspException;12 import javax.servlet.jsp.PageContext;13 import javax.servlet.jsp.tagext.SimpleTagSupport;14 15 public class ForEachTag extends SimpleTagSupport {16   private String var;17   private Collection items;18   19   public void setItems(Object items) {20     if(items instanceof List){21       this.items=(List)items;22     }else if(items instanceof Set){23       this.items=(Set)items;24     }else if(items instanceof Map){25       this.items=((Map)items).entrySet();26     }else if(items.getClass().isArray()){27       this.items=new ArrayList();28       int length=Array.getLength(items);29       for(int i=0;i<length;i++){30         this.items.add(Array.get(items, i));31       }32     }else{33       throw new RuntimeException("对不起,不支持的类型");34     }35   }36   public void setVar(String var) {37     this.var = var;38   }39   @Override40   public void doTag() throws JspException, IOException {41     PageContext pageContext=(PageContext) getJspContext();42     for(Object obj:items){43       pageContext.setAttribute(var, obj);44       getJspBody().invoke(null);45     }46   }47   48 }

 

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

 1 <tag><!-- forEach标签 --> 2     <description>for each</description> 3     <name>forEach</name> 4     <tag-class>cn.wzbrilliant.el.ForEachTag</tag-class> 5     <body-content>scriptless</body-content> 6     <attribute> 7       <name>items</name> 8       <required>true</required> 9       <rtexprvalue>true</rtexprvalue>10     </attribute>11     <attribute>12       <name>var</name>13       <required>true</required>14       <rtexprvalue>true</rtexprvalue>15     </attribute>16 </tag>

 

使用方法:

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

与JSTL中forEach标签使用无异,如此便可遍历数组、集合的元素。

 

 

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

 

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

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

父标签choose实现类:

 

 1 package cn.wzbrilliant.el; 2  3 import java.io.IOException; 4  5 import javax.servlet.jsp.JspException; 6 import javax.servlet.jsp.tagext.SimpleTagSupport; 7  8 public class ChooseTag extends SimpleTagSupport { 9   private boolean flag=false;10   11   protected boolean isFlag(){12     return flag;13   }14   15   protected void setFlag(boolean flag){16     this.flag=flag;17   }18 19   @Override20   public void doTag() throws JspException, IOException {21 22     getJspBody().invoke(null);23   }24   25   26 }

 

 

子标签when实现类:

 1 package cn.wzbrilliant.el; 2  3 import java.io.IOException; 4  5 import javax.servlet.jsp.JspException; 6 import javax.servlet.jsp.tagext.SimpleTagSupport; 7  8 public class WhenTag extends SimpleTagSupport { 9   private boolean test;10   11   public void setTest(boolean test){12     this.test=test;13   }14 15   @Override16   public void doTag() throws JspException, IOException {17     if(test){18       ChooseTag parent=(ChooseTag)getParent();19       parent.setFlag(true);20       getJspBody().invoke(null);21     }22   }23   24   25 }

 

子标签otherwise实现类:

 1 package cn.wzbrilliant.el; 2  3 import java.io.IOException; 4  5 import javax.servlet.jsp.JspException; 6 import javax.servlet.jsp.tagext.SimpleTagSupport; 7  8 public class OtherwiseTag extends SimpleTagSupport { 9 10   @Override11   public void doTag() throws JspException, IOException {12     ChooseTag parent=(ChooseTag)getParent();13     if(!parent.isFlag()){14       getJspBody().invoke(null);15     }16   }17   18 }

 

mytag.tld中添加如下内容:

 1 <tag><!-- choose标签 --> 2     <description>when otherwise</description> 3     <name>choose</name> 4     <tag-class>cn.wzbrilliant.el.ChooseTag</tag-class> 5     <body-content>scriptless</body-content> 6 </tag> 7    8 <tag><!-- when标签 --> 9     <description>when otherwise</description>10     <name>when</name>11     <tag-class>cn.wzbrilliant.el.WhenTag</tag-class>12     <body-content>scriptless</body-content>13         <attribute>14       <name>test</name>15       <required>true</required>16       <rtexprvalue>true</rtexprvalue>17     </attribute>18 </tag>19   20 <tag><!-- otherwise标签 -->21     <description>when otherwise</description>22     <name>otherwise</name>23     <tag-class>cn.wzbrilliant.el.OtherwiseTag</tag-class>24     <body-content>scriptless</body-content>25 </tag>    

 

使用方法,在jsp中:

 1 <% 2   pageContext.setAttribute("p", arr); 3 %> 4  5      6 <mytag:choose> 7   <mytag:when test="${empty p }"> 8       there is empty 9   </mytag:when>10   <mytag:otherwise>11       <mytag:forEach items="${p }" var="v">12           <br>${v}13       </mytag:forEach>14   </mytag:otherwise>15 </mytag:choose>

 

 

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

 

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

实现类代码如下:

 

 1 package cn.wzbrilliant.el; 2  3 import java.io.IOException; 4 import java.io.StringWriter; 5  6 import javax.servlet.jsp.JspException; 7 import javax.servlet.jsp.tagext.SimpleTagSupport; 8  9 public class HtmlTextFilterTag extends SimpleTagSupport {10 11   @Override12   public void doTag() throws JspException, IOException {13     StringWriter sw=new StringWriter();14     getJspBody().invoke(sw);15     String content=sw.toString();16     content = filter(content);17     getJspContext().getOut().write(content);18   }19 20   private String filter(String message) {21     if (message == null)22       return (null);23 24     char content[] = new char[message.length()];25     message.getChars(0, message.length(), content, 0);26     StringBuffer result = new StringBuffer(content.length + 50);27     for (int i = 0; i < content.length; i++) {28       switch (content[i]) {29       case '<':30         result.append("&lt;");31         break;32       case '>':33         result.append("&gt;");34         break;35       case '&':36         result.append("&amp;");37         break;38       case '"':39         result.append("&quot;");40         break;41       default:42         result.append(content[i]);43       }44     }45     return (result.toString());46   }47 }

 

 

mytag.tld中添加如下内容:

1 <tag><!-- 文本中Html代码过滤标签 -->2     <description>htmlfilter</description>3     <name>htmlfilter</name>4     <tag-class>cn.wzbrilliant.el.HtmlTextFilterTag</tag-class>5     <body-content>scriptless</body-content>6 </tag>

 

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

 

④防盗链标签

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

实现代码如下:

 

 1 package cn.wzbrilliant.el; 2  3 import java.io.IOException; 4  5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 import javax.servlet.jsp.JspException; 8 import javax.servlet.jsp.PageContext; 9 import javax.servlet.jsp.tagext.SimpleTagSupport;10 11 public class RefererTag extends SimpleTagSupport {12   private String site;13   private String redirectPath;14 15   public void setSite(String site) {16     this.site = site;17   }18 19   public void setRedirectPath(String redirectPath) {20     this.redirectPath = redirectPath;21   }22 23   @Override24   public void doTag() throws JspException, IOException {25     PageContext pageContext = (PageContext) getJspContext();26     HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();27     HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();28     String referer = request.getHeader("referer");29     if (referer != null && !referer.startsWith(site)) {30       String path;31       if (redirectPath.startsWith("/")) {32         path = request.getContextPath() + redirectPath;33       } else {34         String uri=request.getRequestURI();35         path=uri.substring(0, uri.lastIndexOf("/")+1)+redirectPath;36       }37       response.sendRedirect(path);38     }39   }40 41 }

 

 

mytag.tld中添加如下内容:

 1 <tag><!-- 防盗链 --> 2     <description>referer</description> 3     <name>referer</name> 4     <tag-class>cn.wzbrilliant.el.RefererTag</tag-class> 5     <body-content>empty</body-content> 6     <attribute> 7       <name>site</name> 8       <required>true</required> 9       <rtexprvalue>true</rtexprvalue>10     </attribute>11     <attribute>12       <name>redirectPath</name>13       <required>true</required>14       <rtexprvalue>true</rtexprvalue>15     </attribute>16 </tag>

 

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