EL表达式
1.什么是EL表达式
EL是Expression Language的缩写,它是jsp内置的表达式语言,从jsp2.0开始,就不让再使用java脚本,而是使用el表达式或动态标签来代替java脚本。
EL表达式的格式如下:
${表达式}
EL表达式代替的是java脚本中的<%= …%>,也就是说EL表达式也是向浏览器端输出数据。例如${1+2}会向浏览器端输出3。
EL表达式中不会出现空指针,没有的内容会不显示,不打印null
2.EL表达式的使用
2.1EL之全域查找
下面我们通过练习来掌握EL表达式的使用,如下所示:
(1)创建一个web应用,Example6,对该应用的index.jsp页面进行编辑,如例1-1所示:
例1-1 index.jsp
<body> This is my JSP page. <br> <% request.setAttribute("request_attribute", "request_haha"); %> ${request_attribute } </body> |
例1-1中,首先向request域中存放名字为“request_attribute“的域属性,值为”request_haha“,然后使用EL表达式将request_attribute从request域中取出,输出在浏览器端。
(2)将Example6发布到服务器端,然后启动服务器,在浏览器端访问index.jsp页面,浏览器显示结果如图1-1所示:
图1-1 浏览器显示结果
由图1-1可知,使用EL表达式成功的从request域中取出了数据。
(3)再次修改index.jsp页面,如例1-2所示:
例1-2 index.jsp
<body> This is my JSP page. <br> <% pageContext.setAttribute("attribute", "pageContext_haha"); session.setAttribute("attribute", "session_haha"); application.setAttribute("attribute", "application_haha"); request.setAttribute("attribute", "request_haha"); %> ${attribute } </body> |
例1-2中,在jsp的四大域中都存放了名字为“attribute“的与属性,但值各不相同。现在使用EL表达式向浏览器端输出attribute的值,那么浏览器端会输出哪个域的属性值?
(4)再次在浏览器端访问index.jsp页面,浏览器显示结果如图1-2所示:
图1-2 浏览器显示结果
由图1-2可知,${attribute}表达式是从pageContext域中取数据。
(5)将index.jsp页面中的向pageContext域中存放数据的代码注释掉,然后再在浏览器端访问index.jsp,浏览器显示结果如图1-3所示:
图1-3 浏览器显示结果
由图1-3可知,el表达式是从request域中取出的数据。现在再将向request域中存放数据的代码注释掉,再次在浏览器端访问index.jsp页面,浏览器显示结果如图1-4所示:
图1-4 浏览器显示结果
图1-4中,el表达式取出的是session域中的属性值,如果再将向session域存放数据的代码注释掉,再次访问index.jsp页面,浏览器端输出的仍然是“session_haha“,这是因为session对象还存在,那么它当中的域属性自然也就存在,将浏览器关闭,再打开然后再访问index.jsp,浏览器端的输出结果如图1-5所示:
图1-5 浏览器显示结果
通过以上对jsp四大域的操作,可以发现使用EL表达式获取数据是依次从jsp的四大域中获取,即全域查找,次序是page域,request域,session域最后是application域,如果page域中存在,就返回并结束查找,如果没有,就去request域中查找,找到就返回并结束查找,如果request域中也没有,那么就继续去session域中查找,以此类推,最后查找到application域。如果这四个域中都没有,那么EL表达式就返回一个空字符串,即在页面上什么也不显示,如图1-6所示:
图1-6 浏览器显示结果
2.2EL之获取指定域中的数据
在2.1小节中,我们学习了使用EL表达式进行全域查找,但是进行全域查找必然会影响效率,因此现在我们来学习使用EL表达式从指定域中获取数据,具体如下:
(1)再次对index.jsp页面进行修改,如例1-3所示:
<body> This is my JSP page. <br> <% request.setAttribute("attribute", "request_haha"); pageContext.setAttribute("attribute", "pageContext_haha"); session.setAttribute("attribute", "session_haha"); application.setAttribute("attribute", "application_haha"); %> <p>全域查找:${attribute }</p> <p>从page域中查找:${pageScope.attribute }</p> <p>从request域中查找:${requestScope.attribute }</p> <p>从session域中查找: ${sessionScope.attribute }</p> <p>从application域中查找:${applicationScope.attribute }</p> </body> |
例1-3中,如果要指定从哪个域中获取数据,一定要在指定的域名称后面加上“Scope“,否则不能从指定的域中获取数据。
(2)在浏览器端访问index.jsp,浏览器显示结果如图1-7所示:
图1-7 浏览器显示结果
其实,使用EL表达式获取jsp四个域中的数据:
l pageScope:${pageScope.name}等同与pageContext.getAttribute(“name”);
l requestScope:${requestScope.name}等同与request.getAttribute(“name”);
l sessionScope: ${sessionScope.name}等同与session.getAttribute(“name”);
l applicationScope:${applicationScope.name}等同与application.getAttribute(“name”);
2.3EL表达式之javaBean导航
如果在域中保存的是javaBean对象,那么也可以使用EL表达式来访问javaBean的属性,因为EL表达式只做读操作,所以javaBean一定要为属性提供get方法,而对set方法没有要求。使用EL表达式获取javaBean属性就是javaBean导航。
下面通过一个案例来了解EL表达式是如何进行JavaBean导航的,如下所示:
(1)在Example6应用中,新建一个javaBean类,Address,主要代码如例1-4所示:
例1-4 Address.java
public class Address { private String city; private String street; 此处省略Address类的成员变量的get/set方法 @Override public String toString() { return "Address [city=" + city + ", street=" + street + "]"; } } |
(2)在Example6应用中,再次新建一个javaBean类,Employee,主要代码如例1-5所示:
例1-5 Employee.java
public class Employee { private String name; private double salary; private Address address; 此处省略Employee类的成员变量的get/set方法 @Override public String toString() { return "Employee [name=" + name + ", salary=" + salary + ", address=" + address + "]"; } } |
(3)在Example6下的WebRoot目录下新建一个目录el,然后在该目录下新建一个el.jsp文件,主要代码如例1-6所示:
例1-6 el.jsp
<%@ page import="cn.itcast.domain.*" %><!—由于在跟页面中需要使用Address,Employee类,所以这里需要将它们导入--> <body> <% Address address = new Address(); address.setCity("北京"); address.setStreet("西三旗"); Employee emp = new Employee(); emp.setName("李小四"); emp.setSalary(123456); emp.setAddress(address); request.setAttribute("emp", emp); %> <h3>使用el获取request域的emp</h3> ${requestScope.emp }<br/> </body> |
例1-6中,创建了Address和Employee的对象,并将属性赋值,其中address对象是emp对象的一个属性,然后将emp对象保存在request域中,再使用el表达式获取emp对象。
(4)重新启动服务器,在浏览器端访问el.jsp页面,浏览器显示结果如图1-8所示:
图1-8 浏览器显示结果
现在想获取该emp对象的address属性的street属性,el表达式该如何写?
(5)对el.jsp页面稍作修改,如例1-7所示:
... ... <h3>使用el获取request域的emp对象的address属性的street属性</h3> ${requestScope.emp.address.street} ... ... |
(6)再次访问el.jsp页面,浏览器显示结果如图1-9所示:
图1-9 浏览器显示结果
由图1-9可知,使用例1-7所示的el表达式成功的获取到street属性的值,例1-7中的el表达式就是javaBean导航,其底层代码如下:
Employee _emp=(Employee)request.getAttribute("emp");
String street=_emp.getAddress().getStreet();
因此我们在前面特意强调,如果域中存放的是javaBean对象,javaBean一定要为每个属性提供get方法,因为在使用el表达式获取javaBen属性时,底层就是调用属性的get方法。
(7)在Employee类中添加一个get方法,如例1-8所示:
例1-8 getHehe()方法
此处省略例1-5中的代码 public String getHehe() { return "我去..."; } |
(8)在el.jsp页面中使用el表达式输出该方法的返回值,如例1-9所示:
此处省略例1-6中的代码 ${emp.hehe } |
(9)重新启动服务器,访问index.jsp页面,浏览器显示结果如图1-10所示:
图1-10 浏览器显示结果
由图1-10可知,Employee类中虽然没有名称为”hehe”的成员变量,但是提供了get方法,因此hehe就是Employee的属性,那么在jsp页面中就能通过el表达式${emp.hehe}输出该方法的返回值,进一步说明该el表达式底层就是调用javaBean的get方法。
3.EL表达式运算符
l 点运算符。就是调用对象的getter方法,没有定义getter方法就不能用。
l 中括号运算符。[]就是调用对象的getter方法
${p.name}=${p['name']}=${p["name"]}
获取List和Map中的值。
EL是表达式语言,它可以进行一些运算,可使用的运算符如表1-1所示:
表1-1 EL表达式运算符
运算符 |
说明 |
范例 |
结果 |
+ |
加 |
${17+5} |
22 |
- |
减 |
${17-5} |
12 |
* |
乘 |
${17*5} |
85 |
/或div |
除 |
${17/5}或${17 div 5} |
3 |
%或mod |
取余 |
${17%5}或${17 mod 5} |
2 |
==或eq |
等于 |
${5==5}或${5 eq 5} |
true |
!=或ne |
不等于 |
${5!=5}或${5 ne 5} |
false |
<或lt |
小于 |
${3<5}或${3 lt 5} |
true |
>或gt |
大于 |
${3>5}或${3 gt 5} |
false |
<=或le |
小于等于 |
${3<=5}或${3 le 5} |
true |
>=或ge |
大于等于 |
${3>=5}或${3 ge 5} |
false |
&&或and |
并且 |
${true&&false}或${true and false} |
false |
!或not |
非 |
${!true}或${not true} |
false |
||或or |
或者 |
${true||false}或${true or false} |
true |
empty |
是否为空 |
${empty “”},可以判断字符串、数据、集合的长度是否为0,为0返回true。empty还可以与not或!一起使用。${not empty “”},null也为true |
true |
三元运算符如:${user!=null?user.name:””}
EL表达式不支持用+进行字符串连接。
EL表达式的11个内置对象
我们知道jsp有九个内置对象,而EL表达式有11个对象,这些内置对象无需创建可直接使用。今天我们就来学习EL表达式的11个内置对象。11个内置对象如下所示:
EL隐式对象 |
类型 |
对应的JSP隐式对象 |
备注 |
pageContext |
javax.servlet.jsp.PageContext |
pageContext |
一样 |
pageScope |
java.util.Map |
没有 |
表示页面范围数据 |
requestScope |
java.util.Map |
没有 |
表示请求范围数据 |
sessionScope |
java.util.Map |
没有 |
表示会话范围数据 |
applicationScope |
java.util.Map |
没有 |
表示应用范围数据 |
param |
java.util.Map |
没有 |
单个请求参数。key是名称,value是值 |
paramValues |
java.util.Map |
没有 |
重名请求参数。key是名称,value是String[] |
header |
java.util.Map |
没有 |
单个请求消息头。key是头名,value是头值 |
headerValues |
java.util.Map |
没有 |
重名请求消息头。key是头名,value是String[] |
initParam |
java.util.Map |
没有 |
web.xml中配置的全局参数 |
cookie |
java.util.Map |
没有 |
代表是一个Map。key是cookie对象的name,value是cookie对象 |
其中,pageScope,requestScope,sessionScope,applicationScope是域相关的内置对象,这里我们就不再多说。这11个内置对象中,有10个内置对象的类型是Map类型,只有pageContext的类型不是Map类型,它的类型是PageContext。
1.请求参数相关内置对象
请求参数相关的内置对象是:
param:
该内置对象的类型是Map<String,String>
可以用来获取值为单值的请求参数
使用param获取请求参数与request.getParameter()方法一样。
例如:
${param.age}
//打印发送到本页请求中请求参数中name=”age”的value值。
paramValues:
该内置对象的类型是Map<String,String[]>,可以用来获取值为多值的请求参数,其中key是参数名,value是多个参数值组成的字符串数组。
注意,在使用EL获取参数时,如果参数不存在,返回的是空字符串,而不是null。这一点与使用request.getParameter()方法是不同的。
实例:
(1)创建一个web工程,Example7,在该应用的WebRoot目录下新建一个目录:params,然后在该目录下新建一个params.jsp页面,主要代码如例1-1所示:
例1-1 params.jsp
<body> <%-- map.key这是el的语法! map['key']也可以操作map --%> ${param.username }<br/> </body> |
EL表达式操作map的语法是${map.key},或${map['key’]}。
(2)将Example7发布到服务器,然后启动服务器,在浏览器端访问:http://localhost:8080/Example7/params/params.jsp?username=zhangsan,浏览器显示结果如图1-1所示:
图1-1 浏览器显示结果
由图1-1可知,使用${param.username}成功的将请求参数的值获取到了。
(3)如果在浏览器端访问时发送了一个多值的请求参数给服务器,在params.jsp页面中使用paramValues内置对象获取,params.jsp页面内容如例1-2所示:
<body> ${param.username }<br/> ${paramValues.hobby }<br/> </body> |
(4)在浏览器端访问:http://localhost:8080/Example7/params/params.jsp?username=zhangsan& hobby=sw& hobby=sj,浏览器显示结果如图1-2所示:
图1-2 浏览器显示结果
现在如果希望将数组中的元素使用el表达式输出在浏览器端,el表达式的格式为:${map.key[索引值]}。
(5)修改params.jsp页面,如例1-3所示:
<body> ${param.username }<br/> ${paramValues.hobby[0] }<br/> ${paramValues.hobby[1] }<br/> </body> |
(6)再次访问params.jsp,访问路径为:http://localhost:8080/Example7/params/params.jsp?username=
zhangsan& hobby=sw& hobby=sj,浏览器显示的结果如图1-3所示:
图1-3 浏览器显示结果
2.请求头相关内置对象
与请求头相关的内置对象是:
header:
l 该内置对象的类型是Map<String,String>,用来获取值为单值的请求头信息,其中key代表的是请求头名称,value代表的是请求头的值;
headerValues:
l 该内置对象的类型是Map<String,String[]>,用来获取值为多值的请求头信息,key代表的是请求头名称,value代表的是请求头的多个值。
下面通过一个小例子来学习如何使用这两个内置对象获取请求头信息,如下所示:
(1)在Example7的WebRoot目录下新建一个目录header,然后再该目录下新建一个header.jsp页面,主要代码如例1-4所示:
例1-4 header.jsp
<body> ${header['User-Agent']} </body> |
例1-4中,请求头:User-Agent的名字中有一个特殊字符“-“,因此我们获取这个请求头的值时,el表达式需要写成“${map['key’]}”。
(2)在浏览器端访问:http://localhost:8080/Example7/header/header.jsp,浏览器端显示结果如图1-4所示:
图1-4 浏览器显示结果
由图1-4可知,使用${header['User-Agent']}成功的获取到请求头的值。至于headerValues内置对象这里就不再演示,因为在以后的开发中很少在页面中使用el表达式获取请求头的信息。
3.初始化参数相关内置对象
我们再学习Servlet时,讲过在web.xml文件中配置全局初始化参数,并且全局初始化参数可以使用ServletContext对象获取,现在在EL表达式中内置了一个与初始化参数相关的对象:
initParam:
l 该内置对象的类型是Map<String,String>,用来获取web.xml文件中<context-param>标签的参数值,其中key代表的是参数名,value代表的是参数值。
下面通过一个小例子来学习如何使用initParam内置对象获取全局初始化参数,如下所示:
(1)对Example7应用下的web.xml文件进行编辑,添加全局初始化参数,主要如例1-5所示:
例1-5 web.xml
<context-param> <param-name>name</param-name> <param-value>itcast</param-value> </context-param> <context-param> <param-name>address</param-name> <param-value>beijing</param-value> </context-param> |
(2)在Example7的WebRoot目录下新建一个目录initParam,然后再该目录下新建一个initParam.jsp页面,页面的主要代码如例1-6所示:
例1-6 initParam.jsp
<body> ${initParam.name } ${initParam.address } </body> |
(3)在浏览器端访问:http://localhost:8080/Example7/initParam/initParam.jsp,浏览器显示结果如图1-5所示:
图1-5 浏览器显示结果
4.Cookie相关内置对象
EL表达式也内置一个名为cookie的对象,该内置对象与cookie相关,如下:
cookie:
该内置对象的类型为Map<String,Cookie>,其中key是Cookie的名字value是Cookie对象本身。
下面我们就来通过一个小例子来学习如何使用cookie内置对象获取cookie相关信息,如下所示:
(1)在Example7的WebRoot目录下新建一个cookie目录,然后在该目录下新建一个cookie.jsp页面,主要代码如例1-6所示:
例1-6 cookie.jsp
<body> <h1> 名字为JSESSIONID的cookie的值: ${cookie.JSESSIONID.value } </h1> </body> |
例1-6中,因为cookie内置对象的key值是cookie的名称,所以${cookie.JSESSIONID}获取的是名为JSESSIONID的Cookie对象,而Cookie类有getValue()方法,所以${cookie.JSESSIONID.value}就是获取Cookie的值。当然如果想要获取cookie的name值,el表达式为${cookie.JSESSIONID.name}。
(2)在浏览器端访问:http://localhost:8080/Example7/cookie/cookie.jsp,浏览器显示结果如图1-6所示:
图1-6 浏览器显示结果
将例1-6中的el表达式修改为“${cookie.JSESSIONID}”,再访问cookie.jsp,浏览器显示结果如图1-7所示:
图1-7 浏览器显示结果
由图1-7可知,${cookie.JSESSIONID}获取的是名字为JSESSIONID的cookie对象。
5.pageContext内置对象
在文档的开头我们就说过,EL表达式的11个内置对象中,有10个内置对象的类型是Map类型,只有pageContext的类型是PageContext。下面我们就来学习如何使用这个内置对象,如下所示:
(1)在Example7的WebRoot目录下新建一个pageContext目录,然后在该目录下新建一个pageContext.jsp页面,主要内容如例1-7所示:
例1-7 pageContext.jsp
<body> ${pageContext.request} </body> |
(2)在浏览器端访问:http://localhost:8080/Example7/pageContext/pageContext.jsp,浏览器显示结果如图1-8所示:
图1-8 浏览器显示结果
图1-8中输出的正是request对象,我们知道pageContext内置对象的类型是PageContext,而该类有一个方法:getRequest(),该方法的返回值就是一个ServletRequest类型的对象。因此${pageContext.request}输出的就是一个request对象。
(3)将例1-7中的el表达式进行修改,该成“${pageContext.request.contextPath}“,然后再访问pageContext.jsp页面,浏览器端显示结果如图1-9所示:”
图1-9 浏览器显示结果
图1-9中,浏览器端显示的是当前应用的名称,我们在学习request对象时讲过:调用request的getContextPath()方法可以获得当前应用的名称,而el表达式底层就是调用get方法,所以${pageContext.request.contextPath}输出的是当前工程的名字。
我们在表单或超链接中写的访问路径之前都是:/工程名/资源路径,为了以后开发的维护方便,我们以后在表单或超链接中写的路径不要直接写工程名,用${pageContext.request.contextPath}代替,如例1-8所示:
<body> ${pageContext.request.contextPath } <hr/> <a href="${pageContext.request.contextPath }/header/header.jsp">点击这里</a> <form action="${pageContext.request.contextPath }/cookie/cookie.jsp" method="post"> <input type="submit" value="xxx"/> </form> <hr/> </body> |
浏览器访问结果如图1-10所示:
图1-10 浏览器显示结果
当然,使用pageContext内置对象还可以获取session对象的id值,如:${pageContext.session.id}。pageContext对象可以获取jsp的其他内置对象,所以通过pageContext对象可以获取其他内置对象的任意的属性值。
EL函数库
1.什么是EL函数库
EL函数库是由第三方对EL的扩展,我们现在学习的EL函数库是有JSTL提供的,JSTL我们会在后面的课程中详解。EL函数库就是定义了一些有返回值的静态方法,然后通过EL表达式来调用它们,不仅仅JSTL可以定义EL函数库,我们自己也可以自定义EL函数库,这个后面我们也会讲到。
在jsp页面中使用taglib指令导入EL函数库,就可以在页面中使用函数库中的方法。另外,导入的函数库可以使用的前提是,我们的项目中有相关的jar包,我们自己并没有将jar包拷贝的lib目录下,但是当我们的项目发布到服务器下,lib目录中就有了jar包,如图1-1所示:
图1-1 lib目录
2.使用EL函数库
要使用EL函数库,首先要在jsp文件的上面使用taglib指令导入函数库:
l <%@ taglib prefix=”fn” uri=”http://java.sun.com/jsp/jstl/functions”%>
其中,uri的值并不是一个网络路径,只是在定义函数库时,拟定的一个位置。
下面我们来了解EL函数库中的相关方法,具体如下:
l String toUpperCase(String input):把字符串参数转换成大写,并返回;
l String toLowerCase(String input):把字符串参数转换成小写,并返回;
l int indexOf(String input, String substring):返回input中substring出现的索引位置;
l boolean contains(String input, String substring):查看input中是否包含substring,包含返回true,否则返回false;
l boolean containsIgnoreCase(String input, String substring):在忽略大小写的情况下,查看input中是否包含substring,包含返回true,否则返回false;
l boolean startsWith(String input, String substring):判断input是否是以substring为前缀,如果是就返回true,否则就返回false;
l boolean endsWith(String input, String substring):判断input是否是以substring为后缀,如果是就返回true,否则就返回false;
l String substring(String input, int beginIndex, int endIndex):以beginIndex为开始值,endIndex为结束值,在input上截取子串;
l String substringAfter(String input, String substring):获取input中,substring所在位置后面的字符串;
l substringBefore(String input, String substring):获取input中,substring所在位置前面的字符串;
l String escapeXml(String input):把input中“<”、“>“、”&“、”'“、“"”进行转义;
l String trim(String input):去除input中的前后空格;
l String replace(String input, String substringBefore, String substringAfter):将input中的substringBefore替换成substringAfter;
l String[] split(String input, String delimiters):以delimiters为标识分割input,返回一个字符串数组;
l int length(Object obj):可以获取字符串、数组、各种集合的长度!
l String join(String array[], String separator):将array数组中的元素以separator连接起来,返回一个字符串。
EL函数库的使用实例
通过以上对EL函数库中的方法的讲解,下面通过一个案例来学习这些方法的使用,如下:
(1)创建一个web应用,Example8,在该应的WebRoot目录下新建一个fn目录,然后在该目录下新建一个fn.jsp文件,主要代码如例1-1所示:
例1-1 fn.jsp
<!-- 导入函数库 --> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.util.*"%> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> ... ... <body> <% String[] strs = {"a", "b","c"};//定义一个字符数组 List list = new ArrayList();//定义一个list集合 list.add("a");//向集合中添加一个字符 pageContext.setAttribute("arr", strs);//将字符数据以arr的名字保存在page域中 pageContext.setAttribute("list", list);//将list集合以list的名字保存在page域中 %> ${fn:length(arr) }<br/><!--返回arr的长度--> ${fn:length(list) }<br/><!--返回list的长度--> ${fn:toLowerCase("Hello") }<br/> <!-- 将Hello变成小写 --> ${fn:toUpperCase("Hello") }<br/> <!-- 将Hello变成大写 --> ${fn:contains("abc", "a")}<br/><!-- 判断abc中是否包含a --> ${fn:containsIgnoreCase("abc", "Ab")}<br/><!-- 在忽略大小写的情况下,判断abc中是否包含Ab --> ${fn:contains(arr, "a")}<br/><!-- 判断arr数组中是否包含a --> ${fn:containsIgnoreCase(list, "A")}<br/><!-- 在忽略大小写的情况下,判断list集合中是否包含A --> ${fn:endsWith("Hello.java", ".java")}<br/><!-- 判断Hello.java是否以.java结束 --> ${fn:startsWith("Hello.java", "Hell")}<br/><!-- 判断Hello.java是否以Hell开始 --> ${fn:indexOf("Hello-World", "-")}<br/><!-- 返回“-”在Hello-World中出现的位置 --> ${fn:join(arr, ";")}<br/><!-- 将arr数组中的元素以“-”连接,并返回 --> ${fn:replace("Hello-World", "-", "+")}<br/><!-- 将Hello-World中的“-”替换成“+” --> ${fn:join(fn:split("a;b;c;", ";"), "-")}<br/><!--最终是将数组的元素以“-”连接,并返回 --> ${fn:substring("0123456789", 6, 9)}<br/><!-- 返回0123456789中索引值为6到索引值为9之间的元素 --> ${fn:substring("0123456789", 5, -1)}<br/><!-- 返回0123456789中索引值为6到结束的元素 --> ${fn:substringAfter("Hello-World", "-")}<br/><!-- 返回Hello-World中“-”后面的字符串 --> ${fn:substringBefore("Hello-World", "-")}<br/><!-- 返回Hello-World中“-”前面的字符串 --> ${fn:trim(" a b c ")}<br/><!-- 去掉 a b c 前后的空格 --> ${fn:escapeXml("<html></html>")}<br/> <!-- 将“<html></html>”中的“<”,“>”转义,即原样输出 --> </body> |
(2)将Example8发布到服务器,然后启动服务器,在浏览器端访问fn.jsp,浏览器显示结果如图1-2所示:
图1-2 浏览器显示结果
例1-1中,在使用函数库中的方法之前,分别定义了一个字符串数组str和一个list集合,然后将这两个变量存放在page域中,这样做的原因是,函数库中的这些方法的参数如果是变量,那么必须将变量放在域中,否则EL表达式就获取不到这些变量,例如将例1-1中的存放数据到域中的代码注释掉,再次方法fn.jsp,浏览器运行结果如图1-3所示:
图1-3 浏览器显示结果
自定义EL函数库
在EL函数库中,我们学习的那些方法都是由JSTL提供的,我们自己也可以定义函数库。自定义EL函数库有以下三个步骤:
l 写一个public类,在该类中定义一个有返回值的静态方法;
l 编写tld(Tag Library Definition)的xml文件;
l 在页面中添加taglib指令,导入自定义标签库。
下面根据以上步骤,我们来完成自定义EL函数库,点击此处下载案例源代码,具体如下所示:
(1)新建一个web应用Example9,在src目录下新建一个类,MyFunciton,主要代码如例1-1所示:
例1-1 MyFunction.java
package cn.itcast.fn; public class MyFunction { public static String print(){ return "创智播客之EL函数库"; } } |
例1-1中,MyFunction中的print()方法必须是静态的,有返回值的。
(2)因为tld文件我们不希望别人能够直接访问,因此我们将tld文件放在WEB-INF目录下。在该目录下创建一个目录tlds,然后将itcast.tld文件放在tlds目录中,文件内容如例1-2所示:
例1-2 itcast.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>itcast</description> <display-name>itcast-function</display-name> <tlib-version>1.0</tlib-version> <short-name>it</short-name> <uri>http://www.itcast.cn/el/functions</uri> <function> <name>print</name> <function-class>cn.itcast.fn.MyFunction</function-class> <function-signature>java.lang.String print()</function-signature> </function> </taglib> |
例1-2中,文件的头与约束都是从jstl函数库中的fn.tld文件中拷贝过来的,下面对文件中的比较重要的标签进行解析,如下所示:
l <tlib-version>:当前函数库的版本号;
l <short-name>:函数库的前缀,例如fn;
l <uri>:把tld文件绑定到一个名称空间上,没有实际意义,一般写的像网址;
l <function>:定义函数的一个标签;
l <name>:指明函数的名称;
l <function-class>:指明函数所在的类的名称,要全类名;
l <function-signature>:指明函数的名字及返回值类型,如果有参数,也包括参数类型,要全类型基本数据类型不用,如int,boolean如:<function-signature>boolean contains(java.lang.String, java.lang.String)</function-signature>。
另外在tld文件中,还存在一个标签,如下:
<function> <description> Tests if an input string contains the specied substring. </description> <name>contains</name> <function-class>org.apache.taglibs.standard.functions.Functions</function-class> <function-signature>boolean contains(java.lang.String, java.lang.String)</function-signature> <example> <c:if test="${fn:contains(name, searchString)}"> </example> </function> |
其中<example>标签表示的是该函数在jsp页面中的示范。
(3)在Example9的WebRoot目录下新建一个fn目录,然后在该目录下新建一个fn.jsp页面,主要代码如例1-3所示:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="it" uri="/WEB-INF/tlds/itcast.tld" %><!--导入标签--> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>${it:print() }</h1><!--实际应用-->d </body> </html> |
例1-3中,taglib指令中的uri属性的值为“/WEB-INF/tlds/itcast.tld”,该值正是itcast.tld文件的位置。
(4)将Example9发布到服务器,然后启动服务器,在浏览器端访问:http://localhost:8080/Example9/fn/fn.jsp,浏览器显示的结果如图1-1所示:
图1-1 浏览器显示结果