﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-&lt;font color="red"&gt;JRen&lt;/font&gt;&lt;font color="lightgreen"&gt;大鹏一曰同风起，扶摇直上九万里&lt;/font&gt;-随笔分类-JSP</title><link>http://www.blogjava.net/liaojiyong/category/11431.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 15 May 2007 09:10:59 GMT</lastBuildDate><pubDate>Tue, 15 May 2007 09:10:59 GMT</pubDate><ttl>60</ttl><item><title>JSTL 入门（转）</title><link>http://www.blogjava.net/liaojiyong/archive/2007/03/21/105235.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Wed, 21 Mar 2007 04:15:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2007/03/21/105235.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/105235.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2007/03/21/105235.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/105235.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/105235.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr valign="top">
								<td width="100%">
										<p id="subtitle">通过避免使用脚本编制元素来简化对 JSP 应用程序的软件维护</p>
										<img class="display-img" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="1" />
								</td>
								<td class="no-print" width="192">
								</td>
						</tr>
				</tbody>
		</table>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr valign="top">
								<td width="10">
										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
								</td>
								<td width="100%">
										<table class="no-print" cellspacing="0" cellpadding="0" width="160" align="right" border="0">
												<tbody>
														<tr>
																<td width="10">
																		<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
																</td>
																<td>
																		<table cellspacing="0" cellpadding="0" width="150" border="0">
																				<tbody>
																						<tr>
																								<td class="v14-header-1-small">
																								</td>
																						</tr>
																				</tbody>
																		</table>
																		<table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0">
																				<tbody>
																						<tr>
																								<td class="no-padding" width="150">
																										<table cellspacing="0" cellpadding="0" width="143" border="0">
																												<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																												<form name="email" action="https://www.ibm.com/developerworks/secure/email-it.jsp">
																														<script language="JavaScript" type="text/javascript">
																																<!--
document.write('<tr valign="top"><td width="8"><img src="//www.ibm.com/i/c.gif" width="8" height="1" alt=""/></td><td width="16"><img src="//www.ibm.com/i/v14/icons/em.gif" height="16" width="16" vspace="3" alt="将此页作为电子邮件发送" /></td><td width="122"><p><a class="smallplainlink" href="javascript:document.email.submit();"><b>将此页作为电子邮件发送</b></a></p></td></tr>');
//-->
																														</script>
  
<tbody><tr valign="top"><td width="8"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" /></td><td width="16"></td><td width="122"><p><a class="smallplainlink" href="javascript:document.email.submit();"><b><font color="#5c81a7" size="2"></font></b></a> </p></td></tr><noscript></noscript></tbody></form>
																										</table>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
										<!-- 03/20/06 updated by gretchen -->
										<br />
										<table cellspacing="0" cellpadding="0" width="150" border="0">
												<tbody>
														<tr>
																<td class="v14-header-2-small">
																</td>
														</tr>
												</tbody>
										</table>
										<table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td class="no-padding" width="150">
																		<table cellspacing="0" cellpadding="0" width="143" border="0">
																				<tbody>
																						<tr valign="top">
																								<td width="8">
																										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" />
																								</td>
																								<td>
																								</td>
																								<td width="125">
																										<p> </p>
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<p>级别: 初级</p>
		<p>
				<a href="http://www.ibm.com/developerworks/cn/java/j-jstl0211/index.html?ca=j-t10#author">
						<font color="#5c81a7">Mark A. Kolb</font>
				</a> (<a href="mailto:mak@taglib.com?subject=表达式语言&amp;cc=mak@taglib.com"><font color="#5c81a7">mak@taglib.com</font></a>), 软件工程师<br /></p>
		<p>2003 年 5 月 27 日</p>
		<blockquote>JSP 标准标记库（JSP Standard Tag Library，JSTL）是一个实现 Web 应用程序中常见的通用功能的定制标记库集，这些功能包括迭代和条件判断、数据管理格式化、XML 操作以及数据库访问。在 developerWorks 上其新系列的第一篇文章中，软件工程师 Mark Kolb 向您展示了如何使用 JSTL 标记来避免在 JSP 页面中使用脚本编制元素。您还将了解如何通过从表示层删除源代码来简化软件维护。最后，您将了解 JSTL 经过简化的表达式语言，它允许在不必使用功能齐全的编程语言的情况下对 JSTL 操作指定动态属性值。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>JavaServer Pages（JSP）是用于 J2EE 平台的标准表示层技术。JSP 技术提供了用于执行计算（这些计算用来动态地生成页面内容）的脚本编制元素和操作。脚本编制元素允许在 JSP 页面中包括程序源代码，在为响应用户请求而呈现页面时可以执行这些源代码。操作将计算操作封装到很象 HTML 或 XML 标记的标记中，JSP 页面的模板文本通常包含这些标记。JSP 规范只将几种操作定义成了标准，但从 JSP 1.1 开始，开发人员已经能够以定制标记库的方式创建其自己的操作了。</p>
		<p>JSP 标准标记库（JSTL）是 JSP 1.2 定制标记库集，这些标记库实现大量服务器端 Java 应用程序常用的基本功能。通过为典型表示层任务（如数据格式化和迭代或条件内容）提供标准实现，JSTL 使 JSP 作者可以专注于特定于应用程序的开发需求，而不是为这些通用操作“另起炉灶”。</p>
		<p>当然，您可以使用 JSP 脚本编制元素（scriptlet、表达式和声明）来实现此类任务。例如，可以使用三个 scriptlet 实现条件内容，清单 1 中着重显示了这三个 scriptlet。但是，因为脚本编制元素依赖于在页面中嵌入程序源代码（通常是 Java 代码），所以对于使用这些脚本编制元素的 JSP 页面，其软件维护任务的复杂度大大增加了。例如，清单 1 中的 scriptlet 示例严格地依赖于花括号的正确匹配。如果不经意间引入了一个语法错误，则条件内容中的嵌套其它 scriptlet 可能会造成严重破坏，并且在 JSP 容器编译该页面时，要使所产生的错误信息有意义可能会很困难。</p>
		<br />
		<br />
		<a name="listing1">
				<b>清单 1. 通过 scriptlet 实现条件内容</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="500" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;% if (user.getRole() == "member")) { %&gt;
    &lt;p&gt;Welcome, member!&lt;/p&gt;
&lt;% } else { %&gt;
    &lt;p&gt;Welcome, guest!&lt;/p&gt;
&lt;% } %&gt;</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>修正此类问题通常需要相当丰富的编程经验。尽管通常会由十分精通页面布局和图形设计的设计人员来开发和维护 JSP，但是同一页面中的脚本编制元素出现问题时，需要程序员的介入。这种状况将单个文件中代码的责任分担给多人，因而使得开发、调试和增强此类 JSP 页面成为很麻烦的任务。通过将常用功能包装到定制标记库的标准集合中，JSTL 使 JSP 作者可以减少对编制脚本元素的需求，甚至可以不需要它们，并避免了相关的维护成本。</p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																</td>
																<td valign="top" align="right">
																		<b>
																				<font color="#5c81a7">
																				</font>
																		</b>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="1">
						<span class="atitle">JSTL 1.0</span>
				</a>
		</p>
		<p>JSTL 1.0 发布于 2002 年 6 月，由四个定制标记库（ <code>core</code> 、 <code>format</code> 、 <code>xml</code> 和 <code>sql</code> ）和一对通用标记库验证器（ <code>ScriptFreeTLV</code> 和 <code>PermittedTaglibsTLV</code> ）组成。 <code>core</code> 标记库提供了定制操作，通过限制了作用域的变量管理数据，以及执行页面内容的迭代和条件操作。它还提供了用来生成和操作 URL 的标记。顾名思义， <code>format</code> 标记库定义了用来格式化数据（尤其是数字和日期）的操作。它还支持使用本地化资源束进行 JSP 页面的国际化。 <code>xml</code> 库包含一些标记，这些标记用来操作通过 XML 表示的数据，而 <code>sql</code> 库定义了用来查询关系数据库的操作。 </p>
		<p>两个 JSTL 标记库验证器允许开发人员在其 JSP 应用程序中强制使用编码标准。可以配置 <code>ScriptFreeTLV</code> 验证器以在 JSP 页面中禁用各种类型的 JSP 脚本元素 ― scriptlet、表达式和声明。类似地， <code>PermittedTaglibsTLV</code> 验证器可以用来限制可能由应用程序的 JSP 页面访问的定制标记库集（包括 JSTL 标记库）。 </p>
		<p>尽管 JSTL 最终将会成为 J2EE 平台的必需组件，但目前只有少数应用程序服务器包括它。JSTL 1.0 的参考实现可作为 Apache 软件基金会（Apache Software Foundation）的 Jakarta Taglibs 项目（请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-jstl0211/index.html?ca=j-t10#resources"><font color="#5c81a7">参考资料</font></a>）的一部分而获得。可以将该参考实现中的定制标记库合并到任何支持 JSP 1.2 和 Servlet 2.3 规范的服务器，以添加对 JSTL 的支持。 </p>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" />
										<br />
										<img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" />
								</td>
						</tr>
				</tbody>
		</table>
		<table class="no-print" cellspacing="0" cellpadding="0" align="right">
				<tbody>
						<tr align="right">
								<td>
										<img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
										<br />
										<table cellspacing="0" cellpadding="0" border="0">
												<tbody>
														<tr>
																<td valign="center">
																		<br />
																</td>
																<td valign="top" align="right">
																		<a class="fbox" href="http://www.ibm.com/developerworks/cn/java/j-jstl0211/index.html?ca=j-t10#main">
																				<b>
																						<font color="#5c81a7">
																						</font>
																				</b>
																		</a>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="2">
						<span class="atitle">表达式语言</span>
				</a>
		</p>
		<p>在 JSP 1.2 中，可以使用静态字符串或表达式（如果允许的话）指定 JSP 操作的属性。例如，在清单 2 中，对 <code>&lt;jsp:setProperty&gt;</code> 操作的 <code>name</code> 和 <code>property</code> 属性指定了静态值，而用表达式指定了其 <code>value</code> 属性。这个操作的效果是将请求参数的当前值赋予命名的 bean 特性。以这种形式使用的表达式被称为 <i>请求时属性值（request-time attribute value）</i>，这是构建到 JSP 规范中的用于动态指定属性值的唯一机制。 </p>
		<br />
		<br />
		<a name="IDAHFSVB">
				<b>清单 2. 合并请求时属性值的 JSP 操作</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;jsp:setProperty name="user" property="timezonePref"
                 value='&lt;%= request.getParameter("timezone") %&gt;'/&gt;
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>因为请求时属性值是用表达式指定的，所以它们往往有和其它脚本元素一样的软件维护问题。因此，JSTL 定制标记支持另一种用于指定动态属性值的机制。可以用简化的 <i>表达式语言</i>（EL）而不使用完整的 JSP 表达式来指定 JSTL 操作的属性值。EL 提供了一些标识符、存取器和运算符，用来检索和操作驻留在 JSP 容器中的数据。EL 在某种程度上以 EcmaScript（请参阅 <a href="http://www.ibm.com/developerworks/cn/java/j-jstl0211/index.html?ca=j-t10#resources"><font color="#5c81a7">参考资料</font></a>）和 XML 路径语言（XML Path Language，XPath）为基础，因此页面设计人员和程序员都应该熟悉它的语法。EL 擅长寻找对象及其特性，然后对它们执行简单操作；它不是编程语言，甚至不是脚本编制语言。但是，与 JSTL 标记一起使用时，它就能使用简单而又方便的符号来表示复杂的行为。EL 表达式的格式是这样的：用美元符号（$）定界，内容包括在花括号（{}）中，如清单 3 所示。 </p>
		<br />
		<br />
		<a name="IDAYFSVB">
				<b>清单 3. 说明 EL 表达式定界符的 JSTL 操作</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;c:out value="${user.firstName}"/&gt;
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>此外，您可以将多个表达式与静态文本组合在一起以通过字符串并置来构造动态属性值，如清单 4 所示。单独的表达式由标识符、存取器、文字和运算符组成。标识符用来引用存储在数据中心中的数据对象。EL 有 11 个保留标识符，对应于 11 个 EL 隐式对象。假定所有其它标识符都引用 <i>限制了作用域的变量</i>。存取器用来检索对象的特性或集合的元素。文字表示固定的值 ― 数字、字符、字符串、布尔型或空值。运算符允许对数据和文字进行组合以及比较。 </p>
		<br />
		<br />
		<a name="IDAHGSVB">
				<b>清单 4. 组合静态文本和多个 EL 表达式以指定动态属性值</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;c:out value="Hello ${user.firstName} ${user.lastName}"/&gt;
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="3">
						<span class="atitle">限制了作用域的变量</span>
				</a>
		</p>
		<p>JSP API 通过 <code>&lt;jsp:useBean&gt;</code> 操作允许从 JSP 容器内的四个不同作用域中存储和检索数据。JSTL 通过提供用于指定和除去这些作用域中的对象的附加操作来扩展这一能力。此外，EL 提供将这些对象作为限制了作用域的变量进行检索的内置支持。特别地，任何出现在 EL 表达式中但不对应于任何 EL 隐式对象的标识符，都被自动假定为引用存储在四个 JSP 作用域的其中某个中的对象，这四个作用域是： </p>
		<ul>
				<li>页面作用域 
</li>
				<li>请求作用域 
</li>
				<li>会话作用域 
</li>
				<li>应用程序作用域 </li>
		</ul>
		<p>您可能还记得，只有在为特定请求处理页面期间才能检索存储在该页面作用域中的对象。如果对象是存储在请求作用域中的，可以在处理所有参与处理某请求的页面期间检索这些对象（譬如在对某个请求的处理中遇到了一个或多个 <code>&lt;jsp:include&gt;</code> 或 <code>&lt;jsp:forward&gt;</code> 操作）。如果对象是存储在会话作用域中的，则在与 Web 应用程序的交互式会话期间，可以由用户访问的任何页面检索它（即，直到与该用户交互相关联的 <code>HttpSession</code> 对象无效为止）。可以由任何用户从任何页面访问存储在应用程序作用域中的对象，直到卸载 Web 应用程序本身为止（通常是由于关闭 JSP 容器所致）。 </p>
		<p>通过将字符串映射为期望作用域中的对象来将对象存储到该作用域。然后，就可以通过提供相同字符串来从该作用域检索该对象。在作用域的映射中查找字符串，并返回被映射的对象。在 Servlet API 中，将此类对象称为相应作用域的 <i>属性</i>。但是，在 EL 的上下文中，也将与属性相关联的字符串看作变量的名称，该变量通过属性映射的方式获得特定的值。 </p>
		<p>在 EL 中，与隐式对象无关联的标识符被认为是存储在四个 JSP 作用域中的名称对象。首先对页面作用域检查是否存在这样的标识符，其次对请求作用域、然后对会话作用域、最后对应用程序作用域依次进行这样的检查，然后测试该标识符的名称是否与存储在该作用域中的某个对象的名称匹配。第一个这样的匹配作为 EL 标识符的值被返回。通过这种方法，可以将 EL 标识符看作引用限制了作用域的变量。</p>
		<p>从更技术的方面来说，没有映射到隐式对象的标识符是用 <code>PageContext</code> 实例的 <code>findAttribute()</code> 方法求值的，该实例表示对页面的处理，在该页面上，当前正在处理用于请求的表达式。标识符的名称作为参数传递给这个方法，然后该方法依次在四个作用域中搜索具有相同名称的属性。并将所找到的第一个匹配项作为 <code>findAttribute()</code> 方法的值返回。如果未在这四个作用域中找到这样的属性，则返回 <code>null</code> 。 </p>
		<p>最终，限制了作用域的变量是四个 JSP 作用域的属性，这些属性具有可以用作 EL 标识符的名称。只要对限制了作用域的变量赋予由字母数字组成的名称，就可以通过 JSP 中提供的用于设置属性的任何机制来创建它们。这包括内置的 <code>&lt;jsp:useBean&gt;</code> 操作，以及由 Servlet API 中的几个类定义的 <code>setAttribute()</code> 方法。此外，四个 JSTL 库中定义的许多定制标记本身就能够设置作为限制了作用域的变量使用的属性值。 </p>
		<p>
				<a name="4">
						<span class="atitle">隐式对象</span>
				</a>
		</p>
		<p>表 1 中列出了 11 个 EL 隐式对象的标识符。不要将这些对象与 JSP 隐式对象（一共只有九个）混淆，其中只有一个对象是它们所共有的。</p>
		<p>
				<a name="N10148">
						<span class="smalltitle">
								<strong>
										<font face="Arial">表 1. EL 隐式对象</font>
								</strong>
						</span>
				</a>
		</p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="3" width="100%" border="1">
				<tbody>
						<tr valign="top">
								<td>
										<strong>类别</strong>
								</td>
								<td>
										<b>标识符</b>
								</td>
								<td>
										<b>描述</b>
								</td>
						</tr>
						<tr valign="top">
								<td>JSP</td>
								<td>
										<code>pageContext</code>
								</td>
								<td>
										<code>PageContext</code> 实例对应于当前页面的处理 </td>
						</tr>
						<tr valign="top">
								<td rowspan="4">作用域</td>
								<td>
										<code>pageScope</code>
								</td>
								<td>与页面作用域属性的名称和值相关联的 <code>Map</code> 类 </td>
						</tr>
						<tr valign="top">
								<td>
										<code>requestScope</code>
								</td>
								<td>与请求作用域属性的名称和值相关联的 <code>Map</code> 类 </td>
						</tr>
						<tr valign="top">
								<td>
										<code>sessionScope</code>
								</td>
								<td>与会话作用域属性的名称和值相关联的 <code>Map</code> 类 </td>
						</tr>
						<tr valign="top">
								<td>
										<code>applicationScope</code>
								</td>
								<td>与应用程序作用域属性的名称和值相关联的 <code>Map</code> 类 </td>
						</tr>
						<tr valign="top">
								<td rowspan="2">请求参数</td>
								<td>
										<code>param</code>
								</td>
								<td>按名称存储请求参数的主要值的 <code>Map</code> 类 </td>
						</tr>
						<tr valign="top">
								<td>
										<code>paramValues</code>
								</td>
								<td>将请求参数的所有值作为 <code>String</code> 数组存储的 <code>Map</code> 类 </td>
						</tr>
						<tr valign="top">
								<td rowspan="2">请求头</td>
								<td>
										<code>header</code>
								</td>
								<td>按名称存储请求头主要值的 <code>Map</code> 类 </td>
						</tr>
						<tr valign="top">
								<td>
										<code>headerValues</code>
								</td>
								<td>将请求头的所有值作为 <code>String</code> 数组存储的 <code>Map</code> 类 </td>
						</tr>
						<tr valign="top">
								<td>Cookie</td>
								<td>
										<code>cookie</code>
								</td>
								<td>按名称存储请求附带的 cookie 的 <code>Map</code> 类 </td>
						</tr>
						<tr valign="top">
								<td>初始化参数</td>
								<td>
										<code>initParam</code>
								</td>
								<td>按名称存储 Web 应用程序上下文初始化参数的 <code>Map</code> 类 </td>
						</tr>
				</tbody>
		</table>
		<p>尽管 JSP 和 EL 隐式对象中只有一个公共对象（ <code>pageContext</code> ），但通过 EL 也可以访问其它 JSP 隐式对象。原因是 <code>pageContext</code> 拥有访问所有其它八个 JSP 隐式对象的特性。实际上，这是将它包括在 EL 隐式对象中的主要理由。 </p>
		<p>其余所有 EL 隐式对象都是映射，可以用来查找对应于名称的对象。前四个映射表示先前讨论的各种属性作用域。可以用它们来查找特定作用域中的标识符，而不用依赖于 EL 在缺省情况下使用的顺序查找过程。</p>
		<p>接下来的四个映射用来获取请求参数和请求头的值。因为 HTTP 协议允许请求参数和请求头具有多个值，所以它们各有一对映射。每对中的第一个映射返回请求参数或头的主要值，通常是恰巧在实际请求中首先指定的那个值。每对中第二个映射允许检索参数或头的所有值。这些映射中的键是参数或头的名称，但这些值是 <code>String</code> 对象的数组，其中的每个元素都是单一参数值或头值。 </p>
		<p>cookie 隐式对象提供了对由请求设置的 cookie 名称的访问。这个对象将所有与请求相关联的 cookie 名称映射到表示那些 cookie 特性的 <code>Cookie</code> 对象。 </p>
		<p>最后一个 EL 隐式对象 <code>initParam</code> 是一个映射，它储存与 Web 应用程序相关联的所有上下文的初始化参数的名称和值。初始化参数是通过 <code>web.xml</code> 部署描述符文件指定的，该文件位于应用程序的 <code>WEB-INF</code> 目录中。 </p>
		<br />
		<p>
				<a name="5">
						<span class="atitle">存取器</span>
				</a>
		</p>
		<p>因为 EL 标识符是作为隐式对象或限制了作用域的变量（通过属性来实现）解析的，因此有必要将它们转换成 Java 对象。EL 可以自动包装和解包其相应的 Java 类中的基本类型（例如，可以在后台将 <code>int</code> 强制转换成 <code>Integer</code> 类，反之亦可），但大多数的标识符将成为指向完整的 Java 对象的指针。 </p>
		<p>结果是，对这些对象的特性或（在对象是数组和集合的情况下）对其元素的访问通常是令人满意的。就为了实现这种用途，EL 提供了两种不同的存取器（点运算符（ <code>.</code> ）和方括号运算符（ <code>[]</code> ）），也支持通过 EL 操作特性和元素。 </p>
		<p>点运算符通常用于访问对象的特性。例如，在表达式 <code>${user.firstName}</code> 中，使用点运算符来访问 <code>user</code> 标识符所引用对象的名为 <code>firstName</code> 的特性。EL 使用 Java bean 约定访问对象特性，因此必须定义这个特性的 getter 方法（通常是名为 <code>getFirstName()</code> 的方法），以便表达式正确求值。当被访问的特性本身是对象时，可以递归地应用点运算符。例如，如果我们虚构的 <code>user</code> 对象有一个实现为 Java 对象的 <code>address</code> 特性，那么也可以用点运算符来访问这个对象的特性。例如，表达式 <code>${user.address.city}</code> 将会返回这个地址对象嵌套的 <code>city</code> 特性。 </p>
		<p>方括号运算符用来检索数组和集合的元素。在数组和有序集合（也即，实现了 <code>java.util.List</code> 接口的集合）的情况下，把要检索的元素的下标放在方括号中。例如，表达式 <code>${urls[3]}</code> 返回 <code>urls</code> 标识符所引用的数组或集合的第四个元素（和 Java 语言以及 JavaScript 中一样，EL 中的下标是从零开始的）。 </p>
		<p>对于实现 <code>java.util.Map</code> 接口的集合，方括号运算符使用关联的键查找存储在映射中的值。在方括号中指定键，并将相应的值作为表达式的值返回。例如，表达式 <code>${commands["dir"]}</code> 返回与 <code>commands</code> 标识符所引用的 <code>Map</code> 中的 <code>"dir"</code> 键相关联的值。 </p>
		<p>对于上述两种情况，都可允许表达式出现在方括号中。对嵌套表达式求值的结果将被作为下标或键，用来检索集合或数组的适当元素。和点运算符一样，方括号运算符也可以递归应用。这使得 EL 能够从多维数组、嵌套集合或两者的任意组合中检索元素。此外，点运算符和方括号运算符还可以互操作。例如，如果数组的元素本身是对象，则可以使用方括号运算符来检索该数组的元素，并结合点运算符来检索该元素的一个特性（例如 <code>${urls[3].protocol}</code> ）。 </p>
		<p>假定 EL 充当指定动态属性值的简化语言，EL 存取器有一个有趣的功能（与 Java 语言的存取器不同），那就是它们在应用于 <code>null</code> 时不抛出异常。如果应用 EL 存取器的对象（例如， <code>${foo.bar}</code> 和 <code>${foo["bar"]}</code> 中的 <code>foo</code> 标识符）是 <code>null</code> ，那么应用存取器的结果也是 <code>null</code> 。事实证明，在大多数情况下，这是一个相当有用的行为，不久您就会了解这一点。 </p>
		<p>最后，点运算符和方括号运算符可能实现某种程度的互换。例如，也可以使用 <code>${user["firstName"]}</code> 来检索 <code>user</code> 对象的 <code>firstName</code> 特性，正如可以用 <code>${commands.dir}</code> 获取与 <code>commands</code> 映射中的 <code>"dir"</code> 键相关联的值一样。 </p>
		<br />
		<p>
				<a name="6">
						<span class="atitle">运算符</span>
				</a>
		</p>
		<p>EL 还可以通过使用标识符和存取器，遍历包含应用程序数据（通过限制了作用域的变量公开）或关于环境的信息（通过 EL 隐式对象）的对象层次结构。但是，只是访问这些数据，通常不足以实现许多 JSP 应用程序所需的表示逻辑。</p>
		<p>最终，EL 还包括了几个用来操作和比较 EL 表达式所访问数据的运算符。表 2 中汇总了这些运算符。</p>
		<p>
				<a name="N1032A">
						<span class="smalltitle">
								<strong>
										<font face="Arial">表 2. EL 运算符</font>
								</strong>
						</span>
				</a>
		</p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="3" width="100%" border="1">
				<tbody>
						<tr valign="top">
								<td>
										<strong>类别</strong>
								</td>
								<td>
										<b>运算符</b>
								</td>
						</tr>
						<tr valign="top">
								<td>算术运算符</td>
								<td>
										<code>+</code> 、 <code>-</code> 、 <code>*</code> 、 <code>/</code> （或 <code>div</code> ）和 <code>%</code> （或 <code>mod</code> ） </td>
						</tr>
						<tr valign="top">
								<td>关系运算符</td>
								<td>
										<code>==</code> （或 <code>eq</code> ）、 <code>!=</code> （或 <code>ne</code> ）、 <code>&lt;</code> （或 <code>lt</code> ）、 <code>&gt;</code> （或 <code>gt</code> ）、 <code>&lt;=</code> （或 <code>le</code> ）和 <code>&gt;=</code> （或 <code>ge</code> ） </td>
						</tr>
						<tr valign="top">
								<td>逻辑运算符</td>
								<td>
										<code>&amp;&amp;</code> （或 <code>and</code> ）、 <code>||</code> （或 <code>or</code> ）和 <code>!</code> （或 <code>not</code> ） </td>
						</tr>
						<tr valign="top">
								<td>验证运算符</td>
								<td>
										<code>empty</code>
								</td>
						</tr>
				</tbody>
		</table>
		<p>算术运算符支持数值的加法、减法、乘法和除法。还提供了一个求余运算符。注：除法和求余运算符都有替代的、非符号的名称（为的是与 XPath 保持一致）。清单 5 中显示了一个演示算术运算符用法的示例表达式。对几个 EL 表达式应用算术运算符的结果是将该算术运算符应用于这些表达式返回的数值所得的结果。</p>
		<br />
		<br />
		<a name="IDAD5SVB">
				<b>清单 5. 利用算术运算符的 EL 表达式</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">${item.price * (1 + taxRate[user.address.zipcode])}
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>关系运算符允许比较数字或文本数据。比较的结果作为布尔值返回。逻辑运算符允许合并布尔值，返回新的布尔值。因此，可以将 EL 逻辑运算符应用于嵌套的关系或逻辑运算符的结果，如清单 6 所示。</p>
		<br />
		<br />
		<a name="IDAO5SVB">
				<b>清单 6. 利用关系和逻辑运算符的 EL 表达式</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">${(x &gt;= min) &amp;&amp; (x &lt;= max)}
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>最后一种 EL 运算符是 <code>empty</code> ，它对于验证数据特别有用。 <code>empty</code> 运算符采用单个表达式作为其变量（也即， <code>${empty input}</code> ），并返回一个布尔值，该布尔值表示对表达式求值的结果是不是“空”值。求值结果为 <code>null</code> 的表达式被认为是空，即无元素的集合或数组。如果参数是对长度为零的 <code>String</code> 求值所得的结果，则 <code>empty</code> 运算符也将返回 <code>true</code> 。 </p>
		<p>表 3 显示了 EL 运算符的优先级。正如清单 5 和 6 所示，可以用圆括号对表达式分组，高于普通的优先级规则。</p>
		<p>
				<a name="N10416">
						<span class="smalltitle">
								<strong>
										<font face="Arial">表 3. EL 运算符优先级（自顶到底，从左到右）</font>
								</strong>
						</span>
				</a>
		</p>
		<p>
		</p>
		<table cellspacing="0" cellpadding="3" width="100%" border="1">
				<tbody>
						<tr valign="top">
								<td>
										<code>[]</code> , <code>.</code></td>
						</tr>
						<tr valign="top">
								<td>
										<code>()</code>
								</td>
						</tr>
						<tr valign="top">
								<td>unary <code>-</code> 、 <code>not</code> 、 <code>!</code> 、 <code>empty</code></td>
						</tr>
						<tr valign="top">
								<td>
										<code>*</code> 、 <code>/</code> 、 <code>div</code> 、 <code>%</code> 、 <code>mod</code></td>
						</tr>
						<tr valign="top">
								<td>
										<code>+</code> 、binary <code>-</code></td>
						</tr>
						<tr valign="top">
								<td>() <code>&lt;&lt;/code&gt;</code> 、 <code>&gt;</code> 、 <code>&lt;=</code> 、 <code>&gt;=</code> 、 <code>lt</code> 、 <code>gt</code> 、 <code>le</code> 、 <code>ge</code></td>
						</tr>
						<tr valign="top">
								<td>
										<code>==</code> 、 <code>!=</code> 、 <code>eq</code> 、 <code>ne</code></td>
						</tr>
						<tr valign="top">
								<td>
										<code>&amp;&amp;</code> 、 <code>and</code></td>
						</tr>
						<tr valign="top">
								<td>
										<code>||</code> 、 <code>or</code></td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="7">
						<span class="atitle">文字</span>
				</a>
		</p>
		<p>在 EL 表达式中，数字、字符串、布尔值和 <code>null</code> 都可以被指定为文字值。字符串可以用单引号或双引号定界。布尔值被指定为 <code>true</code> 和 <code>false</code> 。 </p>
		<br />
		<p>
				<a name="8">
						<span class="atitle">Taglib 伪指令</span>
				</a>
		</p>
		<p>正如我们先前讨论的，JSTL 1.0 包括四个定制标记库。为了演示 JSTL 标记和表达式语言的交互，我们将研究几个来自 JSTL <code>core</code> 库的标记。和使用任何 JSP 定制标记库一样，必须在您想要使用这个库标记的任何页面中包括 <code>taglib</code> 伪指令。清单 7 显示了用于这个特定库的伪指令。 </p>
		<br />
		<br />
		<a name="IDAFCTVB">
				<b>清单 7. 用于 JSTL core 库 EL 版本的 taglib 伪指令</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %&gt;
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>实际上，对应于 JSTL <code>core</code> 库的 <code>taglib</code> 伪指令有两种，因为在 JSTL 1.0 中，EL 是可选的。所有四个 JSTL 1.0 定制标记库都有使用 JSP 表达式（而不是 EL）指定动态属性值的备用版本。因为这些备用库依赖于 JSP 的更传统的请求时属性值，所以它们被称为 <i>RT</i>库，而那些使用表达式语言的则被称为 <i>EL</i> 库。开发人员用不同的 <code>taglib</code> 伪指令来区分每个库的这两个版本。清单 8 显示了使用 core 库的 RT 版本的伪指令。但是，由于现在我们讨论的重点是 EL，所以首先需要这些伪指令。 </p>
		<br />
		<br />
		<a name="IDAADTVB">
				<b>清单 8. 用于 JSTL core 库 RT 版本的 taglib 伪指令</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c_rt" %&gt;
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="9">
						<span class="atitle">变量标记</span>
				</a>
		</p>
		<p>我们首先要考虑的 JSTL 定制标记是 <code>&lt;c:set&gt;</code> 操作。正如已经说明的，限制了作用域的变量在 JSTL 中起关键作用， <code>&lt;c:set&gt;</code> 操作提供基于标记的机制来创建和设置限制了作用域的变量。清单 9 中显示了该操作的语法，其中 <code>var</code> 属性指定了限制了作用域的变量的名称， <code>scope</code> 属性表明了该变量驻留在哪个作用域中， <code>value</code> 属性指定了分配给该变量的值。如果指定变量已经存在，则简单地将所指明的值赋给它。如果不存在，则创建新的限制了作用域的变量，并用该值初始化这个变量。 </p>
		<br />
		<br />
		<a name="IDAHETVB">
				<b>清单 9. &lt;c:set&gt; 操作的语法</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;c:set var="
        <i>name</i>" scope="
        <i>scope</i>" value="
        <i>expression</i>"/&gt;
      </pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<code>scope</code> 属性是可选的，其缺省值是 <code>page</code> 。 </p>
		<p>清单 10 中显示了 <code>&lt;c:set&gt;</code> 的两个示例。在第一个示例中，将会话作用域变量设置成 <code>String</code> 值。在第二个示例中，用表达式来设置数值：将页面作用域内名为 <code>square</code> 的变量赋值为名为 <code>x</code> 的请求参数的值的平方。 </p>
		<br />
		<br />
		<a name="IDARFTVB">
				<b>清单 10. &lt;c:set&gt; 操作示例</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;c:set var="timezone" scope="session" value="CST"/&gt;
