对于JSP中一些简单的属性、请求参数、标头与Cookie等信息的取得,一些简单的运算或判断,可以使用表达式语言来处理,还可以将一些常用的功用函数编写为EL函数,这样可以减少网页上一部分的Scriptlet。
例如,对于以下的Scriptlet:
<%
String a = request.getParameter("a");
String b = request.getParameter("b");
out.println("a + b = " + (Integer.parseInt(a) + Integer.parseInt(b)));
%>
如果使用EL,则可以只用一行程序代码来改写,甚至加强这段Scriptlet。例如:
<body>
${param.a} + ${param.b} = ${param.a + param.b}
</body>
EL使用${
和}
来包括要进行处理的表达式。可使用点运算符(.)指定要访问的属性,使用加号(+)运算符进行加法运算。param是EL的隐含对象之一,表示用户的请求参数,param.a表示取得用户所发出的请求参数a的值,所输入的请求参数自动转换为基本类型并进行运算。
在参数为null时,EL直接以空字符串表示,不会直接显示null值,在进行运算是时,也不会因此发生错误而抛出异常。
EL的点运算符可以连续访问对象,就如同在Java程序代码中一样。例如,原来需要这样写:
<%= ((HttpServletRequest)pageContext.getRequest()).getMethod() %>
<%= ((HttpServletRequest)pageContext.getRequest()).getQueryString() %>
<%= ((HttpServletRequest)pageContext.getRequest()).getRemoteAddr() %>
使用EL,则可以这样编写:
<b>${pageContext.request.method}</b><br />
<b>${pageContext.request.queryString}</b><br />
<b>${pageContext.request.remoteAddr}</b><br />
pageContext也是EL的隐含对象之一。通过点运算符之后街上xxx名称,表示嗲用调用getXxx()方法。如果必须转换类型,EL也会自行处理。
可以使用page指示元素的isELIgnored属性(默认为true),来设置JSP网页是否使用EL。会这样做的原因可能在于,网页中已含有与EL类似的${}
语法功能。例如,使用了某个模板(Template)框架之类。
也可以在web.xml中设置<el-ignored>
标签为true,来决定不使用EL。例如:
<web-app ...>
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<el-ignored>true</el-ignored>
</jsp-property-group>
</jsp-config>
</web-app>
以上标签用来设置符合<url-pattern>
的JSP网页是否使用EL。如果JSP网页使用page命令元素的isElIgnored来设置是否支持EL,则以page命令元素的设置为主。
在EL中,可以使用EL隐含对象指定范围来访问属性。如果不指定属性的存在范围,则默认是以page、request、session、application的顺序来寻找EL中所指定的属性。
如果EL所访问的对象是一个数组对象或者List类型对象,则可以使用[]
运算符来指定索引以访问数组中的元素。
使用点运算符与[]
运算符的总结:
[]
运算符,则左边可以是JavaBean、Map、数组或List对象。当左边是Map对象时,建议使用[]
运算符,因为设置Map时键(key)名称可能有空白或点字符。
在EL中提供了11个隐含对象,其中除了pageContext银行对象对应pageContext之外,其他隐含对象都对应Map类型。
对应于PageContext类型,PageContext本身就是一个JavaBean,只要是getXxx()
方法,就可以用${pageContext.Xxx}
来取得。
与属性范围相关的隐含对象由pageScope、requestScope、sessionScope与applicationScope,分别可以取得使用JSP隐含对象pageContext、request、session与application的setAttribute()方法所设置的属性对象。如果不使用EL隐含对象指定作用范围,则默认从pageScope的属性开始查找。
EL隐含对象pageScope、requestScope、sessionScope与applicationScope不等同于JSP隐含对象pageContext、request、session与application。EL隐含对象仅仅代表作用范围。
与请求参数相关的EL隐含对象由param与paramValues。对应request的getParameter()和getParameterValues()方法。
如果要取得用户请求的标头数据,则可以使用header或headrValues隐含对象。对应request的getHeader()和getHeaders()方法。
cookie隐含对象可以用来取得用户的Cookie设置值。如果在Cookie中设置了username属性,则可以使用${cookie.username}
来取得值。
initParam可以用来取得web.xml中设置的ServletContext初始参数,也就是在<context-param>
中设置的初始参数。
+ - * (/或div) (%或mod) ?:
and or not
< 或 lt
<= 或le
> 或 gt
>=或 ge
== 或 eq
EL运算符的优先级与Java运算符对应
自定义函数的第一步是编写类,它必须是一个公开类,而想要调用的方法也必须是公开的且为静态方法。例如:
public class Infix {
public static double eval(String infix) {
double result = 0;
//other process
return result;
}
}
web容器必须知道如何将这个类的eval()方法当做EL函数来使用,所以必须编写一个标签链接库描述文件(Tag Library Descriptor, TLD)文件,这个文件是个XML文件,扩展名为*.tld
。
infix.tld:
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 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/j2eeweb-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>infix</short-name>
<uri>http://club.chuxing/infix</uri> <!-- 设置URI对应名称 -->
<function>
<description>Eval Infix</description>
<name>eval</name> <!-- 自定义的EL函数名称 -->
<function-class>
cc.openhome.InFix <!-- 对应到哪个类 -->
</function-class>
<function-signature>
double eval(java.lang.String) <!-- 对应到该类的哪个方法 -->
</function-signature>
</function>
</taglib>
在${infix:eval(...)}
中,eval名称就对应于<name>
标签的设置,而实际上eval名称背后执行的类与真正的静态方法,分别是由<function-class>
和<functio-signature>
设置的。
可以将这个TLD文件直接放在WEB-INF文件夹下,容器会自动找到TLD文件并将其加载。现在可以编写一个JSP来使用这个自定义的EL函数,例如:
express.jsp:
<%@ page language="java" contentType="text/html; utf-8" pageEncoding="utf-8"%>
<%@taglib uri="http://club.chuxing/infix" prefix="infix" %> <!-- 使用taglib元素 -->
<!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>自定义EL函数</title>
</head>
<body>
${param.expression} = ${infix:eval(param.expression}} <!-- 使用自定义EL -->
</body>
</html>
taglib指示元素告诉容器在转译JSP时,会用到对应uri属性的自定义函数,prefix则用来设置前置名称。当JSP中有来自多个不同设计者的EL自定义函数时,就可以避免名称冲突问题。