JSP的产生在一定程度上将Servlet中负责表现的功能抽取了出来,但JSP页内嵌入的Java代码也破坏了页面中负责表现的页面结构,特别是当运算逻辑稍微复杂一点的话,那么JSP页面中大量的Java代码增加了页面维护的难度。所以使用简单的标签来表现复杂的逻辑以及使用简单的形式表现运算的关系就是EL表达式和JSP标签出现的原因。
一套简单的运算规则,用于给JSTL标签的属性赋值,也可以直接用来输出而脱离标签单独使用。
EL(Expression Language)是从 JavaScript 脚本语言得到启发的一种表达式语言,它借鉴了 JavaScript 多类型转换无关性的特点。在使用 EL 从 scope 中得到参数时可以自动转换类型,因此对于类型的限制更加宽松。 Web 服务器对于 request 请求参数通常会以 String 类型来发送,在得到时使用的 Java 语言脚本就应该是request.getParameter(“XXX”) ,这样的话,对于实际应用还必须进行强制类型转换。而 EL 就将用户从这种类型转换的繁琐工作脱离出来,允许用户直接使用EL 表达式取得的值,而不用关心它是什么类型。
在JSP页面中经常要输出系统定义的对象的属性,而按照以往的写法需要自己去对象域中获取、转换再输出,使用EL表达式可以非常明显的简化过程。
Bean:指的是一个公共的类,按照固定的方式提供属性的get/set访问方式。针对这种特殊类型的属性访问使用EL表达式实现有两种方式,如下。
${user.name}
执行的过程为:从pageContext、request、session、application中依次查找绑定名为“user”的对象,找到后调用“getName”方法,将返回值输出。
假定在session中绑定了一个对象,如下:
User obj = new User(1,“胡萝卜”); session.setAttribute(“user”,obj);
那么${user.name}等价于下面代码:
<% User u = (User)session.getAttribute(“user”); out.print(u.getName(); %>
这种繁琐的取值,转换,输出的过程就都由系统代劳了。而且表达式比以上繁琐代码更会处理null。如果没有为name属性赋过值,页面输出“”,不会输出null。如果取值时绑定名写错,如${obj.name},页面也会输出“”,而不是报空指针异常。但属性名写错会报错,如${user.naaa}.
表达式也支持属性名的动态读取,这时需要采用方式二${user[“name”]}的形式。
假定在Servlet中有如下代码:
User obj = new User(1,”胡萝卜”); session.setAttribute(“user”,obj); session.setAttribute(“pName”,”id”);
在JSP中编写如下代码会输出“1”:
${sessionScope.user[“id“]}
在JSP中编写如下代码也会输出“1”:
${sessionScope.user[sessionScope.pName]}
如果pName在绑定时不指定id,而是name,那么这个表达式就会输出“胡萝卜“,所以这种写法可以认为是表达式中有一个变量。sessionScope.pName 等价于 session.getAttribute(“pName”)。
如果User类型的定义如下:
package bean; public class User { private String name; private int age; private String[] interests; private String gender; public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String[] getInterests() { return interests; } public void setInterests(String[] interests) { this.interests = interests; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
那么对于interests这个数组属性的值可以使用如下表达式访问:
${user.interests[0]}
在书写表达式时,如果没有指定搜索范围,那么系统会依次调用pageContext、request、session、application的getAttribute()方法。这样不限定查找范围的代码不利于排错,所以这种取值的操作可以限定对象的查找范围。如:
${sessionScope.user.name}
一旦指定了对象所在的范围,那么只会在范围内查找绑定对象,不会在找不到的时候再去其他区域中查找了。
sessionScope的位置还可以填写pageScope、requestScope、applicationScope。
使用EL表达式可以单独进行运算得出结果并直接输出,如下代码所示,EL进行算术运算,逻辑运算,关系运算,及empty运算。
empty 空运算主要用于判断字符串,集合是否为空,是空或为null及找不到值时都会输出true。
<%request.getSession().setAttribute("sampleValue", new Integer(10));%> ${sessionScope.sampleValue} // 显示 10 ${sessionScope.sampleValue + 12} <br> // 显示22 ${(sessionScope.sampleValue + 12)/3} <br> // 显示7.3 ${(sessionScope.sampleValue + 12) /3==4} <br> // 显示 false ${(sessionScope.sampleValue + 12) /3>=5} <br> // 显示 true <input type="text" name="sample1" value="${sessionScope.sampleValue + 10}"> // 显示值为20的 Text 控件 ${empty null} //显示true
在地址栏中输入http://localhost:8080/day09/el03.jsp?username=Luffy&city=Beijing后,
以下两种写法分别等价:
${param.username} 与 request.getParameter(“username”); ${paramValues.city} 与request.getParameterValues("city");
如果参数是数组形式,如‘city=bj&city=sh’,则可通过 `${paramValues.city[0]}`的方式获取数组中指定下标的元素。
Sun 公司 Java 标准规范的 JSTL 由 apache组织负责维护。作为开源的标准技术,它一直在不断地完善。 JSTL 的发布包有两个版本: Standard-1.0 Taglib 、 Standard-1.1 Taglib ,它们在使用时是不同的。
Standard-1.0 Taglib ( JSTL1.0 )支持 Servlet2.3 和 JSP1.2 规范, Web 应用服务器 Tomcat4 支持这些规范,而它的发布也在 Tomcat 4.1.24 测试通过了。
Standard-1.1 Taglib ( JSTL1.1 )支持 Servlet2.4 和 JSP2.0 规范, Web 应用服务器 Tomcat5 支持这些规范,它的发布在 Tomcat 5.0.3 测试通过了。
将标签库对应的jar包拷贝到WEB-INF/lib目录下,以便于系统可以加载所需要的类。使用taglib指令在页面上引入标签的命名空间和前缀,帮助系统定位对应的类。
如:
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
使用if标签实现属性判断后的输出。代码如下所示:
<% User user = new User(); user.setName("胡萝卜"); user.setGender("f"); request.setAttribute("user",user); %> 姓名:${user.name}<br/> 性别: <c:if test="${user.gender =='m'}" var="rs" scope="request">男</c:if> <c:if test="${!rs}">女</c:if>
使用choose标签简化多个if标签的判断。代码如下所示:
<% User user = new User(); user.setName("胡萝卜"); user.setGender("x"); request.setAttribute("user",user); %> 性别: <c:choose> <c:when test="${user.gender == 'm'}">男</c:when> <c:when test="${user.gender =='f'}">女</c:when> <c:otherwise>未知</c:otherwise> </c:choose>
使用forEach标签完成对集合的遍历输出。
其中items属性为要遍历的集合,var属性为每次取出来的一个对象,varStatus指定当前迭代的状态。代码如下:
输出varStatus中的index和count的值。index代表对象在集合中的下标,count代表访问过的对象的个数。(参见CASE07)
<table> <tr> <td>序号</td> <td>姓名</td> <td>年龄</td> </tr> <c:forEach items="${users}" var="u" varStatus="s"> <tr> <td>${s.count}</td> <td>${u.name}</td> <td>${u.age}</td> </tr> </c:forEach> </table>
编写一个继承自SimpleTagSupport的Java类:
import javax.servlet.jsp.tagext.SimpleTagSupport; public class HelloTag extends SimpleTagSupport{ }
重写该类的doTag方法,在其中添加处理逻辑:
import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.SimpleTagSupport; public class HelloTag extends SimpleTagSupport{ private String info; private int qty; public void setInfo(String info) { this.info = info; } public void setQty(int qty) { this.qty = qty; } @Override public void doTag() throws JspException, IOException { PageContext ctx =(PageContext)getJspContext(); JspWriter out = ctx.getOut(); for(int i=0;i< qty;i++){ out.println(info+"<br/>"); } } }
在WEB-INF下面新建一个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"> <tlib-version>1.1</tlib-version> <short-name>c1</short-name> <uri>http://www.tarena.com.cn/mytag</uri> <tag> <name>hello</name> <tag-class>tag.HelloTag</tag-class> <body-content>empty</body-content> <attribute> <name>info</name> <required>true</required> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <name>qty</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
标签在页面中被引用时的代码如下:
<%@taglib uri="http://www.tarena.com.cn/mytag" prefix="c1" % //… … <c1:hello info="hello kitty" qty="${1+5}"/>
容器依据JSP页面中的uri找到tld文件(依据标签中的<c1:hello>hello这个名字找到标签类tag.HelloTag。接下来实例化该标签,同时属性值赋给参数,调用doTag方法。