&lt;c:set var="square" value="${param['x'] * param['x']}"/&gt;
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>您还可以将限制了作用域的变量的值指定为 <code>&lt;c:set&gt;</code> 操作的主体内容，而不是使用属性。使用这种方法，您可以重新编写清单 10 中的第一个示例，如清单 11 所示。此外，正如我们马上可以看到的， <code>&lt;c:set&gt;</code> 标记的主体内容本身也可以使用定制标记。 <code>&lt;c:set&gt;</code> 主体内生成的所有内容都将作为一个 <code>String</code> 值赋给指定变量。 </p>
		<br />
		<br />
		<a name="listing11">
				<b>清单 11. 通过主体内容指定 &lt;c:set&gt; 操作的值</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;c:set var="timezone" scope="session"&gt;CST&lt;/c:set&gt;
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>JSTL core 库包含第二个用于管理限制了作用域的变量的标记 ― <code>&lt;c:remove&gt;</code> 。顾名思义， <code>&lt;c:remove&gt;</code> 操作是用来删除限制了作用域的变量的，它获取两个属性。 <code>var</code> 属性指定待删除变量的名称， <code>scope</code> 属性是可选的，它表示待删除变量来自哪个作用域，缺省为 <code>page</code> ，如清单 12 所示。 </p>
		<a name="IDALHTVB">
				<b>清单 12. &lt;c:remove&gt; 操作示例</b>
		</a>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;c:remove var="timezone" scope="session"/&gt;
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<a name="10">
						<span class="atitle">输出</span>
				</a>
		</p>
		<p>尽管 <code>&lt;c:set&gt;</code> 操作允许将表达式结果赋给限制了作用域的变量，但开发人员通常会希望只显示表达式的值，而不存储它。JSTL <code>&lt;c:out&gt;</code> 定制标记承担这一任务，其语法如清单 13 所示。该标记对由其 <code>value</code> 属性指定的表达式进行求值，然后打印结果。如果指定了可选属性 <code>default</code> ，那么，在对 <code>value</code> 属性的表达式求值所得结果为 <code>null</code> 或空 <code>String</code> 的情况下， <code>&lt;c:out&gt;</code> 将打印其值。 </p>
		<br />
		<br />
		<a name="IDABJTVB">
				<b>清单 13. &lt;c:out&gt; 操作的语法</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;c:out value="
        <i>expression</i>" default="
        <i>expression</i>" escapeXml="
        <i>boolean</i>"/&gt;
      </pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<code>escapeXml</code> 属性也是可选的。它控制当用 <code>&lt;c:out&gt;</code> 标记输出诸如“&lt;”、“&gt;”和“&amp;”之类的字符（在 HTML 和 XML 中具有特殊意义）时是否应该进行转义。如果将 <code>escapeXml</code> 设置为 true，则会自动将这些字符转换成相应的 XML 实体（此处提到的字符分别转换成 <code>&lt;</code> 、 <code>&gt;</code> 和 <code>&amp;</code> ）。 </p>
		<p>例如，假定有一个名为 <code>user</code> 的会话作用域变量，它是一个类的实例，该类为用户定义了两个特性： <code>username</code> 和 <code>company</code> 。每当用户访问站点时，这个对象被自动分配给会话，但直到用户实际登录后，才会设置这两个特性。假定是这种方案，请考虑清单 14 中的 JSP 片段。在用户登录之后，这个片段将显示单词“Hello”，其后是他／她的用户名和一个惊叹号。但是，在用户登录之前，由这个片段生成的内容则是短语“Hello Guest!”。在这种情况下，因为 <code>username</code> 特性还有待初始化，所以 <code>&lt;c:out&gt;</code> 标记将转而打印出 <code>default</code> 属性的值（即字符串“Guest”）。 </p>
		<br />
		<br />
		<a name="IDADLTVB">
				<b>清单 14. 带缺省内容的 &lt;c:out&gt; 操作示例</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">Hello &lt;c:out value="${user.username}" default=="Guest"/&gt;!
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>接下来，考虑清单 15，它使用了 <code>&lt;c:out&gt;</code> 标记的 <code>escapeXml</code> 属性。如果在这种情况下已经将 <code>company</code> 特性设置成 Java <code>String</code> 值 <code>"Flynn &amp; Sons"</code> ，那么，实际上该操作生成的内容将是 <code>Flynn &amp; Sons</code> 。如果这个操作是生成 HTML 或 XML 内容的 JSP 页面的一部分，那么，这个字符串中间的“&amp;”符号最终可能被解释为 HTML 或 XML 控制字符，从而妨碍了对该内容的显示或解析。但是，如果将 <code>escapeXml</code> 属性值设置成 <code>true</code> ，则所生成的内容将是 <code>Flynn &amp; Sons</code> 。浏览器或解析器不会因在解释时遇到这种内容而出问题。假定 HTML 和 XML 是 JSP 应用程序中最常见的内容类型，所以 <code>escapeXml</code> 属性的缺省值是 <code>true</code> 就不足为奇了。 </p>
		<br />
		<br />
		<a name="IDA0MTVB">
				<b>清单 15. 禁用转义的 &lt;c:out&gt; 操作示例</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;c:out value="${user.company}" escapeXml=="false"/&gt;
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<br />
		<br />
		<br />
		<p>
				<a name="11">
						<span class="atitle">用缺省值设置变量</span>
				</a>
		</p>
		<p>除了简化动态数据的显示之外，当通过 <code>&lt;c:set&gt;</code> 设置变量值时， <code>&lt;c:out&gt;</code> 指定缺省值的能力也很有用。正如 <a href="http://www.ibm.com/developerworks/cn/java/j-jstl0211/index.html?ca=j-t10#listing11"><font color="#5c81a7">清单 11</font></a> 所示，用来赋给限制了作用域的变量的值可以指定为 <code>&lt;c:set&gt;</code> 标记的主体内容，也可以通过其值属性来指定。通过将 <code>&lt;c:out&gt;</code> 操作嵌套在 <code>&lt;c:set&gt;</code> 标记的主体内容中，变量赋值就可以利用其缺省值能力。 </p>
		<p>清单 16 中说明了这种方法。外部 <code>&lt;c:set&gt;</code> 标记的行为非常简单：它根据其主体内容设置会话作用域 <code>timezone</code> 变量的值。但是，在这种情况下，主体内容是通过 <code>&lt;c:out&gt;</code> 操作生成的。这个嵌套操作的值属性是表达式 <code>${cookie['tzPref'].value}</code> ，它尝试通过 <code>cookie</code> 隐式对象返回名为 <code>tzPref</code> 的 cookie 值。（ <code>cookie</code> 隐式对象将 cookie 名称映射到相应的 <code>Cookie</code> 实例，这意味着必须通过对象的 <code>value</code> 特性使用点运算符来检索储存在 cookie 中的实际数据。） </p>
		<br />
		<br />
		<a name="IDAKPTVB">
				<b>清单 16. 合并 &lt;c:set&gt; 和 &lt;c:out&gt; 以提供缺省变量值</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;c:set var="timezone" scope=="session"&gt;
   &lt;c:out value="${cookie['tzPref'].value}" default=="CST"/&gt;
&lt;/c:set&gt;
</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>但是，请考虑以下情况，用户是第一次尝试使用这段代码的 Web 应用程序。结果是，请求中没有提供名为 <code>tzPref</code> 的 cookie。这意味着使用隐式对象的查找将返回 <code>null</code> ，在这种情况下整个表达式将返回 <code>null</code> 。因为对 <code>&lt;c:out&gt;</code> 标记的 <code>value</code> 属性求值的结果是 <code>null</code> ，所以 <code>&lt;c:out&gt;</code> 标记会转而输出对其 <code>default</code> 属性求值的结果。在这里是字符串 <code>CST</code> 。因此，实际的结果是将 <code>timezone</code> 限制了作用域的变量设置成用户的 <code>tzPref</code> cookie 中存储的时区，或者，如果没有，则使用缺省时区 <code>CST</code> 。 </p>
		<table cellspacing="0" cellpadding="0" width="40%" align="right" border="0">
				<tbody>
						<tr>
								<td width="10">
										<img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" />
								</td>
								<td>
										<table cellspacing="0" cellpadding="5" width="100%" border="1">
												<tbody>
														<tr>
																<td bgcolor="#eeeeee">
																		<a name="IDAFRTVB">
																				<b>EL 和 JSP 2.0</b>
																		</a>
																		<br />
																		<p>目前，表达式语言仅可用于指定 JSTL 定制标记中的动态属性值。但 JSTL 1.0 表达式语言的一个扩展已经被提出，会把它包括到 JSP 2.0 中去，眼下正在进行最后评审。这个扩展将允许开发人员通过自己的定制标记来使用 EL。页面作者将可以在目前允许使用 JSP 表达式的任何地方使用 EL 表达式，譬如将动态值插入模板文本中： <code>&lt;p&gt;Your preferred time zone is ${timezone}&lt;/p&gt;</code> 。 </p>
																		<p>这个 JSP 2.0 功能（就象 JSTL 本身一样）将支持页面作者进一步减少对 JSP 编制脚本元素的依赖，从而改进 JSP 应用程序的可维护性。 </p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>
				<a name="12">
						<span class="atitle">结束语</span>
				</a>
		</p>
		<p>EL（与四个 JSTL 定制标记库提供的操作结合起来）允许页面作者不使用脚本元素即可实现表示层逻辑。例如，对比本文开头 <a href="http://www.ibm.com/developerworks/cn/java/j-jstl0211/index.html?ca=j-t10#listing1"><font color="#5c81a7">清单 1</font></a> 中的 JSP 代码和清单 17 中显示的通过 JSTL 实现的同样功能。（JSTL <code>core</code> 库中其余的标记，包括 <code>&lt;c:choose&gt;</code> 及其子标记，将在本系列的下一篇文章中讨论。）尽管显然执行了条件逻辑，但是 JSTL 版本中没有 Java 语言源代码，并且标记之间的关系（尤其是关于嵌套需求）对于任何精通 HTML 语法的人都应该是熟悉的。 </p>
		<br />
		<br />
		<a name="IDAISTVB">
				<b>清单 17. 合并 &lt;c:set&gt; 和 &lt;c:out&gt; 以提供缺省变量值</b>
		</a>
		<br />
		<table cellspacing="0" cellpadding="0" width="400" border="0">
				<tbody>
						<tr>
								<td class="code-outline">
										<pre class="displaycode">&lt;c:choose&gt;&lt;c:when test="${user.role == 'member'}"&gt;
    &lt;p&gt;Welcome, member!&lt;/p&gt;
  &lt;/c:when&gt;&lt;c:otherwise&gt;
    &lt;p&gt;Welcome, guest!&lt;/p&gt;
  &lt;/c:otherwise&gt;&lt;/c:choose&gt;</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<p>通过提供大多数 Web 应用程序常用功能的标准实现，JSTL 有助于加速开发周期。与 EL 结合起来，JSTL 可以不需要对表示层程序编写代码，这极大地简化了 JSP 应用程序的维护。</p>
		<br />
		<br />
		<p>
				<a name="resources">
						<span class="atitle">参考资料 </span>
				</a>
		</p>
		<ul>
				<li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/library/j-jstl0211.html?S_TACT=105AGX52&amp;S_CMP=cn-a-j"><font color="#5c81a7">英文原文</font></a>. <br /><br /></li>
				<li>Sun 的 <a href="http://java.sun.com/products/jsp/jstl/index.html"><font color="#5c81a7">JSP 标准标记库主页</font></a>是了解关于 JSTL 的更多信息的良好起点。 <br /><br /><br /></li>
				<li>
						<a href="http://jcp.org/aboutJava/communityprocess/final/jsr052/">
								<font color="#5c81a7">JSTL 1.0 规范</font>
						</a>是关于 EL 和四个 JSTL 标记库的最终权威文本。 <br /><br /><br /></li>
				<li>
						<a href="http://jakarta.apache.org/taglibs/index.html">
								<font color="#5c81a7">Jakarta Taglibs</font>
						</a>项目是 JSTL 1.0 参考实现的起源。 <br /><br /><br /></li>
				<li>Shawn Bayern 所著的 <a href="http://www.manning.com/bayern/index.html"><font color="#5c81a7"><i>JSTL in Action</i></font></a>（Manning Publications Co.，2002 年）提供了对所有 JSTL 功能的精彩论述，作者是该参考实现的领导。 <br /><br /><br /></li>
				<li>David Geary 是 Java 技术方面很受欢迎的作者，他也写了一本关于 JSTL 的书，书名是 <a href="http://www.amazon.com/exec/obidos/tg/detail/-/0131001531/103-4207394-1320606?vi=glance"><font color="#5c81a7"><i>Core JSTL</i></font></a>。 <br /><br /><br /></li>
				<li>
						<a href="http://jsptags.com/index.jsp">
								<font color="#5c81a7">JSPTags.com</font>
						</a>是 JSP 技术参考资料的目录，它尤其专注于定制标记库。 <br /><br /><br /></li>
				<li>Sun 的 <a href="http://java.sun.com/webservices/docs/ea2/tutorial/doc/JSTL3.html"><font color="#5c81a7">Java Web Services Tutorial</font></a>中包含了对 JSTL 的讨论。 <br /><br /><br /></li>
				<li>“ <a href="http://www7b.software.ibm.com/wsdd/library/tutorials/vajwebsph353/Part-I/JSP11Part-I.html"><font color="#5c81a7">Using JSPs and custom tags within VisualAge for Java and WebSphere Studio</font></a>”（ <a href="http://www7b.software.ibm.com/wsdd/"><font color="#5c81a7">WebSphere 开发者园地</font></a>）是一篇 WBOnline 实用论文，它演示了 servlet、JSP 和定制标记库的使用。 <br /><br /><br /></li>
				<li>通过 Jeff Wilson 精彩的文章“ <a href="http://www.ibm.com/developerworks/cn/java/j-taglib/index.html"><font color="#5c81a7">使用定制标记控制 JSP 页面</font></a>”（ <i>developerWorks</i>，2002 年 1 月）了解关于定制标记库的一切。 <br /><br /><br /></li>
				<li>Noel Bergman 的文章“ <a href="http://www.ibm.com/developerworks/cn/java/j-jsptags/index.html"><font color="#5c81a7">JSP 标记库：着意设计的更好的可用性</font></a>”（ <i>developerWorks</i>，2001 年 12 月）向您展示了声明性标记是如何帮助提高 JSP 页面的可用性的。 <br /><br /><br /></li>
				<li>有关 EcmaScript 的更多详细信息，请参阅 Sing Li 的“ <a href="http://www.ibm.com/developerworks/cn/java/j-qdjava/index.html"><font color="#5c81a7">快速上手 Java 编程</font></a>”（ <i>developerWorks</i>，2001 年 7 月）。 <br /><br /><br /></li>
				<li>在 <a href="http://www.ibm.com/developerworks/cn/java/index.html"><font color="#5c81a7"><i>developerWorks</i>Java 技术专区 </font></a>可以找到多达数百篇的 Java 技术参考资料。 <br /></li>
		</ul>
		<br />
		<br />
		<p>
				<a name="author">
						<span class="atitle">关于作者</span>
				</a>
		</p>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td colspan="3">
										<img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="100%" />
								</td>
						</tr>
						<tr valign="top" align="left">
								<td>
										<p>
										</p>
								</td>
								<td>
										<img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="4" />
								</td>
								<td width="100%">
										<p>Mark Kolb 是一名在德克萨斯州奥斯汀工作的软件工程师。他经常就服务器端 Java 主题在业界发表演讲，并且与人合著了 <a href="http://www.manning.com/fields2/index.html"><font color="#5c81a7"><i>Web Development with JavaServer Pages，第二版</i></font></a>一书。可通过 <a href="mailto:mak@taglib.com?cc=mak@taglib.com"><font color="#5c81a7">mak@taglib.com</font></a>与 Mark 联系。 </p>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
