一、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)的xml文件。内容如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" 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.xml中的uri想对应即可
③(可选步骤)前提是把tld文件放到了WEB-INF目录下。告知应用,tld文件和tld中的uri的对应。修改web.xml,增加以下内容:
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)的xml文件。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" 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.xml中对tld文件和名称空间进行映射对应。
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("<");31 break;32 case '>':33 result.append(">");34 break;35 case '&':36 result.append("&");37 break;38 case '"':39 result.append(""");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是将外部应用的请求转发的目标地址,可以是相对路径,也可以是绝对路径。
四、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():是否是最后一条记录
新闻热点
疑难解答