首页 > 代码库 > JTSL/EL Expression学习
JTSL/EL Expression学习
最早的一个学习笔记,时间过去了久了,供java web初学者参考。
JTSL/EL Expression学习安排
学习目标:掌握几个常见标签的使用,通晓工作原理,详细到代码层面,遇到问题时能查得出异常,能排除异常。
学习时间:2天
a) 掌握逻辑判断标签<c:if>,<c:choose>,<c:when>,<c:otherwise>
b) 掌握EL表达式页面隐式对象:requestScope,sessionScope,pageScope,pageContext,applicationScope,param等几个常见对象在不同场景下的使用,
了解paramValues,header,headerValues,cookie,initParam的用法
c) 掌握几个程序流控制标签<:catch><c:redirect>
d) 掌握<c:out>输出标签,<c:set>,<c:remove>等多用途标签
e) 掌握标签中几个常用的函数fn:contains,fn:containsIgnoreCase,fn:indexOf, fn:length,fn:substring,fn:trim
f) 掌握迭代标签的使用c:forEach,c:forTokens
g) 掌握时间格式化函数fmt:parseDate,fmt:formatDate
| Jsp版本 | Servlet版本 | JSTL标签库 | EL表达式 | JAVA版本 |
Tomcat3.3.2 | 1.1 | 2.2 |
|
|
|
Tomcat4.1.39 | 1.2 | 2.3 | Standard-1.0 | 已经出现,作为JSTL的一部分,必须依赖于JSTL | 1.2 |
| 1.3 |
| Standard-1.0.6 | 支持EL |
|
Tomcat5.5.27 | 2.0 | 2.4 | Standard-1.1 | 可独立使用 | 1.4 |
Tomcat6.0.18 | 2.1 | 2.5 | Standard-1.2 | 可独立使用 | 5 |
标签库的下载
Standard Taglib
JSP(tm) Standard Tag Library implementations
Apache hosts the Apache Standard Taglib, an implementation of the JSP Standard Tag Library (JSTL) specification. Various versions are available.
Version | JSTL version | Requirements | Getting the Taglib |
Standard 1.2 | JSTL 1.2 (not yet JCP approved) | Servlet 2.5, JavaServer Pages 2.1 | svn |
Standard 1.1 | JSTL 1.1 | Servlet 2.4, JavaServer Pages 2.0 | download |
Standard 1.0 | JSTL 1.0 | Servlet 2.3, JavaServer Pages 1.2 | download |
Table 1. The EL implicit objects
Category | Identifier | Description |
JSP | pageContext | The PageContext instance corresponding to the processing of the current page |
Scopes | pageScope | A Map associating the names and values of page-scoped attributes |
requestScope | A Map associating the names and values of request-scoped attributes | |
sessionScope | A Map associating the names and values of session-scoped attributes | |
applicationScope | A Map associating the names and values of application-scoped attributes | |
Request parameters | Param | A Map storing the primary values of the request parameters by name |
paramValues | A Map storing all values of the request parameters as String arrays | |
Request headers | Header | A Map storing the primary values of the request headers by name |
headerValues | A Map storing all values of the request headers as String arrays | |
Cookies | Cookie | A Map storing the cookies accompanying the request by name |
Initialization parameters | initParam | A Map storing the context initialization parameters of the Web application by name |
Table 2 .Methods That the EL Invokes for You
Identifier Type | Example Use | Method Invoked |
JavaBean component | ${colorBean.red} ${colorBean["red"]} | colorBean.getRed() |
Array | ${colorArray[2]} ${colorArray["2"]} | Array.get(colorArray, 2) |
List | colorList[2] colorList["2"] | colorList.get(2) |
Map | colorMap[red] colorMap["red"] | colorMap.get(pageContext. findAttribute("red")) colorMap.get("red") |
A Closer Look at the [] Operator
As discussed in "Accessing JavaBeans Components" on page 46 and "Accessing Objects Stored in Arrays, Lists, and Maps" on page 52, you use the [] operator with this syntax: ${identifier[subexpression]}. Here‘s how expressions with that syntax are evaluated:
Evaluate the identifier and the subexpression; if either resolves to null, the expression is null.
If the identifier is a bean: The subexpression is coerced to a String value and that string is regarded as a name of one of the bean‘s properties. The expression resolves to the value of that property; for example, the expression ${name.["lastName"]} translates into the value returned by name.getLastName().
If the identifier is an array: The subexpression is coerced to an int value—which we‘ll call subexpression-int—and the expression resolves to identifier[subexpression-int]. For example, for an array named colors, colors[3] represents the fourth object in the array. Because the subexpression is coerced to an int, you can also access that color like this: colors["3"]; in that case, JSTL coerces "3" into 3. That feature may seem like a very small contribution to JSTL, but because request parameters are passed as strings, it can be quite handy.
If the identifier is a list: The subexpression is also coerced to an int—which we will also call subexpression-int—and the expression resolves to the value returned from identifier.get(subexpression-int), for example: colorList[3] and colorList["3"] both resolve to the fourth element in the list.
If the identifier is a map: The subexpression is regarded as one of the map‘s keys. That expression is not coerced to a value because map keys can be any type of object. The expression evaluates to identifier.get(subexpression), for example, colorMap[Red] and colorMap["Red"]. The former expression is valid only if a scoped variable named Red exists in one of the four JSP scopes and was specified as a key for the map named colorMap.
JSTL1.1常用函数
函数描述
fn:contains(string,substring)
如果参数string中包含参数substring,返回true
fn:containsIgnoreCase(string, substring)
如果参数string中包含参数substring(忽略大小写),返回true
fn:endsWith(string, suffix)
如果参数 string 以参数suffix结尾,返回true
fn:escapeXml(string)
将有特殊意义的XML (和HTML)转换为对应的XML实体字符,并返回转义后的字符
fn:indexOf(string, substring)
返回参数substring在参数string中第一次出现的位置
fn:join(array, separator)
将一个给定的数组array用给定的间隔符separator串在一起,组成一个新的字符串并返回。
fn:length(item)
返回参数item中包含元素的数量。参数Item类型是普通对象、数组、Collection、Map、Iterator迭代器、Enumeration枚举对象、或者String。
如果是String类型,返回值是String中的字符数。
如果是 数组类型,返回值是数组的长度。
如果是Collection容器类的子类,返回值是该容器类的包含元素的个数。
如果是Map类型,返回值是此映射中的键-值映射关系数。
如果是Iterator类型,返回值是Iterator中的元素个数。
如果是Enumeration类型,返回值是Enumeration中的元素个数
fn:replace(string, before, after)
返回一个String对象。用参数after字符串替换参数string中所有出现参数before字符串的地方,并返回替换后的结果
fn:split(string, separator)
返回一个数组,以参数separator 为分割符分割参数string,分割后的每一部分就是数组的一个元素
fn:startsWith(string, prefix)
如果参数string以参数prefix开头,返回true
fn:substring(string, begin, end)
返回参数string部分字符串, 从参数begin开始到参数end位置,包括end位置的字符
fn:substringAfter(string, substring)
返回参数substring在参数string中后面的那一部分字符串
fn:substringBefore(string, substring)
返回参数substring在参数string中前面的那一部分字符串
fn:toLowerCase(string)
将参数string所有的字符变为小写,并将其返回
fn:toUpperCase(string)
将参数string所有的字符变为大写,并将其返回
fn:trim(string)
去除参数string 首尾的空格,并将其返回
EL隐式对象参照表
类别 | 标识符 | 类对应关系 | 数据来源 | 值所在作用域 | 描述 |
JSP | pageContext | org.apache.jasper.runtime.PageContextImpl
|
| 当前页面 | PageContext 实例对应于当前页面的处理 |
作用域 | pageScope | 当前jsp页面 | 当前页面中的Map类 | 当前页面 | 与页面作用域属性的名称和值相关联的 Map 类 |
requestScope | org.apache.commons.el.ImplicitObjects | 请求作用域中的Map类 | 一次请求过程 | 与请求作用域属性的名称和值相关联的 Map 类 | |
sessionScope | org.apache.commons.el.ImplicitObjects | 会话作用域中的Map类 | 一次会话过程 | 与会话作用域属性的名称和值相关联的 Map 类 | |
applicationScope | org.apache.jasper.runtime.JspApplicationContextImpl | 应用程序作用域的Map类 | 应用程序域 | 与应用程序作用域属性的名称和值相关联的 Map 类 | |
请求参数 | Param | org.apache.commons.el.ImplicitObjects | request.getParameterNames () |
| 按名称存储请求参数的主要值的 Map 类 |
paramValues | org.apache.commons.el.ImplicitObjects | request.getParameterValues(String) |
| 将请求参数的所有值作为 String 数组存储的 Map 类 | |
请求头 | Header | org.apache.commons.el.ImplicitObjects | request.getHeaderNames () |
| 按名称存储请求头主要值的 Map 类 |
headerValues | org.apache.commons.el.ImplicitObjects | request.getHeaders(String) |
| 将请求头的所有值作为 String 数组存储的 Map 类 | |
Cookie | Cookie | Javax.servlet.http.Cookie | request.getCookies () |
| 按名称存储请求附带的 cookie 的 Map 类 |
初始化参数 | initParam | org.apache.commons.el.ImplicitObjects | ServletContext. getInitParameter(String) | 当前web应用 | 按名称存储 Web 应用程序上下文初始化参数的 Map 类 |
通过将字符串映射为期望作用域中的对象来将对象存储到该作用域, 然后,就可以通过提供相同字符串来从该作用域检索该对象。
在作用域的映射中查找字符串,并返回被映射的对象。
EL表达式查找值的方法:
1 EL表达式常用的隐式作用域
首先对页面作用域检查是否存在这样的标识符,其次对请求作用域、然后对会话作用域、最后对应用程序作用域依次进行这样的检查,然后测试该标识符的名称是否与存储在该作用域中的某个对象的名称匹配。第一个这样的匹配作为 EL 标识符的值被返回。通过这种方法,可以将 EL 标识符看作引用限制了作用域的变量。
pageContext,pageScope,requestScope,sessionScope,applicationScope
从技术方面来说,没有映射到隐式对象的标识符是用 PageContext 实例的 findAttribute() 方法求值的,该实例表示对页面的处理,在该页面上,当前正在处理用于请求的表达式。标识符的名称作为参数传递给这个方法,然后该方法依次在四个作用域中搜索具有相同名称的属性。并将所找到的第一个匹配项作为 findAttribute() 方法的值返回。如果未在这四个作用域中找到这样的属性,则返回 null。
HashMap<String,Object> map=new HashMap<String,Object>();
map.put("name","张三");
pageContext.setAttribute("customerScope",map);
${customerScope.name}
表达式运算结果: 张三
2点运算符(.)和方括号运算符([])
EL 提供了两种不同的存取器(点运算符(.)和方括号运算符([])),也支持通过 EL 操作特性和元素
点运算符通常用于访问对象的特性。例如,在表达式 ${user.firstName} 中,使用点运算符来访问user 标识符所引用对象的名为 firstName 的特性。EL 使用 Java bean 约定访问对象特性,因此必须定义这个特性的 getter 方法(通常是名为 getFirstName() 的方法),以便表达式正确求值。
当被访问的特性本身是对象时,可以递归地应用点运算符。例如,如果我们虚构的 user 对象有一个实现为 Java 对象的 address 特性,那么也可以用点运算符来访问这个对象的特性。例如,表达式 ${user.address.city} 将会返回这个地址对象嵌套的 city 特性。
方括号运算符用来检索数组和集合的元素。在数组和有序集合(也即,实现了 java.util.List 接口的集合)的情况下,把要检索的元素的下标放在方括号中。例如,表达式 ${urls[3]} 返回 urls 标识符所引用的数组或集合的第四个元素(和 Java 语言以及 JavaScript 中一样,EL 中的下标是从零开始的)。
对于实现 java.util.Map 接口的集合,方括号运算符使用关联的键查找存储在映射中的值。在方括号中指定键,并将相应的值作为表达式的值返回。例如,表达式 ${commands["dir"]} 返回与commands 标识符所引用的 Map 中的 "dir" 键相关联的值。
3 .EL 运算符的优先级
EL 运算符优先级(自顶到底,从左到右)
[], .
()
unary -、not、!、empty
*、/、div、%、mod
+、binary -
() <</code>、>、<=、>=、lt、gt、le、ge
==、!=、eq、ne
&&、and
||、or
四种标准标签库
JSTL提供一组四个标准标记库(core核心、internationalization/format国际标准化/格式、SQL和 XML)并支持EL
函数 fn functions
库:Core(核心库)
URI:http://java.sun.com/jsp/jstl/core
前缀:c
1. <c:catch>
<c:catch>动作用于捕获JSP元素在其体中抛出的异常,从而提供细粒度的错误控制,此异常也可以保存为一个页面作用域变量。
语法:
<c:catch[var="var"]>
JSP elements
</c:catch>
属性:
属性名 | Java 类型 | 是否接受动态值 | 描述 |
var
| String
| No | 变量名 |
示例:
<c:catchvar="importException">
<fmt:parseDate value="http://www.mamicode.com/${param.empDate}" dateStyle="short"/>
</c:catch>
<c:if test="${importException != null}">
<jsp:forward page="input.jsp">
<jsp:param name="msg" value="http://www.mamicode.com/Invalid date format" />
</jsp:forward>
</c:if>
2. <c:choose>
<c:choose>动作用于控制嵌套<c:when>和<c:otherwise>动作的处理,它只允许第一个测试表达式计算为true的<c:when>动作得到处理;如果所有<c:when>动作的测试表达式都计算为false,则会处理一个<c:otherwise>动作。
语法:
<c:catch[var="var"]>
JSP elements
</c:catch>
属性:
无
示例:
<c:choose>
<c:when test="${product.onSale}">
${product.salesPrice} On sale!
</c:when>
<c:otherwise>
${product.price}
</c:otherwise>
</c:choose>
3. <c:forEach>
<c:forEach>动作将其体反复计算固定次数,或者针对一个集合中的每个元素分别计算一次体。当前元素(如果未指定集合则为当前索引)和迭代状态可以通过嵌套变量提供给体中的动作元素。
此动作接受属性表中所列的类型集合。当前元素的类型即为底层集合的类型,仅有两个例外。对于一个基本类型的数组,当前元素将作为相应包装类(Integer、Float等等)的一个实例提供。对于一个java.util.Map,当前元素则作为一个java.util.Map.Entry提供。
语法1:基于集合元素进行迭代
<c:forEachitems="collection" [var="var"][varStatus="varStatus"]
[begin="startIndex"] [end="stopIndex"][step="increment"]>
JSP elements
</c:forEach>
语法2:迭代固定次数
<c:forEach[var="var"] [varStatus="varStatus"]
begin="startIndex" end="stopIndex"[step="increment"]>
JSP elements
</c:forEach>
属性
属性名 | Java 类型 | 是否接受动态值 | 描述 |
begin
| int
| Yes | 结合集合使用时的开始索引,从0计起。对于集合来说默认为0 |
end
| int
| Yes | 结合集合使用时的结束索引(元素引要小于等于此结束索引),从0计起。默认为集合的最后一个元素。如果end小于begin,则根本不计算体集合,迭代即要针对此集合进行。 |
items
| java.util.Collection, java.util.Iterator, java.util.Enumeration, java.util.Map, 对象数组或基本类型数组。 | Yes | 集合,迭代即要针对此集合进行。 |
step
| int
| Yes | 每次迭代时索引的递增值。默认为1。 |
var
| String
| No | 保存当前元素的嵌套变量的名字。 |
varStatus
| String
| No | 保存LoopTagStatus对象的嵌套变量的名字。 |
示例:
<%-- Iteratefive times, writing 1, 2, 3, 4, 5 --%>
<c:forEach begin="1" end="5" var="current">
${current}
</c:forEach>
<%-- Iterateover all request parameters --%>
<c:forEach items="${param}" var="current">
Name: <c:out value="http://www.mamicode.com/${current.key}" />
Value: <c:out value="http://www.mamicode.com/${current.value}" />
</c:forEach>
4. <c:forTokens>
<c:forTokens>动作对于String中的每个token(单字)计算其体一次,在String中这些token由某个所指定的分隔符相分隔。当前token和迭代状态可以通过嵌套变量提供给体中的动作元素。
语法
<c:forTokensitems="stringOfTokens" delims="delimiters"
[var="var"] [varStatus="varStatus"]
[begin="startIndex"] [end="stopIndex"][step="increment"]>
JSP elements
</c:forTokens>
属性
属性名 | Java 类型 | 是否接受动态值 | 描述 |
items
| String
| Yes | 一组token,迭代即要针对这些token进行 |
delims
| String
| Yes | 分隔符列表 |
var
| String
| No | 保存当前元素的嵌套变量的名字 |
varStatus
| String
| No | 保存LoopTagStatus对象的嵌套变量的名字 |
begin
| int
| Yes | 开始索引,从0计起,默认为0 |
end
| int
| Yes | 结束索引(小于等于此索引),从0计起。默认为最后一个token。如果end小于begin,则根本不计算体。 |
step
| int
| Yes | 每次迭代时索引的递增值。默认为1。 |
示例
<%-- Iterateover tokens separated by vertical bars --%>
<c:forTokens items="${tokens}" delims="|"var="current">
<c:out value="http://www.mamicode.com/${current }" />
</c:forTokens>
5.<c:if>
<c:if>动作仅当所指定的表达式计算为true时才计算其体。计算结果也可以保存为一个作用域Boolean变量。
语法1:没有体
<c:iftest="booleanExpression "
var="var " [scope="page|request|session|application"]/>
语法2:有体
<c:iftest="booleanExpression">
JSP elements
</c:if>
属性
属性名 | Java 类型 | 是否接受动态值 | 描述 |
test
| Boolean
| Yes | 测试表达式 |
var
| String
| No | 变量名 |
Scope
| String
| No | 变量作用域 |
示例
<c:iftest="${empty param.empDate}">
<jsp:forwardpage="input.jsp">
<jsp:paramname="msg" value="http://www.mamicode.com/Missing the Employment Date" />
</jsp:forward>
</c:if>
EL支持
要理解当前JSTL对EL支持的状态,让我们检查相关的说明书是怎样处理的。Java说明书请求(JSR)专家组成员决定:由于某种原因,EL规范说明应该是JSP说明书的一部份,而不是JSTL说明书的一部分。EL完整的说明书成为JSP2.0的一部分。因为JSTL1.0在JSP1.3之前已经完成,JSTL作者不得不对用于JSTL1.0的EL支持实现做一个合理的猜测(结果可能是相当好的)。一个JSTL维护版本将与JSP1.3说明书保持一致,并为了使EL适合JSP1.3说明书,JSTL维护版本做了一些修正。
另附一些用法(以下内容一部分转载自网络,一部分原创)
- pageContext
- 请求参数:${pageContext.request.queryString}
- 绝对路径:${pageContext.request.requestURL}:http://localhost/jstl/pages/MyJsp.jsp
- 工程名(相对路径):${pageContext.request.contextPath}:/jstl
- 请求方法:${pageContext.request.method}:GET
- HTTP版本:${pageContext.request.protocol}:HTTP/1.1
- 远程计算机用户名:${pageContext.request.remoteUser}:
- ${pageContext.request.remotePort}:2067
- 本地开设的服务器端口:${pageContext.request.localPort}:81
- ${pageContext.request.scheme}:http
- 远程计算机名:${pageContext.request.remoteHost}:127.0.0.1
- IP地址:${pageContext.request.remoteAddr }:127.0.0.1
- session状态:${pageContext.session.new}:true
- session编号:${pageContext.session.id}:00EB0C78103D46152844178CCEAABA2E
- HTTP连接头部的host值 :${header["host"]}
- HTTP头部的accept值:${header["accept"]}
- HTTP头部的user-agent值:${header["user-agent"]}
- 请求参数
- 表达式 ${param.name} 相当于 request.getParameter (name)
- 表达式 ${paramvalues.name) 相当于 request.getParamterValues(name)
- 请求头
- 表达式 ${header.name} 相当于 request.getHeader(name)
- 表达式 ${headerValues.name} 相当于 request.getHeaderValues(name)
- Cookie
- 表达式 ${cookie.name.value} 返回带有特定名称的第一个 cookie 值
- 初始化参数
- ${initParam . name} name 是你在web.xml 文件中配置的初始化参数
- 将上下文初始化参数名称映射到单个值(通过调用 ServletContext.getInitparameter(String name) 获得)
- ·requestScope
- 在页面请求时将javaBean一起传递
- 只在使用<jsp:forward> 时有效,当页面使用sendRedirect时不会传递
- 变量
- 任何出现在EL 表达式中的变量(除了上面的内置对象),都会被容器认为是在引用存储在某个作用域中的对象,可以这样认为,变量是某个作用域的属性,当EL 中出现了一个变量时,EL将到作用域中去找与它同名的属性,然后将值映射给变量EL语言中的变量与其他语言中的变量的权限和作用是不一样的
- EL 中的变量是不能够赋予新值的
- EL中的变量只能与某一个作用域相关联
- 将会在作用域中查找,顺序是: pageScope,requestScope,sessionScope,applicationScope
jsp页面9大隐式对象与el表达式11个隐式对象的比较
EL表达式 11个隐式对象及其功能的简单描述如下
● pageContext:用于该网页的pageContext对象
● pageScope,requestScope, sessionScope, 和applicationScope:这些是映射这些范围的每一个变量到值上的Map集。
● param 和 paramValues:用页访问传递的参数,与在JSP中一样
● header 和 headerValues:用页请求传递的头,与在JSP中一样
● cookie Map映射cookie程序到特定的cookie对象上
● config
JSP 9个隐式对象及其功能的简单描述如下:
- application 是使用范围最广的上下文状态。它允许 JSP 页面的 servlet 与包括在同一应用程序中的任何 Web 组件共享信息。
- config 允许将初始化数据传递给一个 JSP 页面的 servlet。
- exception include 含有只能由指定的 JSP“error pages”访问的异常数据。
- out 提供对 servlet 的输出流的访问。
- page 是JSP页面的处理当前请求的 servlet 的实例。一般来说,JSP 页面作者不使用该对象。
- pageContext 是 JSP 页面本身的上下文。它提供惟一一个 API 来管理具有不同作用域的属性。这个 API 在实现 JSP 自定义标记处理程序时使用得非常多。
- request 提供对 HTTP 请求数据的访问,同时还提供用于加入特定于请求的数据的上下文。
- response 允许直接访问 HTTPServletResponse 对象,JSP 程序员很少使用该对象。
- session 可能是状态管理上下文中使用得最多的对象。“会话”的概念是指单个用户与 Web 应用程序在几个请求上进行交互。
虽然有些隐式对象只提供单一的功能,但是几个结合起来使用就可以提供多种功能。在接下来的一节里,我们将按照功能分类来考察隐式对象:
- 会话管理: application , session , request , pageContext
- 流控制: application , config , pageContext , request , session
- 日志记录和异常: application , config , exception , pageContext , request , session
- 输入/输出控制: request , response , out
- 初始化参数: config
为 JSP 定义的四个隐式对象可以用来在一个特定的上下文或者作用域中加入有状态数据。这四个对象是 application
、 session
、 request
和
pageContext
。下表列出了这四个对象和它们定义的状态上下文,同时还给出了对每个对象的简单描述。
表1. JSP 状态管理
隐式对象 | 作用域 | 描述 |
javax.servlet.ServletContext |
| 代表整个运行时的 Web 模块(应用程序)。作用域为 application 的数据在同一个应用程序模块的所有 Web 组件之间共享。这很像J2EE 中提供的“全局(global)”数据 |
javax.servlet.http.HttpSession |
| 代表当前的 HTTP 会话。除 |
javax.servlet.http.HttpServletRequest |
| 代表当前的 HTTP 请求。这个上下文可以跨越多个 Web 组件(servlet 和 JSP 页面),只要这些组件属于同一原子请求的一部分。由客户机提供的特定于请求的数据(请求方法、URI、HTTP 参数等等)都被自动地保存在一个 |
javax.servlet.jsp.PageContext |
| 代表当前 JSP 页面的上下文。因为一个 JSP 页面的上下文包括当前的请求、会话和应用程序,所以使用 |
从最佳实践的立场来看,我们应该尽可能地使用 page
作用域。它简单,而且是
JSP
数据的默认作用域。
request
作用域非常适合于运行期间在组件间共享数据以处理一个特定的请求。
session
作用域被设计用来为单个用户提供持久的、有状态的体验,它可以跨越多个请求。
application
作用域只有需要在组件之间跨用户会话共享数据时才应该使用。参阅
参考资料
以了解更多有关
session
作用域的信息。
流控制
面向对象设计方法的最大好处是可重用性。特别是,J2EE 系统将它们借用到模块化风格的开发中,其中组件可以在其他应用程序中重新安排、重新打包和重新使用。即使您对设计可重用的 Web 模块不感兴趣,也很可能会发现您的 J2EE 应用程序由几个部分组成。任何时候使用多个 servlet 或者 JSP 页面(也就是组件)完成一个请求的时候,都需要使用某种类型的流控制技术。Servlet 架构提供两种这样的技术:forward(转发) 和 include(包括)。
在 J2EE Web 开发中, forward会把处理用户请求的控制权转交给到其他 Web 组件。forward 在有些时候会比较有用,比如说需要用一个组件设置一些 JavaBean、打开或关闭资源、认证用户,或者在将控制权传递给下一个组件之前需要执行一些准备工作。在转发之前可以执行很多类型的任务,但是要转发的组件不能设置响应头部信息,也不能有内容发送到输出缓冲区。所有与向客户发送内容直接相关的任务必须由被转发的组件完成。
J2EE 中第二种流控制技术是 include。在使用 forward 时,要传递控制权。与此不同的是,执行 include 的组件维持对请求的控制权,而只是简单地请求将另一个组件的输出包括在该页面的某个特定的地方。对于常见的设计元素,例如页首、页脚和导航栏等,这是一个非常好的方法。
forward 和 include 都是通过一个专门的对象java.servlet.RequestDispatcher 来完成的。简单地调用一个 ServletContext 对象的getRequestDispatcher() 方法就可以获得一个 RequestDispatcher 对象。得到对 ServletContext 对象的引用有几种方法,我们可以:
- 使用隐式声明的 application 变量,因为它的类型本身已经是 ServletContext。
- 调用方法 getServletContext() ,该方法返回一个对隐式声明的 application 变量的引用。
- 调用隐式声明的 config 变量的 g etServletContext() 方法 。
- 调用隐式声明的 pageContext 变量的 getServletContext() 方法 。
- 调用隐式声明的 request 变量的 getServletContext() 方法 。
- 调用隐式声明的 session 变量的 getServletContext() 方法 。
清单1给出了使用隐式变量 application
的 forward 流控制机制的代码示例。
清单1. forward 流控制示例
javax.servlet.RequestDispatcher rd; /* Obtain a reference to a RequestDispatcher object via the implicit application variable*/ rd = application.getRequestDispatcher( "/NextPage.jsp" ); /* Perform the forward specified by the RequestDispatcher and pass along a reference to the current request and response objects */ rd.forward( request, response ); |
清单2给出了同样使用变量 application
的 include 流控制的代码示例。
清单2. include 流控制示例
javax.servlet.RequestDispatcher rd; /* Obtain a reference to a RequestDispatcher object via the implicit application variable*/ rd = application.getRequestDispatcher( "/Header.jsp" ); /* Perform the include specified by the RequestDispatcher and pass along a reference to the current request and response objects */ rd.include( request, response ); |
forward 和 include 是添加到 J2EE Web 开发工具包中的两个非常棒的技术。还有其他一些方法可以在 JSP 页面中完成 include,而且还有很多解决 J2EE 设计模式方面的文献中讲到了如何结合使用这两种技术。参阅 参考资料以了解更多信息。
日志记录和异常
如果您需要把与 Web 应用程序相关的信息存储到一个日志中,依然有内建的方法可用。 ServletContext 接口声明了两个方法,用于把数据传给一个日志。其中一个方法接受简单的文本消息: log( java.lang.String ) ,另一个方法接受一个异常信息和一个文本消息: log(java.lang.Throwable, java.lang.String ) 。
在有了 ServletContext 接口提供的两个可用的日志记录方法之后,剩下的关键是获取一个对 ServletContext 类型的对象的引用。像我们前面讨论过的流控制对象一样,有多种方法可以获取对 ServletContext 类型的对象的引用。在获得了对象引用之后,简单地调用 log() 方法并向方法中传递必需的数据即可。一旦调用了这个方法,您当然就会希望能够查看应用程序日志以查看消息。 ServletContext 是一个简单的接口,并且也没有规定怎样实现它声明的方法。因而 log 方法的具体实现是由供应商处理的。他们可以把日志信息存储到一个文本文件、二进制文件、数据库中,或者是供应商认为合适的其他格式中。您需要从服务器的文档中得知存储日志的位置。
输入和输出控制
因为 JSP 页面仅仅是 HTTP servlet 的一个简单抽象,所以您可以访问 HttpServletRequest 和 HttpServletResponse 对象。如果需要特定于请求的信息,比如客户机浏览器的类型、HTTP post 的内容类型、客户机性能、Cookie 数据或者请求参数,简单地用隐式声明的 request 变量直接调用适当的方法即可。类似地,如果您需要设置响应头部信息,比如说浏览器类型、内容类型、内容长度等等,简单地用隐式变量 response 调用适当的方法即可。
如果需要直接访问 JSP 页面的输出流,您可能会试图通过隐式 response 变量调用 getWriter() 或 getOutputStream() 。然而由于 JSP 页面的特殊性,您不能这样做。如果需要直接访问输出流,必须通过一个 avax.servlet.jsp.JSPWriter 类型的特殊缓冲 PrintWriter 对象来访问。怎样定位这样一个对象的引用呢?JSP 容器将会为您隐式地声明一个,并通过 out 变量提供给您。在 JSP scriptlet 中可以通过简单地调用 out.print() 或 out.println() 使用它。
一般来说不需要像这样直接使用 JSPWriter 对象,而只需简单地把内容作为普通文本或者通过 JSP 表达式写入,然后允许容器将这些信息翻译成 JSPWriter 调用。然而,在两种情况下您需要直接使用 out 变量。一种情况是要为 JSP 自定义标记定义处理程序,这部分内容我们将在下个月重点讲到。另外一种情况是您想要对 JSP 创建的输出拥有更多的控制。如果您有一段夹杂着 JSP scriptlets 和表达式的 HTML,您可能会发现创建大的 scriptlet 然后在需要输出内容到客户机的时候使用 out.println() 语句这样做会更简洁、更容易。
初始化参数
如果您有一些静态数据想提供给 JSP 页面使用,并且那些数据不会频繁地改动,初始化参数可能会是一个比较好的选择。初始化参数有时候又叫环境变量或者“init”参数,这些参数通过位于一个 per-servlet/JSP 内的 Web 应用程序的 web.xml 文件指定,并且它们在servlet 的生命周期中只读取一次,即在初始化时读取。
清单3是一个初始化参数声明的例子。
清单3.初始化参数声明
<webapp> <servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.gabhart.MyTestServlet</servlet-class> <init-param> <param-name>contactEmail</param-name> <param-value>kyle@gabhart.com</param-value> </init-param> </servlet> </webapp> |
使用隐式变量 config 可以访问这些参数的值,隐式变量 config 是对 JSP 页面的 ServletConfig 对象的引用。通过 ServletConfig 接口提供了两个处理 init 参数的方法。可以根据名字对一个特定的参数完成一个查找( getInitParameter( java.lang.String) ),或者也可以检索到为 JSP 页面定义的所有参数名字的一个 enumeration( getInitParameterNames() )。在拥有了enumeration 之后,可以通过循环查找每一个值。所有 init参数都是 String 对象。如果需要其他的数据类型,比如说整数、浮点数或者布尔值,必须使用相应的包装器类来解析字符串。
版本更替带来的使用习惯改变以及特性的体验
在JSTL1.0的时候,在页面显示数据必须用<c:out>来进行,然而在JSTL1.1中,由于JSP2.0规范已经默认支持
EL表达式,因此可以直接在JSP页面使用表达式,看下面一个例子
<c:out value=http://www.mamicode.com/“${sessionScope.anyValue}” default=“no value” escapeXml=“false”/>
在EL表达式尚未出现之前,Structs1中一直用<bean:write>输出变量内容
其他
length -7,empty -5,foreach – 14
empty,not empty,or,and运算符
fn:length(java.lang.Object item) 其中item可以是普通对象、数组、Collection、Map、Iterator迭代器、Enumeration枚举对象、或者String
empty item 其中item可以是普通对象、数组、List集合、Map集合、字符串
<c:forEach item=“collection”>其中collection可以是Object数组、int数组、bollean数组、byte数组、char数组、short数组、long、float数组、double数组、
Collection容器、Iterator迭代器、Enumeration枚举对象、Map容器类、以”,”为分隔符的String对象内容
重点学习org.apache.commons.el包和org.apache.taglibs.standard.lang.jstl包下面的类,并进行参照对比
EL表达式是从Servlet2.4中开始使用的
Everything in EL is an object;null表示不存在的值
EL表达式中转移用 \
访问的属性需要具备该属性的getter/setter方法,类如Collection中的size、count方法因为相对应的getter/setter,所以无法直接调用
JSP、Servlet、Tomcat、JDK、J2EE版本比较
关键字: 版本比较
一 JSP2.0与JSP1.2比较
JSP 2.0是对JSP 1.2的升级,新增功能:
1. Expression Language
2. 新增Simple Tag和Tag File
3.web.xml新增<jsp:config>元素
特别说明web.xml.
web.xml新增<jsp:config>元素
<jsp-config> 元素主要用来设定JSP相关配置,<jsp-config> 包括<taglib>和<jsp-property-group>
子元素。
(1)其中<taglib>以前的Jsp1.2中就有的,taglib主要作用是作为页面taglib标签中的uri和tld文件的一个映射关系
(2)其中<jsp-property-group>是JSP2.0种新增的元素。
<jsp-property-group> 主要包括8个子元素,它们分别是:
<jsp-property-group>
<description>
设定的说明
</description>
<display-name>设定名称</display-name>
<url-pattern>设定值所影响的范围</url-pattern>
<el-ignored>若为true则不支持EL语法</el-ignored>
<page-encoding>ISO-8859-1</page-encoding>
<scripting-invalid> 若为true则不支持<% scripting%> 语法</scripting-invalid>
<include-prelude>设置JSP网页的抬头,扩展名为.jspf </include-prelude>
<include-coda>设置JSP网页的结尾,扩展名为.jspf</include-coda>
</jsp-property-group>
例如: 其中抬头程序:
prelude.jspf
<br>
<center>
文本内容
</center>
<hr>
结尾程序:
coda.jspf
<br>
<center>
文本内容
</center>
<hr>
二、Servlet个版本比较
Servlet 2.2新增功能:
引入了self-contained Web applications的概念。
servlet2.3 新增功能:
2000年10月份出来
Servlet API 2.3中最重大的改变是增加了filters
Servlet 2.3增加了filters和filter chains的功能。引入了context和session listeners的概念,当context 或session被初始化或者被将要被释放的时候,和当向context或session中绑定属性或解除绑定的时候,可以对类进行监测。
servlet2.4 新增功能:
2003年11月份出来
Servlet2.4加入了几个引起关注的特性,没有特别突出的新内容,而是在推敲和阐明以前存在的一些特性上花费了更多的功夫,对一些不严谨的地方进行了校验。
Servlet2.4增加了新的最低需求,监测request的新方法,处理response的新方法,新的国际化支持,RequestDispatcher的几个处理,新的request listener类,session的描述,和一个新的基于Schema的并拥有J2EE元素的发布描述符。这份文档规范全面而严格的进行了修订,除去了一些可能会影响到跨平台发布的模糊不清的因素。总而言之,这份规范增加了四个新类,七个新方法,一个新常量,不再推荐使用一个类。
1、web.xml DTD改用了XML Schema;
Servlet 2.3之前的版本使用DTD作为部署描述文件的定义,其web.xml的格式为如下所示:
<?xml version="1.0" encoding="IS0-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//sunMicrosystems,Inc.//DTD WebApplication 2.3f//EN"
"http://java.sun.com/j2ee/dtds/web-app_2.3.dtd">
<web-app>
.......
</web-app>
Servlet 2.4版首次使用XML Schema定义作为部署描述文件,这样Web容器更容易校验web.xml语法。同时XML Schema提供了更好的扩充性,其web.xml中的格式如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:workflow="http://www.workflow.com"
xmins: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-app_2_4.xsd">
.........
</web-app>
注意: 改为Schema后主要加强了两项功能:
(1) 元素不依照顺序设定
(2) 更强大的验证机制
主要体现在:
a.检查元素的值是否为合法的值
b.检查元素的值是否为合法的文字字符或者数字字符
c.检查Servlet,Filter,EJB-ref等等元素的名称是否唯一
2.新增Filter四种设定:REQUEST、FORWARD、INCLUDE和ERROR。
3.新增Request Listener、Event和Request Attribute Listener、Enent。
4.取消SingleThreadModel接口。当Servlet实现SingleThreadModel接口时,它能确保同时间内,只能有一个thread执行此Servlet。
5.<welcome-file-list>可以为Servlet。
6.ServletRequest接口新增一些方法。
public String getLocalName()
public String getLocalAddr()
public int getLocalPort()
public int getRemotePort()
Servlet 2.5的新特征
2005年9月发布Servlet 2.5
Servlet2.5一些变化的介绍:
1) 基于最新的J2SE 5.0开发的。
2) 支持annotations 。
3) web.xml中的几处配置更加方便。
4) 去除了少数的限制。
5) 优化了一些实例
servlet的各个版本对监听器的变化有:
(1)servlet2.2和jsp1.1
新增Listener:HttpSessionBindingListener
新增Event: HttpSessionBindingEvent
(2)servlet2.3和jsp1.2
新增Listener:ServletContextListener,ServletContextAttributeListener
,HttpSessionListener,HttpSessionActivationListener,HttpSessionAttributeListener
新增Event:ServletContextEvent,ServletContextAttributeEvent,HttpSessionEvent
(3)servlet2.4和jsp2.0
新增Listener:ServletRequestListener,ServletRequestAttribureListener
新增Event: ServletRequestEvent,ServletRequestAttributeEvent
三、J2EE规范版本比较
1.J2EE的发展
1997 年Servlet技术的产生以及紧接着JSP的产生,为Java对抗PHP,ASP等等服务器端语言带来了筹码。1998年,Sun发布了EJB1.0标准,至此J2EE平台的三个核心技术都已经出现。于是,1999年,Sun正式发布了J2EE的第一个版本。并与1999年底发布了J2EE1.2,在 2001年发布了J2EE1.3,2003年发布了J2EE1.4。
2.J2EE1.3
J2EE1.3的架构,其中主要包含了Applet容器,Application Client容器,Web容器和EJB容器,并且包含了Web Component,EJB Component,Application Client Component,以JMS,JAAS,JAXP,JDBC,JAF,JavaMail,JTA等等技术做为基础。
1.3中引入了几个值得注意的功能:Java消息服务(定义了JMS的一组API),J2EE连接器技术(定义了扩展J2EE服务到非J2EE应用程序的标准),XML解析器的一组Java API,Servlet2.3,JSP1.2也都进行了性能扩展与优化,全新的CMP组件模型和MDB(消息Bean)。
3.J2EE1.4
J2EE1.4 大体上的框架和J2EE1.3是一致的,1.4增加了对Web服务的支持,主要是Web Service,JAX-RPC,SAAJ,JAXR,还对EJB的消息传递机制进行了完善(EJB2.1),部署与管理工具的增强(JMX),以及新版本的Servlet2.4和JSP2.0使得Web应用更加容易。
4.JAVAEE 5
JAVA EE5拥有许多值得关注的特性。其中之一就是新的 Java Standard Tag Library (JSTL) 1.2 规范。JSTL 1.2 的关键是统一表达式语言,它允许我们在 JavaServer Faces (JSF) 中结合使用 JSTL 的最佳特性。
四、Tomcat版本比较
Tomcat 3.x
servlet2.2和jsp1.1标准
Tomcat 4.x
Servlet 2.3 和 JSP 1.2 版本
Tomcat 5.x
Servlet 2.4或2.5 和 JSP 2.0 版本
五、JDK版本比较
已发行的版本:
版本号 名称 中文名 发布日期
JDK 1.1.4 Sparkler 宝石 1997-09-12
JDK 1.1.5 Pumpkin 南瓜 1997-12-13
JDK 1.1.6 Abigail 阿比盖尔--女子名 1998-04-24
JDK 1.1.7 Brutus 布鲁图--古罗马政治家和将军 1998-09-28
JDK 1.1.8 Chelsea 切尔西--城市名 1999-04-08
J2SE 1.2 Playground 运动场 1998-12-04
J2SE 1.2.1 none 无 1999-03-30
J2SE 1.2.2 Cricket 蟋蟀 1999-07-08
J2SE 1.3 Kestrel 美洲红隼 2000-05-08
J2SE 1.3.1 Ladybird 瓢虫 2001-05-17
J2SE 1.4.0 Merlin 灰背隼 2002-02-13
J2SE 1.4.1 grasshopper 蚱蜢 2002-09-16
J2SE 1.4.2 Mantis 螳螂 2003-06-26
将发行的版本:
J2SE 5.0 (1.5.0) Tiger 老虎 已发布
J2SE 5.1 (1.5.1) Dragonfly 蜻蜓 未发布
J2SE 6.0 (1.6.0) Mustang 野马 已发布
JTSL/EL Expression学习