<img src ="http://www.blogjava.net/liaojiyong/aggbug/105235.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2007-03-21 12:15 <a href="http://www.blogjava.net/liaojiyong/archive/2007/03/21/105235.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编码问题（转）</title><link>http://www.blogjava.net/liaojiyong/archive/2006/12/10/86656.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Sun, 10 Dec 2006 03:46:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/12/10/86656.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/86656.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/12/10/86656.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/86656.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/86656.html</trackback:ping><description><![CDATA[今天看了子华的博客中关于昨晚我们讨论编码方面的问题，发现其中有一个关键点没有谈到。<br />    情况是这样的：我们现在使用的一个名为Notepad++的编辑器，它大体上和UltraEdit类似，是我从sourceforge上下载下载使用的。它有个格式的功能，简单而言就是设置使用ascii编码编辑文档还是使用utf-8编码，其实这里主要是对应非英文方面的字符才发生差异。<br />    如前那篇随笔所述utf-8只是用于在数据传输时将字符串分割成字节传输出去，它对于unicode编码有着严格的一一对应关系，而对于gb2312、gbk、gb18030之类的中文编码是没有对应关系的。gb2312、gbk、gb18030是在ascii编码之上进行的中文编码开发，所以它们是与ascii相兼容的，可以这么理解在我们的文本编辑器中ascii方式编辑的文本是以ascii码保存，而以utf-8方式编辑的文本是以unicode编码保存。<br />    现在，编码的差异就在这里发生了，unicode中的英文部分编码是与ascii相兼容的，具体而言是iso8859-1兼容，所以我们无论用什么编码保存方式保存jsp文件，在网页上显示的都是正确的英文字符。但是对于中文这个保存的格式却非常重要。在了解了jsp页面的显示过程我们就会明白其中的原因。<br />    现在回头来看看jsp文件是经过了哪些步骤才在网页上显示出来的。<br />    1、首先我们用编辑器编辑jsp页面代码保存；<br />    2、web服务器对其进行编译，将jsp页面编译成为一个java的class文件；<br />    3、web服务器将其class文件用传输格式在网络上传输；<br />    4、客户端浏览器解析代码生成页面。<br />    过程大致如上，能够影响编码方面的基本上在1、2、4方面，所以对其进行详细讲解。<br />    我们的编辑器是有一种默认的编码保存方式的。这会到后面java编译器是否将其中的中文进行转换的问题。大家都知道java是以十六位的unicode编码编译、存储java文件的。因为同一个汉字在unicode编码和gb2312编码中的位置是不一样的，（具体而言就是这两种编码没有兼容性，也不能通过公式换算出来，只能通过字符对应表进行转换）<br />    上面指出的保存格式的重要性就在这里体现出来了，这也是很多人容易遗漏之处，当我们用默认格式位gbk的编辑器编辑jsp页面，而在其头部声明charset＝utf－8，那么返回的页面会出现乱码，而charset＝gb2312则正常显示。本人分析原因在于，在charset＝utf－8的声明有误时，java编译器会错误的认为现在保存的文件就是以unicode编码格式保存的文件，所以在编译中就不对其中的中文字符进行gb2312－－unicode的转化，而直接将其gb2312指向的编码地址保存为unicode的编码地址。反之，当编辑器的默认编辑保存格式为utf－8时，在jsp中声明为gb2312，就会让编译器画蛇添足的多进行一次中文编码转换，从而乱码出现。<br />    综上所述，编辑器的默认编码方式是在解决中文乱码方面是很重要的一个因素，当然我们可以用pageEncoding参数来说明文本编码形式。弄清中文显示后面的具体调用过程是彻底解决该类问题的终极之道！<br /><p class="postfoot">posted on 2006-12-07 14:42 <a href="/stme/"><font color="#0066aa">stme</font></a> 阅读(490) <a href="/stme/archive/2006/12/07/86083.html#Post"><font color="#0066aa">评论(7)</font></a>  <a href="/stme/admin/EditPosts.aspx?postid=86083"><font color="#0066aa">编辑</font></a> <a href="/stme/AddToFavorite.aspx?id=86083"><font color="#0066aa">收藏</font></a><a href="/stme/services/trackbacks/86083.aspx"><font color="#0066aa">引用</font></a><a href="javascript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&amp;u='+escape(d.location.href)+'&amp;c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();"><font color="#0066aa">收藏至365Key</font></a></p><img height="1" src="/stme/aggbug/86083.html?webview=1" width="1" /><!--
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
<rdf:Description
rdf:about="http://www.blogjava.net/stme/archive/2006/12/07/86083.html"
dc:identifier="http://www.blogjava.net/stme/archive/2006/12/07/86083.html"
dc:title="编码问题"
trackback:ping="http://www.blogjava.net/stme/services/trackbacks/86083.aspx" />
</rdf:RDF>
--><a name="pagedcomment"></a><a name="评论"><div id="comments"><h3>评论</h3><h4><a title="permalink: re: 编码问题" href="/stme/archive/2006/12/07/86083.html#86113"><font color="#0066aa">#</font></a> <a name="86113"></a>re: 编码问题 <span><font color="#999999">2006-12-07 16:22 </font></span><a id="Comments1_CommentList_ctl00_NameLink" href="/beansoft/" target="_blank"><font color="#0066aa">BeanSoft</font></a></h4><p>不错, 必须在头部加入下列声明: <br /><br />&lt;%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="GBK"%&gt; <br /><br />要不然你就得用编辑器另存为的时候(例如记事本就有这个功能, 但是貌似有问题)转换编码为 UTF-8. <br /><br />服务器看到 contentType="text/html; charset=UTF-8" 的页面声明的时候, 就认为下面的内容都是 UTF-8, 如果这时候不加上 pageEncoding, 出来的内容自然就是乱码. <br /><br />因此要么都用 GBK, 要么都用 UTF-8. 可以在 Eclipse 里进行设置让所有的源文件的默认字符集都是 UTF-8. 如果要做开源项目, 强烈建议的是不要用 GBK 格式的编码, 用 UTF-8 是上上策. 还有就是鼓励英文注释, 网页内容国际化, 呵呵.  <a onclick="return SetReplyAuhor(&quot;BeanSoft&quot;)" href="/stme/archive/2006/12/07/86083.html#post"><font color="#0066aa">回复</font></a><a id="Comments1_CommentList_ctl00_DeleteLink" href="javascript:__doPostBack('Comments1$CommentList$ctl00$DeleteLink','')"></a>  <a id="Comments1_CommentList_ctl00_EditLink"></a></p><h4><a title="permalink: re: 编码问题" href="/stme/archive/2006/12/07/86083.html#86126"><font color="#0066aa">#</font></a> <a name="86126"></a>re: 编码问题 <span><font color="#999999">2006-12-07 17:00 </font></span><a id="Comments1_CommentList_ctl01_NameLink" target="_blank">hahahehe</a></h4><p>1、首先我们用编辑器编辑jsp页面代码保存； <br />2、web服务器对其进行编译，将jsp页面编译成为一个java的class文件； <br />3、web服务器将其class文件用传输格式在网络上传输； <br />4、客户端浏览器解析代码生成页面。 <br /><br />非applet的情况下，服务器怎么可能把class传输到网络上去，浏览器又怎么可能解析class？服务器传输的是html，class生成html的过程早在服务器端就已经完成。 <br /><br />乱码的直接原因就在于服务器在头里告诉浏览器的编码 charset=UTF-8 和事实上生成html的编码是不一致的  <a onclick="return SetReplyAuhor(&quot;hahahehe&quot;)" href="/stme/archive/2006/12/07/86083.html#post"><font color="#0066aa">回复</font></a><a id="Comments1_CommentList_ctl01_DeleteLink" href="javascript:__doPostBack('Comments1$CommentList$ctl01$DeleteLink','')"></a>  <a id="Comments1_CommentList_ctl01_EditLink"></a></p><h4><a title="permalink: re: 编码问题" href="/stme/archive/2006/12/07/86083.html#86129"><font color="#0066aa">#</font></a> <a name="86129"></a>re: 编码问题 <span><font color="#999999">2006-12-07 17:13 </font></span><a id="Comments1_CommentList_ctl02_NameLink" target="_blank">BeanSoft[匿名]</a></h4><p>呵呵, 这段话的确是有点问题... <br /><br />应该是: <br />1. 我们用代码编辑器编辑了一个页面(encoding=GBK) <br />2. Web 服务器调用编译器将其编译为 servlet(编译器也会有个 encoding 选项, 一般都是跟着系统的 encoding 走, 页面有 charset 的话就跟页面的 charset 或者 pageEncoding 一致, 所以有时候不指定JSP编译默认编码, 不同的服务器出来的结果就不一样), (encoding=GBK); <br />3. 生成 HTML, 这没啥, 直接 write string; <br />4. 浏览器根据 head 里的 contentType (UTF-8)来判断编码, 或者根据页面里的 meta 来判断编码 <br />&lt;meta http-equiv="content-type" content="text/html; charset=UTF-8"&gt;, 什么都没的时候就当成西欧字符集, 具体哪个优先? 印象中是页面里的 meta 优先, 这时候客户需要手工选一个编码才能看到正确的网页. <br /><br />所以只有这些条件都一致的时候, 才不会乱码, 否则都会乱码. 一般推荐全用 UTF-8(英文服务器环境) 或者 GBK(中文服务器).  <a onclick="return SetReplyAuhor(&quot;BeanSoft[匿名]&quot;)" href="/stme/archive/2006/12/07/86083.html#post"><font color="#0066aa">回复</font></a><a id="Comments1_CommentList_ctl02_DeleteLink" href="javascript:__doPostBack('Comments1$CommentList$ctl02$DeleteLink','')"></a>  <a id="Comments1_CommentList_ctl02_EditLink"></a></p><h4><a title="permalink: re: 编码问题" href="/stme/archive/2006/12/07/86083.html#86210"><font color="#0066aa">#</font></a> <a name="86210"></a>re: 编码问题 <span><font color="#999999">2006-12-08 00:27 </font></span><a id="Comments1_CommentList_ctl03_NameLink" href="/weidagang2046/" target="_blank"><font color="#0066aa">weidagang2046</font></a></h4><p>上次看你另一篇文章，对编码分析得很详细，很有帮助。再接再厉！  <a onclick="return SetReplyAuhor(&quot;weidagang2046&quot;)" href="/stme/archive/2006/12/07/86083.html#post"><font color="#0066aa">回复</font></a><a id="Comments1_CommentList_ctl03_DeleteLink" href="javascript:__doPostBack('Comments1$CommentList$ctl03$DeleteLink','')"></a>  <a id="Comments1_CommentList_ctl03_EditLink"></a></p><h4><a title="permalink: re: 编码问题" href="/stme/archive/2006/12/07/86083.html#86241"><font color="#0066aa">#</font></a> <a name="86241"></a>re: 编码问题 <span><font color="#999999">2006-12-08 09:44 </font></span><a id="Comments1_CommentList_ctl04_NameLink" target="_blank">stme[匿名]</a></h4><p>谢谢大家的点评，大家一起进步吧！  <a onclick="return SetReplyAuhor(&quot;stme[匿名]&quot;)" href="/stme/archive/2006/12/07/86083.html#post"><font color="#0066aa">回复</font></a><a id="Comments1_CommentList_ctl04_DeleteLink" href="javascript:__doPostBack('Comments1$CommentList$ctl04$DeleteLink','')"></a>  <a id="Comments1_CommentList_ctl04_EditLink"></a></p><h4><a title="permalink: re: 编码问题" href="/stme/archive/2006/12/07/86083.html#86315"><font color="#0066aa">#</font></a> <a name="86315"></a>re: 编码问题 <span><font color="#999999">2006-12-08 13:44 </font></span><a id="Comments1_CommentList_ctl05_NameLink" target="_blank">laoshi</a></h4><p>&gt;&gt;utf-8只是用于在数据传输时将字符串分割成字节传输出去，它对于unicode编码有着严格的一一对应关系，而对于gb2312、gbk、gb18030之类的中文编码是没有对应关系的。gb2312、gbk、gb18030是在ascii编码之上进行的中文编码开发，所以它们是与ascii相兼容的 <br />gb18030也和unicode有着严格的一一对应关系，gb2312、gbk和unicode的子集有着严格的一一对应关系 <br />UTF-8和gb18030都是所谓的外码标准 <br />“gb2312、gbk、gb18030是在ascii编码之上进行的中文编码开发，所以它们是与ascii相兼容的”是错误的，只能说UTF-8以及国标编码的单字节编码区和ascii的0~7F区的编码是一致的。 <br />Notepad++和UltraEdit的ascii其实并不是ascii，而是指Windows平台的本地多字节字符集，一般咱们用的中文Windows上就是gbk  <a onclick="return SetReplyAuhor(&quot;laoshi&quot;)" href="/stme/archive/2006/12/07/86083.html#post"><font color="#0066aa">回复</font></a><a id="Comments1_CommentList_ctl05_DeleteLink" href="javascript:__doPostBack('Comments1$CommentList$ctl05$DeleteLink','')"></a>  <a id="Comments1_CommentList_ctl05_EditLink"></a></p><h4><a title="permalink: re: 编码问题" href="/stme/archive/2006/12/07/86083.html#86383"><font color="#0066aa">#</font></a> <a name="86383"></a>re: 编码问题<a name="Post"></a><span><font color="#999999">2006-12-08 16:13 </font></span><a id="Comments1_CommentList_ctl06_NameLink" target="_blank">luguoren</a></h4><p>”gb18030也和unicode有着严格的一一对应关系，gb2312、gbk和unicode的子集有着严格的一一对应关系“ <br />这个是对的吗？本人好像没有看到这样的资料，gb18030只是一部分与unicode对应，不会是全部一一对应吧  <a onclick="return SetReplyAuhor(&quot;luguoren&quot;)" href="/stme/archive/2006/12/07/86083.html#post"><font color="#0066aa">回复</font></a><a id="Comments1_CommentList_ctl06_DeleteLink" href="javascript:__doPostBack('Comments1$CommentList$ctl06$DeleteLink','')"></a>  <a id="Comments1_CommentList_ctl06_EditLink"></a></p></div><style><![CDATA[
td { font-size: 12px }
.commentTextBox 
{ 
    font-family : Verdana; 
    font-size: 13px;
 }
]]&gt;</style><!--Beging Temp Save--><style><![CDATA[userData { BEHAVIOR: url(#default#userdata) }
	]]&gt;</style></a><img src ="http://www.blogjava.net/liaojiyong/aggbug/86656.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-12-10 11:46 <a href="http://www.blogjava.net/liaojiyong/archive/2006/12/10/86656.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>代码生成工具MySQL2JSP 0.3 版本发布了</title><link>http://www.blogjava.net/liaojiyong/archive/2006/08/24/65499.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Thu, 24 Aug 2006 05:19:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/08/24/65499.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/65499.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/08/24/65499.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/65499.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/65499.html</trackback:ping><description><![CDATA[
		<p>代码生成工具<a href="http://freshmeat.net/releases/234324/"><font color="#000066">MySQL2JSP 0.3</font></a> 版本发布了。</p>
		<p>MySQL2JSP是一个快速开发工具，可以让你从Mysql中直接生成JSP、servlets，以及JavaBeans。并且会生成增加、删除、修改、查看记录等JSP页面。使用JDBC。某种程度上，有点像是简化的RAILS。<br /><a href="http://sourceforge.net/projects/db2jspgen/">http://sourceforge.net/projects/db2jspgen/</a></p>
<img src ="http://www.blogjava.net/liaojiyong/aggbug/65499.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-08-24 13:19 <a href="http://www.blogjava.net/liaojiyong/archive/2006/08/24/65499.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用SiteMesh简化网页布局（转）</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/24/59819.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Mon, 24 Jul 2006 07:25:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/24/59819.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/59819.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/24/59819.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/59819.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/59819.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在公司项目使用了				Appfuse				，其带有				SiteMesh				对于网页布局简化让我感觉很好用，本文旨在对对				Sitemesh				的基本原理和在项目中使用				Sitemesh				的实现流程、使用技巧的介绍。														1.   								基本原理								Site...&nbsp;&nbsp;<a href='http://www.blogjava.net/liaojiyong/archive/2006/07/24/59819.html'>阅读全文</a><img src ="http://www.blogjava.net/liaojiyong/aggbug/59819.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-24 15:25 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/24/59819.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP实现留言板的JavaBean类和分页显示的源码</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/21/59319.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Thu, 20 Jul 2006 17:43:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/21/59319.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/59319.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/21/59319.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/59319.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/59319.html</trackback:ping><description><![CDATA[
		<div>
				<p>//留言bean<br />package userinfobean;</p>
				<p>/**<br /> * &lt;p&gt;Title: &lt;/p&gt;<br /> * &lt;p&gt;Description: &lt;/p&gt;<br /> * &lt;p&gt;Copyright: Copyright (c) 2004&lt;/p&gt;<br /> * &lt;p&gt;Company: &lt;/p&gt;<br /> * @author not attributable<br /> * @version 1.0<br /> */</p>
				<p>public class memoBean {</p>
				<p>  private String id;//1.用户名<br />  private String email;//2.密码<br />  private String content;//3.留言  </p>
				<p>  public memoBean() {<br />  }<br />  //1.用户名<br />  public void setId(String s){<br />    this.id=s;<br />  }<br />  //2.密码<br />  public void setEmail(String s){<br />    this.email=s;<br />  }<br />  //3.留言<br />   public void setContent(String s){<br />    this.content=s;<br />  }<br /> </p>
				<p>  //1.用户名<br />   public String getId( ){<br />     return this.id;<br />   }<br />   //2.密码<br />   public String getEmail(){<br />     return this.email;<br />   }<br />   //3.留言 <br />   public String getContent(){<br />     return this.content;<br />   }<br />}<br />//// 用于数据库操作的bean           <br />package userinfobean;</p>
				<p>import userinfobean.*;<br />import java.io.*;<br />import java.util.*;<br />import java.sql.*;</p>
				<p>
						<br />public class databaseBean{<br />  private String dbName;<br />  private String dbUser;<br />  private String dbPass;<br />   private Vector memoVector;</p>
				<p>   Connection connection;</p>
				<p>  public databaseBean(){<br />    dbName=new String("×××××××");<br />    dbUser=new String("××××××");<br />    dbPass=new String("×××××××");<br />    String connectionUrl="jdbc:mysql://localhost/"+dbName;<br />    try{<br />      Class.forName("org.gjt.mm.mysql.Driver");<br />      connection=DriverManager.getConnection(connectionUrl,dbUser,dbPass);<br />    }<br />    catch(Exception e){<br />      System.out.println(e.toString());<br />      }<br />  }</p>
				<p>  public void dbQueryMemos(){<br />    try{<br />       memoVector=new Vector();<br />      Statement stmt=connection.createStatement();<br />      ResultSet rs=stmt.executeQuery("select * from memo;");<br />      while(rs.next()){<br />        memoBean temp=new memoBean();<br />        temp.setId(rs.getString(2));<br />        temp.setEmail(rs.getString(3));<br />        temp.setContent(rs.getString(4));<br />        memoVector.add(temp);<br />      }</p>
				<p>   }<br />   catch(SQLException e){<br />     System.out.println(e.toString());<br />   }</p>
				<p> </p>
				<p>  }<br /><br />    public void setDbName(String s){<br />    this.dbName=s;<br />  }<br />  public void setDbUser(String s){<br />    this.dbUser=s;<br />  }<br />  public void setDbPass(String s){<br />    this.dbPass=s;<br />  }</p>
				<p>  public String getDbName(){<br />    return this.dbName;<br />  }<br />  public String getDbUser(){<br />    return this.dbUser;<br />  }<br />  public String getDbPass(){<br />    return this.dbPass;<br />  }<br />    public Vector getMemoVector(){<br />    return this.memoVector;</p>
				<p>  }</p>
				<p>}<br /><br />///以下是网页源码<br /><br />&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;<br />&lt;%@ page language="java" import="java.util.*" %&gt;<br />&lt;%@ page  import="java.text.*" %&gt;<br />&lt;%@ page  import="userinfobean.*" %&gt;<br />&lt;jsp:useBean id="memoInfo" scope="page" class="userinfobean.memoBean"/&gt;<br />&lt;jsp:useBean id="memoQuery" scope="page" class="userinfobean.databaseBean"/&gt;<br />&lt;%!<br />int totalPages;<br />int countPerPage=3;<br />int totalCount;<br />int currentPage=0;<br />int currentStart;<br />%&gt;<br />&lt;%<br />memoQuery.dbQueryMemos();<br />Vector vt=memoQuery.getMemoVector();<br />totalCount=vt.size();<br />totalPages=totalCount/countPerPage;<br />if(totalCount%countPerPage&gt;0)totalPages=totalPages+1;<br />if(request.getParameter("page")==null)<br />{<br />currentPage=1;<br />}<br />else<br />{<br />currentPage=Integer.parseInt(request.getParameter("page"));<br />if(currentPage&gt;totalPages)currentPage=totalPages;<br />if(currentPage&lt;1)currentPage=1;<br />}<br />currentStart=totalCount-1-countPerPage * (currentPage-1);<br />%&gt;<br />&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;NetGreen&lt;/title&gt;<br />&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;<br />  &lt;link rel="stylesheet" href="main.css"&gt;                             <br />&lt;/head&gt;<br />&lt;script language="JavaScript" &gt;<br />function page_check()<br />{<br />if(document.pageForm.page.value=="")<br />{alert("请输入页数");<br />document.pageForm.page.focus();<br />return false;<br />}<br />return true;<br />}&lt;/script&gt;<br />&lt;body bgcolor="ffffff"  &gt;</p>
				<p>&lt;center&gt;<br />  &lt;table width="800" border="0" height="622"&gt;<br />    &lt;tr&gt; <br />      &lt;td height="71" align="center" valign="middle"&gt; &lt;table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0099CC"&gt;<br />          &lt;tr&gt; <br />            &lt;td width="19%" height="60" align="left" valign="bottom" bgcolor="#FFFFFF"&gt;&lt;b&gt;&lt;font size="4" color="#00cc66" &gt;&lt;img src="image/logo.gif" width="156" height="60"&gt;&lt;/font&gt;&lt;/b&gt;&lt;/td&gt;<br />            &lt;td width="57%" align="left" valign="bottom" bgcolor="#FFFFFF"&gt;&lt;img src="image/banner.gif" width="100%" height="60"&gt;&lt;/td&gt;<br />            &lt;td width="24%" align="left" valign="bottom"&gt; &lt;table width="102%" height="60" border="1" cellpadding="0" cellspacing="0" bordercolor="#0099CC" bgcolor="#FFFFFF"&gt;<br />                &lt;tr&gt; <br />                  &lt;td width="50%" height="27" align="center"&gt;上 传&lt;/td&gt;<br />                  &lt;td width="50%" align="center"&gt;收藏本页&lt;/td&gt;<br />                &lt;/tr&gt;<br />                &lt;tr&gt; <br />                  &lt;td height="21" align="center" bgcolor="#FFFFFF" &gt;退 出 &lt;/td&gt;<br />                  &lt;td align="center"&gt;&lt;a href="memoForm.htm" target="_self"&gt;我要留言&lt;/a&gt;&lt;/td&gt;<br />                &lt;/tr&gt;<br />              &lt;/table&gt;&lt;/td&gt;<br />          &lt;/tr&gt;<br />        &lt;/table&gt;&lt;/td&gt;<br />    &lt;/tr&gt;<br />    &lt;tr&gt; <br />      &lt;td height="31"&gt;&lt;table width="100%" border="1" bordercolor="#0099CC"&gt;<br />          &lt;tr bgcolor="#00CC66"&gt; <br />            &lt;td width="12%" height="23" align="center" bgcolor="#CCFFFF"&gt;&lt;a href="index.htm" &gt;首页&lt;/a&gt;&lt;/td&gt;<br />            &lt;td width="12%" align="center" bgcolor="#CCFFFF"&gt;&lt;a href="loginForm.htm" &gt;登陆&lt;/a&gt;&lt;/td&gt;<br />            &lt;td width="12%" align="center" bgcolor="#CCFFFF"&gt;&amp;nbsp;&lt;/td&gt;<br />            &lt;td width="12%" align="center" bgcolor="#CCFFFF"&gt;&amp;nbsp;&lt;/td&gt;<br />            &lt;td width="12%" align="center" bgcolor="#CCFFFF" &gt;&amp;nbsp; &lt;/td&gt;<br />            &lt;td width="12%" align="center" bgcolor="#CCFFFF"&gt;&amp;nbsp;&lt;/td&gt;<br />            &lt;td width="12%" align="center" bgcolor="#CCFFFF"&gt;&lt;a href="memoDisplay.jsp" &gt;留言板&lt;/a&gt;&lt;/td&gt;<br />            &lt;td width="12%" align="center"  bgcolor="#CCFFFF"&gt;&lt;a href="registForm.htm"&gt;注册&lt;/a&gt;&lt;/td&gt;<br />          &lt;/tr&gt;<br />        &lt;/table&gt;&lt;/td&gt;<br />    &lt;/tr&gt;<br />    &lt;tr&gt; <br />      &lt;td height="435" align="center" valign="top" nowrap&gt; <br />        &lt;table width="100%"  border="1" cellpadding="0" cellspacing="0" bordercolor="#0099CC"&gt;<br />          &lt;tr&gt; <br />            &lt;td width="18%" height="431" align="center" valign="middle" bgcolor="#CCFFFF"&gt; <br />            &lt;/td&gt;<br />            &lt;td width="83%" align="center" valign="top" bgcolor="#FFFFFF"&gt;&lt;table width="100%" border="1"&gt;&lt;form name="pageForm" method="post"  onSubmit="return page_check();"action="memoDisplay.jsp"&gt;<br />                &lt;tr&gt; <br />                  &lt;td width="36%"&gt;共有留言&lt;%out.print(totalPages);%&gt; 页，现在是第&lt;%out.print(currentPage);%&gt;  页&lt;/td&gt;<br />                    &lt;td width="64%"&gt;<br />     &lt;a href="memoDisplay.jsp?page=&lt;%=currentPage-1%&gt;" &gt;上一页 &lt;/a&gt;<br />     &lt;a href="memoDisplay.jsp?page=&lt;%=currentPage+1%&gt;" &gt;下一页  &lt;/a&gt;<br />     &lt;a href="memoDisplay.jsp?page=1" &gt;首页 &lt;/a&gt;<br />      &lt;a href="memoDisplay.jsp?page=&lt;%=totalPages%&gt;" &gt;尾页  &lt;/a&gt;<br />      &lt;input type="submit" name="Submit" value="G0"&gt; <br />                      &lt;input name="page" type="text" size="10"&gt;<br />                      页&lt;/td&gt;<br />                &lt;/tr&gt;<br />              &lt;/form&gt;&lt;/table&gt; <br />              &lt;%<br />    <br />    for(int i=0;i&lt;countPerPage&amp;&amp;currentStart-i&gt;=0;i++)<br />    {<br />     memoInfo.setId(((memoBean)vt.get(currentStart-i)).getId());<br />     memoInfo.setEmail(((memoBean)vt.get(currentStart-i)).getEmail());<br />     memoInfo.setContent(((memoBean)vt.get(currentStart-i)).getContent());<br />     <br />     <br />     <br />   out.print("&lt;table width='100%' border='1' &gt;&lt;tr&gt;&lt;td width='19%'&gt;");<br />   out.print(memoInfo.getId());<br />   out.print("&lt;/td&gt;&lt;td width='81%'&gt;");<br />   out.print(memoInfo.getEmail());<br />   out.print("&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td height='44' colspan='2'&gt;");<br />   out.print(memoInfo.getContent());<br />   out.print("&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; ");<br />   out.print("&lt;br&gt;");<br />     <br />    }<br />  <br />   %&gt;<br />   &lt;/td&gt;<br />          &lt;/tr&gt;<br />        &lt;/table&gt;<br />      &lt;/td&gt;<br />    &lt;/tr&gt;<br />    &lt;tr&gt;<br />      &lt;td height="73" align="center" valign="top" nowrap&gt; <br />        &lt;table width="100%" border="0"&gt;<br />          &lt;tr&gt; <br />            &lt;td height="21" align="center" bgcolor="#FFFFFF"&gt;&lt;hr width="85%" noshade  color="#00CC66"&gt;&lt;/td&gt;<br />          &lt;/tr&gt;<br />          &lt;tr&gt; <br />            &lt;td height="12" align="center"&gt;Copyright @ HomeLee. All rights reserved. <br />            &lt;/td&gt;<br />          &lt;/tr&gt;<br />          &lt;tr&gt; <br />            &lt;td height="12" align="center" bgcolor="#FFFFFF"&gt;&amp;nbsp;&lt;/td&gt;<br />          &lt;/tr&gt;<br />        &lt;/table&gt;&lt;/td&gt;<br />    &lt;/tr&gt;<br />  &lt;/table&gt;<br />  &lt;/center&gt;&lt;/body&gt;<br />&lt;/html&gt;</p>
		</div>
<img src ="http://www.blogjava.net/liaojiyong/aggbug/59319.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-21 01:43 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/21/59319.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>上传下载全攻略jspSmartUpload（转）</title><link>http://www.blogjava.net/liaojiyong/archive/2006/07/03/56388.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Mon, 03 Jul 2006 09:24:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/07/03/56388.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/56388.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/07/03/56388.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/56388.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/56388.html</trackback:ping><description><![CDATA[
		<div align="left">一、安装篇 <br /><br />　　<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload是由www.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>smart.com网站开发的一个可免费使用的全功能的文件上传下载组件，适于嵌入执行上传下载操作的JSP文件中。该组件有以下几个特点： <br /><br />1、使用简单。在JSP文件中仅仅书写三五行JAVA代码就可以搞定文件的上传或下载，方便。 <br /><br />2、能全程控制上传。利用<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload组件提供的对象及其操作方法，可以获得全部上传文件的信息（包括文件名，大小，类型，扩展名，文件数据等），方便存取。 <br /><br />3、能对上传的文件在大小、类型等方面做出限制。如此可以滤掉不符合要求的文件。 <br /><br />4、下载灵活。仅写两行代码，就能把Web服务器变成文件服务器。不管文件在Web服务器的目录下或在其它任何目录下，都可以利用<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload进行下载。 <br /><br />5、能将文件上传到数据库中，也能将数据库中的数据下载下来。这种功能针对的是MYSQL数据库，因为不具有通用性，所以本文不准备举例介绍这种用法。 <br /><br />　　<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload组件可以从www.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>smart.com网站上自由下载，压缩包的名字是<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload.zip。下载后，用WinZip或WinRAR将其解压到Tomcat的webapps目录下（本文以Tomcat服务器为例进行介绍）。解压后，将webapps/<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>smartupload目录下的子目录Web-inf名字改为全大写的WEB-INF，这样一改<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload类才能使用。因为Tomcat对文件名大小写敏感，它要求Web应用程序相关的类所在目录为WEB-INF，且必须是大写。接着重新启动Tomcat，这样就可以在JSP文件中使用<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload组件了。 <br /><br />　　注意，按上述方法安装后，只有webapps/<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>smartupload目录下的程序可以使用<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload组件，如果想让Tomcat服务器的所有Web应用程序都能用它，必须做如下工作： <br /><br />1．进入命令行状态，将目录切换到Tomcat的webapps/<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>smartupload/WEB-INF目录下。 <br /><br />2．运行JAR打包命令：jar cvf <a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload.jar com <br /><br />（也可以打开资源管理器，切换到当前目录，用WinZip将com目录下的所有文件压缩成<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload.zip，然后将<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload.zip换名为<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload.jar文件即可。） <br /><br />3．将<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload.jar拷贝到Tomcat的shared/lib目录下。 <br /><br />二、相关类说明篇 <br /><br />㈠ File类 <br /><br />　　这个类<a class="Channel_KeyLink" href="http://www.skyuu.com/pm/ShowClass.asp?ClassID=148">包装</a>了一个上传文件的所有信息。通过它，可以得到上传文件的文件名、文件大小、扩展名、文件数据等信息。 <br /><br />　　File类主要提供以下方法： <br /><br />1、saveAs作用：将文件换名另存。 <br /><br />原型： <br /><br />public void saveAs(java.lang.String destFilePathName) <br /><br />或 <br /><br />public void saveAs(java.lang.String destFilePathName, int optionSaveAs) <br /><br />其中，destFilePathName是另存的文件名，optionSaveAs是另存的选项，该选项有三个值，分别是SAVEAS_PHYSICAL,SAVEAS_VIRTUAL，SAVEAS_AUTO。SAVEAS_PHYSICAL表明以操作系统的根目录为文件根目录另存文件，SAVEAS_VIRTUAL表明以Web应用程序的根目录为文件根目录另存文件，SAVEAS_AUTO则表示让组件决定，当Web应用程序的根目录存在另存文件的目录时，它会选择SAVEAS_VIRTUAL，否则会选择SAVEAS_PHYSICAL。 <br /><br />例如，saveAs("/upload/sample.zip",SAVEAS_PHYSICAL)执行后若Web服务器安装在C盘，则另存的文件名实际是c:\upload\sample.zip。而saveAs("/upload/sample.zip",SAVEAS_VIRTUAL)执行后若Web应用程序的根目录是webapps/<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>smartupload，则另存的文件名实际是webapps/<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>smartupload/upload/sample.zip。saveAs("/upload/sample.zip",SAVEAS_AUTO)执行时若Web应用程序根目录下存在upload目录，则其效果同saveAs("/upload/sample.zip",SAVEAS_VIRTUAL)，否则同saveAs("/upload/sample.zip",SAVEAS_PHYSICAL)。 <br /><br />建议：对于Web程序的开发来说，最好使用SAVEAS_VIRTUAL，以便移植。 <br /><br />2、isMissing <br /><br />作用：这个方法用于判断用户是否选择了文件，也即对应的表单项是否有值。选择了文件时，它返回false。未选文件时，它返回true。 <br /><br />原型：public boolean isMissing() <br /><br />3、getFieldName <br /><br />作用：取HTML表单中对应于此上传文件的表单项的名字。 <br /><br />原型：public String getFieldName() <br /><br />4、getFileName <br /><br />作用：取文件名（不含目录信息） <br /><br />原型：public String getFileName() <br /><br />5、getFilePathName <br /><br />作用：取文件全名（带目录） <br /><br />原型：public String getFilePathName <br /><br />6、getFileExt <br /><br />作用：取文件扩展名（后缀） <br /><br />原型：public String getFileExt() <br /><br />7、getSize <br /><br />作用：取文件长度（以字节计） <br /><br />原型：public int getSize() <br /><br />8、getBinaryData <br /><br />作用：取文件数据中指定位移处的一个字节，用于检测文件等处理。 <br /><br />原型：public byte getBinaryData(int index)。其中，index表示位移，其值在0到getSize()-1之间。 <br /><br />㈡ Files类 <br /><br />　　这个类表示所有上传文件的集合，通过它可以得到上传文件的数目、大小等信息。有以下方法： <br /><br />1、getCount <br /><br />作用：取得上传文件的数目。 <br /><br />原型：public int getCount() <br /><br />2、getFile <br /><br />作用：取得指定位移处的文件对象File（这是com.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>smart.upload.File，不是java.io.File，注意区分）。 <br /><br />原型：public File getFile(int index)。其中，index为指定位移，其值在0到getCount()-1之间。 <br /><br />3、getSize <br /><br />作用：取得上传文件的总长度，可用于限制一次性上传的数据量大小。 <br /><br />原型：public long getSize() <br /><br />4、getCollection <br /><br />作用：将所有上传文件对象以Collection的形式返回，以便其它应用程序引用，浏览上传文件信息。 <br /><br />原型：public Collection getCollection() <br /><br />5、getEnumeration <br /><br />作用：将所有上传文件对象以Enumeration（枚举）的形式返回，以便其它应用程序浏览上传文件信息。 <br /><br />原型：public Enumeration getEnumeration() <br /><br />㈢ Request类 <br /><br />　　这个类的功能等同于JSP内置的对象request。只所以提供这个类，是因为对于文件上传表单，通过request对象无法获得表单项的值，必须通过<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload组件提供的Request对象来获取。该类提供如下方法： <br /><br />1、getParameter <br /><br />作用：获取指定参数之值。当参数不存在时，返回值为null。 <br /><br />原型：public String getParameter(String name)。其中，name为参数的名字。 <br /><br />2、getParameterValues <br /><br />作用：当一个参数可以有多个值时，用此方法来取其值。它返回的是一个字符串数组。当参数不存在时，返回值为null。 <br /><br />原型：public String[] getParameterValues(String name)。其中，name为参数的名字。 <br /><br />3、getParameterNames <br /><br />作用：取得Request对象中所有参数的名字，用于遍历所有参数。它返回的是一个枚举型的对象。 <br /><br />原型：public Enumeration getParameterNames() <br /><br />㈣ SmartUpload类这个类完成上传下载工作。 <br /><br />A．上传与下载共用的方法： <br /><br />只有一个：initialize。 <br /><br />作用：执行上传下载的初始化工作，必须第一个执行。 <br /><br />原型：有多个，主要使用下面这个： <br /><br />public final void initialize(javax.servlet.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>.PageContext pageContext) <br /><br />其中，pageContext为JSP页面内置对象（页面上下文）。 <br /><br />B．上传文件使用的方法： <br /><br />1、upload <br /><br />作用：上传文件数据。对于上传操作，第一步执行initialize方法，第二步就要执行这个方法。 <br /><br />原型：public void upload() <br /><br />2、save <br /><br />作用：将全部上传文件保存到指定目录下，并返回保存的文件个数。 <br /><br />原型：public int save(String destPathName) <br /><br />和public int save(String destPathName,int option) <br /><br />其中，destPathName为文件保存目录，option为保存选项，它有三个值，分别是SAVE_PHYSICAL,SAVE_VIRTUAL和SAVE_AUTO。（同File类的saveAs方法的选项之值类似）SAVE_PHYSICAL指示组件将文件保存到以操作系统根目录为文件根目录的目录下，SAVE_VIRTUAL指示组件将文件保存到以Web应用程序根目录为文件根目录的目录下，而SAVE_AUTO则表示由组件自动选择。 <br /><br />注：save(destPathName)作用等同于save(destPathName,SAVE_AUTO)。 <br /><br />3、getSize <br /><br />作用：取上传文件数据的总长度 <br /><br />原型：public int getSize() <br /><br />4、getFiles <br /><br />作用：取全部上传文件，以Files对象形式返回，可以利用Files类的操作方法来获得上传文件的数目等信息。 <br /><br />原型：public Files getFiles() <br /><br />5、getRequest <br /><br />作用：取得Request对象，以便由此对象获得上传表单参数之值。 <br /><br />原型：public Request getRequest() <br /><br />6、setAllowedFilesList <br /><br />作用：设定允许上传带有指定扩展名的文件，当上传过程中有文件名不允许时，组件将抛出异常。 <br /><br />原型：public void setAllowedFilesList(String allowedFilesList) <br /><br />其中，allowedFilesList为允许上传的文件扩展名列表，各个扩展名之间以逗号分隔。如果想允许上传那些没有扩展名的文件，可以用两个逗号表示。例如：setAllowedFilesList("doc,txt,,")将允许上传带doc和txt扩展名的文件以及没有扩展名的文件。 <br /><br />7、setDeniedFilesList <br /><br />作用：用于限制上传那些带有指定扩展名的文件。若有文件扩展名被限制，则上传时组件将抛出异常。 <br /><br />原型：public void setDeniedFilesList(String deniedFilesList) <br /><br />其中，deniedFilesList为禁止上传的文件扩展名列表，各个扩展名之间以逗号分隔。如果想禁止上传那些没有扩展名的文件，可以用两个逗号来表示。例如：setDeniedFilesList("exe,bat,,")将禁止上传带exe和bat扩展名的文件以及没有扩展名的文件。 <br /><br />8、setMaxFileSize <br /><br />作用：设定每个文件允许上传的最大长度。 <br /><br />原型：public void setMaxFileSize(long maxFileSize) <br /><br />其中，maxFileSize为为每个文件允许上传的最大长度，当文件超出此长度时，将不被上传。 <br /><br />9、setTotalMaxFileSize <br /><br />作用：设定允许上传的文件的总长度，用于限制一次性上传的数据量大小。 <br /><br />原型：public void setTotalMaxFileSize(long totalMaxFileSize) <br /><br />其中，totalMaxFileSize为允许上传的文件的总长度。<br /><br /><br /><br />1、setContentDisposition <br /><br />作用：将数据追加到MIME文件头的CONTENT-DISPOSITION域。<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload组件会在返回下载的信息时自动填写MIME文件头的CONTENT-DISPOSITION域，如果用户需要添加额外信息，请用此方法。 <br /><br />原型：public void setContentDisposition(String contentDisposition) <br /><br />其中，contentDisposition为要添加的数据。如果contentDisposition为null，则组件将自动添加"attachment;"，以表明将下载的文件作为附件，结果是IE浏览器将会提示另存文件，而不是自动打开这个文件（IE浏览器一般根据下载的文件扩展名决定执行什么操作，扩展名为doc的将用word程序打开，扩展名为pdf的将用acrobat程序打开，等等）。 <br /><br />2、downloadFile <br /><br />作用：下载文件。 <br /><br />原型：共有以下三个原型可用，第一个最常用，后两个用于特殊情况下的文件下载（如更改内容类型，更改另存的文件名）。 <br /><br />① public void downloadFile(String sourceFilePathName) <br /><br />其中，sourceFilePathName为要下载的文件名（带目录的文件全名） <br /><br />② public void downloadFile(String sourceFilePathName,String contentType) <br /><br />其中，sourceFilePathName为要下载的文件名（带目录的文件全名）,contentType为内容类型（MIME格式的文件类型信息，可被浏览器识别）。 <br /><br />③ public void downloadFile(String sourceFilePathName,String contentType,String destFileName) <br /><br />其中，sourceFilePathName为要下载的文件名（带目录的文件全名）,contentType为内容类型（MIME格式的文件类型信息，可被浏览器识别）,destFileName为下载后默认的另存文件名。 <br /><br />三、文件上传篇 <br /><br />㈠ 表单要求 <br /><br />对于上传文件的FORM表单，有两个要求： <br /><br />1、METHOD应用POST，即METHOD="POST"。 <br /><br />2、增加属性：ENCTYPE="multipart/form-data" <br /><br />下面是一个用于上传文件的FORM表单的例子： <br /><br /><br /><br />&lt;FORM METHOD="POST" ENCTYPE="multipart/form-data" <br />ACTION="/<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload/upload.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>"&gt;<br />&lt;INPUT TYPE="FILE" NAME="MYFILE"&gt;<br />&lt;INPUT TYPE="SUBMIT"&gt;<br />&lt;/FORM&gt;<br /> <br /><br /><br />㈡ 上传的例子 <br /><br />1、上传页面upload.html <br /><br />本页面提供表单，让用户选择要上传的文件，点击"上传"按钮执行上传操作。 <br /><br />页面源码如下： <br /><br />&lt;!--<br />    文件名：upload.html<br />作  者：纵横软件制作中心雨亦奇(zhsoft88@sohu.com)<br />--&gt;<br />&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;<br />&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;文件上传&lt;/title&gt;<br />&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;<br />&lt;/head&gt;<br /><br />&lt;body&gt;<br />&lt;p&gt; &lt;/p&gt;<br />&lt;p align="center"&gt;上传文件选择&lt;/p&gt;<br />&lt;FORM METHOD="POST" ACTION="<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>/do_upload.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>"<br />ENCTYPE="multipart/form-data"&gt;<br />&lt;input type="hidden" name="TEST" value="good"&gt;<br />  &lt;table width="75%" border="1" align="center"&gt;<br />    &lt;tr&gt; <br />      &lt;td&gt;&lt;div align="center"&gt;1、 <br />          &lt;input type="FILE" name="FILE1" size="30"&gt;<br />        &lt;/div&gt;&lt;/td&gt;<br />    &lt;/tr&gt;<br />    &lt;tr&gt; <br />      &lt;td&gt;&lt;div align="center"&gt;2、 <br />          &lt;input type="FILE" name="FILE2" size="30"&gt;<br />        &lt;/div&gt;&lt;/td&gt;<br />    &lt;/tr&gt;<br />    &lt;tr&gt; <br />      &lt;td&gt;&lt;div align="center"&gt;3、 <br />          &lt;input type="FILE" name="FILE3" size="30"&gt;<br />        &lt;/div&gt;&lt;/td&gt;<br />    &lt;/tr&gt;<br />    &lt;tr&gt; <br />      &lt;td&gt;&lt;div align="center"&gt;4、 <br />          &lt;input type="FILE" name="FILE4" size="30"&gt;<br />        &lt;/div&gt;&lt;/td&gt;<br />    &lt;/tr&gt;<br />    &lt;tr&gt; <br />      &lt;td&gt;&lt;div align="center"&gt;<br />          &lt;input type="submit" name="Submit" value="上传它！"&gt;<br />        &lt;/div&gt;&lt;/td&gt;<br />    &lt;/tr&gt;<br />  &lt;/table&gt;<br />&lt;/FORM&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;<br /> <br /><br /><br />2、上传处理页面do_upload.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a> <br /><br />本页面执行文件上传操作。页面源码中详细介绍了上传方法的用法，在此不赘述了。 <br /><br />页面源码如下： <br /><br />&lt;%--<br />文件名：do_upload.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a><br />作  者：纵横软件制作中心雨亦奇(zhsoft88@sohu.com)<br />--%&gt;<br />&lt;%@ page contentType="text/html; charset=gb2312" language="java" <br />import="java.util.*,com.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>smart.upload.*" errorPage="" %&gt;<br />&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;文件上传处理页面&lt;/title&gt;<br />&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;<br />&lt;/head&gt;<br /><br />&lt;body&gt;<br />&lt;%<br />// 新建一个SmartUpload对象<br />SmartUpload su = new SmartUpload();<br />// 上传初始化<br />su.initialize(pageContext);<br />// 设定上传限制<br />// 1.限制每个上传文件的最大长度。<br />// su.setMaxFileSize(10000);<br />// 2.限制总上传数据的长度。<br />// su.setTotalMaxFileSize(20000);<br />// 3.设定允许上传的文件（通过扩展名限制）,仅允许doc,txt文件。<br />// su.setAllowedFilesList("doc,txt");<br />// 4.设定禁止上传的文件（通过扩展名限制）,禁止上传带有exe,bat,<br /><a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>,htm,html扩展名的文件和没有扩展名的文件。<br />// su.setDeniedFilesList("exe,bat,<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>,htm,html,,");<br />// 上传文件<br />su.upload();<br />// 将上传文件全部保存到指定目录<br />int count = su.save("/upload");<br />out.println(count+"个文件上传成功！&lt;br&gt;");<br /><br />// 利用Request对象获取参数之值<br />out.println("TEST="+su.getRequest().getParameter("TEST")<br />+"&lt;BR&gt;&lt;BR&gt;");<br /><br />// 逐一提取上传文件信息，同时可保存文件。<br />for (int i=0;i&lt;su.getFiles().getCount();i++)<br />{<br />com.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>smart.upload.File file = su.getFiles().getFile(i);<br /><br />// 若文件不存在则继续<br />if (file.isMissing()) continue;<br /><br />// 显示当前文件信息<br />out.println("&lt;TABLE BORDER=1&gt;");<br />out.println("&lt;TR&gt;&lt;TD&gt;表单项名（FieldName）&lt;/TD&gt;&lt;TD&gt;"<br />+ file.getFieldName() + "&lt;/TD&gt;&lt;/TR&gt;");<br />out.println("&lt;TR&gt;&lt;TD&gt;文件长度（Size）&lt;/TD&gt;&lt;TD&gt;" + <br />file.getSize() + "&lt;/TD&gt;&lt;/TR&gt;");<br />out.println("&lt;TR&gt;&lt;TD&gt;文件名（FileName）&lt;/TD&gt;&lt;TD&gt;" <br />+ file.getFileName() + "&lt;/TD&gt;&lt;/TR&gt;");<br />out.println("&lt;TR&gt;&lt;TD&gt;文件扩展名（FileExt）&lt;/TD&gt;&lt;TD&gt;" <br />+ file.getFileExt() + "&lt;/TD&gt;&lt;/TR&gt;");<br />out.println("&lt;TR&gt;&lt;TD&gt;文件全名（FilePathName）&lt;/TD&gt;&lt;TD&gt;"<br />+ file.getFilePathName() + "&lt;/TD&gt;&lt;/TR&gt;");<br />out.println("&lt;/TABLE&gt;&lt;BR&gt;");<br /><br />// 将文件另存<br />// file.saveAs("/upload/" + myFile.getFileName());<br />// 另存到以WEB应用程序的根目录为文件根目录的目录下<br />// file.saveAs("/upload/" + myFile.getFileName(), <br />su.SAVE_VIRTUAL);<br />// 另存到操作系统的根目录为文件根目录的目录下<br />// file.saveAs("c:\\temp\\" + myFile.getFileName(), <br />su.SAVE_PHYSICAL);<br /><br />}<br />%&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;<br /> <br /><br /><br />四、文件下载篇 <br /><br />1、下载链接页面download.html <br /><br />页面源码如下： <br /><br />&lt;!--<br />文件名：download.html<br />作  者：纵横软件制作中心雨亦奇(zhsoft88@sohu.com)<br />--&gt;<br />&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;<br />&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;下载&lt;/title&gt;<br />&lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312"&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;a href="<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>/do_download.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>"&gt;点击下载&lt;/a&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;<br /> <br /><br /><br />2、下载处理页面do_download.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a> do_download.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>展示了如何利用<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload组件来下载文件，从下面的源码中就可以看到，下载何其简单。 <br /><br />源码如下： <br /><br />&lt;%@ page contentType="text/html;charset=gb2312" <br />import="com.<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>smart.upload.*" %&gt;&lt;%<br />// 新建一个SmartUpload对象<br />SmartUpload su = new SmartUpload();<br />// 初始化<br />su.initialize(pageContext);<br />// 设定contentDisposition为null以禁止浏览器自动打开文件，<br />//保证点击链接后是下载文件。若不设定，则下载的文件扩展名为<br />//doc时，浏览器将自动用word打开它。扩展名为pdf时，<br />//浏览器将用acrobat打开。<br />su.setContentDisposition(null);<br />// 下载文件<br />su.downloadFile("/upload/如何赚取我的第一桶金.doc");<br />%&gt;<br /> <br /><br /><br />注意，执行下载的页面，在Java脚本范围外（即&lt;% ... %&gt;之外），不要包含HTML代码、空格、回车或换行等字符，有的话将不能正确下载。不信的话，可以在上述源码中%&gt;&lt;%之间加入一个换行符，再下载一下，保证出错。因为它影响了返回给浏览器的数据流，导致解析出错。 <br /><br />3、如何下载中文文件 <br /><br /><a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload虽然能下载文件，但对中文支持不足。若下载的文件名中有汉字，则浏览器在提示另存的文件名时，显示的是一堆乱码，很扫人兴。上面的例子就是这样。（这个问题也是众多下载组件所存在的问题，很少有人解决，搜索不到相关资料，可叹！） <br /><br />为了给<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload组件增加下载中文文件的支持，我对该组件进行了研究，发现对返回给浏览器的另存文件名进行UTF-8编码后，浏览器便能正确显示中文名字了。这是一个令人高兴的发现。于是我对<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload组件的SmartUpload类做了升级处理，增加了toUtf8String这个方法，改动部分源码如下： <br /><br />public void downloadFile(String s, String s1, String s2, int i)<br />throws ServletException, IOException, SmartUploadException<br />    {<br />if(s == null)<br />    throw new IllegalArgumentException("File ''" + s +<br />    "'' not found (1040).");<br />if(s.equals(""))<br />    throw new IllegalArgumentException("File ''" + s +<br />    "'' not found (1040).");<br />if(!isVirtual(s) &amp;&amp; m_denyPhysicalPath)<br />    throw new SecurityException("Physical path is<br />    denied (1035).");<br />if(isVirtual(s))<br />    s = m_application.getRealPath(s);<br />java.io.File file = new java.io.File(s);<br />FileInputStream fileinputstream = new FileInputStream(file);<br />long l = file.length();<br />boolean flag = false;<br />int k = 0;<br />byte abyte0[] = new byte[i];<br />if(s1 == null)<br />    m_response.setContentType("application/x-msdownload");<br />else<br />if(s1.length() == 0)<br />    m_response.setContentType("application/x-msdownload");<br />else<br />    m_response.setContentType(s1);<br />m_response.setContentLength((int)l);<br />m_contentDisposition = m_contentDisposition != null ?<br />m_contentDisposition : "attachment;";<br />if(s2 == null)<br />    m_response.setHeader("Content-Disposition", <br />    m_contentDisposition + " filename=" + <br />    toUtf8String(getFileName(s)));<br />else<br />if(s2.length() == 0)<br />    m_response.setHeader("Content-Disposition", <br />    m_contentDisposition);<br />else<br />    m_response.setHeader("Content-Disposition", <br />    m_contentDisposition + " filename=" + toUtf8String(s2));<br />while((long)k &lt; l)<br />{<br />    int j = fileinputstream.read(abyte0, 0, i);<br />    k += j;<br />    m_response.getOutputStream().write(abyte0, 0, j);<br />}<br />fileinputstream.close();<br />    }<br /><br />    /**<br />     * 将文件名中的汉字转为UTF8编码的串,以便下载时能正确显示另存的文件名.<br />     * 纵横软件制作中心雨亦奇2003.08.01<br />     * @param s 原文件名<br />     * @return 重新编码后的文件名<br />     */<br />    public static String toUtf8String(String s) {<br />StringBuffer sb = new StringBuffer();<br />for (int i=0;i&lt;s.length();i++) {<br />    char c = s.charAt(i);<br />    if (c &gt;= 0 &amp;&amp; c &lt;= 255) {<br />sb.append(c);<br />    } else {<br />byte[] b;<br />try {<br />    b = Character.toString(c).getBytes("utf-8");<br />} catch (Exception ex) {<br />    System.out.println(ex);<br />    b = new byte[0];<br />}<br />for (int j = 0; j &lt; b.length; j++) {<br />    int k = b[j];<br />    if (k &lt; 0) k += 256;<br />    sb.append("%" + Integer.toHexString(k).<br />    toUpperCase());<br />}<br />    }<br />}<br />return sb.toString();<br />    }<br /> <br /><br /><br />注意源码中粗体部分，原<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload组件对返回的文件未作任何处理，现在做了编码的转换工作，将文件名转换为UTF-8形式的编码形式。UTF-8编码对英文未作任何处理，对中文则需要转换为%XX的形式。toUtf8String方法中，直接利用Java语言提供的编码转换方法获得汉字字符的UTF-8编码，之后将其转换为%XX的形式。 <br /><br />将源码编译后打包成<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload.jar，拷贝到Tomcat的shared/lib目录下（可为所有WEB应用程序所共享），然后重启Tomcat服务器就可以正常下载含有中文名字的文件了。另，toUtf8String方法也可用于转换含有中文的超级链接，以保证链接的有效，因为有的WEB服务器不支持中文链接。 <br /><br />小结：<a class="Channel_KeyLink" href="http://www.skyuu.com/Article/ShowClass.asp?ClassID=115">jsp</a>SmartUpload组件是应用JSP进行B/S程序开发过程中经常使用的上传下载组件，它使用简单，方便。现在我又为其加上了下载中文名字的文件的支持，真个是如虎添翼，必将赢得更多开发者的青睐。<br /><br /><br /><br /><br /><span class="bright-subject"><a name="204493"></a><font color="#cc0066">smartupload中文乱码文题</font><br />smartupload存在字符编码的问题，下面是处理下载时使用中文文件名的处理方法(转贴)，上传可以采用类似的方法：<br />jspSmartUpload虽然能下载文件，但对中文支持不足。若下载的文件名中有汉字，则浏览器在提示另存的文件名时，显示的是一堆乱码，很扫人兴。上面的例子就是这样。（这个问题也是众多下载组件所存在的问题，很少有人解决，搜索不到相关资料，可叹！） <br /><br />为了给jspSmartUpload组件增加下载中文文件的支持，我对该组件进行了研究，发现对返回给浏览器的另存文件名进行UTF-8编码后，浏览器便能正确显示中文名字了。这是一个令人高兴的发现。于是我对jspSmartUpload组件的SmartUpload类做了升级处理，增加了toUtf8String这个方法，改动部分源码如下： <br /><br />public void downloadFile(String s, String s1, String s2, int i)<br />throws ServletException, IOException, SmartUploadException<br />    {<br />if(s == null)<br />    throw new IllegalArgumentException("File ''''" + s +<br />    "'''' not found (1040).");<br />if(s.equals(""))<br />    throw new IllegalArgumentException("File ''''" + s +<br />    "'''' not found (1040).");<br />if(!isVirtual(s) &amp;&amp; m_denyPhysicalPath)<br />    throw new SecurityException("Physical path is<br />    denied (1035).");<br />if(isVirtual(s))<br />    s = m_application.getRealPath(s);<br />java.io.File file = new java.io.File(s);<br />FileInputStream fileinputstream = new FileInputStream(file);<br />long l = file.length();<br />boolean flag = false;<br />int k = 0;<br />byte abyte0[] = new byte<i>;<br />if(s1 == null)<br />    m_response.setContentType("application/x-msdownload");<br />else<br />if(s1.length() == 0)<br />    m_response.setContentType("application/x-msdownload");<br />else<br />    m_response.setContentType(s1);<br />m_response.setContentLength((int)l);<br />m_contentDisposition = m_contentDisposition != null ?<br />m_contentDisposition : "attachment;";<br />if(s2 == null)<br />    m_response.setHeader("Content-Disposition", <br />    m_contentDisposition + " filename=" + <br />    toUtf8String(getFileName(s)));<br />else<br />if(s2.length() == 0)<br />    m_response.setHeader("Content-Disposition", <br />    m_contentDisposition);<br />else<br />    m_response.setHeader("Content-Disposition", <br />    m_contentDisposition + " filename=" + toUtf8String(s2));<br />while((long)k &lt; l)<br />{<br />    int j = fileinputstream.read(abyte0, 0, i);<br />    k += j;<br />    m_response.getOutputStream().write(abyte0, 0, j);<br />}<br />fileinputstream.close();<br />    }<br /><br />    /**<br />     * 将文件名中的汉字转为UTF8编码的串,以便下载时能正确显示另存的文件名.<br />     * 纵横软件制作中心雨亦奇2003.08.01<br />     * @param s 原文件名<br />     * @return 重新编码后的文件名<br />     */<br />    public static String toUtf8String(String s) {<br />StringBuffer sb = new StringBuffer();<br />for (int i=0;i&lt;s.length();i++) {<br />    char c = s.charAt(i);<br />    if (c &gt;= 0 &amp;&amp; c &lt;= 255) {<br />sb.append(c);<br />    } else {<br />byte[] b;<br />try {<br />    b = Character.toString(c).getBytes("utf-8");<br />} catch (Exception ex) {<br />    System.out.println(ex);<br />    b = new byte[0];<br />}<br />for (int j = 0; j &lt; b.length; j++) {<br />    int k = b[j];<br />    if (k &lt; 0) k += 256;<br />    sb.append("%" + Integer.toHexString(k).<br />    toUpperCase());<br />}<br />    }<br />}<br />return sb.toString();<br />    }<br /></i><br /></span></div>
<img src ="http://www.blogjava.net/liaojiyong/aggbug/56388.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-07-03 17:24 <a href="http://www.blogjava.net/liaojiyong/archive/2006/07/03/56388.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>介绍一篇关于session的好文章,写的很详细(jsp-servlet 技术) （转）</title><link>http://www.blogjava.net/liaojiyong/archive/2006/06/29/55750.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Thu, 29 Jun 2006 06:54:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/06/29/55750.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/55750.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/06/29/55750.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/55750.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/55750.html</trackback:ping><description><![CDATA[
		<div class="postTitle">
				<span class="content">
						<br />
						<br />
						<font color="#000000">摘要：虽然session机制在web应用程序中被采用已经很长时间了，但是仍然有很多人不清楚session机制的本质，以至不能正确的应用这一技术。本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答。<br /><br />目录：<br />一、术语session<br />二、HTTP协议与状态保持<br />三、理解cookie机制<br />四、理解session机制<br />五、理解javax.servlet.http.HttpSession<br />六、HttpSession常见问题<br />七、跨应用程序的session共享<br />八、总结<br />参考文档<br /><br />一、术语session<br />在我的经验里，session这个词被滥用的程度大概仅次于transaction，更加有趣的是transaction与session在某些语境下的含义是相同的。<br /><br />session，中文经常翻译为会话，其本来的含义是指有始有终的一系列动作/消息，比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个 session。有时候我们可以看到这样的话“在一个浏览器会话期间，...”，这里的会话一词用的就是其本义，是指从一个浏览器窗口打开到关闭这个期间 ①。最混乱的是“用户（客户端）在一次会话期间”这样一句话，它可能指用户的一系列动作（一般情况下是同某个具体目的相关的一系列动作，比如从登录到选购商品到结账登出这样一个网上购物的过程，有时候也被称为一个transaction），然而有时候也可能仅仅是指一次连接，也有可能是指含义①，其中的差别只能靠上下文来推断②。<br /><br />然而当session一词与网络协议相关联时，它又往往隐含了“面向连接”和/或“保持状态”这样两个含义， “面向连接”指的是在通信双方在通信之前要先建立一个通信的渠道，比如打电话，直到对方接了电话通信才能开始，与此相对的是写信，在你把信发出去的时候你并不能确认对方的地址是否正确，通信渠道不一定能建立，但对发信人来说，通信已经开始了。“保持状态”则是指通信的一方能够把一系列的消息关联起来，使得消息之间可以互相依赖，比如一个服务员能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有“一个TCP session”或者 “一个POP3 session”③。<br /><br />而到了web服务器蓬勃发展的时代，session在web开发语境下的语义又有了新的扩展，它的含义是指一类用来在客户端与服务器之间保持状态的解决方案④。有时候session也用来指这种解决方案的存储结构，如“把xxx保存在session 里”⑤。由于各种用于web开发的语言在一定程度上都提供了对这种解决方案的支持，所以在某种特定语言的语境下，session也被用来指代该语言的解决方案，比如经常把Java里提供的javax.servlet.http.HttpSession简称为session⑥。<br /><br />鉴于这种混乱已不可改变，本文中session一词的运用也会根据上下文有不同的含义，请大家注意分辨。<br />在本文中，使用中文“浏览器会话期间”来表达含义①，使用“session机制”来表达含义④，使用“session”表达含义⑤，使用具体的“HttpSession”来表达含义⑥<br /><br />二、HTTP协议与状态保持<br />HTTP 协议本身是无状态的，这与HTTP协议本来的目的是相符的，客户端只需要简单的向服务器请求下载某些文件，无论是客户端还是服务器都没有必要纪录彼此过去的行为，每一次请求之间都是独立的，好比一个顾客和一个自动售货机或者一个普通的（非会员制）大卖场之间的关系一样。<br /><br />然而聪明（或者贪心？）的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用，就像给有线电视加上点播功能一样。这种需求一方面迫使HTML逐步添加了表单、脚本、DOM等客户端行为，另一方面在服务器端则出现了CGI规范以响应客户端的动态请求，作为传输载体的HTTP协议也添加了文件上载、 cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的session机制则是又一种在客户端与服务器之间保持状态的解决方案。<br /><br />让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠，然而一次性消费5杯咖啡的机会微乎其微，这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案：<br />1、该店的店员很厉害，能记住每位顾客的消费数量，只要顾客一走进咖啡店，店员就知道该怎么对待了。这种做法就是协议本身支持状态。<br />2、发给顾客一张卡片，上面记录着消费的数量，一般还有个有效期限。每次消费时，如果顾客出示这张卡片，则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。<br />3、发给顾客一张会员卡，除了卡号之外什么信息也不纪录，每次消费时，如果顾客出示该卡片，则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。<br /><br />由于HTTP协议是无状态的，而出于种种考虑也不希望使之成为有状态的，因此，后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案，而session机制采用的是在服务器端保持状态的方案。同时我们也看到，由于采用服务器端保持状态的方案在客户端也需要保存一个标识，所以session机制可能需要借助于cookie机制来达到保存标识的目的，但实际上它还有其他选择。<br /><br />三、理解cookie机制 <br />cookie机制的基本原理就如上面的例子一样简单，但是还有几个问题需要解决：“会员卡”如何分发；“会员卡”的内容；以及客户如何使用“会员卡”。<br /><br />正统的cookie分发是通过扩展HTTP协议来实现的，服务器通过在HTTP的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的cookie。然而纯粹的客户端脚本如JavaScript或者VBScript也可以生成cookie。<br /><br />而cookie 的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的cookie，如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置，则把该cookie附在请求资源的HTTP请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示，如果某家分店还发行了自己的会员卡，那么进这家店的时候除了要出示麦当劳的会员卡，还要出示这家店的会员卡。<br /><br />cookie的内容主要包括：名字，值，过期时间，路径和域。<br />其中域可以指定某一个域比如.google.com，相当于总店招牌，比如宝洁公司，也可以指定一个域下的具体某台机器比如www.google.com或者froogle.google.com，可以用飘柔来做比。<br />路径就是跟在域名后面的URL路径，比如/或者/foo等等，可以用某飘柔专柜做比。<br />路径与域合在一起就构成了cookie的作用范围。<br />如果不设置过期时间，则表示这个cookie的生命期为浏览器会话期间，只要关闭浏览器窗口，cookie就消失了。这种生命期为浏览器会话期的 cookie被称为会话cookie。会话cookie一般不存储在硬盘上而是保存在内存里，当然这种行为并不是规范规定的。如果设置了过期时间，浏览器就会把cookie保存到硬盘上，关闭后再次打开浏览器，这些cookie仍然有效直到超过设定的过期时间。<br /><br />存储在硬盘上的cookie 可以在不同的浏览器进程间共享，比如两个IE窗口。而对于保存在内存里的cookie，不同的浏览器有不同的处理方式。对于IE，在一个打开的窗口上按 Ctrl-N（或者从文件菜单）打开的窗口可以与原窗口共享，而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie；对于 Mozilla Firefox0.8，所有的进程和标签页都可以共享同样的cookie。一般来说是用javascript的window.open打开的窗口会与原窗口共享内存cookie。浏览器对于会话cookie的这种只认cookie不认人的处理方式经常给采用session机制的web应用程序开发者造成很大的困扰。<br /><br />下面就是一个goolge设置cookie的响应头的例子<br />HTTP/1.1 302 Found<br />Location:  </font>
						<a href="http://www.google.com/intl/zh-CN/">
						</a>
						<a href="http://www.google.com/intl/zh-CN/" target="_blank">
								<font color="#000000">http://www.google.com/intl/zh-CN/</font>
						</a>
						<br />
						<font color="#000000">Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com<br />Content-Type: text/html<br /><br /><br /><br /><br />这是使用HTTPLook这个HTTP Sniffer软件来俘获的HTTP通讯纪录的一部分<br /><br /><br /><br /><br />浏览器在再次访问goolge的资源时自动向外发送cookie<br /><br /><br /><br /><br />使用Firefox可以很容易的观察现有的cookie的值<br />使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。<br /><br /><br /><br /><br />IE也可以设置在接受cookie前询问<br /><br /><br /><br /><br />这是一个询问接受cookie的对话框。<br /><br />四、理解session机制<br />session机制是一种服务器端的机制，服务器使用一种类似于散列表的结构（也可能就是使用散列表）来保存信息。<br /><br />当程序需要为某个客户端的请求创建一个session的时候，服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为 session id，如果已包含一个session id则说明以前已经为此客户端创建过session，服务器就按照session id把这个 session检索出来使用（如果检索不到，可能会新建一个），如果客户端请求不包含session id，则为此客户端创建一个session并且生成一个与此session相关联的session id，session id的值应该是一个既不会重复，又不容易被找到规律以仿造的字符串，这个 session id将被在本次响应中返回给客户端保存。<br /><br />保存这个session id的方式可以采用cookie，这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID，而。比如weblogic对于web应用程序生成的cookie，JSESSIONID= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764，它的名字就是 JSESSIONID。<br /><br />由于cookie可以被人为的禁止，必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写，就是把session id直接附加在URL路径的后面，附加方式也有两种，一种是作为URL路径的附加信息，表现形式为 </font>
						<a href="http://...../xxx;jsessionid=">
						</a>
						<a href="http://...../xxx;jsessionid=" target="_blank">
								<font color="#000000">http://...../xxx;jsessionid= </font>
						</a>
						<font color="#000000"> ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764<br />另一种是作为查询字符串附加在URL后面，表现形式为 </font>
						<a href="http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
						</a>
						<a href="http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764" target="_blank">
								<font color="#000000">http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764 </font>
						</a>
						<br />
						<font color="#000000">这两种方式对于用户来说是没有区别的，只是服务器在解析的时候处理的方式不同，采用第一种方式也有利于把session id的信息和正常程序参数区分开来。<br />为了在整个交互过程中始终保持状态，就必须在每个客户端可能请求的路径后面都包含这个session id。<br /><br />另一种技术叫做表单隐藏字段。就是服务器会自动修改表单，添加一个隐藏字段，以便在表单提交时能够把session id传递回服务器。比如下面的表单<br />&lt;form name="testform" action="/xxx"&gt;<br />&lt;input type="text"&gt;<br />&lt;/form&gt;<br />在被传递给客户端之前将被改写成<br />&lt;form name="testform" action="/xxx"&gt;<br />&lt;input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764"&gt;<br />&lt;input type="text"&gt;<br />&lt;/form&gt;<br />这种技术现在已较少应用，笔者接触过的很古老的iPlanet6(SunONE应用服务器的前身)就使用了这种技术。<br />实际上这种技术可以简单的用对action应用URL重写来代替。<br /><br />在谈论session机制的时候，常常听到这样一种误解“只要关闭浏览器，session就消失了”。其实可以想象一下会员卡的例子，除非顾客主动对店家提出销卡，否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的，除非程序通知服务器删除一个session，否则服务器会一直保留，程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭，因此服务器根本不会有机会知道浏览器已经关闭，之所以会有这种错觉，是大部分session机制都使用会话cookie来保存session id，而关闭浏览器后这个 session id就消失了，再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上，或者使用某种手段改写浏览器发出的HTTP请求头，把原来的session id发送给服务器，则再次打开浏览器仍然能够找到原来的session。<br /><br />恰恰是由于关闭浏览器不会导致session被删除，迫使服务器为seesion设置了一个失效时间，当距离客户端上一次使用session的时间超过这个失效时间时，服务器就可以认为客户端已经停止了活动，才会把session删除以节省存储空间。<br /><br />五、理解javax.servlet.http.HttpSession<br />HttpSession是Java平台对session机制的实现规范，因为它仅仅是个接口，具体到每个web应用服务器的提供商，除了对规范支持之外，仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作为例子来演示。<br /><br />首先，Weblogic Server提供了一系列的参数来控制它的HttpSession的实现，包括使用cookie的开关选项，使用URL重写的开关选项，session持久化的设置，session失效时间的设置，以及针对cookie的各种设置，比如设置cookie的名字、路径、域， cookie的生存时间等。<br /><br />一般情况下，session都是存储在内存里，当服务器进程被停止或者重启的时候，内存里的session也会被清空，如果设置了session的持久化特性，服务器就会把session保存到硬盘上，当服务器进程重新启动或这些信息将能够被再次使用， Weblogic Server支持的持久性方式包括文件、数据库、客户端cookie保存和复制。<br /><br />复制严格说来不算持久化保存，因为session实际上还是保存在内存里，不过同样的信息被复制到各个cluster内的服务器进程中，这样即使某个服务器进程停止工作也仍然可以从其他进程中取得session。<br /><br />cookie生存时间的设置则会影响浏览器生成的cookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解。<br /><br />cookie的路径对于web应用程序来说是一个非常重要的选项，Weblogic Server对这个选项的默认处理方式使得它与其他服务器有明显的区别。后面我们会专题讨论。<br /><br />关于session的设置参考[5]  </font>
						<a href="http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869">
						</a>
						<a href="http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869" target="_blank">
								<font color="#000000">http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869 </font>
						</a>
						<br />
						<br />
						<font color="#000000">六、HttpSession常见问题<br />（在本小节中session的含义为⑤和⑥的混合）<br /><br /><br />1、session在何时被创建<br />一个常见的误解是以为session在有客户端访问时就被创建，然而事实是直到某server端程序调用 HttpServletRequest.getSession(true)这样的语句时才被创建，注意如果JSP没有显示的使用 &lt;% @page session="false"%&gt; 关闭session，则JSP文件在编译成Servlet时将会自动加上这样一条语句 HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的 session对象的来历。<br /><br />由于session会消耗内存资源，因此，如果不打算使用session，应该在所有的JSP中关闭它。<br /><br />2、session何时被删除<br />综合前面的讨论，session在下列情况下被删除a.程序调用HttpSession.invalidate();或b.距离上一次收到客户端发送的session id时间间隔超过了session的超时设置;或c.服务器进程被停止（非持久session）<br /><br />3、如何做到在浏览器关闭时删除session<br />严格的讲，做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作，然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。<br /><br />4、有个HttpSessionListener是怎么回事<br />你可以创建这样的listener去监控session的创建和销毁事件，使得在发生这样的事件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listener，而不是相反。类似的与HttpSession有关的listener还有 HttpSessionBindingListener，HttpSessionActivationListener和 HttpSessionAttributeListener。<br /><br />5、存放在session中的对象必须是可序列化的吗<br />不是必需的。要求对象可序列化只是为了session能够在集群中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。在 Weblogic Server的session中放置一个不可序列化的对象在控制台上会收到一个警告。我所用过的某个iPlanet版本如果 session中有不可序列化的对象，在session销毁时会有一个Exception，很奇怪。<br /><br />6、如何才能正确的应付客户端禁止cookie的可能性<br />对所有的URL使用URL重写，包括超链接，form的action，和重定向的URL，具体做法参见[6]<br /></font>
						<a href="http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770">
						</a>
						<a href="http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770" target="_blank">
								<font color="#000000">http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770 </font>
						</a>
						<br />
						<br />
						<font color="#000000">7、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session<br />参见第三小节对cookie的讨论，对session来说是只认id不认人，因此不同的浏览器，不同的窗口打开方式以及不同的cookie存储方式都会对这个问题的答案有影响。<br /><br />8、如何防止用户打开两个浏览器窗口操作导致的session混乱<br />这个问题与防止表单多次提交是类似的，可以通过设置客户端的令牌来解决。就是在服务器每次生成一个不同的id返回给客户端，同时保存在session里，客户端提交表单时必须把这个id也返回服务器，程序首先比较返回的id与保存在session里的值是否一致，如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表示层模式的部分。需要注意的是对于使用javascript window.open打开的窗口，一般不设置这个id，或者使用单独的id，以防主窗口无法操作，建议不要再window.open打开的窗口里做修改操作，这样就可以不用设置。<br /><br />9、为什么在Weblogic Server中改变session的值后要重新调用一次session.setValue<br />做这个动作主要是为了在集群环境中提示Weblogic Server session中的值发生了改变，需要向其他服务器进程复制新的session值。<br /><br />10、为什么session不见了<br />排除session正常失效的因素之外，服务器本身的可能性应该是微乎其微的，虽然笔者在iPlanet6SP1加若干补丁的Solaris版本上倒也遇到过；浏览器插件的可能性次之，笔者也遇到过3721插件造成的问题；理论上防火墙或者代理服务器在cookie处理上也有可能会出现问题。<br />出现这一问题的大部分原因都是程序的错误，最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨论这个问题。<br /><br />七、跨应用程序的session共享<br /><br />常常有这样的情况，一个大项目被分割成若干小项目开发，为了能够互不干扰，要求每个小项目作为一个单独的web应用程序开发，可是到了最后突然发现某几个小项目之间需要共享一些信息，或者想使用session来实现SSO(single sign on)，在session中保存login的用户信息，最自然的要求是应用程序间能够访问彼此的session。<br /><br />然而按照Servlet规范，session的作用范围应该仅仅限于当前应用程序下，不同的应用程序之间是不能够互相访问对方的session的。各个应用服务器从实际效果上都遵守了这一规范，但是实现的细节却可能各有不同，因此解决跨应用程序session共享的方法也各不相同。<br /><br />首先来看一下Tomcat是如何实现web应用程序之间session的隔离的，从 Tomcat设置的cookie路径来看，它对不同的应用程序设置的cookie路径是不同的，这样不同的应用程序所用的session id是不同的，因此即使在同一个浏览器窗口里访问不同的应用程序，发送给服务器的session id也可以是不同的。<br /><br /><br />  <br /><br />根据这个特性，我们可以推测Tomcat中session的内存结构大致如下。<br /><br /><br /><br /><br />笔者以前用过的iPlanet也采用的是同样的方式，估计SunONE与iPlanet之间不会有太大的差别。对于这种方式的服务器，解决的思路很简单，实际实行起来也不难。要么让所有的应用程序共享一个session id，要么让应用程序能够获得其他应用程序的session id。<br /><br />iPlanet中有一种很简单的方法来实现共享一个session id，那就是把各个应用程序的cookie路径都设为/（实际上应该是/NASApp，对于应用程序来讲它的作用相当于根）。<br />&lt;session-info&gt;<br />&lt;path&gt;/NASApp&lt;/path&gt;<br />&lt;/session-info&gt;<br /><br />需要注意的是，操作共享的session应该遵循一些编程约定，比如在session attribute名字的前面加上应用程序的前缀，使得 setAttribute("name", "neo")变成setAttribute("app1.name", "neo")，以防止命名空间冲突，导致互相覆盖。<br /><br /><br />在Tomcat中则没有这么方便的选择。在Tomcat版本3上，我们还可以有一些手段来共享session。对于版本4以上的Tomcat，目前笔者尚未发现简单的办法。只能借助于第三方的力量，比如使用文件、数据库、JMS或者客户端cookie，URL参数或者隐藏字段等手段。<br /><br />我们再看一下Weblogic Server是如何处理session的。<br /><br /><br />  <br /><br />从截屏画面上可以看到Weblogic Server对所有的应用程序设置的cookie的路径都是/，这是不是意味着在Weblogic Server中默认的就可以共享session了呢？然而一个小实验即可证明即使不同的应用程序使用的是同一个session，各个应用程序仍然只能访问自己所设置的那些属性。这说明Weblogic Server中的session的内存结构可能如下<br /><br /><br /><br /><br />对于这样一种结构，在 session机制本身上来解决session共享的问题应该是不可能的了。除了借助于第三方的力量，比如使用文件、数据库、JMS或者客户端 cookie，URL参数或者隐藏字段等手段，还有一种较为方便的做法，就是把一个应用程序的session放到ServletContext中，这样另外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下，<br /><br />应用程序A<br />context.setAttribute("appA", session); <br /><br />应用程序B<br />contextA = context.getContext("/appA");<br />HttpSession sessionA = (HttpSession)contextA.getAttribute("appA"); <br /><br />值得注意的是这种用法不可移植，因为根据ServletContext的JavaDoc，应用服务器可以处于安全的原因对于context.getContext("/appA");返回空值，以上做法在Weblogic Server 8.1中通过。<br /><br />那么Weblogic Server为什么要把所有的应用程序的cookie路径都设为/呢？原来是为了SSO，凡是共享这个session的应用程序都可以共享认证的信息。一个简单的实验就可以证明这一点，修改首先登录的那个应用程序的描述符weblogic.xml，把cookie路径修改为/appA 访问另外一个应用程序会重新要求登录，即使是反过来，先访问cookie路径为/的应用程序，再访问修改过路径的这个，虽然不再提示登录，但是登录的用户信息也会丢失。注意做这个实验时认证方式应该使用FORM，因为浏览器和web服务器对basic认证方式有其他的处理方式，第二次请求的认证不是通过 session来实现的。具体请参看[7] secion 14.8 Authorization，你可以修改所附的示例程序来做这些试验。<br /><br />八、总结<br />session机制本身并不复杂，然而其实现和配置上的灵活性却使得具体情况复杂多变。这也要求我们不能把仅仅某一次的经验或者某一个浏览器，服务器的经验当作普遍适用的经验，而是始终需要具体情况具体分析。<br />摘要：虽然session机制在web应用程序中被采用已经很长时间了，但是仍然有很多人不清楚session机制的本质，以至不能正确的应用这一技术。本文将详细讨论session的工作机制并且对在Java web application中应用session机制时常见的问题作出解答。 </font>
				</span>
				<font color="#000000">
				</font>
		</div>
<img src ="http://www.blogjava.net/liaojiyong/aggbug/55750.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-06-29 14:54 <a href="http://www.blogjava.net/liaojiyong/archive/2006/06/29/55750.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP实用篇（转）</title><link>http://www.blogjava.net/liaojiyong/archive/2006/06/29/55749.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Thu, 29 Jun 2006 06:52:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/06/29/55749.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/55749.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/06/29/55749.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/55749.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/55749.html</trackback:ping><description><![CDATA[
		<div class="postText">一，重定向页面<br /><br />1,response.sendRedirect("url");<br />2,response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);<br />response.setHeader("Location",newLocation);<br /><br />二，HTML Encoder和URL Encoder<br /><br />1,HTML Encoder自定义，原则：''不输出,'&amp;'-"&amp;amp;",'&lt;'-"&amp;lt;",'&gt;'-"gt;",'"'-"&amp;quot;"<br />2,URLEncoder 在java.net包中有定义<br />原型：public static String encode(String s)<br />例如：URLEncoder.encode("http://wwww.aaa.com/sss.jsp?name=小鬼")<br /><br />三，在JSP中读写文件<br /><br />1，用FileOutputStream初始化PrintWriter,然后用print或者println方法写文件<br />PrintWriter pw=new PrintWriter(new FileOutputStream("file1.txt"));<br />pw.println("Hello world!");<br />pw.close();//若有错误thow IOException<br /><br />用FileWriter初始化PrintWriter,然后用print或者println方法写文件<br />File f=new File("file1.txt");<br />PrintWriter pw=new PrintWriter(new FileWriter(f));<br />pw.print("Hello world!\n");<br />pw.close();<br />2，用InputStreamReader或者FileReader初始化BufferedReader,然后用readLine()方法读取文件<br />BufferedReader br=new BufferedReader(new FileReader("file1.txt"));<br />String rt=br.readLine();//结尾为null<br />br.close();<br />3，用FileWriter初始化PrintWriter,然后用pint或者println方法添加文件<br />PrintWriter pw=new PrintWriter(new FileWriter("file1.txt"),true);<br />4，import java.io.*;<br />File f=new File(request.getRealPath(""),"file1.txt");<br />boolean f.exists();<br />f.delete();f.createNewFile();<br /><br />File d=new File(request.getRealPath(""));<br />boolean d.exists();<br />d.delete();d.mkdir();<br /><br />request.getRealPath("url");//虚拟目录映射为实际目录<br />request.getRealPath("./");//网页所在的目录<br />request.getRealPath("../");//网页所在目录的上一层目录<br /><br />File f=new File("path","file1.txt");<br />f.getName();<br />f.isFile();<br />f.isDirectory();<br />f.canRead();<br />f.canWrite();<br />f.isHidden();<br />f.lastModified;<br />f.createNewFile();<br />f.length();<br /><br />File d=new File("path");<br />File list[]=d.listFiles();//list是一个File数组<br />for(int i=0;i&lt;list.length;i++)out.println(list[i].getName());<br /><br />FileReader fr=new FileReader("path"+"\\file1.txt");<br />if(fr.read()==-1)//空文件<br />fr.close();<br />fr.read(int i)//读取i个字符，-1如果不再有数据<br />//用BufferedReader可以一次读取一行数据<br />fr.skip(int i);//略过i个字符<br /><br /><br />在引用parseInt等函数的时候，出错是NumberFormatException等<br />Random获得随机数，<br />Random rd=new Random((new Date()).getTime());<br />int p=Math.abs(rd.nextInt())%s;//s为0到的范围<br /><br />四，URL重组、表单隐藏域Cookie<br /><br />1,这些是用来弥补HTTP协议无状态特征的技术（Sessions技术）的一部分<br />2，URL重组是用Get方法向服务器发送的信息“?param1=value1&amp;param2=value2&amp;...&amp;paramn=valuen”<br />如果服务器已经在超链接上面作了session标记，那么客户端通过这个走超链接发送请来时就会包含此标记<br />3，form中的&lt;input type=hidden name="key1" value="value1" /&gt;也可以像URL重组那样使用。<br />4，Cookie对象<br />Cookie <span id="google-navclient-hilite" style="COLOR: black; BACKGROUND-COLOR: yellow">c</span>=new Cookie("key", "value");<br />response.addCookie(<span id="google-navclient-hilite" style="COLOR: black; BACKGROUND-COLOR: yellow">c</span>);<br /><br />Cookie[] <span id="google-navclient-hilite" style="COLOR: black; BACKGROUND-COLOR: yellow">c</span>=request.getCookies();<br /><span id="google-navclient-hilite" style="COLOR: black; BACKGROUND-COLOR: yellow">c</span>.<span id="google-navclient-hilite" style="COLOR: black; BACKGROUND-COLOR: cyan">setMaxAge</span>(int k);//k以秒为单位<br />一般浏览器能放20个Cookie<br /><br />五，session对象<br /><br />1，session对象不仅仅能放String数据，还能放复杂的对象。<br />2，session.putValue("key1",Object1);<br />Object o=session.getValue("key1");<br /><br />六，处理JSP中的中文问题<br /><br />1，ASCII码<br />8bit存储，0~31和127是控制字符，32～126是可见字符。<br />2，GB2312<br />两个8bit表示。前一个127～255，以区分ASCII码。<br />3，Unicode<br />可以将世界上几十种文字编码统一在同一种编码机制下。以16bit为单位存储。0x0000~0xffff<br />4，ISO-8859-1 或称为Latin-1,8859-1。在Unicode所占的值域为0~255,低位为ASCII扩展到0～255，然后在高位补上0x00,组成16bit（此处不太懂）。<br />5，字节和unicode Java内核是unicode,class文件也是。但是流却是采用的byte方式。char为unicode方式，byte是字节方式。转换函数：sun.io里面：<br />public static ByteToCharConverter getDefault();//获取系统使用的编码方式。<br />public static ByteToCharConverter getConverter(String encoding);<br />ByteToCharConverter <span id="google-navclient-hilite" style="COLOR: black; BACKGROUND-COLOR: yellow">c</span>=New ByteToCharConverter(["encoding"]);<br />Byte[] s=<span id="google-navclient-hilite" style="COLOR: black; BACKGROUND-COLOR: yellow">c</span>.convertAll(Char[] d);<br />也可以 Char[] d=<span id="google-navclient-hilite" style="COLOR: black; BACKGROUND-COLOR: yellow">c</span>.converterAll(Byte[] s);<br />6,一些函数：<br />Integer.toHexString(int i);<br />String s;s.getBytes();<br />String(byte[]);String(byte[],encoding);//constructors<br />//关于Unicode编码打算单独写一篇<br /><br />七，获取JVM属性值<br /><br />Properties props=System.getProperties();<br />Enumeration enum=props.propertyNames(); //key枚举<br />key=(String)enum.nextElement();<br />String s=(String)props.getProperty(key);<br /><br />八，JSP错误处理<br /><br />1，所有可被throw和catch的Exception对象都继承自Throwable。Exception应该被catch才对;Error对象也是继承自Throwable，只是不应该catch，而的结束程序。<br />2，catch序列针对的Exception应该从低级到高级才对。<br />3，转译错误和客户端端请求错误。jsp源程序错误、import路径不正确等会在生成Servlet Class文档时产生转译错误(500)。在执行Servlet Class时客户端请求错误会被catch。<br />4，错误产生时，可以jsp:forward来控制，但更好是用errorPage来处理。也可以throw new Exception("errMsg")。<br /><br /><p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=601253</p></div>
<img src ="http://www.blogjava.net/liaojiyong/aggbug/55749.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-06-29 14:52 <a href="http://www.blogjava.net/liaojiyong/archive/2006/06/29/55749.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于JSP文件路径问题 (转)</title><link>http://www.blogjava.net/liaojiyong/archive/2006/06/16/53301.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Fri, 16 Jun 2006 06:45:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/06/16/53301.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/53301.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/06/16/53301.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/53301.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/53301.html</trackback:ping><description><![CDATA[
		<code>＜%@ page contentType="text/html;charset=gb2312"%&gt; <br />＜%@ page import="java.io.*"%&gt; <br />＜html&gt; <br />＜head&gt; <br />＜title&gt;文件的建立、检查与删除＜/title&gt; <br />＜/head&gt; <br />＜body&gt; <br />＜% <br />String path=request.getRealPath(""); <br />//out.println(path); <br />File f=new File(path,"File.txt"); <br />//out.println(f); <br />//out.println(f.exists()); <br /><br />if(f.exists()){//检查File.txt是否存在 <br />f.delete();//删除File.txt文件 <br />out.println(path + "\\File.txt 存在，已删除。"); <br />}else{ <br />f.createNewFile();//在当前目录下建立一个名为File.txt的文件 <br />out.println(path + "\\File.txt 不存在，已建立。");//输出目前所在的目录路径 <br />} <br />%&gt; <br /><br /></code>
		<strong>目录的建立/检查与删除</strong>
		<br />
		<code>＜%@ page contentType="text/html;charset=gb2312"%&gt; <br />＜%@ page import="java.io.*"%&gt; <br />＜html&gt; <br />＜head&gt; <br />＜title&gt;目录的建立/检查与删除＜/title&gt; <br />＜/head&gt; <br />＜body&gt; <br />＜% <br />String path=request.getRealPath(""); <br />path=path + "\\Sub";//将要建立的目录路径 <br />File d=new File(path);//建立代表Sub目录的File对象，并得到它的一个引用 <br />if(d.exists()){//检查Sub目录是否存在 <br />d.delete(); <br />out.println("Sub目录存在，已删除"); <br />}else{ <br />d.mkdir();//建立Sub目录 <br />out.println("Sub目录不存在，已建立"); <br />} <br />%&gt; <br />＜/body&gt; <br />＜/html&gt; <br /><br /></code>
		<br />
		<strong>如何在JSP中处理虚拟目录</strong>
		<br />
		<code>＜%@ page contentType="text/html;charset=gb2312"%&gt; <br />＜%@ page import="java.io.*"%&gt; <br />＜html&gt; <br />＜head&gt; <br />＜title&gt;JSP中如何处理虚拟目录＜/title&gt; <br />＜/head&gt; <br />＜body&gt; <br />取得虚拟目录对应的磁盘路径＜br&gt; <br />Web站点主目录的位置为＜font color=#ff0000&gt;＜%=request.getRealPath("/")%&gt;＜/font&gt;＜br&gt; <br />JSP网页所在的目录位置＜font color=#ff0000&gt;＜%=request.getRealPath("./")%&gt;＜/font&gt;＜br&gt; <br />JSP网页所在目录上一层目录的位置＜font color=#ff0000&gt;＜%=request.getRealPath("../")%&gt;＜/font&gt;＜br&gt; <br />＜/body&gt; <br />＜/html&gt; <br /><br /><br /><strong>文件属性的取得 <br /></strong>＜%@ page contentType="text/html;charset=gb2312"%&gt; <br />＜%@ page import="java.util.Date,java.io.*"%&gt; <br />＜html&gt; <br />＜head&gt; <br />＜title&gt;文件属性的取得＜/title&gt; <br />＜/head&gt; <br />＜body&gt; <br />＜% <br />String path=request.getRealPath("/"); <br />File f=new File(path,"ReadData.txt"); <br />if(f.exists()){ <br />%&gt; <br />＜%=f.getName()%&gt;的属性如下：＜br&gt;＜br&gt; <br />文件长度为：＜%=f.length()%&gt; <br />＜%=f.isFile()?"是文件":"不是文件"%&gt;＜br&gt; <br />＜%=f.isDirectory()?"是目录":"不是目录"%&gt;＜br&gt; <br />＜%=f.canRead()?"可读取":"不可读取"%&gt;＜br&gt; <br />＜%=f.canWrite()?"可写入":"不可写入"%&gt;＜br&gt; <br />＜%=f.isHidden()?"是隐藏文件":"不是隐藏文件"%&gt;＜br&gt; <br />文件的最后修改日期为：＜%=new Date(f.lastModified())%&gt;＜br&gt; <br />＜% <br />}else{ <br />f.createNewFile();//在当前目录下建立一个名为ReaData.txt的文件 <br />%&gt; <br />＜%=f.getName()%&gt;的属性如下：＜br&gt;＜br&gt; <br />文件长度为：＜%=f.length()%&gt; <br />＜%=f.isFile()?"是文件":"不是文件"%&gt;＜br&gt; <br />＜%=f.isDirectory()?"是目录":"不是目录"%&gt;＜br&gt; <br />＜%=f.canRead()?"可读取":"不可读取"%&gt;＜br&gt; <br />＜%=f.canWrite()?"可写入":"不可写入"%&gt;＜br&gt; <br />＜%=f.isHidden()?"是隐藏文件":"不是隐藏文件"%&gt;＜br&gt; <br />文件的最后修改日期为：＜%=new Date(f.lastModified())%&gt;＜br&gt; <br />＜% <br />} <br />%&gt; <br />＜/body&gt; <br />＜/html&gt; <br /><br /><br /></code>
		<strong>取出目录中文件的方法</strong>
		<br />
		<code>＜%@ page contentType="text/html;charset=gb2312"%&gt; <br />＜%@ page import="java.io.*"%&gt; <br />＜html&gt; <br />＜head&gt; <br />＜title&gt;取出目录中文件的方法--列出目录中的文件＜/title&gt; <br />＜/head&gt; <br />＜body&gt; <br />＜% <br />String path=request.getRealPath("/"); <br />File d=new File(path);//建立当前目录中文件的File对象 <br />File list[]=d.listFiles();//取得代表目录中所有文件的File对象数组 <br />out.println("＜font color=#ff0000&gt;" + path + "目录下的文件：＜/font&gt;＜br&gt;"); <br />for(int i=0;i＜list.length;i++){ <br />if(list＜I&gt;.isFile()){ <br />out.println(list＜I&gt;.getName() + "＜br&gt;"); <br />} <br />} <br />out.println("＜br&gt;＜font color=#ff0000&gt;" + path + "目录下的目录：＜/font&gt;＜br&gt;"); <br />for(int i=0;i＜list.length;i++){ <br />if(list＜I&gt;.isDirectory()){ <br />out.println(list＜I&gt;.getName() + "＜br&gt;"); <br />} <br />} <br />%&gt; <br />＜/body&gt; <br />＜/html&gt; <br /><br /></code>
		<br />
		<strong>判断是否为空白文件 <br /></strong>
		<code>＜%@ page contentType="text/html;charset=gb2312"%&gt; <br />＜%@ page import="java.io.*"%&gt; <br />＜html&gt; <br />＜head&gt; <br />＜title&gt;判断是否为空白文件＜/title&gt; <br />＜/head&gt; <br />＜body&gt; <br />＜% <br />String path=request.getRealPath("/"); <br />out.println(path); <br />FileReader fr=new FileReader(path + "\\AtEnd.txt");//建立FileReader对象，并实例化为fr <br />//对FileReader类生成的对象使用read()方法，可以从字符流中读取下一个字符。 <br />if(fr.read()==-1)//判断是否已读到文件的结尾 <br />{ <br />out.print("AtEnd.txt文件中没有数据＜br&gt;"); <br />}else{ <br />out.println("AtEnd.txt文件中有数据"); <br />} <br />fr.close(); <br />%&gt; <br />＜/body&gt; <br />＜/html&gt; <br /><br /></code>
		<br />
		<strong>读取所有的文件数据</strong>
		<br />
		<code>＜%@ page contentType="text/html;charset=gb2312"%&gt; <br />＜%@ page import="java.io.*,java.lang.*"%&gt; <br />＜html&gt; <br />＜head&gt; <br />＜title&gt;读取所有的文件数据＜/title&gt; <br />＜/head&gt; <br />＜body&gt; <br />＜% <br />String path=request.getRealPath("."); <br />FileReader fr=new FileReader(path + "\\ReadData.txt"); <br />//关键在于读取过程中，要判断所读取的字符是否已经到了文件的末尾，并且这个字符是不是文件中的断行符，即判断该字符值是否为13。 <br />int c=fr.read();//从文件中读取一个字符 <br />//判断是否已读到文件结尾 <br />while(c!=-1){ <br />out.print((char)c);//输出读到的数据 <br />c=fr.read();//从文件中继续读取数据 <br />if(c==13){//判断是否为断行字符 <br />out.print("＜br&gt;");//输出分行标签 <br />fr.skip(1);//略过一个字符 <br />//c=fr.read();//读取一个字符 <br />} <br />} <br />fr.close(); <br />%&gt; <br />＜/body&gt; <br />＜/html&gt; <strong>一行一行读取数据</strong><br /><code>＜%@ page contentType="text/html;charset=gb2312"%&gt; <br />＜%@ page import="java.io.*"%&gt; <br />＜html&gt; <br />＜head&gt; <br />＜title&gt;文件读取＜/title&gt; <br />＜/head&gt; <br />＜body&gt; <br />＜% <br />String path=request.getRealPath("");//取得当前目录的路径 <br />FileReader fr=new FileReader(path + "\\file\\inc\\t.txt");//建立FileReader对象，并实例化为fr <br />BufferedReader br=new BufferedReader(fr);//建立BufferedReader对象，并实例化为br <br />String Line=br.readLine();//从文件读取一行字符串 <br />//判断读取到的字符串是否不为空 <br />while(Line!=null){ <br />out.println(Line + "＜br&gt;");//输出从文件中读取的数据 <br />Line=br.readLine();//从文件中继续读取一行数据 <br />} <br />br.close();//关闭BufferedReader对象 <br />fr.close();//关闭文件 <br />%&gt; <br />＜/body&gt; <br />＜/html&gt; <br /><br /></code><br /><strong>略过文件中的字符不读取</strong><br /><code>＜%@ page contentType="text/html;charset=gb2312"%&gt; <br />＜%@ page import="java.io.*"%&gt; <br />＜html&gt; <br />＜head&gt; <br />＜title&gt;略过字节不读取＜/title&gt; <br />＜/head&gt; <br />＜body&gt; <br />＜% <br />String path=request.getRealPath("."); <br />FileReader fr=new FileReader(path + "\\ReadData.txt"); <br />fr.skip(2);//跳过2个字节 <br />int c=fr.read();//读取一个字节 <br />while(c!=-1){ <br />out.print((char)c); <br />c=fr.read(); <br />} <br />fr.close(); <br />%&gt; <br />＜/body&gt; <br />＜/html&gt; <br /><br /></code><br /><strong>将数据写入文件</strong><br /><code>＜%@ page contentType="text/html;charset=gb2312"%&gt; <br />＜%@ page import="java.io.*"%&gt; <br />＜html&gt; <br />＜head&gt; <br />＜title&gt;将数据写入文件＜/title&gt; <br />＜/head&gt; <br />＜body&gt; <br />＜% <br />String path=request.getRealPath("."); <br />FileWriter fw=new FileWriter(path + "\\WriteData.txt");//建立FileWriter对象，并实例化fw <br />//将字符串写入文件 <br />fw.write("大家好！"); <br />fw.write("本书是《JSP编程技巧》"); <br />fw.write("请多多指教！"); <br />fw.write("email:stride@sina.com"); <br />fw.close(); <br /><br />FileReader fr=new FileReader(path + "\\WriteData.txt"); <br />BufferedReader br=new BufferedReader(fr);//建立BufferedReader对象，并实例化为br <br />String Line=br.readLine(); <br />//读取一行数据 <br />out.println(Line + "＜br&gt;"); <br />br.close();//关闭BufferedReader对象 <br />fr.close(); <br />%&gt; <br />＜/body&gt; <br />＜/html&gt; <br /><br /></code><br /><strong>将写入文件的数据分行</strong><br /><code>＜%@ page contentType="text/html;charset=gb2312"%&gt; <br />＜%@ page import="java.io.*"%&gt; <br />＜html&gt; <br />＜head&gt; <br />＜title&gt;将写入文件的数据分行＜/title&gt; <br />＜/head&gt; <br />＜body&gt; <br />＜% <br />String path=request.getRealPath("."); <br />FileWriter fw=new FileWriter(path + "\\WriteData.txt"); <br />BufferedWriter bw=new BufferedWriter(fw); <br />bw.write("大家好！"); <br />bw.write("本书是《JSP编程技巧》。"); <br />bw.newLine();//断行 <br />bw.write("请多多指教！"); <br />bw.newLine();//断行 <br />bw.write("email: stride@sina.com"); <br />bw.flush();//将数据更新至文件 <br />fw.close();//关闭文件流 <br />out.println("写入文件内容为：＜br&gt;"); <br />FileReader fr=new FileReader(path + "\\WriteData.txt"); <br />BufferedReader br=new BufferedReader(fr); <br />String Line=br.readLine();//读取一行数据 <br />while(Line!=null){ <br />out.println(Line + "＜br&gt;"); <br />Line=br.readLine(); <br />} <br />fr.close(); <br />%&gt; <br />＜/body&gt; <br />＜/html&gt; <br />如何将数据追加写入到文件 <br />＜%@ page contentType="text/html;charset=gb2312"%&gt; <br />＜%@ page import="java.io.*"%&gt; <br />＜html&gt; <br />＜head&gt; <br />＜title&gt;将写入文件的数据分行＜/title&gt; <br />＜/head&gt; <br />＜body&gt; <br />＜% <br />String path=request.getRealPath("."); <br />RandomAccessFile rf=new RandomAccessFile(path + "\\WriteData.txt","rw");//定义一个类RandomAccessFile的对象，并实例化 <br />rf.seek(rf.length());//将指针移动到文件末尾 <br />rf.writeBytes("\nAppend a line to the file!"); <br />rf.close();//关闭文件流 <br />out.println("写入文件内容为：＜br&gt;"); <br />FileReader fr=new FileReader(path + "\\WriteData.txt"); <br />BufferedReader br=new BufferedReader(fr);//读取文件的BufferedRead对象 <br />String Line=br.readLine(); <br />while(Line!=null){ <br />out.println(Line + "＜br&gt;"); <br />Line=br.readLine(); <br />} <br />fr.close();//关闭文件 <br />%&gt; <br />＜/body&gt; <br />＜/html&gt;＜/I&gt;＜/I&gt;＜/I&gt;＜/I&gt; </code><br /></code>
<img src ="http://www.blogjava.net/liaojiyong/aggbug/53301.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-06-16 14:45 <a href="http://www.blogjava.net/liaojiyong/archive/2006/06/16/53301.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP内建对象</title><link>http://www.blogjava.net/liaojiyong/archive/2006/05/24/47876.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Wed, 24 May 2006 11:24:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/05/24/47876.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/47876.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/05/24/47876.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/47876.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/47876.html</trackback:ping><description><![CDATA[<font face="Courier New"><strong>① out - javax.servlet.jsp.jspWriter</strong> <br>&nbsp;&nbsp; out对象用于把结果输出到网页上。</font>
<p><font face="Courier New">方法：<br>1. void clear() ;<br>&nbsp;&nbsp; 清除输出缓冲区的内容，但是不输出到客户端。</font> </p>
<p><font face="Courier New">2. void clearBuffer() ;<br>&nbsp;&nbsp; 清除输出缓冲区的内容，并输出到客户端。</font> </p>
<p><font face="Courier New">3. void close() ;<br>&nbsp;&nbsp; 关闭输出流，清除所有内容。</font> </p>
<p><font face="Courier New">4. void flush() ;<br>&nbsp;&nbsp; 输出缓冲区里面的数据。</font> </p>
<p><font face="Courier New">5. int getBufferSize() ;<br>&nbsp;&nbsp; 获取以kb为单位的目前缓冲区大小。</font> </p>
<p><font face="Courier New">6. int getRemaining() ;<br>&nbsp;&nbsp; 获取以kb为单位的缓冲区中未被占用的空间大小。</font> </p>
<p><font face="Courier New">7. boolean isAutoFlush() ;<br>&nbsp;&nbsp; 是否自动刷新缓冲区。</font> </p>
<p><font face="Courier New">8. void newLine() ;<br>&nbsp;&nbsp; 输出一个换行字符。</font> </p>
<p><font face="Courier New">9. void print( boolean b ) ;<br>&nbsp;&nbsp; void print( char c ) ;<br>&nbsp;&nbsp; void print( char[] s ) ;<br>&nbsp;&nbsp; void print( double d ) ;<br>&nbsp;&nbsp; void print( float f ) ;<br>&nbsp;&nbsp; void print( int i ) ;<br>&nbsp;&nbsp; void print( long l ) ;<br>&nbsp;&nbsp; void print( Object obj ) ;<br>&nbsp;&nbsp; void print( String s ) ;<br>&nbsp;&nbsp; 将指定类型的数据输出到Http流，不换行。</font> </p>
<p><font face="Courier New">10. void println( boolean b ) ;<br>&nbsp;&nbsp;&nbsp; void println( char c ) ;<br>&nbsp;&nbsp;&nbsp; void println( char[] s ) ;<br>&nbsp;&nbsp;&nbsp; void println( double d ) ;<br>&nbsp;&nbsp;&nbsp; void println( float f ) ;<br>&nbsp;&nbsp;&nbsp; void println( int i ) ;<br>&nbsp;&nbsp;&nbsp; void println( long l ) ;<br>&nbsp;&nbsp;&nbsp; void println( Object obj ) ;<br>&nbsp;&nbsp;&nbsp; void println( String s ) ;<br>&nbsp;&nbsp;&nbsp; 将指定类型的数据输出到Http流，并输出一个换行符。<br>&nbsp;&nbsp;&nbsp; <br>11. Appendable append( char c ) ;<br>&nbsp;&nbsp;&nbsp; Appendable append( CharSequence cxq, int start, int end ) ;<br>&nbsp;&nbsp;&nbsp; Appendable append( CharSequence cxq ) ;<br>&nbsp;&nbsp;&nbsp; 将一个字符或者实现了CharSequence接口的对象添加到输出流的后面。</font> </p>
<p><font face="Courier New">成员：<br>int DEFAULT_BUFFER = 0&nbsp;&nbsp;&nbsp; - 缺省缓冲区大小<br>int NO_BUFFER = -1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - writer是否处于缓冲输出状态<br>int UNBOUNDED_BUFFER = -2 - 是否限制缓冲区大小</font> </p>
<p><br><font face="Courier New"><strong>② request - javax.servlet.http.HttpServletRequest<br></strong>&nbsp;&nbsp; request对象包含所有请求的信息，如请求的来源、标头、cookies和请求相关的参数值等。</font> </p>
<p><font face="Courier New">方法：<br>1. Object getAttribute( String name ) ;<br>&nbsp;&nbsp; 返回由name指定的属性值，该属性不存在时返回null。</font> </p>
<p><font face="Courier New">2. Enumeration getAttributeNames() ;<br>&nbsp;&nbsp; 返回request对象的所有属性名称的集合。</font> </p>
<p><font face="Courier New">3. String getAuthType() ;<br>&nbsp;&nbsp; 返回用来保护servlet的认证方法的名称，未受保护时返回null。</font> </p>
<p><font face="Courier New">4. String getCharacterEncoding() ;<br>&nbsp;&nbsp; 返回请求中的字符编码方法，可以在response对象中设置。</font> </p>
<p><font face="Courier New">5. int getContentLength() ;<br>&nbsp;&nbsp; 返回请求的BODY的长度，不能确定长度时返回-1。可以在response中设置。</font> </p>
<p><font face="Courier New">6. String getContentType() ;<br>&nbsp;&nbsp; 返回在response中定义的内容类型。</font> </p>
<p><font face="Courier New">7. String getContentPath() ;<br>&nbsp;&nbsp; 返回请求的路径。</font> </p>
<p><font face="Courier New">8. Cookie[] getCookies() ;<br>&nbsp;&nbsp; 返回客户端所有的Cookie的数组。</font> </p>
<p><font face="Courier New">9. Enumeration getHeaderNames() ;<br>&nbsp;&nbsp; 返回所有HTTP头的名称的集合。</font> </p>
<p><font face="Courier New">10. Enumeration getHeaders( String name ) ;<br>&nbsp;&nbsp;&nbsp; 返回指定HTTP头的所有值的集合。</font> </p>
<p><font face="Courier New">11. String getHeader( String name ) ;<br>&nbsp;&nbsp;&nbsp; 返回指定名称的HTTP头的信息。</font> </p>
<p><font face="Courier New">12. long getDateHeader( String name ) ;<br>&nbsp;&nbsp;&nbsp; 返回指定名称的Data类型的HTTP头的信息。</font> </p>
<p><font face="Courier New">13. int getIntHeader( String name ) ;<br>&nbsp;&nbsp;&nbsp; 返回指定名称的Int类型的HTTP头的信息。</font> </p>
<p><font face="Courier New">14. ServletInputStream getInputStream() ;<br>&nbsp;&nbsp;&nbsp; 返回请求的输入流。</font> </p>
<p><font face="Courier New">15. Locale getLocale() ;<br>&nbsp;&nbsp;&nbsp; 返回当前页的Locale对象，可以在response中设定。</font> </p>
<p><font face="Courier New">16. Enumeration getLocales() ;<br>&nbsp;&nbsp;&nbsp; 返回请求中所有的Locale对象的集合。</font> </p>
<p><font face="Courier New">17. String getLocalName() ;<br>&nbsp;&nbsp;&nbsp; 获取响应请求的服务器端主机名。</font> </p>
<p><font face="Courier New">18. String getLocalAddr() ;<br>&nbsp;&nbsp;&nbsp; 获取响应请求的服务器端地址。</font> </p>
<p><font face="Courier New">19. int getLocalPort() ;<br>&nbsp;&nbsp;&nbsp; 获取响应请求的服务器端端口</font> </p>
<p><font face="Courier New">20. String getMethod() ;<br>&nbsp;&nbsp;&nbsp; 获取客户端向服务器端发送请求的方法(GET、POST)。</font> </p>
<p><font face="Courier New">21. String getParameter( String name ) ;<br>&nbsp;&nbsp;&nbsp; 获取客户端发送给服务器端的参数值。</font> </p>
<p><font face="Courier New">22. Map getParameterMap() ;<br>&nbsp;&nbsp;&nbsp; 该方法返回包含请求中所有参数的一个Map对象。</font> </p>
<p><font face="Courier New">23. Enumeration getParameterNames() ;<br>&nbsp;&nbsp;&nbsp; 返回请求中所有参数的集合。</font> </p>
<p><font face="Courier New">24. String[] getParameterValues( String name ) ;<br>&nbsp;&nbsp;&nbsp; 获得请求中指定参数的所有值。</font> </p>
<p><font face="Courier New">25. String getQueryString() ;<br>&nbsp;&nbsp;&nbsp; 返回get方法传递的参数字符串，该方法不分解出单独的参数。</font> </p>
<p><font face="Courier New">26. String getPathInfo() ;<br>&nbsp;&nbsp;&nbsp; 取出请求中处于ServletPath和QueryString之间的额外信息。</font> </p>
<p><font face="Courier New">27. String getPathTranslated() ;<br>&nbsp;&nbsp;&nbsp; 返回用getPathInfo()方法取得的路径信息的实际路径。</font> </p>
<p><font face="Courier New">28. String getProtocol() ;<br>&nbsp;&nbsp;&nbsp; 返回请求使用的协议。可以是HTTP1.1或者HTTP1.0。</font> </p>
<p><font face="Courier New">29. BufferedReader getReader() ;<br>&nbsp;&nbsp;&nbsp; 返回请求的输入流对应的Reader对象，该方法和getInputStream()方法在一个页面中只能调用一个。</font> </p>
<p><font face="Courier New">30. String getRemoteAddr() ;<br>&nbsp;&nbsp;&nbsp; 获取发出请求的客户端IP地址。</font> </p>
<p><font face="Courier New">31. String getRemoteHost() ;<br>&nbsp;&nbsp;&nbsp; 获取发出请求的客户端主机名</font> </p>
<p><font face="Courier New">32. String getRemoteUser() ;<br>&nbsp;&nbsp;&nbsp; 返回经过客户端验证的用户名，未经验证返回null。</font> </p>
<p><font face="Courier New">33. int getRemotePort() ;<br>&nbsp;&nbsp;&nbsp; 返回发出请求的客户端主机端口。</font> </p>
<p><font face="Courier New">34. String getRealPath( String path ) ;<br>&nbsp;&nbsp;&nbsp; 返回给定虚拟路径的物理路径。</font> </p>
<p><font face="Courier New">35. RequestDispatcher getRequestDispatcher( String path ) ;<br>&nbsp;&nbsp;&nbsp; 按给定的路径生成资源转向处理适配器对象。</font> </p>
<p><font face="Courier New">36. String getRequestedSessionId() ;<br>&nbsp;&nbsp;&nbsp; 返回请求的session的标识。</font> </p>
<p><font face="Courier New">37. String RequestURI() ;<br>&nbsp;&nbsp;&nbsp; 返回发出请求的客户端地址，但是不包括请求的参数字符串。</font> </p>
<p><font face="Courier New">38. StringBuffer getRequestURI() ;<br>&nbsp;&nbsp;&nbsp; 返回响应请求的服务器端地址</font> </p>
<p><font face="Courier New">39. String getScheme() ;<br>&nbsp;&nbsp;&nbsp; 获取协议名称，缺省值为HTTP协议。</font> </p>
<p><font face="Courier New">40. String getServerName() ;<br>&nbsp;&nbsp;&nbsp; 返回响应请求的服务器名称。</font> </p>
<p><font face="Courier New">41. String getServletPath() ;<br>&nbsp;&nbsp;&nbsp; 获取客户端所请求的脚本文件的文件路径。</font> </p>
<p><font face="Courier New">42. int getServerPort() ;<br>&nbsp;&nbsp;&nbsp; 获取响应请求的服务器端主机端口号。</font> </p>
<p><font face="Courier New">43. void removeAttribute( String name ) ;<br>&nbsp;&nbsp;&nbsp; 在属性列表中删除指定名称的属性。</font> </p>
<p><font face="Courier New">44. void setAttribute( String name, Object value ) ;<br>&nbsp;&nbsp;&nbsp; 在属性列表中添加/删除指定的属性。</font> </p>
<p><font face="Courier New">45. void setCharacterEncoding( String name ) ;<br>&nbsp;&nbsp;&nbsp; 设置请求的字符编码格式。</font> </p>
<p><font face="Courier New">46. HttpSession getSession() ;<br>&nbsp;&nbsp;&nbsp; HttpSession getSession( boolean create ) ;<br>&nbsp;&nbsp;&nbsp; 获取session，如果create为true，在无session的情况下创建一个。<br>&nbsp;&nbsp;&nbsp; <br>47. boolean isRequestedSessionIdFromCookie() ;<br>&nbsp;&nbsp;&nbsp; 检查请求的会话ID是否为通过Cookie传入。</font> </p>
<p><font face="Courier New">48. boolean isRequestedSessionIdFromURL() ;<br>&nbsp;&nbsp;&nbsp; 检查请求的会话ID是否为通过URL传入。</font> </p>
<p><font face="Courier New">49. boolean isRequestedSessionIdValid() ;<br>&nbsp;&nbsp;&nbsp; 检查请求的会话ID是否仍然有效。</font> </p>
<p><font face="Courier New">50. boolean isSecure() ;<br>&nbsp;&nbsp;&nbsp; 检查请求是否使用安全链接，如果HTTPS等。</font> </p>
<p><font face="Courier New">51. boolean isUserInRole( String role ) ;<br>&nbsp;&nbsp;&nbsp; 检查已经通过验证的用户是否在是role所指定的角色。</font> </p>
<p><font face="Courier New">52. Principal getUserPrincipal() ;<br>&nbsp;&nbsp;&nbsp; 返回包含用户登陆名的一个java.security.Principal对象。</font> </p>
<p><font face="Courier New">成员：<br>String BASIC_AUTH = "BASIC"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - <br>String CLIENT_CERT_AUTH = "CLIENT_CERT" - <br>String DIGEST_AUTH = "DIGEST"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - <br>String FORM_AUTH = "FORM"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - </font></p>
<p><br><font face="Courier New"><strong>③ response - javax.servlet.http.HttpServletResponse</strong> <br>&nbsp;&nbsp; response对象主要将JSP容器处理后的结果传回到客户端。</font> </p>
<p><font face="Courier New">方法：<br>1. void addCookie( Cookie cookie ) ;<br>&nbsp;&nbsp; 添加一个Cookie对象，保存客户端信息。</font> </p>
<p><font face="Courier New">2. void addDateHeader( String name, long value ) ;<br>&nbsp;&nbsp; 添加一个日期类型的HTTP头信息，覆盖同名的HTTP头信息。</font> </p>
<p><font face="Courier New">3. void addHeader( String name, String value ) ;<br>&nbsp;&nbsp; 添加一个HTTP头，覆盖同名的旧HTTP头。</font> </p>
<p><font face="Courier New">4. void addIntHeader( String name, int value ) ;<br>&nbsp;&nbsp; 添加一个整型的HTTP头，覆盖同名的旧HTTP头。</font> </p>
<p><font face="Courier New">5. boolean containsHeader( String name ) ;<br>&nbsp;&nbsp; 判断指定的HTTP头是否存在。</font> </p>
<p><font face="Courier New">6. String encodeRedirectURL( String url ) ;<br>&nbsp;&nbsp; 对sendRedirect()方法使用的URL进行编码。</font> </p>
<p><font face="Courier New">7. String encodeURL( String url ) ;<br>&nbsp;&nbsp; 将URL予以编码，回传包含session ID的URL。<br>&nbsp;&nbsp; <br>8. void flushBuffer() ;<br>&nbsp;&nbsp; 强制把当前缓冲区的内容发送到客户端。</font> </p>
<p><font face="Courier New">9. int getBufferSize() ;<br>&nbsp;&nbsp; 取得以kb为单位的缓冲区大小。</font> </p>
<p><font face="Courier New">10. String getCharacterEncoding() ;<br>&nbsp;&nbsp;&nbsp; 获取响应的字符编码格式。</font> </p>
<p><font face="Courier New">11. String getContentType() ;<br>&nbsp;&nbsp;&nbsp; 获取响应的类型。</font> </p>
<p><font face="Courier New">12. Locale getLocale() ;<br>&nbsp;&nbsp;&nbsp; 获取响应的Locale对象。</font> </p>
<p><font face="Courier New">13. ServletOutputStream getOutputStream() ;<br>&nbsp;&nbsp;&nbsp; 返回客户端的输出流对象。</font> </p>
<p><font face="Courier New">14. PrintWriter getWriter() ;<br>&nbsp;&nbsp;&nbsp; 获取输出流对应的writer对象。</font> </p>
<p><font face="Courier New">15. boolean isCommitted() ;<br>&nbsp;&nbsp;&nbsp; 判断服务器端是否已经将数据输出到客户端。</font> </p>
<p><font face="Courier New">16. void reset() ;<br>&nbsp;&nbsp;&nbsp; 清空buffer中的所有内容。</font> </p>
<p><font face="Courier New">17. void resetBuffer() ;<br>&nbsp;&nbsp;&nbsp; 情况buffer中所有的内容，但是保留HTTP头和状态信息。</font> </p>
<p><font face="Courier New">18. void sendError( int xc, String msg ) ;<br>&nbsp;&nbsp;&nbsp; void sendError( int xc ) ;<br>&nbsp;&nbsp;&nbsp; 发送错误，包括状态码和错误信息。</font> </p>
<p><font face="Courier New">19. void sendRedirect( String locationg ) ;<br>&nbsp;&nbsp;&nbsp; 把响应发送到另外一个位置进行处理。</font> </p>
<p><font face="Courier New">20. void setBufferSize( int size ) ;<br>&nbsp;&nbsp;&nbsp; 设置以kb为单位的缓冲区大小。</font> </p>
<p><font face="Courier New">21. void setCharacterEncoding( String charset ) ;<br>&nbsp;&nbsp;&nbsp; 设置响应使用的字符编码格式。</font> </p>
<p><font face="Courier New">22. void setContentLength( int length ) ;<br>&nbsp;&nbsp;&nbsp; 设置响应的BODY长度。</font> </p>
<p><font face="Courier New">23. void setContentType( String type ) ;<br>&nbsp;&nbsp;&nbsp; 设置响应的类型。</font> </p>
<p><font face="Courier New">24. void setDateHeader( String name, long value ) ;<br>&nbsp;&nbsp;&nbsp; 设置指定名称的Data类型的HTTP头的值。</font> </p>
<p><font face="Courier New">25. void setHeader( String name, String value ) ;<br>&nbsp;&nbsp;&nbsp; 设置指定名称的HTTP头的值。</font> </p>
<p><font face="Courier New">26. void setIntHeader( String name, int value ) ;<br>&nbsp;&nbsp;&nbsp; 设置指定名称的int类型的HTTP头的值。</font> </p>
<p><font face="Courier New">27. void setStatus( int xc ) ;<br>&nbsp;&nbsp;&nbsp; 设置响应状态码，新值会覆盖当前值。</font> </p>
<p><font face="Courier New">成员(HTTP状态码)：<br>int SC_CONTINUE = 100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_SWITCHING_PROTOCOLS = 101<br>int SC_OK = 200&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_NON_AUTHORITATIVE_INFORMATION = 203<br>int SC_ACCEPTED = 202&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_CREATED = 201<br>int SC_NO_CONTENT = 204&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_RESET_CONTENT = 205<br>int SC_PARTIAL_CONTENT = 206&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_MULTIPLE_CHOICES = 300<br>int SC_MOVED_PERMANENTLY = 301&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_MOVED_TEMPORARILY = 302<br>int SC_FOUND = 302&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_SEE_OTHER = 303<br>int SC_NOT_MODIFIED = 304&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_USE_PROXY = 305<br>int SC_TEMPORARY_REDIRECT = 307&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_BAD_REQUEST = 400<br>int SC_UNAUTHORIZED = 401&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_PAYMENT_REQUIRED = 402<br>int SC_FORBIDDEN = 403&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_NOT_FOUND = 404<br>int SC_METHOD_NOT_ALLOWED = 405&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_NOT_ACCEPTABLE = 406<br>int SC_PROXY_AUTHENTICATION_REQUIRED = 407 int SC_REQUEST_TIMEOUT = 408<br>int SC_CONFLICT = 409&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_GONE = 410<br>int SC_LENGTH_REQUIRED = 411&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_PRECONDITION_FAILED = 412<br>int SC_REQUEST_ENTITY_TOO_LARGE = 413&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_REQUEST_URI_TOO_LONG = 414<br>int SC_UNSUPPORTED_MEDIA_TYPE = 415&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416<br>int SC_EXPECTATION_FAILED = 417&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_INTERNAL_SERVER_ERROR = 500<br>int SC_NOT_IMPLEMENTED = 501&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_BAD_GATEWAY = 502<br>int SC_SERVICE_UNAVAILABLE = 503&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int SC_GATEWAY_TIMEOUT = 504<br>int SC_HTTP_VERSION_NOT_SUPPORTED = 505</font> </p>
<p><br><font face="Courier New"><strong>④ session - javax.servlet.http.HttpSession</strong> <br>&nbsp;&nbsp; session对象表示目前个别用户的会话状态，用来识别每个用户。</font> </p>
<p><font face="Courier New">方法：<br>1. Object getAttribute( String name ) ;<br>&nbsp;&nbsp; 获取与指定名字相关联的session属性值。</font> </p>
<p><font face="Courier New">2. Enumeration getAttributeNames() ;<br>&nbsp;&nbsp; 取得session内所有属性的集合。</font> </p>
<p><font face="Courier New">3. long getCreationTime() ;<br>&nbsp;&nbsp; 返回session的创建时间，最小单位千分之一秒。</font> </p>
<p><font face="Courier New">4. String getId() ;<br>&nbsp;&nbsp; 取得session标识。</font> </p>
<p><font face="Courier New">5. long getLastAccessedTime() ;<br>&nbsp;&nbsp; 返回与当前session相关的客户端最后一次访问的时间，由1970-01-01算起，单位毫秒。</font> </p>
<p><font face="Courier New">6. int getMaxInactiveInterval( int interval ) ;<br>&nbsp;&nbsp; 返回总时间，以秒为单位，表示session的有效时间(session不活动时间)。-1为永不过期。</font> </p>
<p><font face="Courier New">7. ServletContext getServletContext() ;<br>&nbsp;&nbsp; 返回一个该JSP页面对应的ServletContext对象实例。</font> </p>
<p><font face="Courier New">8. HttpSessionContext getSessionContext() ;<br>&nbsp;&nbsp; </font></p>
<p><font face="Courier New">9. Object getValue( String name ) ;<br>&nbsp;&nbsp; 取得指定名称的session变量值，不推荐使用。</font> </p>
<p><font face="Courier New">10. String[] getValueNames() ;<br>&nbsp;&nbsp;&nbsp; 取得所有session变量的名称的集合，不推荐使用。</font> </p>
<p><font face="Courier New">11. void invalidate() ;<br>&nbsp;&nbsp;&nbsp; 销毁这个session对象。</font> </p>
<p><font face="Courier New">12. boolean isNew() ;<br>&nbsp;&nbsp;&nbsp; 判断一个session是否由服务器产生，但是客户端并没有使用。</font> </p>
<p><font face="Courier New">13. void pubValue( String name, Object value ) ;<br>&nbsp;&nbsp;&nbsp; 添加一个session变量，不推荐使用。</font> </p>
<p><font face="Courier New">14. void removeValue( String name ) ;<br>&nbsp;&nbsp;&nbsp; 移除一个session变量的值，不推荐使用。</font> </p>
<p><font face="Courier New">15. void setAttribute( String name, String value ) ;<br>&nbsp;&nbsp;&nbsp; 设置指定名称的session属性值。</font> </p>
<p><font face="Courier New">16. void setMaxInactiveInterval( int interval ) ;<br>&nbsp;&nbsp;&nbsp; 设置session的有效期。</font> </p>
<p><font face="Courier New">17. void removeAttribute( String name ) ;<br>&nbsp;&nbsp;&nbsp; 移除指定名称的session属性。</font> </p>
<p><br><font face="Courier New"><strong>⑤ pageContext - javax.servlet.jsp.PageContext</strong> <br>&nbsp;&nbsp; pageContext对象存储本JSP页面相关信息，如属性、内建对象等。</font> </p>
<p><font face="Courier New">方法：<br>1. void setAttribute( String name, Object value, int scope ) ;<br>&nbsp;&nbsp; void setAttribute( String name, Object value ) ;<br>&nbsp;&nbsp; 在指定的共享范围内设置属性。</font> </p>
<p><font face="Courier New">2. Object getAttribute( String name, int scope ) ;<br>&nbsp;&nbsp; Object getAttribute( String name ) ;<br>&nbsp;&nbsp; 取得指定共享范围内以name为名字的属性值。</font> </p>
<p><font face="Courier New">3. Object findAttribute( String name ) ;<br>&nbsp;&nbsp; 按页面、请求、会话和应用程序共享范围搜索已命名的属性。</font> </p>
<p><font face="Courier New">4. void removeAttribute( String name, int scope ) ;<br>&nbsp;&nbsp; void removeAttribute( String name ) ;<br>&nbsp;&nbsp; 移除指定名称和共享范围的属性。</font> </p>
<p><font face="Courier New">5. void forward( String url ) ;<br>&nbsp;&nbsp; 将页面导航到指定的URL。</font> </p>
<p><font face="Courier New">6. Enumeration getAttributeNamesScope( int scope ) ;<br>&nbsp;&nbsp; 取得指定共享范围内的所有属性名称的集合。</font> </p>
<p><font face="Courier New">7. int getAttributeScope( String name ) ;<br>&nbsp;&nbsp; 取得指定属性的共享范围。</font> </p>
<p><font face="Courier New">8. ErrorData getErrorDate() ;<br>&nbsp;&nbsp; 取得页面的errorData对象。</font> </p>
<p><font face="Courier New">9. Exception getException() ;<br>&nbsp;&nbsp; 取得页面的exception对象。</font> </p>
<p><font face="Courier New">10. ExpressionEvaluator getExpressionEvaluator() ;<br>&nbsp;&nbsp;&nbsp; 取得页面的expressionEvaluator对象。</font> </p>
<p><font face="Courier New">11. JspWriter getOut() ;<br>&nbsp;&nbsp;&nbsp; 取得页面的out对象。</font> </p>
<p><font face="Courier New">12. Object getPage() ;<br>&nbsp;&nbsp;&nbsp; 取得页面的page对象。</font> </p>
<p><font face="Courier New">13. ServletRequest getRequest() ;<br>&nbsp;&nbsp;&nbsp; 取得页面的request对象。</font> </p>
<p><font face="Courier New">14. ServletResponse getResponse() ;<br>&nbsp;&nbsp;&nbsp; 取得页面的response对象。</font> </p>
<p><font face="Courier New">15. ServletConfig getConfig() ;<br>&nbsp;&nbsp;&nbsp; 取得页面的config对象。</font> </p>
<p><font face="Courier New">16. ServletContext getServletContext() ;<br>&nbsp;&nbsp;&nbsp; 取得页面的servletContext对象。</font> </p>
<p><font face="Courier New">17. HttpSession getSession() ;<br>&nbsp;&nbsp;&nbsp; 取得页面的session对象。</font> </p>
<p><font face="Courier New">18. VariableResolver getVariableResolver() ;<br>&nbsp;&nbsp;&nbsp; 取得页面的variableResolver对象。</font> </p>
<p><font face="Courier New">19. void include( String url, boolean flush ) ;<br>&nbsp;&nbsp;&nbsp; void include( String url ) ;<br>&nbsp;&nbsp;&nbsp; 包含其他的资源，并指定是否自动刷新。</font> </p>
<p><font face="Courier New">20. void release() ;<br>&nbsp;&nbsp;&nbsp; 重置pageContext内部状态，释放所有内部引用。</font> </p>
<p><font face="Courier New">21. void initialize( Servlet servlet, ServletRequest request, ServletResponse response,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String errorPageURL, boolean needSession, int bufferSize, boolean autoFlush ) ;<br>&nbsp;&nbsp;&nbsp; 初始化未经初始化的pageContext对象。</font> </p>
<p><font face="Courier New">22. BodyContext pushBody() ;<br>&nbsp;&nbsp;&nbsp; BodyContext pushBody( Writer writer ) ;<br>&nbsp;&nbsp;&nbsp; 保存当前的out对象，并更新pageContext中page范围内的out对象。</font> </p>
<p><font face="Courier New">23. JspWrite popBody() ;<br>&nbsp;&nbsp;&nbsp; 取出由pushBody()方法保存的out对象。</font> </p>
<p><font face="Courier New">24. void handlePageException( Exception e ) ;<br>&nbsp;&nbsp;&nbsp; void handlePageException( Thrwoable t ) ;<br>&nbsp;&nbsp;&nbsp; </font></p>
<p><font face="Courier New">成员：<br>int PAGE_SCOPE = 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - 页面共享范围<br>int REQUEST_SCOPE = 2&nbsp;&nbsp;&nbsp;&nbsp; - 请求共享范围<br>int SESSION_SCOPE = 3&nbsp;&nbsp;&nbsp;&nbsp; - 会话共享范围<br>int APPLICATION_SCOPE = 4 - 应用程序共享范围<br>String PAGE = "javax.servlet.jsp.jspPage"<br>String PAGECONTEXT = "javax.servlet.jsp.jspPageContext"<br>String REQUEST = "javax.servlet.jsp.jspRequest"<br>String RESPONSE = "javax.servlet.jsp.jspResponse"<br>String CONFIG = "javax.servlet.jsp.jspConfig"<br>String SESSION = "javax.servlet.jsp.jspSession"<br>String OUT = "javax.servlet.jsp.jspOut"<br>String APPLICATION = "javax.servlet.jsp.jspApplication"<br>String EXCEPTION = "javax.servlet.jsp.jspException"</font> </p>
<p><br><font face="Courier New"><strong>⑥ application - javax.servlet.ServletContext</strong> <br>&nbsp;&nbsp; application主要功用在于取得或更改Servlet的设定。</font> </p>
<p><font face="Courier New">方法：<br>1. Object getAttribute( String name ) ;<br>&nbsp;&nbsp; 返回由name指定的application属性。</font> </p>
<p><font face="Courier New">2. Enumeration getAttributes() ;<br>&nbsp;&nbsp; 返回所有的application属性。</font> </p>
<p><font face="Courier New">3. ServletContext getContext( String uripath ) ;<br>&nbsp;&nbsp; 取得当前应用的ServletContext对象。</font> </p>
<p><font face="Courier New">4. String getInitParameter( String name ) ;<br>&nbsp;&nbsp; 返回由name指定的application属性的初始值。</font> </p>
<p><font face="Courier New">5. Enumeration getInitParameters() ;<br>&nbsp;&nbsp; 返回所有的application属性的初始值的集合。</font> </p>
<p><font face="Courier New">6. int getMajorVersion() ;<br>&nbsp;&nbsp; 返回servlet容器支持的Servlet API的版本号。</font> </p>
<p><font face="Courier New">7. String getMimeType( String file ) ;<br>&nbsp;&nbsp; 返回指定文件的类型，未知类型返回null。一般为"text/html"和"image/gif"。</font> </p>
<p><font face="Courier New">8. int getMinorVersion() ;<br>&nbsp;&nbsp; 返回servlet容器支持的Servlet API的副版本号。</font> </p>
<p><font face="Courier New">9. String getRealPath( String path ) ;<br>&nbsp;&nbsp; 返回给定虚拟路径所对应物理路径。</font> </p>
<p><font face="Courier New">10. RequestDispatcher getNamedDispatcher( String name ) ;<br>&nbsp;&nbsp;&nbsp; 为指定名字的Servlet对象返回一个RequestDispatcher对象的实例。</font> </p>
<p><font face="Courier New">11. RequestDispatcher getRequestDispatcher( String path ) ;<br>&nbsp;&nbsp;&nbsp; 返回一个RequestDispatcher对象的实例。</font> </p>
<p><font face="Courier New">12. URL getResource( String path ) ;<br>&nbsp;&nbsp;&nbsp; 返回指定的资源路径对应的一个URL对象实例，参数要以"/"开头。</font> </p>
<p><font face="Courier New">13. InputStream getResourceAsStream( String path ) ;<br>&nbsp;&nbsp;&nbsp; 返回一个由path指定位置的资源的InputStream对象实例。</font> </p>
<p><font face="Courier New">14. Set getResourcePaths( String path ) ;<br>&nbsp;&nbsp;&nbsp; 返回存储在web-app中所有资源路径的集合。</font> </p>
<p><font face="Courier New">15. String getServerInfo() ;<br>&nbsp;&nbsp;&nbsp; 取得应用服务器版本信息。</font> </p>
<p><font face="Courier New">16. Servlet getServlet( String name ) ;<br>&nbsp;&nbsp;&nbsp; 在ServletContext中检索指定名称的servlet。</font> </p>
<p><font face="Courier New">17. Enumeration getServlets() ;<br>&nbsp;&nbsp;&nbsp; 返回ServletContext中所有servlet的集合。</font> </p>
<p><font face="Courier New">18. String getServletContextName() ;<br>&nbsp;&nbsp;&nbsp; 返回本web应用的名称。</font> </p>
<p><font face="Courier New">19. Enumeration getServletContextNames() ;<br>&nbsp;&nbsp;&nbsp; 返回ServletContext中所有servlet的名称集合。</font> </p>
<p><font face="Courier New">20. void log( Exception ex, String msg ) ;<br>&nbsp;&nbsp;&nbsp; void log( String msg, Throwable t ) ;<br>&nbsp;&nbsp;&nbsp; void log( String msg ) ;<br>&nbsp;&nbsp;&nbsp; 把指定的信息写入servlet log文件。</font> </p>
<p><font face="Courier New">21. void removeAttribute( String name ) ;<br>&nbsp;&nbsp;&nbsp; 移除指定名称的application属性。</font> </p>
<p><font face="Courier New">22. void setAttribute( String name, Object value ) ;<br>&nbsp;&nbsp;&nbsp; 设定指定的application属性的值。</font> </p>
<p><br><font face="Courier New"><strong>⑦ config - javax.servlet.ServletConfig<br></strong>&nbsp;&nbsp; config对象用来存放Servlet初始的数据结构。</font> </p>
<p><font face="Courier New">方法：<br>1. String getInitParameter( String name ) ;<br>&nbsp;&nbsp; 返回名称为name的促使参数的值。</font> </p>
<p><font face="Courier New">2. Enumeration getInitParameters() ;<br>&nbsp;&nbsp; 返回这个JSP所有的促使参数的名称集合。</font> </p>
<p><font face="Courier New">3. ServletContext getContext() ;<br>&nbsp;&nbsp; 返回执行者的servlet上下文。</font> </p>
<p><font face="Courier New">4. String getServletName() ;<br>&nbsp;&nbsp; 返回servlet的名称。</font> </p>
<p><br><font face="Courier New"><strong>⑧ exception - java.lang.Throwable</strong> <br>&nbsp;&nbsp; 错误对象，只有在JSP页面的page指令中指定isErrorPage="true"后，才可以在本页面使用exception对象。</font> </p>
<p><font face="Courier New">方法：<br>1. Throwable fillInStackTrace() ;<br>&nbsp;&nbsp; 将当前stack信息记录到exception对象中。</font> </p>
<p><font face="Courier New">2. String getLocalizedMessage() ;<br>&nbsp;&nbsp; 取得本地语系的错误提示信息。</font> </p>
<p><font face="Courier New">3. String getMessage()<br>&nbsp;&nbsp; 取得错误提示信息。</font> </p>
<p><font face="Courier New">4. StackTrackElement[] getStackTrace() ;<br>&nbsp;&nbsp; 返回对象中记录的call stack track信息。</font> </p>
<p><font face="Courier New">5. Throwable initCause( Throwable cause ) ;<br>&nbsp;&nbsp; 将另外一个异常对象嵌套进当前异常对象中。<br>&nbsp;&nbsp; <br>6. Throwable getCause() ;<br>&nbsp;&nbsp; 取出嵌套在当前异常对象中的异常。</font> </p>
<p><font face="Courier New">7. void printStackTrace() ;<br>&nbsp;&nbsp; void printStackTrace( printStream s ) ;<br>&nbsp;&nbsp; void printStackTrace( printWriter s ) ;<br>&nbsp;&nbsp; 打印出Throwable及其call stack trace信息。</font> </p>
<p><font face="Courier New">8. void setStackTrace( StackTraceElement[] stackTrace )<br>&nbsp;&nbsp; 设置对象的call stack trace信息。</font> </p>
<p><br><font face="Courier New"><strong>⑨ page - javax.servlet.jsp.HttpJspPage</strong> <br>&nbsp;&nbsp; page对象代表JSP对象本身，或者说代表编译后的servlet对象，<br>&nbsp;&nbsp; 可以用( (javax.servlet.jsp.HttpJspPage)page )来取用它的方法和属性。</font> </p>
<img src ="http://www.blogjava.net/liaojiyong/aggbug/47876.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-05-24 19:24 <a href="http://www.blogjava.net/liaojiyong/archive/2006/05/24/47876.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在struts1.1框架下，利用smartupload实现文件的上传（可以是多个文件）（转）</title><link>http://www.blogjava.net/liaojiyong/archive/2006/05/23/47686.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 23 May 2006 09:49:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/05/23/47686.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/47686.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/05/23/47686.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/47686.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/47686.html</trackback:ping><description><![CDATA[
		<div class="postText">1、前端页面upload.jsp，后台处理程序UplodAction.java<br />2、struts.config的配置参数如下（没有设置<span style="COLOR: red">ActionForm</span>）：<br />&lt;action input="/upload.jsp"  path="/save" scope="request" type="yhp.test.web.UploadAction" validate="false"&gt;<br />      &lt;forward name="success" path="/list.do" /&gt;<br />    &lt;/action&gt;<br />3、upload.jsp页面中主要部分代码<br />&lt;%@ page contentType="text/html; charset=GBK"%&gt;<br />&lt;%@ taglib uri="<a href="http://jakarta.apache.org/struts/tags-html"><font color="#000080">http://jakarta.apache.org/struts/tags-html</font></a>" prefix="html" %&gt;<br />&lt;%@ taglib uri="<a href="http://java.sun.com/jstl/core"><font color="#000080">http://java.sun.com/jstl/core</font></a>" prefix="c" %&gt;<br />&lt;html:html&gt;<br />&lt;head&gt;<br />&lt;title&gt; 测试Struts利用SmartUpload上传文件 &lt;/title&gt;<br />&lt;meta http-equiv="Content-Type" content="text/html; charset=GBK"&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;html:form action="/save.do" styleId="formItem" method="post"  <span style="COLOR: red">enctype="multipart/form-data"</span>&gt;<br /><span style="COLOR: red">&lt;html:hidden property="id"/&gt;<br /></span>&lt;html:file property="serverpath" styleClass="input-text"&gt;&lt;/html:file&gt;<br />&lt;/html:form&gt;<br />&lt;/body&gt;<br />&lt;/html:html&gt;<br />4、UploadAction.java<br />import com.jspsmart.upload.File;<br />import com.jspsmart.upload.Files;<br />import com.jspsmart.upload.SmartUpload;<br /><br />public ActionForward doBatchsave(ActionMapping actionMapping,<br />   ActionForm actionForm, HttpServletRequest httpServletRequest,<br />   HttpServletResponse httpServletResponse) throws Exception {<br />SmartUpload mySmartUpload = new SmartUpload();<br />  mySmartUpload.initialize(getServlet().getServletConfig(),httpServletRequest, httpServletResponse);  <br />  mySmartUpload.upload();<br />  //获取除文件以外的相关信息，例如upload.jsp中隐藏控件id的值<br />  String strId=(String)mySmartUpload.getRequest().getParameter("id");<br />  Files files=mySmartUpload.getFiles();<br />  Collection col=files.getCollection();<br />  Iterator it=col.iterator();<br />  while(it.hasNext()){<br />    File file=(File)it.next();    <br />    String oldFileName=file.getFileName();     <br />    String extname=file.getFileExt();<br />    String fileName=Sequence.getSequence()+"."+extname;//产生一个唯一的文件名<br />    file.saveAs("c:\\temp\"+fileName);    <br />  }<br />  return (actionMapping.findForward("success"));<br />｝ </div>
<img src ="http://www.blogjava.net/liaojiyong/aggbug/47686.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-05-23 17:49 <a href="http://www.blogjava.net/liaojiyong/archive/2006/05/23/47686.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>forward,include,redirect　区别（转）</title><link>http://www.blogjava.net/liaojiyong/archive/2006/05/23/47673.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 23 May 2006 09:03:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/05/23/47673.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/47673.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/05/23/47673.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/47673.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/47673.html</trackback:ping><description><![CDATA[
		<div class="postTitle">forward,include,redirect是jsp中web页面(jsp或servelt)的三种不同的路由关系，三个貌似相同，其实还是有许多差别的，而了解这些细微的差别，在web开发中是很重要的。 <br />说明： <br />一、forward、include由javax.servlet.RequestDispatcher来封装,由包容器container提供RequestDispatcher接口的实现，其中声明如下： <br />void forward(ServletRequest req,ServletResponse res) <br />void include(ServeltRequest req,ServletResponse res) <br />可以通过两种方式得到RequestDispatcher: <br />1、ServletContext.getRequestDispatcher(String path); <br />其中这里的path必须开始为"/"，即这里的path必须相对于context的root. <br />2、ServeltRequest.getRequestDispatcher(String path) <br />这里的path可以为相对路径,如果path开始为"/",则也认为是从context的root开始的。 <br />二、Redirect由HttpServletResponse.sendRedirect(String location)来支持 <br />差别： <br />三个都可以对用户的request进行转发，但是还是有许多的不同，差别最主要集中在如下几个方面： <br />1、forward与include共亨Request范围内的对象,而redirect则不行，即：如果一个javabean被声明为request范围的话，则被forward到的资源也可以访问这个javabean,而redriect则不行。 <br />2、forward与include基本上都是转发到context内部的资源，而redirect可以重定向到外部的资源,如： req.sendRedriect("http://www.mocuai.com"); <br /><br />Forward功能的实现，这样 <br />private void setForward(String url,ServletRequest request, ServletResponse response)throws Exception {   <br />        HttpServletRequest hreq = (HttpServletRequest) request; <br />        RequestDispatcher dispatcher =  hreq.getSession().getServletContext().getRequestDispatcher(url); <br />        dispatcher.forward(request,response); <br />}</div>
<img src ="http://www.blogjava.net/liaojiyong/aggbug/47673.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-05-23 17:03 <a href="http://www.blogjava.net/liaojiyong/archive/2006/05/23/47673.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jsp页面，以excel的方式输出</title><link>http://www.blogjava.net/liaojiyong/archive/2006/05/23/47667.html</link><dc:creator>liaojiyong</dc:creator><author>liaojiyong</author><pubDate>Tue, 23 May 2006 08:36:00 GMT</pubDate><guid>http://www.blogjava.net/liaojiyong/archive/2006/05/23/47667.html</guid><wfw:comment>http://www.blogjava.net/liaojiyong/comments/47667.html</wfw:comment><comments>http://www.blogjava.net/liaojiyong/archive/2006/05/23/47667.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/liaojiyong/comments/commentRss/47667.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/liaojiyong/services/trackbacks/47667.html</trackback:ping><description><![CDATA[
		<div class="postTitle">在jsp页面中加入以下的语句，就可以使jsp以excel的形式输出。<br />response.setHeader("Content-Type", "application/vnd.ms-excel;charset=GBK");<br />response.setContentType("application/vnd.ms-excel;charset=GBK"); </div>
<img src ="http://www.blogjava.net/liaojiyong/aggbug/47667.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/liaojiyong/" target="_blank">liaojiyong</a> 2006-05-23 16:36 <a href="http://www.blogjava.net/liaojiyong/archive/2006/05/23/47667.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>