﻿<?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-鹰翔宇空-文章分类-web</title><link>http://www.blogjava.net/TrampEagle/category/9795.html</link><description>学习和生活
</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 10:33:12 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 10:33:12 GMT</pubDate><ttl>60</ttl><item><title>STRUTS 技巧集</title><link>http://www.blogjava.net/TrampEagle/articles/62568.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Wed, 09 Aug 2006 07:11:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/62568.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/62568.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/62568.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/62568.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/62568.html</trackback:ping><description><![CDATA[
		<p>
				<font size="4">
						<strong>引自：<a href="http://www.35dx.com/html/java/8/java7727.html">http://www.35dx.com/html/java/8/java7727.html</a><br /><br /><br />1.对bean:write输出的数据进行格式化</strong>
				</font>
		</p>
		<p>在我们的struts应用中，如果bean:write输出的是很大的Double数据的话，默认情况下它会用科学计数化表示 如 1.316E8等。</p>
		<p>我们需要将他进行格式化，如千分位格式化等。即输出为13,160,000.00。</p>
		<p>如果是个别现象，我们用bean:write的format属性处理，即format="0,000.00"</p>
		<p>如果是普遍现象，我们可以在资源文件(在struts-config.xml的message-resources节点配置)里设置org.apache.struts.taglib.bean.format.float=0,000.00 ，当然实际处理时format属性是优先的。也就是说，如果format属性存在，bean:write将用format属性值进行格式化，否则用默认的org.apache.struts.taglib.bean.format.float的值格式化。</p>
		<p>此类格式化参数有：</p>
		<p>? 
</p>
		<table style="WIDTH: 81.44%; HEIGHT: 317px" cellspacing="1" cellpadding="1" border="1">
				<tbody>
						<tr>
								<td>
										<strong>序号</strong>
								</td>
								<td>
										<strong>格式化参数</strong>
								</td>
								<td>
										<strong>适用类型</strong>
								</td>
						</tr>
						<tr>
								<td>1</td>
								<td>org.apache.struts.taglib.bean.format.sql.timestamp</td>
								<td>java.sql.Timestamp</td>
						</tr>
						<tr>
								<td>2</td>
								<td>org.apache.struts.taglib.bean.format.sql.date</td>
								<td>java.sql.Date</td>
						</tr>
						<tr>
								<td>3</td>
								<td>org.apache.struts.taglib.bean.format.sql.time</td>
								<td>java.sql.Time</td>
						</tr>
						<tr>
								<td>4</td>
								<td>org.apache.struts.taglib.bean.format.date</td>
								<td>java.util.Date</td>
						</tr>
						<tr>
								<td>5</td>
								<td>org.apache.struts.taglib.bean.format.int</td>
								<td>Byte，Short，Integer，Long，BigInteger</td>
						</tr>
						<tr>
								<td>6</td>
								<td>org.apache.struts.taglib.bean.format.float</td>
								<td>Float，Double，BigDecimal</td>
						</tr>
				</tbody>
		</table>
		<p>
				<font size="4">
						<strong>2</strong>.<strong>处理输入类型</strong></font>
		</p>
		<p>
				<font size="4">以日期为例，其他类型同理</font>
		</p>
		<pre>struts使用日期包括将string自动转化为日期fill到form中的解决方法：<br /><br />创建如下类：<br />import java.util.*;<br />import org.apache.commons.beanutils.*;<br />import java.text.SimpleDateFormat;<br />public class DateConvert implements Converter {<br />    static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");<br />    public DateConvert() {<br />    }<br />    public Object convert(Class type, Object value) {<br />        if (value == null) {<br />            return null;<br />        }<br />        if (((String) value).trim().length() == 0)<br />            return null;<br />        if (value instanceof String) {<br />            try {<br />                return df.parse((String) value);<br />            } catch (Exception ex) {<br />                throw new ConversionException("输入的日期类型不合乎yyyy-MM-dd"<br />                        + value.getClass());<br />            }<br />        } else {<br />            throw new ConversionException("输入的不是字符类型" + value.getClass());<br />        }<br />    }<br />}</pre>
		<pre>
				<br />
				<br />然后在你的系统初始化的地方使用如下语句初始化（如web的init方法）<br />ConvertUtils.register(new DateConvert(),java.util.Date.class);<br />参数用于表示DateConvert类负责处理java.util.Date类型的转化</pre>
<img src ="http://www.blogjava.net/TrampEagle/aggbug/62568.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-08-09 15:11 <a href="http://www.blogjava.net/TrampEagle/articles/62568.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>weblogic Server内部结构和相关的配置（转）</title><link>http://www.blogjava.net/TrampEagle/articles/60966.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Mon, 31 Jul 2006 02:54:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/60966.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/60966.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/60966.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/60966.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/60966.html</trackback:ping><description><![CDATA[weblogic Server内部结构图：<br /><img onmouseover="this.style.cursor='hand';" style="CURSOR: hand" onclick="window.open(this.src);" height="225" alt="按此在新窗口打开图片" src="http://www.blogjava.net/images/blogjava_net/lqsun/1699/r_3333.jpg" width="518" onload="javascript:DrawImage(this);" border="0" /><br />(一)  原理简单说明<br /><br />服务器启动，就会绑定到相应的端口，并为一个端口分配一个线程以接受连接请求，一旦服务器接受到连接请求并建立好连接以后，监听线程将处理权交给套接字复用器，套接字复用器进行一定的处理，并会负责选择利用那个执行队列并将请求置入其中。当有一个请求进入执行队列，就会有一个空闲的执行县城从该队列里面取走并向调用者返回结果。<br /><br />(二)  执行队列和执行线程的相关配置<br /><br />执行线程数量有一定的限制，在服务器启动的时候，就已经形成了一个含有一定数量执行线程的池，执行线程可能跨servlet，ejb和jdbc等，由于执行线程仅当程序成功结束或者出现异常才能被释放继续处理其他请求，所以如果执行线程执行的不够快，而请求又多的情况下，就会造成执行队列的阻塞。<br /><br />相关的配置信息有：<br /><br />server菜单—〉configuration页---〉高级配置---〉Config Execute Queues中的配置项如下：<br /><br />1、Queue Length队列长度，执行队列的长度<br /><br />2、Queue Length Threshold Percent 一个百分数，当request的数量达到队列长度的这个比例的时候，weblogic会发出overflow的标志信息。<br /><br />3、Thread Count 服务器初始创建的执行线程的数量<br /><br />4、Thread Increase 如果weblogic发出overflow的标志信息，weblogic会尝试增加这个数量的执行线程，以解决处理矛盾。<br /><br />5、Threads Maximum最大执行线程数<br /><br />6、Threads Minimum最小执行线程数<br /><br />7、Thread Priority线程优先级<br /><br />另外server菜单—〉configuration页---〉tuning子页中还有一些相关的配置：<br /><br />1、  Stuck Thread Max Time 黏联线程时间，超过这个时间没有返回的执行线程，系统将认为是黏联线程。<br /><br />2、  Stuck Thread Timer Interval 系统检查黏联线程的时间间隔<br /><br />如果weblogic认为某个队列中的所有的线程全部黏联的话，weblogic将会增加执行线程的数量。<br /><br />注意：执行线程的数量一旦增加，目前weblogic不会去减少他，如果增加了一些线程以后再次出现overflow的警告，weblogic会继续增加执行线程的数量，一直到达到上限为止。<br /><br />(三)  套接字复用器的相关配置<br /><br />Weblogic带有两个版本的套接字复用器，纯java版和本地接口版（jni），一般来说在访问量小的情况下，java版比jni版性能要好一些，因为jni的API调用会损失一部分性能，但是访问量大的情况，一般都是jni版的性能比较好，所以尽量保证weblogic实用本地接口版的套接字复用器。<br /><br />相关的配置参数有两个，在server菜单—〉configuration页---〉tuning子页中的第一个和第二个配置项。<br /><br />Enable Native IO ：启用本地IO，勾选这个配置以后，weblogic就会启用本地接口版的套接字复用器<br /><br />Socket Readers ：如果不选上一个选项，则这个选项可用，也就是说java版的套接字复用器会被启用，并且，java版的复用器会从执行线程中抽出这个比例的线程用于处理socket的请求。（和java客户端访问有关？）<br /><br /><strong>web应用程序的相关配置</strong><br /><br /><br />1、单线程模式servlet<br /><br />默认情况下，一个servlet实例将会产生多个线程来同时响应多个请求。<br /><br />如果某个servlet实现SingleThreadMod旗标接口，那么这个servlet将会自动拒绝多路并行请求的模式。在这种情况下，weblogic会产生一个servlet实例池来满足单线程的要求。<br /><br />目前，应该尽量避免使用单线程模式的servlet，如果需要在大容量的系统中使用单线程模式的servlet，那么应该调整如下的参数：<br /><br />Single Threaded Servlet Pool Size 这个参数可在weblogic.xml或者在weblogic控制台上webapplication菜单---〉configuration页---〉Descriptor  子页中进行设置。<br /><br />默认为5。<br /><br />2、Weblogic生产模式下会自动监测servlet和jsp的更改情况，在产品模式下，不需要这些检查，可以通过下面的参数更改：<br /><br />JSPPage Check Secs和Servlet Reload Check Secs均设为-1这两项是weblogic检查jsp和servlet的时间间隔。设置为-1，weblogic将不再检查。<br /><br />关闭JSPKeep Generated和JSPVerbose，产品模式下也不需要这两个选项。<br /><br />Enable JSP Line Numbers 这个选项是启用jsp行号的选项，启用行号的目的是用来支持调试，有些IDE可以在jsp生成的java源代码中设置断点用于调试。生产模式中也不需要。<br /><br />注意：在产品发布模式下，请禁止对servlet和jsp的变更检查，这样除了能提高效率以外，还可以防止用上传文件的方式对服务器的攻击。如果需要更改servlet和jsp，可以重新部署应用。<br /><br />3、Session和cookie的相关配置<br /><br />概念会话cookie：如果不设置过期时间，则表示这个cookie的生命期为浏览器会话期间，只要关闭浏览器窗口，cookie就消失了。这种生命期为浏览器会话期的 cookie被称为会话cookie。<br /><br />Session Cookie Max Age Secs 就是会话cookie的超时时间，设置小于0表示不限制。<br /><br />Session Invalidation Interval Secs 检查过期session的周期<br /><br />Session Timeout Secs session的超时时间<br /><br />4、Jdbc连接池的配置<br /><br />URL 连接池地址<br /><br />Driver Classname ：jdbc驱动类名<br /><br />Properties ：属性，例如user=examples<br /><br />Password ：密码<br /><br />Initial Capacity ：初始连接数<br /><br />Maximum Capacity ：最大连接数<br /><br />Capacity Increment ：连接池每次增加连接的数量<br /><br /> <br /><br />Statement Cache Type ：prepared statements缓存的策略，LRU算法在有新的语句到来时，将最不经常被用得语句调整出缓存。FIXED算法为先进先出的算法<br />Statement Cache Size ：缓存中语句的最大数量，调整这个数值的大小，有利于提高系统的效率。 <br /><br /><strong>java虚拟机配置</strong><br /><br />JRockit是BEA公司开发的Intel平台之上的高性能以及高可管理性的jvm产品，在Intel平台上使用JRockit无疑会大大的提高效率。使用向导建立server的配置的时候，可以选择JRockit作为该server的虚拟机，另外，也可以在域的startWebLogic.cmd或者startWebLogic.sh脚本中配置使用JRockit。<br /><br /> <br /><br />使用JRockit：<br /><br />set JAVA_VENDOR=BEA<br /><br />set JAVA_HOME=c:\bea\jrockit81sp4_142_05<br /><br />使用Sun的jvm：<br /><br />set JAVA_VENDOR=Sun<br /><br />set JAVA_HOME=c:\bea\jdk142_05<br /><br /> <br /><br />u       与java虚拟机相关的参数配置可在startWebLogic.cmd或者startWebLogic.sh脚本中设置，在其执行java命令之前一行加入如下指令：<br /><br />set JAVA_VM=%JAVA_VM% “这里加入虚拟机参数”<br /><br />JRockit上的一些参数解释如下：<br /><br />选项<br />    <br /><br />描述<br /><br />-X<br />    <br /><br />显示扩展Java选项<br /><br />-Xallotype<br /><br />-Xallocationtype<br />    <br /><br />可取值global和local，定义使用本地线程还是全局线程。<br /><br />global，在最大堆尺寸比较小时（小于128M）或者应用程序大量使用了线程时使用。<br />local，在最大堆尺寸比较大时（大于128M）或者应用程序少量使用了线程时使用。<br /><br />每个本地线程区都要消耗大约2K的内存，如果大量地使用了线程，本地线程不但会造成内存空间浪费，而且还会造成堆碎片。使用全局线程机制会减少堆碎片，但在内存分配方面速度要慢一些。<br /><br />-Xbootclasspath<br />    <br /><br />指定类搜索路径，可以是ZIP和JAR文件，以；或：分隔<br /><br />-Xcleartype<br />    <br /><br />定义内存清理时机，可取值gc, local, alloc。gc表示在垃圾回收时清理内存；local表示时分配一块local线程区时清理；alloc表示内存区要被分配给其它对象时清理<br /><br />-Xgc<br />    <br /><br />选择要使用的垃圾回收器的类型，可取值：<br /><br />gencopy：分代复制收集（默认）适合调试期间使用<br /><br />singlecon：单空间并发，无中断并发<br /><br />gencon：世代并发，暂停时间最短<br /><br />parallel：parallel并行回收器，会导致应用程序间歇暂停，但会带来最大吞吐量。<br /><br />如果-Xmx小于128M，缺省使用gencopy，否则使用gencon<br /><br />-Xgcpause<br />    <br /><br />打印由垃圾回收器造成的停顿时间<br /><br />-Xgcreport<br />    <br /><br />打印垃圾回收报表<br /><br />-Xjvmpi<br />    <br /><br />是否允许JVMPI事件，这些事件有：<br /><br />entryexit（缺省ON）<br /><br />allocs（缺省ON）<br /><br />monitors（缺省ON）<br /><br />arenasdelete（缺省OFF）<br /><br />例如：-Xjvmpi:allocs=off,monitors=off,entryexit=off<br /><br />-Xmanagement<br />    <br /><br />激活JVM中的管理服务器，在JVM的管理控制台能连接到它之前，必须先激活。<br /><br />-Xms<br />    <br /><br />设置初始堆大小，单位有K、M、G<br /><br />-Xmx<br />    <br /><br />设置最大堆大小，单位有K、M、G<br /><br />建议：应设置-Xms=-Xmx以免去分配堆的时间<br /><br />-Xnativethreads<br />    <br /><br />使用本地线程系统，这是缺省选项<br /><br />-Xnoclassgc<br />    <br /><br />禁止对类作垃圾回收<br /><br />-Xnohup<br />    <br /><br />告诉JRockit，忽略CTRL_LOGOFF_EVENT和SIGHUP事件<br /><br />-Xns<br />    <br /><br />设置nursery尺寸，单位有K、M、G<br /><br />Nursery是垃圾回收器用来存放临时对象的地方，应该在保证垃圾回收暂停时间最短的情况下，尽量大的调整nursery的值。<br /><br />对于-Xgc:gencopy，缺省的Nursery大小为320KB/CPU，对于10个CPU的系统来说，Nursery大小为3200KB（3.2M）对于-Xgc:gencon，缺省的Nursery大小为10M/CPU，对于10个CPU的系统来说，Nursery大小为100M<br /><br />-Xss<br />    <br /><br />设置线程栈尺寸，单位有K、M、G<br /><br />-Xthinthreads<br />    <br /><br />使用JRockit的高性能线程系统，在IA64上不可用。<br /><br />注意：瘦线程系统目前还没有全面推广，不建议使用<br /><br />-Xverbose<br />    <br /><br />让JRockit打印更多的信息，可选的参数有：<br /><br />codegen、cpuinfo、gc、load、memory、Opt<br /><br />-Xverify<br />    <br /><br />作完整的bytecode一级的校验<br /><br /> <br /><br />u       JRockit的管理控制台的使用<br /><br />在JRockit的启动参数中加入-Xmanagement，以便启动JRockit的时候同时启动其Management Server。<br /><br />在JRockit的bin目录下，运行console.exe程序<br /><br />建立一个新的连接，连接需要监视的JRockit（监视端口默认为7090）<br /><br />在JRockit Management Console中，将Tools/Preferences菜单中的Mode of operation属性设为developer<br /><br />在Method Profiler属性页中添加你所需要观察的类的成员方法<br />按Start按钮让Method Profiler开始进行统计<br /><br />原文地址：<a href="/lqsun" target="_blank">http://www.blogjava.net/lqsun</a><img src ="http://www.blogjava.net/TrampEagle/aggbug/60966.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-07-31 10:54 <a href="http://www.blogjava.net/TrampEagle/articles/60966.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BEA dev2dev WebLogic管理精华 （转）</title><link>http://www.blogjava.net/TrampEagle/articles/60964.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Mon, 31 Jul 2006 02:52:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/60964.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/60964.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/60964.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/60964.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/60964.html</trackback:ping><description><![CDATA[
		<span id="fontzoom"> 
<p id="fp">日常管理 WebLogic Platform 8.1 永不过期的开发版license<br /><br />下载地址为：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/servlet/D2DServlet/download/81-8992-44196-240/license.bea" target="_blank">http://dev2dev.bea.com.cn/bbs/servlet/D2DSer ... 8992-44196-240/license.bea</a><br /><br /> <br /><br />使用方式：<br /><br />替换c:\bea目录下的这个文件，这样就可以使WebLogic Platform用不过期<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=8992&amp;tstart=0&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID ... 2&amp;tstart=0&amp;quint=true</a><br />如何远程启动WebLogic服务?<br /><br />用telnet远程控制服务器，远程启动WEBLOGIC服务，启动后关闭telnet，WebLogic服务也跟着停止，这是因为使用telnet启动的进程会随着telnet进程的关闭而关闭。所以我们可以使用一些UNIX下的命令来做到不关闭。<br /><br /> <br /><br />使用如下命令：<br /><br />nohup startWeblogic.sh&amp;<br /><br /> <br /><br />如果想要监控标准输出可以使用：<br /><br />tail -f nohup.out<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=7709&amp;tstart=0&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID ... 9&amp;tstart=0&amp;quint=true</a><br /><br /> <br />控制台左边的树结构看不见？<br /><br />这是因为浏览器没有安装合适版本的JRE插件来支持Applet。<br /><br />可以到<a href="http://java.sun.com/products/plugin/ " target="_blank">http://java.sun.com/products/plugin/ </a>下载相应浏览器的插件来解决这个问题。<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=5233&amp;tstart=0&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID ... 3&amp;tstart=0&amp;quint=true</a><br />WebLogic 配置出来的各种域有什么区别？<br /><br />请看这个链接中的Table 16-1 Configuration Template Summary ，说的很明白<br /><a href="http://e-docs.bea.com/platform/docs81/confgwiz/tempref.html" target="_blank">http://e-docs.bea.com/platform/docs81/confgwiz/tempref.html</a><br /><br />Table 16-1 Configuration Template Summary <br /><br />Template<br />    <br /><br />Required WebLogic Platform Component<br />    <br /><br />Filename<br />    <br /><br />Description<br /><br />Avitek Medical Records Sample Domain<br />    <br /><br />WebLogic Server<br />    <br /><br />medrec.jar<br />    <br /><br />Creates the Avitek Medical Records domain outside the installed kit. This domain is a WebLogic Server sample application suite that concisely demonstrates all aspects of the J2EE platform.<br /><br />Basic WebLogic Integration Domain<br />    <br /><br />WebLogic Integration,<br /><br />WebLogic Workshop,<br /><br />WebLogic Server<br />    <br /><br />wli.jar<br />    <br /><br />Creates a domain that supports the development of WebLogic Integration solutions.<br /><br />Note: To create a domain that supports the development of WebLogic Server Process Edition solutions, use the Basic WebLogic Integration Domain template. If you have an existing WebLogic Server-based domain, you can extend it to include the resources required for WebLogic Server Process Edition by using the WebLogic Integration Extension Template.<br /><br />Basic WebLogic Platform Domain<br />    <br /><br />WebLogic Platform (all components must be installed)<br />    <br /><br />platform.jar<br />    <br /><br />Creates a domain that supports the development of applications using all WebLogic Platform components.<br /><br />Basic WebLogic Portal Domain<br />    <br /><br />WebLogic Portal,<br /><br />WebLogic Workshop,<br /><br />WebLogic Server<br />    <br /><br />wlp.jar<br />    <br /><br />Creates a domain that supports the development of WebLogic Portal solutions.<br /><br />Basic WebLogic Server Domain<br />    <br /><br />WebLogic Server<br />    <br /><br />wls.jar<br />    <br /><br />Creates a simple WebLogic Server domain without any sample applications.<br /><br />Basic WebLogic Workshop Domain<br />    <br /><br />WebLogic Workshop,<br /><br />WebLogic Server<br />    <br /><br />wlw.jar<br />    <br /><br />Creates a domain that supports the development of WebLogic Workshop solutions.<br /><br />WebLogic Server Examples Domain<br />    <br /><br />WebLogic Server<br />    <br /><br />examples.jar<br />    <br /><br />Creates the WebLogic Server Examples domain outside the installed kit. This domain contains a collection of examples that illustrate best practices for coding individual J2EE APIs.<br /><br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=9188&amp;tstart=0&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID ... 8&amp;tstart=0&amp;quint=true</a><br /><br /> <br />Too many open files错误的处理<br /><br />在有些Linux下由于操作系统的限制，单一进程可以打开的文件数有限制，引起WebLogic报告错误，解决这问题需要编译内核并且调节一些限制参数。<br /><br /> <br /><br />在Linux内核2.4.x中需要修改源代码，然后重新编译内核才生效。编辑Linux内核源代码中的 include/linux/fs.h文件，将 NR_FILE 由8192改为65536，将NR_RESERVED_FILES 由10 改为 128。编辑fs/inode.c 文件将MAX_INODE 由16384改为262144。一般情况下，系统最大打开文件数比较合理的设置为每4M物理内存256，比如256M内存可以设为16384，而最大的使用的i节点的数目应该是最大打开文件数目的3倍到4倍。另外，对每个进程的设置：<br /><br />ulimit -n 4096 将每个进程可以打开的文件数目加大到4096，缺省为1024<br /><br />ulimit -m 4096 限制每个进程使用的内存数。<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=2461&amp;tstart=0&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID ... 1&amp;tstart=0&amp;quint=true</a><br /><br /> <br />Apache2和weblogic7实现虚拟主机<br /><br />选择apache2,是因为目前wls7只支持apache2的结合.<br /><br /> <br /><br />1.首先，正确安装apache2,这里我们假设安装在C:\apache group,安装完毕，需要测试apache2是否支持动态加载模块功能，这样测试，到命令<br /><br /> <br /><br />提示符下运行:<br /><br />c:\&gt;apache group\apache2\bin\apache -l<br /><br />如果列出：<br /><br />mod_so.c<br /><br />则表示支持，然后将本篇文章附件中的mod_wl_20.so拷贝到apache group\apache2\modules下面，运行：<br /><br />c:\&gt;apache group\apache2\bin\apache -t<br /><br />如果输出：<br /><br />Syntax Ok<br /><br />表示WebLogic Server plug-in安装成功。<br /><br /> <br /><br />2.正确安装weblogic7.0。这里我们假设wls7的安装路径是：c:\bea。然后用域配置向导配置一个域，我们假设域<br /><br />的名称为amjn,路径是c:\bea\user_projects\amjn,然后在amjn下面分别建立两个站点web1,web2，修改<br /><br /> <br /><br />c:\bea\user_projects\amjn\config.xml文件，在<br /><br />&lt;Application Deployed="true" Name="DefaultWebApp"<br /><br />Path=".\applications" StagedTargets="" TwoPhase="false"&gt;<br /><br />&lt;WebAppComponent Name="DefaultWebApp" Targets="myserver" URI="DefaultWebApp"/&gt;<br /><br />&lt;/Application&gt;<br /><br />下面添加：<br /><br />&lt;Application Deployed="true" Name="web1" Path=".\applications\web1"<br /><br />StagedTargets="" TwoPhase="false"&gt;<br /><br />&lt;WebAppComponent Name="web1" URI="web1" VirtualHosts="web1_vh"/&gt;<br /><br />&lt;/Application&gt;<br /><br />&lt;Application Deployed="true" Name="web2" Path=".\applications\web2"<br /><br />StagedTargets="" TwoPhase="false"&gt;<br /><br />&lt;WebAppComponent Name="web2" Targets="myserver" URI="web2" VirtualHosts="web2_vh"/&gt;<br /><br />&lt;/Application&gt;<br /><br />在文件最下面的<br /><br />&lt;/Domain&gt;<br /><br />的上面添加<br /><br />&lt;VirtualHost DefaultWebApp="web1" Name="web1_vh" Targets="myserver" VirtualHostNames="www.web1.com"/&gt;<br /><br />&lt;VirtualHost DefaultWebApp="web2" Name="web2_vh" Targets="myserver" VirtualHostNames="www.web2.com"/&gt;<br /><br />,然后重新启动运行\amjn\startWebLogic.cmd,一定要运行正常。到这里，weblogic算是配置完成了。<br /><br /> <br /><br />3.现在开始配置apache多个虚拟主机，首先我们先打开c:\winnt\system32\drivers\etc\hosts文件，在其中添加：<br /><br />10.1.3.30 www.web1.com<br /><br />10.1.3.30 www.web2.com<br /><br />这里面的10.1.3.30是你的weblogic服务器绑定的ip,然后打开apache2\conf\httpd.conf文件，在174行，注意是174行加入如下语句：<br /><br />#WebLogic Server Proxy Settings-------该行是174行<br /><br />LoadModule weblogic_module modules/mod_wl_20.so<br /><br />&lt;IfModule mod_weblogic.c&gt;<br /><br />WebLogicHost www.synnex-china.com<br /><br />WebLogicPort 7001<br /><br />MatchExpression *.jsp<br /><br />MatchExpression *.do<br /><br />&lt;/IfModule&gt;<br /><br />然后修改httpd.conf文件中的Listen:80为Listen:10.1.3.30:80,在文件section 3部分添加:<br /><br />NameVirtualHost 10.1.3.30<br /><br />&lt;VirtualHost 10.1.3.30&gt;<br /><br />ServerName www.web1.com<br /><br />DocumentRoot "c:/bea/user_projects/amjn/applications/web1"<br /><br />ErrorLog logs/web1.com.log<br /><br />&lt;/VirtualHost&gt;<br /><br /> <br /><br />&lt;VirtualHost 10.1.3.30&gt;<br /><br />ServerName www.web2.com<br /><br />DocumentRoot "c:/bea/user_projects/amjn/applications/web2"<br /><br />ErrorLog logs/web2.com.log<br /><br />&lt;/VirtualHost&gt;<br /><br />启动apache,如果没有问题（可以通过logs/error.log查看），那就一切ok了<br /><br /> <br /><br />4.现在你可以分别敲入www.web1.com/index.jsp，访问的将是web1/index.jsp,敲入www.web2.com/index.jsp访问的将是web2/index.jsp<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=6326&amp;tstart=0&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID ... 6&amp;tstart=0&amp;quint=true</a><br />如何限制公网用户访问WebLogic的控制台呢？<br /><br />我们的weblogic（版本6.1）应用部署在内部网上，通过防火墙映射到公网上，但公网用户通过键入域名：www.xxx.com/console，就可进入weblogic的登陆页面，用户可猜测管理员的密码，如何屏蔽公网用户对weblogic控制台的访问呢？<br /><br /> <br /><br />方法1：<br /><br />在控制台上点击左边的你那个domain，将Console Enabled这个选项去掉，这样就完全不能使用console了<br /><br />方法2：<br /><br />将“console”改名，改“Console Context Path”的“console”为一个希奇古怪的名字就可以了<br /><br />方法3：<br /><br />不要给WebLogic公网ip，通过一个有公网ip的apache等proxy来访问WebLogic<br /><br />方法4：<br /><br />启动Administration Port<br /><br />方法5：<br /><br />应用不发布在Admin Server上，Admin Serve在外网不可见<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=2230" target="_blank">http://dev2dev.bea.com.cn/bbs/threa ... =81&amp;threadID=2230</a><br /><br /> <br />开机自动启动oracle和weblogic<br /><br />我的机器是5L，oracle9i，weblogic6.1，HTTPServer<br />由于给别人装的机器，对方水平有限，为了省心，还是让系统起来自动运行各项应用比较好：）<br />首先自动启动oracle9i，9i装在oracle文件系统下，在/oracle下建立文件startdb，<br />文件内容<br />echo "begin to start oracle"<br />lsnrctl start<br />sqlplus /nolog &lt;&lt;EOF<br />connect /as sysdba<br />startup<br />exit<br />exit<br />echo "oracle have started"<br />给startdb执行权限<br />自动关闭oracle9i，在/oracle下建立文件stopdb<br />sqlplus /nolog &lt;&lt;EOF<br />connect /as sysdba<br />shutdown immediate<br />好了启动和关闭oracle脚本完成还要加到系统的启动和关闭文件里，另外还要在启动oracle后启动weblogic<br />在/etc下建立文件rc.startdb，脚本如下<br /><br />su - oracle "-c /oracle/startdb"    ＃启动oracle<br />cd /weblogic/wlserver6.1/config/mydomain  ＃转到weblogic启动目录，必须<br />./startWebLogic.sh  ＃启动weblogic<br />给文件执行权限<br />注意由于weblogic在启动后如果用户退出telnet 就自动关闭，所以要把weblogic放在后台执行，所以在startWebLogic.sh文件中启动weblogic的命令行改为可以在后台运行，用 nohup （启动命令行） &gt;/home/weblogic.log &amp;<br />把weblogic的运行信息存到/home/weblogic.log文件中<br /><br />下面要把启动信息放到inittab中，加入一行<br />startdb:2345678:wait:/etc/rc.startdb<br />这样系统启动后会自动启动oracle9i<br /><br /><br />系统关机自动关闭oracle9i<br />在/etc下建立脚本文件rc.stopdb<br />su - oracle "-c /oracle/stopdb"<br />给执行权限<br />由于5L中安装完成后没有/etc/rc.shutdown文件，需要手工创建一个<br />内容如下<br />#!/bin/ksh <br />rc.stopdb<br />给执行权限<br />这样当系统关机时会自动寻找rc.shutdown并执行，系统可以自动关闭oracle9i<br /><br />当然可以把一些命令行直接写入inittab或rc.shutdown中，看自己的喜好了：）<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=8415&amp;tstart=25&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID= ... 5&amp;tstart=25&amp;quint=true</a><br /><br /> <br />如何测试虚拟主机<br /><br />在本机配置了虚拟主机，没有DNS Server，如何进行测试呢？<br /><br />C:\WINNT\system32\drivers\etc\hosts加入一行：127.0.0.1 test.project.com.cn<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=9776&amp;tstart=25&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID= ... 6&amp;tstart=25&amp;quint=true</a><br /><br /> <br />WebLogic的Startup Class应该放在那个目录里<br /><br />WebLogic在启动的时候可以指定Startup Class，它在任何一个应用的类被加载之前调用，所以应该加到启动时的系统类路径下，可以修改startWebLogic.cmd或 commEnv.cmd文件相应的CLASSPATH部分，加入Startup Class的类路径。<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=9119&amp;tstart=25&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID= ... 9&amp;tstart=25&amp;quint=true</a><br /><br /> <br />如何停止WebLogic服务？<br /><br />直接杀死进程不是标准的做法，应该使用如下Java命令：<br /><br />java -classpath weblogic.jar;%CLASSPATH% weblogic.Admin -url &lt;host_name&gt;:&lt;port_number&gt; SHUTDOWN -username &lt;system_user_name&gt; -password &lt;system_user_password&gt;<br /><br />例如：<br /><br />java -classpath weblogic.jar;%CLASSPATH% weblogic.Admin -url 192.168.0.1:7001<br /><br />SHUTDOWN -username system -password password<br /><br />其中如果SHUTDOWN管不掉，可以使用FORCESHUTDOWN代替SHUTDOWN来强制关掉服务器。<br /><br /> <br /><br />另外也可以直接使用stopWebLogic.cmd。<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=5519&amp;tstart=25&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID= ... 9&amp;tstart=25&amp;quint=true</a><br /><br /> <br /><br />应用管理 JNDI里面加和不加java:comp/env/前缀有什么区别？<br /><br />java:comp/env是标准的J2EE环境查找规则，使用这种方式必须做一次环境名到JNDI名的映射，这种隔离使得在写程序时不必关注真正的JNDI名字，其实说白了跟把JNDI名放到配置文件里是一样的，用法如下：<br /><br />如把java:comp/env/my/datasource映射到my.ora.dataource<br /><br />web.xml<br />&lt;resource-ref&gt;<br />&lt;res-ref-name&gt;my/datasource&lt;/res-ref-name&gt;<br />&lt;res-type&gt;javax.sql.DataSource&lt;/res-type&gt;<br />&lt;res-auth&gt;CONTAINER&lt;res-auth&gt;<br />&lt;/resource-ref&gt;<br /><br />weblogic.xml<br />&lt;reference-descriptor&gt;<br />&lt;resource-description&gt;<br />&lt;res-ref-name&gt;my/datasource&lt;/res-ref-name&gt;<br />&lt;jndi-name&gt;my.ora.dataource&lt;/jndi-name&gt;<br /><br />………………….<br /><br />而不使用这个前缀的，其实就是直接的JNDI名<br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=17074&amp;tstart=0&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID= ... 74&amp;tstart=0&amp;quint=true</a><br /><br /> <br />如何更改默认打开主页？如何设置虚拟目录？<br /><br />设置默认打开主页：<br /><br />web.xml增加<br />&lt;welcome-file-list&gt;<br />&lt;welcome-file&gt;yourfile&lt;/welcome-file&gt;<br />&lt;/welcome-file-list&gt;<br /><br /> <br /><br />虚拟目录的配置方法：<br />在weblogic.xml中添加如下的类似配置<br />   &lt;virtual-directory-mapping&gt;<br />     &lt;local-path&gt;c:/usr/common_jsps.jar&lt;/local-path&gt;<br />     &lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;<br />   &lt;/virtual-directory-mapping&gt;<br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=16333&amp;tstart=0&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID= ... 33&amp;tstart=0&amp;quint=true</a><br /><br /> <br />WebLogic Builder使用简介<br /><br />在DEV2DEV论坛上有网友会问类似于这样的问题“如何为EJB写那些部署描述文件如ejb-jar.xml以及WebLogic-ejb- jar.xml呢？”，对初学EJB的朋友来说，是一个比较困难的问题，如果不想手写的话，可以采用BEA提供的WebLogic Builder工具或是JBuilder等工具来自动生成。本文就WebLogic Builder的使用进行一个简单的介绍，权且当一个入门的指引，同时欢迎各位朋友就你的经验对这篇文章进行补充完善。使用步骤如下：<br /><br /> <br /><br />一、准备。<br />例子就用WebLogic安装完后的example中statelessSession EJB的例子，给个路径参考<br />C: \bea\weblogic700\samples\server\src\examples\ejb20\basic\statelessSession 　将这个目录下的.java文件全部拷贝出来放到一个临时目录中比如C:\temp\WebLogic_Builder_Test来做这个实验，拷贝的文件有Client.java，Trader.java，TraderBean.java，TradeResult.java， TraderHome.java。<br /><br /> <br /><br />二、对java原文件进行编译<br />命令行中进入C:\temp\WebLogic_Builder_Test，键入　javac -d . *.java，<br /><br /> <br /><br />三、打jar包<br />命令行中，C:\temp\WebLogic_Builder_Test目录下，键入jar -cvf test.jar *.*，生成test.jar包。<br /><br /> <br /><br />四、打开WebLogic Builder工具，选择并打开我们在步骤三中创建的test.jar包，这时WebLogic Builder给出一个提示“Unable to locate deployment descriptors. C:\temp\WebLogic_Builder_Test\test.jar. Would you like new descriptors created for you?”，这意思明白了吧，WebLogic Builder要为你创建基本的部署描述符文件了，当然点击是咯，然后选择保存，这样你的C:\temp\WebLogic_Builder_Test目录下的test.jar文件就有那两个部署描述文件了，可以通过WebLogic Builder工具中的View--&gt;XML Source进行查看。<br /><br /> <br /><br />恭喜你，对WebLogic Builder这个工具的使用入门了，至于该工具的其它的一些使用功能比如BEAN属性配置、server部署什么的，就请大家自己研究吧！^Q^<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=2683" target="_blank">http://dev2dev.bea.com.cn/bbs/threa ... =81&amp;threadID=2683</a><br /><br /> <br />WebLogic部署应用的方式简明列表<br /><br />1、WebLogic中应用可分三种，分别对应不同的描述文件及扩展名或目录结构：<br /><br />（1）*.JAR: 是EJB的压缩包(有3个描述文件ejb-jar.xml，WEBLOGIC*.0-ejb-jar.xml，WEBLOGIC*.0-cmp-rdbms-jar.xml)<br /><br />（2）*.WAR: 是只包含JSP和SERVLET的WEB APPLICATION压缩包(有2个描述文件web.xml，weblogic.xml)<br /><br />（3）*.EAR: 是包含EJB和WEB APPLICATION 的J2EE Enterprise Application压缩包(有1 个描述文件，application.xml)<br /><br />注意：它们不能混用，如WEB APPLICATOIN不能打包成.EAR文件。<br /><br /> <br /><br />2、WebLogic的应用用两种发布方式:<br /><br />（1）以目录形式存放在WEBLOGIC的APPLICATIONS目录下，适用于开发阶段<br /><br />（2）以一个压缩包形式存放在WEBLOGIC的APPLICATIONS目录下，适用于运行阶段，可用JAR 打包，如D:\test &gt;jar cf testwar.war *<br /><br />把TEST目录下的所有文件打包成一个testwar.war文件。<br /><br /> <br /><br />3、WebLogic应用的布置方式有2种<br /><br />（1）静态布置:即把应用在CONFIG.XML中登记，可通过WEBLOGIC的控制台进行添加，WEBLOGIC会自动把该应用对应的压缩包拷到APPLICAITONS目录下，如果对该应用修改，需要重新布置才行。<br /><br />（2）动态布置:没有在config.xml中登记，可直接把压缩包或目录拷到APPLICATIONS目录下，WebLogic会自动检测到. WebLogic每次启动时会自动对APPLICATIONS目录下没有进行静态布置的应用，进行动态布置。<br /><br /> <br /><br />4、一个例子:<br /><br />如果一个应用中有EJB，JSP，SERVLET，其布置步骤如下:<br /><br />（1）生成EJB的JAR文件，最好一个JAR文件对应一个EJB<br /><br />（2）生成WEB APPLICATION的WAR文件，在web.xml，weblogic.xml中登记，配置SERVLET，JSP等。<br /><br />（3）创建一个application.xml文件，设置该应用的属性.把application.xml，*.JAR， *.WAR，打包成一个*.EAR<br /><br />（4）WebLogic的控制台中登记该应用或把该EAR文件拷到application目录下。到此处就完成了部署。<br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=8766&amp;tstart=25&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID= ... 6&amp;tstart=25&amp;quint=true</a><br /><br /> <br />WebLogic如何设置session超时时间<br /><br />1 web.xml<br /><br />设置WEB应用程序描述符web.xml里的&lt;session-timeout&gt;元素。这个值以分钟为<br />单位，并覆盖weblogic.xml中的TimeoutSecs属性<br />  &lt;session-config&gt;<br />    &lt;session-timeout&gt;54&lt;/session-timeout&gt;<br />  &lt;/session-config&gt;<br />此例表示Session将在54分钟后过期<br />当&lt;session-timeout&gt;设置为－2，表示将使用在weblogic.xml中设置的<br />TimeoutSecs这个属性值。<br />当&lt;session-timeout&gt;设置为－1，表示Session将永不过期，而忽略在<br />weblogic.xml中设置的TimeoutSecs属性值。<br />该属性值可以通过console控制台来设置<br /><br />2 weblogic.xml<br /><br />设置WebLogic特有部署描述符weblogic.xml的&lt;session-descriptor&gt;元素的<br />TimeoutSecs属性。这个值以秒为单位<br />&lt;session-descriptor&gt;<br />   &lt;session-param&gt;<br />      &lt;param-name&gt;TimeoutSecs&lt;/param-name&gt;<br />      &lt;param-value&gt;3600&lt;/param-value&gt;<br />   &lt;/session-param&gt;<br />&lt;/session-descriptor&gt;<br />默认值是3600秒<br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=1972&amp;tstart=25&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID= ... 2&amp;tstart=25&amp;quint=true</a><br /><br />监控调优 理解JVM的垃圾收集机制<br />简述<br /><br />GC即垃圾收集机制是指JVM用于释放那些不再使用的对象所占用的内存。java语言并不要求JVM有GC，也没有规定GC如何工作。不过常用的JVM都有GC，而且大多数GC都使用类似的算法管理内存和执行收集操作。<br /><br /> <br /><br />在充分理解了垃圾收集算法和执行过程后，才能有效的优化它的性能。有些垃圾收集专用于特殊的应用程序。比如，实时应用程序主要是为了避免垃圾收集中断，而大多数OLTP应用程序则注重整体效率。理解了应用程序的工作负荷和JVM支持的垃圾收集算法，便可以进行优化配置垃圾收集器。<br /><br /> <br /><br />垃圾收集的目的在于清除不再使用的对象。GC通过确定对象是否被活动对象引用来确定是否收集该对象。GC首先要判断该对象时候可以收集。两种常用的方法是引用计数和对象引用遍历。引用计数存储对特定对象的所有引用数，也就是说，当应用程序创建引用以及引用超出范围时，JVM必须适当增减引用数。当某对象的引用数为0时，便可以进行垃圾收集。<br /><br /> <br /><br />早期的JVM使用引用计数，现在大多数JVM采用对象引用遍历。对象引用遍历从一组对象开始，沿着整个对象图上的每条链接，递归确定可到达（reachable）的对象。如果某对象不能从这些根对象的一个（至少一个）到达，则将它作为垃圾收集。在对象遍历阶段，GC必须记住哪些对象可以到达，以便删除不可到达的对象，这称为标记（marking）对象。<br /><br /> <br /><br />下一步，GC要删除不可到达的对象。删除时，有些GC只是简单的扫描堆栈，删除未标记的对象，并释放它们的内存以生成新的对象，这叫做清除（sweeping）。这种方法的问题在于内存会分成好多小段，而它们不足以用于新的对象，但是组合起来却很大。因此，许多GC可以重新组织内存中的对象，并进行压缩（compact），形成可利用的空间。<br /><br /> <br /><br />为此，GC需要停止其他的活动活动。这种方法意味着所有与应用程序相关的工作停止，只有GC运行。结果，在响应期间增减了许多混杂请求。另外，更复杂的GC不断增加或同时运行以减少或者清除应用程序的中断。有的GC使用单线程完成这项工作，有的则采用多线程以增加效率。<br /><br /> <br />下面列举一些JVM使用的GC<br /><br />标记－清除收集器：这种收集器首先遍历对象图并标记可到达的对象，然后扫描堆栈以寻找未标记对象并释放它们的内存。这种收集器一般使用单线程工作并停止其他操作。<br /><br />标记－压缩收集器：有时也叫标记－清除－压缩收集器，与标记－清除收集器有相同的标记阶段。在第二阶段，则把标记对象复制到堆栈的新域中以便压缩堆栈。这种收集器也停止其他操作。<br /><br />复制收集器这种收集器将堆栈分为两个域，常称为半空间。每次仅使用一半的空间，JVM生成的新对象则放在另一半空间中。GC运行时，它把可到达对象复制到另一半空间，从而压缩了堆栈。这种方法适用于短生存期的对象，持续复制长生存期的对象则导致效率降低。<br /><br />增量收集器增量收集器把堆栈分为多个域，每次仅从一个域收集垃圾。这会造成较小的应用程序中断。有多种方法可以定义实际的GC。<br /><br />分代收集器  这种收集器把堆栈分为两个或多个域，用以存放不同寿命的对象。JVM生成的新对象一般放在其中的某个域中。过一段时间，继续存在的对象将获得使用期并转入更长寿命的域中。分代收集器对不同的域使用不同的算法以优化性能。<br /><br />并发收集器  并发收集器与应用程序同时运行。这些收集器在某点上一般都不得不停止其他操作以完成特定的任务，但是因为其他应用程序可进行其他的后台操作，所以中断其他处理的实际时间大大降低。<br /><br />并行收集器  并行收集器使用某种传统的算法并使用多线程并行的执行它们的工作。在多cpu机器上使用多线程技术可以显著的提高java应用程序的可扩展性。<br />Sun Hotspot 1.4.1 JVM堆大小的调整<br /><br />Sun Hotspot 1.4.1使用分代收集器，它把堆分为三个主要的域：新域、旧域以及永久域。JVM生成的所有新对象放在新域中。一旦对象经历了一定数量的垃圾收集循环后，便获得使用期并进入旧域。在永久域中JVM则存储class和method对象。就配置而言，永久域是一个独立域并且不认为是堆的一部分。下面介绍如何控制这些域的大小。<br /><br />可使用-Xms和-Xmx控制整个堆的原始大小或最大值。比如，下面的命令是把初始大小设置为128M：<br /><br /> java –Xms128m –Xmx256m<br /><br />为控制新域的大小，可使用-XX:NewRatio设置新域在堆中所占的比例。比如下面的命令把整个堆设置成128m，新域比率设置成3，即新域与旧域比例为1：3，新域为堆的1/4或32M：<br /><br />java –Xms128m –Xmx128m –XX:NewRatio =3<br /><br />可使用-XX:NewSize和-XX:MaxNewsize设置新域的初始值和最大值。比如，下面的命令把新域的初始值和最大值设置成64m:<br /><br /> java –Xms256m –Xmx256m –Xmn64m<br /><br />一般不把永久域当作堆的一部分。永久域默认大小为4m。运行程序时，JVM会调整永久域的大小以满足需要。每次调整时，JVM会对堆进行一次完全的垃圾收集。使用-XX:MaxPerSize标志来增加永久域搭大小。在WebLogic Server应用程序加载较多类时，经常需要增加永久域的最大值。当JVM加载类时，永久域中的对象急剧增加，从而使JVM不断调整永久域大小。为了避免调整，可使用-XX:PerSize标志设置初始值。比如，下面把永久域初始值设置成32m，最大值设置成64m。<br /><br />java –Xms512m –Xmx512m –Xmn128m –XX:PermSize=32m –XX:MaxPermSize=64m<br /><br />默认状态下，HotSpot在新域中使用复制收集器。该域一般分为三个部分。第一部分为Eden，用于生成新的对象。另两部分称为救助空间，当 Eden充满时，收集器停止应用程序，把所有可到达对象复制到当前的from救助空间，一旦当前的from救助空间充满，收集器则把可到达对象复制到当前的to救助空间。From和to救助空间互换角色。维持活动的对象将在救助空间不断复制，直到它们获得使用期并转入旧域。<br /><br />使用-XX:SurvivorRatio可控制新域子空间的大小。同NewRation一样，SurvivorRation规定某救助域与Eden空间的比值。比如，以下命令把新域设置成64m，Eden占32m，每个救助域各占16m：<br /><br />java –Xms256m –Xmx256m –Xmn64m –XX:SurvivorRation=2<br /><br />如前所述，默认状态下HotSpot对新域使用复制收集器，对旧域使用标记－清除－压缩收集器。在新域中使用复制收集器有很多意义，因为应用程序生成的大部分对象是短寿命的。理想状态下，所有过渡对象在移出Eden空间时将被收集。如果能够这样的话，并且移出Eden空间的对象是长寿命的，那么理论上可以立即把它们移进旧域，避免在救助空间反复复制。<br />但是，应用程序不能适合这种理想状态，因为它们有一小部分中长寿命的对象。最好是保持这些中长寿命的对象并放在新域中，因为复制小部分的对象总比压缩旧域廉价。<br /><br />为控制新域中对象的复制，可用-XX:TargetSurvivorRatio控制救助空间的比例。该值是一个百分比，默认值是50。当较大的堆栈使用较低的sruvivorratio时，应增加该值到80至90，以更好利用救助空间。<br /><br />用-XX:maxtenuring threshold可控制上限。为放置所有的复制全部发生以及希望对象从eden扩展到旧域，可以把MaxTenuring Threshold设置成0。设置完成后，实际上就不再使用救助空间了，因此应把SurvivorRatio设成最大值以最大化Eden空间，设置如下：<br /><br />java … -XX:MaxTenuringThreshold=0 –XX:SurvivorRatio＝5000<br /><br /> <br />从JVM中获取信息以助于调整方案<br /><br />-verbose.gc开关可显示GC的操作内容。打开它，可以显示最忙和最空闲收集行为发生的时间、收集前后的内存大小、收集需要的时间等。<br /><br />打开-xx:+ printgcdetails开关，可以详细了解GC中的变化。<br /><br />打开-XX: + PrintGCTimeStamps开关，可以了解这些垃圾收集发生的时间，自JVM启动以后以秒计量。<br /><br />最后，通过-xx: + PrintHeapAtGC开关了解堆的更详细的信息。<br /><br />为了了解新域的情况，可以通过-XX:=PrintTenuringDistribution开关了解获得使用期的对象权。<br />BEA JRockit JVM的使用<br /><br />Bea WebLogic 8.1使用的新的JVM用于Intel平台。在Bea安装完毕的目录下可以看到有一个类似于jrockit81sp1_141_03的文件夹。这就是Bea新JVM所在目录。<br /><br />不同于HotSpot把Java字节码编译成本地码，它预先编译成类。JRockit还提供了更细致的功能用以观察JVM的运行状态，主要是独立的GUI控制台或者WebLogic Server控制台。Bea JRockit JVM支持4种垃圾收集器：<br /><br />分代复制收集器：它与默认的分代收集器工作策略类似。对象在新域中分配，即JRockit文档中的nursery。这种收集器最适合单CPU机上小型堆操作。<br /><br />单空间并发收集器：该收集器使用完整堆，并与背景线程共同工作。尽管这种收集器可以消除中断，但是收集器需花费较长的时间寻找死对象，而且处理应用程序时收集器经常运行。如果处理器不能应付应用程序产生的垃圾，它会中断应用程序并关闭收集。<br /><br />分代并发收集器：这种收集器在护理域使用排它复制收集器，在旧域中则使用并发收集器。由于它比单空间共同发生收集器中断频繁，因此它需要较少的内存，应用程序的运行效率也较高，注意，过小的护理域可以导致大量的临时对象被扩展到旧域中。这会造成收集器超负荷运作，甚至采用排它性工作方式完成收集。<br /><br />并行收集器：该收集器也停止其他进程的工作，但使用多线程以加速收集进程。尽管它比其他的收集器易于引起长时间的中断，但一般能更好的利用内存，程序效率也较高。<br /><br /><br />默认状态下，JRockit使用分代并发收集器。要改变收集器，可使用-Xgc:&lt;gc_name&gt;，对应四个收集器分别为gencopy， singlecon，gencon以及parallel。可使用-Xms和-Xmx设置堆的初始大小和最大值。要设置护理域，则使用-Xns:<br /><br />java –jrockit –Xms512m –Xmx512m –Xgc:gencon –Xns128m…<br /><br />尽管JRockit支持-verbose:gc开关，但它输出的信息会因收集器的不同而异。JRockit还支持memory、load和codegen的输出。<br /><br /> <br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=124&amp;threadID=19031&amp;tstart=0" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa? ... hreadID=19031&amp;tstart=0</a><br /><br /> <br />WebLogic Server Hang产生的一般原因<br />系统内存不足<br /><br />    * 系统CPU忙，系统文件描述符数目不足，线程死锁，JVM有GC方面的bug，对于一些特定的情况可以使用truss命令跟踪系统调用来进行分析。可以打开JVM的gc log,在java命令行上加上-verbose:gc,GC的log输出在java进程的标准输出里,在hp的JVM上，可以通过在java命令行上加 -Xverbosegc:file=gcfilename来将gc log写到指定的文件其输出类似：[GC 15639K-&gt;13700K(65280K), 0.0068439 secs]。解决办法是调整JVM的内存设置和gc算法,升级jvm或是os patch。<br />    * 出现 OutOfMemoryError或是观察到内存吃紧，操作系统本身的剩余内存，通过top或是vmstat观察，操作系统的swap区，Swap区太小可能导致编译jsp时报“Not enough space”的错，操作系统kernel参数中maxsize的大小，如果观测到数据库连接池里的连接泄漏，极可能是内存泄漏的先兆<br />    * JVM 的heap区大小，通过java命令行中的-Xms,-Xmx指定，建议最小值和最大值设成一样，可以通过WebLogic console上server/monitor/performance来观察其使用情况，建议生产系统最256M，一般情况下可以设置为系统剩余物理内存的80％，Heap size太大在一些JVM上会有问题，对于sun和hp的JVM，permanent size太小也会出OutOfMemoryError，在java命令行上加-XX:MaxPermSize=128m<br />    * 尽量减少内存消耗，Session中不要放大的数据，并尽量在不再需要的时候remove掉，如果可以调整session timeout到较小的值，避免在J2EE server端应用里边调用AWT/swing作图，调整ejb的cache/pool设置<br />    * 内存泄漏，可以通过WebLogic console来观察JVM的heap memory使用情况来获知是否有内存泄漏情况，采用第三方辅助工具来获取更详细信息，如Jprobe/OptimizeIt；有可能是weblogic 的bug，但绝大部分情况是由用户的应用引起的，最常见的代码问题是数据库连接没正常关闭。<br /><br /> <br />系统CPU忙<br /><br />    * 如果用户访问量很大，CPU占用很高（user态）并不是异常<br />    * 如果是kernel态很多，需要OS厂商调整操作系统<br />    * 采用top找到占用CPU很多的进程，如果是非weblogic进程，应该考虑将其移到另外的server上运行，如果是运行weblogic的java进程，通过做thread dump（详细信息后边会介绍到）来确认是那段代码导致了这么高的CPU使用（也有可能是os/jvm本身不正常）<br /><br />系统文件描述符数目不足<br /><br />Log中有“too many open files”的错误，表示达到了系统对一个进程能同时打开的文件数的限制：<br /><br />    * ulimit –a –H 可以查看当前限制<br />    * ulimit –n number可以来更改当前环境的设置，建议至少设到4096<br />    * Solaris上可以通过/usr/proc/bin/pfiles pid来查看指定进程的限制和当前使用的file descriptor数目<br />    * Solaris上root用户可以通过/usr/proc/bin/plimit -n soft,hard pid 来动态更改进程的文件描述符的限制<br /><br />线程死锁<br /><br />对于原因不明的hang或是响应慢，最根本的方法就是获取thread dump信息，对于windows系统，在运行java的窗口按Ctrl＋Break，对于UNIX系统，首先用ps找到运行weblogic的java 进程的pid，然后执行kill –3 pid，JVM将负责将所有java进程的状态、执行堆栈dump到其标准输出，为了方便获取thread dump信息，在weblogic启动的时候，最好将其标准输出重定向到一个文件，为了反映线程状态的动态变化，需要接连多次做thread dump，每次间隔10-20s。<br /><br /> <br /><br />对于thread dump信息，主要关注的是线程的状态和其执行堆栈，线程的状态一般为三类<br /><br />    * Runnable（R）：当前可以运行的线程<br />    * Waiting on monitor（CW）：线程主动wait<br />    * Waiting for monitor entry（MW）：线程等锁<br /><br />一般关注的都是第一和第三种状态的线程<br />CPU很忙则关注runnable的线程<br />CPU闲则关注waiting for monitor entry的线程<br />一种典型的死锁是由于在server端应用（比如servlet）中请求由同一weblogic实例serve的资源，解决办法就是将该servlet放到另外的执行队列里去执行。<br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=4525&amp;tstart=0&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID ... 5&amp;tstart=0&amp;quint=true</a><br /><br /> <br />"指定的网络名不再可用"错误<br /><br />wl6.1和wl7.0部署应用后都在后台抛出“java.net.SocketException: ReadFile failed: 指定的网络名不再可用”,这不是一个致命的错误，只会在中文Window上。如Hilaser和linstone提出了办法：<br /><br /> <br /><br />    * 如果你是自己随便玩玩，将你的JDK升级到jdk1.3.1_06<br />    * 用wls6.1 sp4，到如下位置下载<br />      <a href="http://commerce.bea.com/SoftwareProductDetailWLS?SWName=WebLogic+Server+Evaluation+Software&amp;SWVersion=Version+6.1+SP4&amp;SWPlatform=Microsoft+Windows+NT%2F2000" target="_blank">http://commerce.bea.com/SoftwareProductDetailWLS?SWName=WebLogic+Server+Evaluation ... .1+SP4&amp;SWPlatform=Microsoft+Windows+NT%2F2000</a><br />    * 运行cmd，打开窗口菜单（点击左上角窗口图标），选择默认值，将默认代码页改为437。<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=9393&amp;tstart=0" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa? ... hreadID=9393&amp;tstart=0</a><br /><br /> <br /><br /> <br /><br />集群配置 集群简明配置过程<br /><br />在wls7中，集群的受管服务器无需使用相同的端口，这使在一个主机上实现集群成为可能。下面的例子是在一个主机（172.30.94.60）上的 wls7里创建一个集群（mycluster）DEMO，包括管理服务器（myserver:7001）、集群（两个受管服务器serverA: 8001、serverB:8003）、代理服务器（ProxyServer:80）。应用WebApp是部署在集群上的web应用，而 DefaultWebApp是部署在代理服务器上用来代理集群应用WebApp的。具体步骤如下：<br /><br /> <br /><br />1．创建集群域clusterdomainnew，管理服务器myserver（7001:7003）；<br /><br />2．创建Machine：admin（myserver,ProxyServer），cluster(serverA,serverB)；<br /><br />3．创建受管服务器serverA(8001)，serverB(8003)；<br /><br />4．创建集群mycluster；<br /><br />Choose Servers for this Cluster: serverA，serverB<br /><br />config.xml:<br /><br />&lt;Cluster ClusterAddress="172.30.94.60:8001,172.30.94.60:8003"<br /><br />MulticastAddress="237.0.0.1" MulticastPort="7777" Name="mycluster"/&gt;<br /><br /> <br /><br />5．部署WebApp应用，targets mucluster；<br /><br />6．创建代理服务器ProxyServer（80），将DefaultWebApptargets ProxyServer；<br /><br />7．编辑DefaultWebApp应用，注册HttpClusterServlet：<br /><br />&lt;servlet&gt;<br /><br />&lt;servlet-name&gt;HttpClusterServlet&lt;/servlet-name&gt;<br /><br />&lt;servlet-class&gt;weblogic.servlet.proxy.HttpClusterServlet&lt;/servlet-class&gt;<br /><br />&lt;init-param&gt;<br /><br />&lt;param-name&gt;WebLogicCluster&lt;/param-name&gt;<br /><br />&lt;param-value&gt;172.30.94.60:8001:8002|172.30.94.60:8003:8004&lt;/param-value&gt;<br /><br />&lt;/init-param&gt;<br /><br />&lt;init-param&gt;<br /><br />&lt;param-name&gt;DebugConfigInfo&lt;/param-name&gt;<br /><br />&lt;param-value&gt;ON&lt;/param-value&gt;<br /><br />&lt;/init-param&gt;<br /><br />&lt;/servlet&gt;<br /><br />&lt;servlet-mapping&gt;<br /><br />&lt;servlet-name&gt;HttpClusterServlet&lt;/servlet-name&gt;<br /><br />&lt;url-pattern&gt;/&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;<br /><br />&lt;servlet-mapping&gt;<br /><br />&lt;servlet-name&gt;HttpClusterServlet&lt;/servlet-name&gt;<br /><br />&lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt; &lt;/servlet-mapping&gt;<br /><br />&lt;servlet-mapping&gt;<br /><br />&lt;servlet-name&gt;HttpClusterServlet&lt;/servlet-name&gt;<br /><br />&lt;url-pattern&gt;*.htm&lt;/url-pattern&gt; &lt;/servlet-mapping&gt;<br /><br />&lt;servlet-mapping&gt;<br /><br />&lt;servlet-name&gt;HttpClusterServlet&lt;/servlet-name&gt;<br /><br />&lt;url-pattern&gt;*.html&lt;/url-pattern&gt;<br /><br />&lt;/servlet-mapping&gt;<br /><br />8．重启myserver；<br /><br />9．启动serverA：startManagedWeblogicserverA<a href="http://172.30.94.60:7001;/" target="_blank">http://172.30.94.60:7001;</a><br /><br />启动成功后，访问<a href="http://172.30.94.60:8001/WebApp/ " target="_blank">http://172.30.94.60:8001/WebApp/ </a>验证一下！<br /><br />10.启动serverB：startManagedWeblogicserverB<a href="http://172.30.94.60:7001;/" target="_blank">http://172.30.94.60:7001;</a><br /><br />启动成功后，访问<a href="http://172.30.94.60:8003/WebApp/ " target="_blank">http://172.30.94.60:8003/WebApp/ </a>验证一下！<br /><br />11. 启动ProxyServer：startManagedWeblogic ProxyServer<a href="http://172.30.94.60:7001/" target="_blank">http://172.30.94.60:7001</a>。<br /><br />访问<a href="http://172.30.94.60/WebApp" target="_blank">http://172.30.94.60/WebApp</a>，是不是大功告成了：）<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=3257&amp;tstart=25&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID= ... 7&amp;tstart=25&amp;quint=true</a><br /><br /> <br />WebLogic应用在集群环境下的一些基本知识<br />基本概念<br /><br />1．硬件的cluster和WebLogic的cluster不是一回事，硬件做的是冷备份，对用户的session，用户请求的负载均衡等的处理是做不到的，而且一般硬件的双机热备也不是时时的备份，而是间隔一段时间再将主机上的数据copy过来，而WebLogic Server的cluster就不是这样，其session的数据是时时的复制的，对不经常更改的jndi等的复制虽然也是定期完成的，但update的时间间隔很短<br /><br />2．WebLogic Server的cluster配置非常方便，请参考dev2dev学堂<br /><br /><a href="http://dev2dev.bea.com.cn/techdoc/200506554.html" target="_blank">http://dev2dev.bea.com.cn/techdoc/200506554.html</a><br /><br />如果你要对集群做扩展，操作也非常方便，你只需要启动一个指向这个集群的Admin Server的managed server就可以了，由这个集群中的唯一的Admin Server往这个managed server上部署应用<br />3．http状态会话复制就是session的复制，例如你登陆了系统，如果一个服务器坏了，cluster会将你的请求转发集群中的另外一个server，由其继续处理你的这个请求，而不要重新登陆。<br />4．EJB集群中有状态，无状态EJB的意义和区别请看J2EE中EJB的相关知识<br />5．对EJB的集群，也是非常简单的，直接把EJB应用target到cluster的server上！<br />6．对WebLogic Server来说，它的cluster做session的in memory的时时复制，这适用于web application及stateful session BEA的session内容的复制<br />7．对非stateful的EJB，WebLogic Server的cluster做其负载均衡及failover的工作（failover只针对EJB的stateless BEAN<br />集群规划<br /><br />在规划集群配置时，应该牢记以下关于网络环境与集群配置的限制。<br /><br /> <br /><br />1．首先，集群中的WebLogic主机必须使用永久的静态IP地址。动态IP地址分配不能用于集群环境。如果服务器位于防火墙后面，而客户机位于防火墙外面，那么服务器必须有公共的静态IP地址，只有这样，客户端才能访问服务器。<br /><br /><br />2．集群中的所有WebLogic服务器必须位于同一个局域网，并且必须是IP广播可到达的。<br /><br /><br />3．集群中的所有WebLogic服务器必须使用相同的版本。配置集群中的服务器，使它们支持所提供的服务。对于使用了JDBC连接的EJB，所有部署了某EJB的服务器必须具有相同的部署与持久化配置。也就是说所有服务器都应该有相同的JDBC配置。所有部署了servlet的主机必须维护一组具有相同 ACL的servlet。<br /><br />如果客户端应用直接使用JDBC连接池，那么你必须为每个WebLogic服务器创建相同的连接池（并具有相同的ACL）。这意味着集群所使用的连接池应该可以在所有的机器上创建。例如，一台运行WebLogic的NT服务器配置了连接Microsoft SQL Server数据库的连接池，那么一个包含非Windows机器（即不支持Microsoft SQL Server连接的机器）的集群不能使用这个连接池。<br /><br />其它配置细节可能会因不同的集群成员而不同。例如，一台Solaris服务器可以比一台小的 NT工作站处理更多的登录请求。这种差异是可以接受的。因此，正如这里所给出的例子，对于那些与性能相关的属性，你可以根据每个集群成员的特点来配置不同的值，只要所有成员的服务配置相同即可。因此，集群中的WebLogic服务器在所有与WebLogic服务、类文件以及外部资源（例如数据库）相关的方面具有相同的配置。<br /><br /> <br />服务器配置任务列表<br /><br />可以通过管理控制台进行以下服务器配置：<br /><br />    * Server节点配置单独的服务器可以配置的属性包括名字：监听端口与IP地址。<br />    * Server节点克隆一个服务器：克隆的服务器保存了原来服务器的属性值，你可以使用Server节点中的Configuration配置新服务器的名字。<br />    * 使用管理控制台的Server节点来删除一个服务器：点击要删除的服务器的图标，将弹出一个删除服务器的确认对话框，点击对话框中的Yes按钮将删除服务器。<br />    * 使用管理控制台的Server节点查看一个服务器的日志：点击要查看的服务器，点击Monitoring标签页，点击View Server Log连结，便可以在管理控制台的右窗格查看服务器日志。<br />    * 使用管理控制台的Server节点查看一个服务器的JNDI树：点击所要查看的服务器，然后点击Monitoring标签页，点击该页面上View JNDI Tree连接，该服务器JNDI树的信息便显示在管理控制台的右窗格中。<br />    * 使用管理控制台的Server节点查看服务器的执行队列：点击所要查看的服务器，然后点击Execute Queue 链接，然后查看管理控制台右边窗格里的表格中的内容。<br />    * 使用管理控制台的Server节点查看服务器的执行线程：点击所要查看的服务器，然后点击Execute Queue 链接，然后查看管理控制台右边窗格里的表格中的内容：<br />    * 使用管理控制台的Server节点查看server sockets：点击所要查看的服务器,点击View Sockets连接，然后查看管理控制台右边窗格里的表格中的内容。<br />    * 使用管理控制台的Server节点查看服务器连接：点击所要查看的服务器，点击View Connections连接，然后查看管理控制台右边窗格里的表格中的内容。<br />    * 使用管理控制台的Server节点进行强制垃圾收集，点击要监控的服务器，点击JVM标签页，点击页面上的Force Garbage Collection连接，将弹出是否要进行垃圾收集的确认对话框。<br />    * Server节点监视服务器的安全：点击要监控的服务器，点击Monitoring标签页，点击Security标签页，将显示安全信息。<br />    * Server节点查看服务器的版本：点击要查看的服务器，点击Version标签页，将显示服务器的版本信息。<br />    * Server节点监控服务器集群：点击要监控的服务器，点击Cluster标签页，将显示该服务器的集群数据。<br />    * Server节点来部署EJB：点击需要部署EJB的服务器，点击需要分发的EJB并使用移动控件将它移到被选列中，点击Apply来保存你的选择。<br />    * Server节点来监视部署在某一服务器上的所有EJB：点击需要监视的服务器，点击Monitor All EJB Deployments连接来显示EJB的部署列表。<br />    * Server节点将web应用组件部署在某一服务器上：选择要部署web应用的服务器：选择需要部署的web应用，然后通过移动控件将它移到被选列中，点击Apply来保存你的选择。<br />    * Server节点来监控某一服务器上的所有web应用组件：点击web应用所在的服务器，然后点击Monitor All Web Applications连接来显示Web Application 的部署列表。<br />    * Server节点在服务器上部署启动与终止类：点击需要部署启动类的服务器，然后点击需要部署的启动类并将它移到被选列中，点击Apply来保存你的选择，使用终止类控件来部署终止类的过程与此相同。<br />    * Server节点为服务器分配JDBC连接池：点击web server分配表中的一个服务器，在Available列中点击一到多个JDBC连接池，并通过移动控件将所选择的JDBC连接池移到Chosen列，点击Apply来保存你所做的分配。<br />    * Server节点为一个服务器分配WLEC连接池：点击需要分配WLEC连接池的服务器：在Available列中选择一个或多个要分配的WLEC连接池，使用移动控件将所选择的WLEC连接池移动到Chosen列。<br />    * 通过管理控制台的Server节点监视某一服务器上的所有WLEC连接池：选择一个需要监视连接池的服务器，点Monitor All WLEC Connection Pools on This Server链接，所有分配给这台服务器的连接池会显示在右窗格中的WLEC Connection Pools列表中。<br />    * Server节点为一台服务器分配XML 注册表，选择要分配XML 注册表的服务器，从XML 注册表的下拉列表中选择一个注册表，点Apply保存设置。<br />    * Server节点分配邮件会话：选择一个要分配邮件会话的服务器，从Available列中选择要分配给服务器的邮件会话，使用移动控件把所选择的移动会话移动到Chosen列中，点Apply按钮保存设置。<br />    * 通过管理控制台为服务器分配文件T3s：选择一个要分配文件T3的服务器，从Available列中选择要分配给服务器的文件T3s，使用移动控件把所选择的文件T3s移动到Chosen列，点Apply按钮保存设置。<br />    * Connection连接，然后查看管理控制台右边窗格里的表格中的内容。<br />    * 使用管理控制台的Server节点进行强制垃圾收集：点击要监控的服务器，点击JVM标签页，点击页面上的Force Garbage Collection连接，将弹出是否要进行垃圾收集的确认对话框。<br /><br /> <br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=4800&amp;tstart=0&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID ... 0&amp;tstart=0&amp;quint=true</a><br /><br /> <br /><br />安全管理 WebLogic AD ldap 配置方法<br /><br />Weblogic AD ldap 配置方法<br /><br /> <br /><br />一创建并配置windows端AD.<br /><br />1 在AD中加入新的OU,myOrg.<br /><br />2 在myOrg中加入两个ou ,groups 和people。在groups中加入两个组group1,group2,在people中加入两个用户user1,user2.<br /><br />3配置user1用户属于组group1，user2用户属于组group2。<br /><br />windows Active Directory 端配置完毕。<br /><br /> <br /><br />二得到配置参数<br /><br />1 下载ldap brSofterra LDAP Browser 2.5 (可用google搜索)<br /><br />2 配置ldap browser。<br /><br />打开ldap browser应用程序。创建新的profile。<br /><br /> <br /><br />填入参数：<br /><br />单击fetch DNs (only ldap v.3) 得到自动配置的ldap 基础配置<br /><br />在DC=www 前面加入AD中配置的OU=myOrg。<br /><br />完成后如下图。表示连接AD 成功<br /><br />得到base DN 参数为 OU=myOrg,DC=www,DC=test,DC=com, (DC=www,DC=test,DC=com视您的windows域而定，本例域为www.test.com)。<br /><br /> <br /><br />三配置weblogic server<br /><br />启动域，打开控制器<a href="http://localhost:7001/console" target="_blank">http://localhost:7001/console</a>。<br /><br />配置新的authentication。<br /><br />点击authentication 。在右边选择configure a new active directory authenticator<br /><br /> <br /><br />1 General 中的配置<br /><br />2 Active Directory栏配置<br /><br />3 user栏配置<br /><br />user栏只需要修改User Base DN 为自己的user base DN,这里填入ldap browser 中得到的数据OU=myOrg,DC=www,DC=test,DC=com,不过我们要得到的是用户所以在前面在加入我们创建的OU=people。<br /><br />4 group 栏配置。<br /><br />group 栏只需要修改group Base DN 为自己的group base DN,这里填入ldap browser 中得到的数据OU=myOrg,DC=www,DC=test,DC=com,不过我们要得到的是组所以在前面在加入我们创建的OU=groups。<br /><br /> <br /><br />保存后其余的都不用在修改了。<br /><br />我们再次点击user时，ldap中的用户和组就加入到weblogic server 的用户中了<br /><br /> <br /><br />原文地址：<br /><br /><a href="http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&amp;threadID=8194&amp;tstart=25&amp;quint=true" target="_blank">http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID= ... 4&amp;tstart=25&amp;quint=true</a><br /><br /> <br />口令的保护<br /><br />保护用来访问WebLogic服务器资源的口令是很重要的。在过去，用户名与口令以明文的形式存储在WebLogic服务器的安全域中。现在 WebLogic服务器对所有口令进行散列化。当WebLogic服务器获得一个客户端请求时，客户端所输入的口令也被散列化，然后把散列化结果与所保存的散列化口令进行比较，看它们是否相互匹配。<br /><br /> <br /><br />每个filerealm.properties文件都有一个与它关联的SerializedSystemIni.dat文件，这个文件被用来散列化口令。在安装时，SerializedSystemIni.dat文件保存在\wlserver6.1\config\mydomain目录下，如果该文件被破坏，那么就需要重新配置WebLogic服务器。<br /><br />我们建议你采用以下预防措施：<br /><br />备份SerializedSystemIni.dat文件，并将其与filerealm.properties文件的备份存放于同一目录下。设置 SerializedSystemIni.dat文件的访问权限，例如只允许WebLogic服务器的管理员有读写这个文件的权限，其它用户没有这个文件的任何权限。<br /><br /> <br /><br />如果你使用的是weblogic.properties文件，并且想散列化这个文件中的口令，你可以用管理控制台主窗口的Convert weblogic.properties选项将weblogic.properties文件转换为config.xml文件。一旦文件被转换，则所有现存的口令就已经被保护了。<br /><br /> <br /><br />Config.xml文件中的不在含有明文的口令，若在其中保存明文的口令，config.xml会对其进行加密并被散列化该口令。被加密的口令不能从一个域复制到另一个域，而是应该使用明文口令替换config.xml中被加密的散列化口令，然后再将文件复制到另外一个域中。管理控制台在下一次写文件时会加密并散列化口令。<br /><br /> <br /><br /> <br /><br /> <br /><br />要保护WebLogic服务器的口令，执行以下操作：<br /><br />1. 打开管理控制台<br /><br />2. 点击Security节点<br /><br />3. 在管理控制台右侧窗格中选择Passwords标签页。<br /><br />4. 定义该标签页中需要配置的属性，按照相应的提示输入值，并选中必须选择的复选框（详细信息，参见下表）。<br /><br />5. 点Apply按钮保存所做的设置<br /><br />6. 重启WebLogic服务器。<br /><br /> <br /><br />如下详细描述了Security Configuration窗口的Password标签页上的各个属性。<br /><br />    * Minimum Password Length: 口令所需的长度，至少为8个字符。缺省为8个字符<br />    * Lockout Enabled: 在超过Lockout Threshold次尝试后，是否需要锁住某个登录无效的帐号。缺省情况下，该属性被启用。<br />    * Lockout Threshold：当一个用户试图登录到一个用户帐户，因口令不对而失败，那么多少次这样的失败登录后将锁住这个帐号。以后对该帐号的访问（即使是 username/password是正确）也将引发Security异常；在管理员对该帐号进行解锁前，或在锁住期限内，该帐号一直处于锁住的状态。注意非法登录必须在Lockout Reset Duration属性所定义范围内。默认为5<br />    * Lockout Duration：该属性定义了当某一帐户因为在Lockout Reset Duration期限内发生非法登录而被锁住后，多长时间范围内该用户帐号不能被使用。要解开一个被锁住的用户帐号，你必须拥有 weblogic.passwordpolicy中的unlockuser权限。默认为30分钟。<br />    * Lockout Reset Duration：该属性定义了在多长时间里，非法登录某一帐号将导致该帐号被锁住。在本属性定义的时间范围内，当非法登录的次数超过了Lockout Threshold属性所定义的值，那么该帐号将被锁住，例如，该属性被设置为5分钟，当帐号在6分钟内被非法登录了3次，那么该帐号不会被锁住，但是，如果在5分钟内，发生了5次非法登录，那么该帐号将被锁住。缺省为5分钟。<br />    * Lockout Cache Size：指定无效的或非法的登录意图的缓存大小。缺省为5<br /></p><p></p><br /></span>
<img src ="http://www.blogjava.net/TrampEagle/aggbug/60964.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-07-31 10:52 <a href="http://www.blogjava.net/TrampEagle/articles/60964.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>weblogic优化(转)</title><link>http://www.blogjava.net/TrampEagle/articles/60947.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Mon, 31 Jul 2006 02:16:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/60947.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/60947.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/60947.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/60947.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/60947.html</trackback:ping><description><![CDATA[
		<p>作者：zhouhg (dev2dev ID)<br />摘要： </p>
		<p>　　随着近来J2EE软件广泛地应用于各行各业，系统调优也越来越引起软件开发者和应用服务器提供商的重视。而对于最终客户来说，在一个高效、稳定地实现他们的业务需求已经是他们的基本要求。所以J2EE调优显得非常重要，而BEA WebLogic Server是业界领先的应用服务器，BEA WebLogic平台下的J2EE调优也就尤为重要,她将为我们提供普遍的J2EE调优方案。最近网络、杂志上的J2EE调优文章层出不穷。本人也将自己平时工作中的一些经验积累分享给大家，抛砖引玉。<a id="0" name="0"></a></p>
		<p>
				<br />目录</p>
		<p>
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1">前 言</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1">第一章 应用程序调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_1_1">1.1.1 通用代码调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_1_2">1.1.2 减小没有必要的操作</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_1_3">1.1.3 使用合适的类型</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_1_4">1.1.4 尽量使用pool,buffer和cache</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_2">1.2 JDBC代码调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_2_1">1.2.1 严格资源使用</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_2_2">1.2.2 实用技巧</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_2_3">1.2.3 优化SQL语句</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_3">1.3 Web代码调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_3_1">1.3.1 HttpSession的使用</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_3_2">1.3.2 JSP代码调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_3_3">1.3.3 Servlet代码调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_4">1.4 JMS代码调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_4_1">1.4.1 注意必要的事项，避免使用不必要的特征</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_4_2">1.4.2 消息类型的选择</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_4_3">1.4.3 确认方式的选择和JMS事务</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_5">1.5 EJB代码调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_5_1">1.5.1 有效使用设计模式</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_5_2">1.5.2 使用EJB和WebLogic的特性</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_5_3">1.5.3 缓存资源</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_5_4">1.5.4 如何选择和使用Entity Bean</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#1_5_5">1.5.5 其他的一些小技巧</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2">第二章 应用服务器调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_1">2.1 JVM调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_1_1">2.1.1 垃圾收集和堆大小</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_1_2">2.1.2 jRockit调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_2">2.2 Server调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_2_1">2.2.1 尽量使用本地I/O库</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_2_2">2.2.2 调整默认执行线程数</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_2_3">2.2.3 调整连接参数</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_2_4">2.2.4 创建新的执行队列</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_3">2.3 JDBC调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_3_1">2.3.1 调整连接池配置</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_4">2.4 WEB调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_4_1">2.4.1 调整WEB应用描述符</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_5">2.5 JMS调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_6">2.6 EJB调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_6_1">2.6.1 调整pool和cache</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_6_2">2.6.2 优化事务隔离级别和事务属性</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#2_6_3">2.6.3 其他一些小技巧</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#3">第三章 数据库调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#3_1_1">3.1.1 Oracle性能优化</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#3_1_2">3.1.2 Oracle的其他调整</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#4">第四章 操作系统调优</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#4_1">4.1 操作系统调整</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#4_1_1">4.1.1 HP-UX</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#4_1_2">4.1.2 Solaris</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#4_1_3">4.1.3 AIX</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#4_1_4">4.1.4 Linux</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#4_1_5">4.1.5 Windows</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#5">第五章 性能监控和性能分析</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#5_1">5.1 性能瓶颈</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#5_2">5.2 操作系统监控</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#5_3">5.3 数据库监控</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#5_4">5.4 WebLogic监控</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#5_4_1">5.4.1 JVM监控</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#5_4_2">5.4.2 Console监控</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#5_4_3">5.4.3 实用工具分析</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#5_5">5.5 应用程序分析</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#6">总结</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#7">参考文献</a>
				<br />
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#8">关于作者</a>
				<a id="1" name="1">
				</a>
		</p>
		<p>
				<b>前 言 </b>
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#0">(目录)</a>
		</p>
		<p>　　随着近来J2EE软件广泛地应用于各行各业，系统调优也越来越引起软件开发者和应用服务器提供商的重视。而对于最终客户来说，在一个高效、稳定地实现他们的业务需求已经是他们的基本要求。所以J2EE调优显得非常重要，而BEA WebLogic Server是业界领先的应用服务器，BEA WebLogic平台下的J2EE调优也就尤为重要,她将为我们提供普遍的J2EE调优方案。最近网络、杂志上的J2EE调优文章层出不穷。本人也将自己平时工作中的一些经验积累分享给大家，抛砖引玉。<br /><br />　　本文从J2EE应用架构（下图）来分别剖析系统调优，首先我们一般会从应用程序出发，去审核代码，做到代码级的优化，然后再调整应用服务器(BEA WebLogic8.1)和数据库 (Oracle9i)的参数，最后当然是调整操作系统和网络的性能(包括硬件升级)。诚然,在我遇到的很多项目中,都是出现了性能问题后才想到调优,而且一般都是先进行系统参数调整,实在解决不了才会对代码进行检查.实际上,我们应当将代码级的调优放在应用设计时来做,测试生产时修改代码将是一件极其痛苦的事情。</p>
		<p align="center">
				<img height="311" src="http://dev2dev.bea.com.cn/images/image2004111688.gif" width="715" />
				<br />WebLogic平台J2EE应用架构</p>
		<p>
				<a id="1" name="1">
				</a>
		</p>
		<p>
				<br />
				<b>第一章 应用程序调</b>优<a id="1_1_1" name="1_1_1"></a><a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#0">(目录)</a><br /><b>1.1.1 通用代码调优</b><a id="1_1_2" name="1_1_2"></a><br /><br /><b>1.1.2 减小没有必要的操作</b><br />　　对象的创建是个很昂贵的工作,所以我们应当尽量减少对象的创建,在需要的时候声明它,初 始化它,不要重复初始化一个对象,尽量能做到再使用,而用完后置null有利于垃圾收集。让类实现Cloneable接口,同时采用工厂模式,将减少类的创建,每次都是通过clone()方法来获得对象。另外使用接口也能减少类的创建。对于成员变量的初始化也应尽量避免, 特别是在一个类派生另一个类时。<br /><br />　　异常抛出对性能不利。抛出异常首先要创建一个新的对象。Throwable接口的构造函数调用名为, fillInStackTrace()的本地（Native）方法，fillInStackTrace()方法检查堆栈，收集调用跟踪信息。只要有异常被抛出，VM就必须调整调用堆栈，因为在处理过程中创建了一个新的对象。 异常只能用于错误处理，不应该用来控制程序流程。<br /><br />　　此外, 建议关闭Debug输出,尽量少用串行化、同步操作和耗时昂贵的服务(如Date())。<a id="1_1_3" name="1_1_3"></a><br /><b><br />1.1.3 使用合适的类型</b><br />　　当原始类型不能满足我们要求时,使用复杂类型。String和StringBuffer的区别自不必说了,是我们使用最多的类型,在涉及到字符运算时,强烈建议使用StringBuffer。在做String匹配时使用intern()代替equal()。<br /><br />　　带有final修饰符的类是不可派生的, 如果指定一个类为final，则该类所有的方法都是final。<br /><br />　　Java编译器会寻找机会内联所有的final方法,这将能够使性能平均提高50%。类的属性和方式使用final或者static修饰符也是有好处的。<br /><br />　　调用方法时传递的参数以及在调用中创建的临时变量都保存在栈（Stack）中，速度较快。所以尽量使用局部变量。<br /><br />　　ArrayList和Vector,HashMap和Hashtable是我们经常用到的类,前者不支持同步,后者支持同步,前者性能更好,大多数情况下选择前者。<a id="1_1_4" name="1_1_4"></a><br /><br /><b>1.1.4 尽量使用pool,buffer和cache</b><br />　　使用pool、buffer和cache能大大提高系统的性能,这在J2EE的大部分技术中都是适用的。<br /><br />　　在WebLogic中就大量使用了池:JDBC Connection Pool、Socket Pool、Object Pool和Thread Pool。I/O操作中,buffer是必须的,特别是对大文件的操作,不然容易造成内存溢出。字节操作最快,所以尽可能采用write(byte[])，Buffered FileOutputStream比Buffered FileWriter要快,因为FileWriter需要Unicode到Byte的转换。<br /><br />　　而后面讲到的JDBC、JSP、EJB和JMS我们都非常建议使用buffer和cache。为HttpServletResponse设置buffersize,使用wl-cache,缓存在JNDI树上获取的对象等等。<br /><br />　　此外,使用JDK 1.4的非阻塞I/O对性能也有很大提高。 <a id="1_2" name="1_2"></a><br /><br /><b>1.2 JDBC代码调优</b><a id="1_2_1" name="1_2_1"></a><br /><b>1.2.1 严格资源使用</b><br />　　JDBC代码调优最大的原则就是使用WebLogic的连接池,而不是自己直连数据库。在我接触的很多自己实现连接池的项目中,大部分遇到死锁和连接泄漏的问题，最后得不得修改代码。而WebLogic提供了功能强大，性能良好的数据库连接池，我们要做的只是封装一个连接管理类，从JNDI树上获取数据源并缓存，得到连接，并提供一系列关闭数据库资源的方法。<br /><br />　　对任何资源使用的原则是用完即关，不管是数据库资源、上下文环境，还是文件。数据库资源的泄漏极易造成内存泄漏，乃至系统崩溃。在使用完数据库资源后依次关闭ResultSet，Statement和Connection，而在一个数据库连接多次进行数据库操作时要特别注意ResultSet和Statement依次关闭。<br /><br />try{<br />　　//open connection<br />　　pstmt =conn.prepareStatement(strSql1);<br />　　pstmt.executeUpdate();<br />　　pstmt.close();<br />　　pstmt =conn.prepareStatement(strSql2);<br />　　rs=pstmt.executeQuery();<br />　　while (rs.next()){<br />　　//process<br />　}<br />rs.close();<br />pstmt.close();<br />　}catch(Exception e){<br />　　//close rs,psmt,con<br />}finally{<br />　　//close rs,psmt,con<br />}<a id="1_2_2" name="1_2_2"></a><br /><br /><b>1.2.2 实用技巧</b><br />　　在JDBC操作中还有一些小的技巧跟大家分享：由于获取连接时默认自动提交方式，使用connection.setAutoCommit(false)关闭自动提交，使用PreparedStatement,批量更新,业务复杂或者大数据量操作时使用存储过程，尽量使用RowSet，此外设置记录集读取缓存FetchSize和设置记录集读取方向FetchDirection对性能也有一定的提高。<a id="1_2_3" name="1_2_3"></a><br /><br /><b>1.2.3 优化SQL语句</b><br />　　SQL语句的优化牵涉到很多数据库的知识，需要与索引配合，因此需要DBA对代码中的SQL进行检查测试。常见的，select *不提倡使用，效率极差，建议显式获取列，即使是所有字段也应罗列，而取总数时使用count(*),为提高cache的命中率，尽量做到SQL重用。对于大数据量的查询，可以充分利用Oracle数据库的特性，每次取出m-n行的数据，实现分页查询。另外，提高性能的好选择可能就是把所有的字符数据都保存为Unicode，Java以Unicode形式处理所有数据，因此，数据库驱动程序不必再执行转换过程。<a id="1_3" name="1_3"></a><br /><br /><b>1.3 Web代码调优</b><a id="1_3_1" name="1_3_1"></a><br /><b>1.3.1 HttpSession的使用</b><br />　　应用服务器保存很多会话时，容易造成内存不足，所以尽量减少session的使用，放置session<br />里的对象不应该是大对象，最好是简单小对象，实现串行化接口。当会话不再需要时，应当及时调用invalidate()方法清除会话。而当某个变量不需要时，及时调用removeAttribute()方法清除变量。请勿将EJB对象放置在session中。<a id="1_3_2" name="1_3_2"></a><br /><br /><b>1.3.2 JSP代码调优</b><br />　　目前，在JSP页面中引入外部资源的方法主要有两种：include指令，以及include动作。 include指令：例如&lt;%@ include file="copyright.html" %&gt;，该指令在编译时引入指定的资源。在编译之前，带有include指令的页面和指定的资源被合并成一个文件。被引用的外部资源在编译时就确定，比运行时才确定资源更高效。<br />include动作：例如&lt;jsp:include page="copyright.jsp" /&gt;。该动作引入指定页面执行后生成的结果。由于它在运行时完成，因此对输出结果的控制更加灵活。但是，只有当被引用的内容频繁地改变时，或者在对主页面的请求没有出现之前，被引用的页面无法确定时，使用include动作才合算。 <br /><br />　　对于那些无需跟踪会话状态的jsp，关闭自动创建的会话可以节省一些资源。使用如下page指令： &lt;%@ page session="false"%&gt; ;尽量不要将JSP页面定义为单线程，应设置为&lt;%@page isThreadSafe=”true”%&gt;;在JSP页面最好使用输出缓存功能，如: &lt;%@page buffer="32kb"%&gt;;尽量用wl:cache定制标记来缓存静态或相对静态的内容，缓存jsp:include操作的结果能显著提高应用程序的运行性能。<a id="1_3_3" name="1_3_3"></a><br /><br /><b>1.3.3 Servlet代码调优</b><br />　　Servlet代码调优比较简单：在Servlet之间跳转时，forward比sendRedirect更有效；设置HttpServletResponse 缓冲区，如：response.setBufferSize(20000);在init()方法里缓存静态数据，而在destroy()中释放它；建议在Servlet里使用ServletOutputStream输出图片等对象；避免在Servlet和Jsp中定界事务等。<a id="1_4" name="1_4"></a><br /><br /><b>1.4 JMS代码调优</b><a id="1_4_1" name="1_4_1"></a><br /><b>1.4.1 注意必要的事项，避免使用不必要的特征</b><br />　　JMS提供了强有力的消息处理机制，但是为了最大限度的提高JMS系统的性能，应避免使用不需要使用的特征，同时也要注意必要的事项。比如：尽量使用接收程序能直接使用的最简单、最小的消息类型；消息选择器要尽可能简单(最好不使用)，尽量不要使用复杂的操作符，如like、in或者between等,使用字符串数据类型的速度最慢;务必为特定的应用程序定义特定的JMS连接工厂，并且禁用默认的JMS连接工厂；不要在javax.*与weblogic.*的名字空间中使用JNDI名称；尽量使用异步消费者，线程不必封锁以等待消息的到达;使用完JNDI树上的资源后注意关闭。<a id="1_4_2" name="1_4_2"></a><br /><br /><b>1.4.2 消息类型的选择</b><br />　　标准JMS提供了五种消息类型，而TextMessage应用最为普遍, 当发送的消息是几种原始数据类型的集合体时，最好使用MapMessage消息类型，而不要使用ObjectMessage，以便减少不同系统间的耦合。此外消息是否使用压缩要慎重考虑，压缩未必能减少消息大小。如果生产者、消费者和目的地并置在同一WebLogic Server内部，通常不使用压缩。WebLogic特有的XMLMessage能为运行于消息主体之上的消息选择器提供内嵌式支持，而且易于数据交换。因此，建议应用程序之间传送消息使用XML消息格式，而应用程序内部间传送消息使用二进制消息格式。<a id="1_4_3" name="1_4_3"></a><br /><br /><b>1.4.3 确认方式的选择和JMS事务</b><br />　　使用事务性会话时,尽量使用恰当的消息确认方式:如果需求允许,使用NO_ACKKNOWLEDGE;非持久的订阅者使用DUPS_OK_ACKNOWLEDGE或者MULTICAST_NO_ACKNOWLEDGE。而使用JTA的UserTransaction，确认方式将被忽略。在使用JMS事务时，无效的消息会导致事务的回滚，以致消息重发这样的死循环。此时，可以将无效消息发送到错误消息队列，并提交JMS事务，这将确保消息不会再次传递。<a id="1_5" name="1_5"></a><br /><br /><b>1.5 EJB代码调优</b><a id="1_5_1" name="1_5_1"></a><br /><b>1.5.1 有效使用设计模式</b><br />　　GoF 的《设计模式》为我们实现高性能、易扩展的J2EE应用提供理论保障和技术支持。而EJB作为J2EE的核心组件和技术，善用设计模式对系统性能影响很大。Service Locator 和Value Object 已为我们所熟悉，Floyd Marinescu的《EJB Design Patterns》中的Session Fa?ade、Message Fa?ade、EJB Command和Data Transfer Object等设计模式更是为我们提供设计典范：缓存对EJBHome的访问；使用门面模式，不暴露Entity Bean，用Session Bean封装Entity Bean；如果可以异步处理，则用MDB代替Session Bean；封装业务逻辑在轻量级JavaBean中；使用值对象等简单对象传递数据;不直接使用get/set方法操作Entity Bean。当然过度使用模式或者牵强套用模式也是不提倡的，总的原则就是减少网络流量，改进事务管理。<a id="1_5_2" name="1_5_2"></a><br /><br /><b>1.5.2 使用EJB和WebLogic的特性</b><br />　　使用EJB和WebLogic的新特性往往能提高性能。与EJB2.0特性相关的技巧有：一个Application中使用本地接口，对于Entity Bean肯定使用本地接口，避免远程调用的开销；使用CMP管理关系，而不是BMP，EJB2.0中CMP的性能大大改善，性能和移植性都优于BMP；使用ejbSelect进行内部查询；使用home方法进行外部查询和批处理; 数据库驱动级联删除等。<br /><br />　　与WebLogic特性相关的技巧有:使用自动生成主键,WebLogic为Oracle和Sqlserver两种数据库的CMP提供了自动生成主键功能,节约了Entity Bean产生主键的时间,同时设key-cache-size不小于100;WebLogic管理事务性能更好,使用容器管理,而不是Bean管理事务;WebLogic提供了为CMP动态查询和批量插入功能,对性能也有很大帮助。<a id="1_5_3" name="1_5_3"></a><br /><br /><b>1.5.3 缓存资源</b><br />　　对SLSB或者MDB来说,使用setMesssageDrivenContext()或者ejbCreate()方法缓存特定资源,在ejbRemove()方法里释放; 对SLSB或者MDB来说,使用setSessionContext()或者ejbCreate()方法缓存特定资源,在ejbRemove()方法里释放;对Entity Bean来说,使用setEntityContext ()方法缓存特定资源,在unSetEntityContext ()方法里释放。<br /><br /><b>1.5.4 如何选择和使用Entity Bean</b><br />　　1. 在设计EJB时，要适当考虑EJB的粒度, 细粒度的EJB在事务管理和资源管理的开销太大,尽量创建粗粒度的 EJB , 不要太粗，粗到能满足实际需求就可以;<br /><br />　　2. Entity Bean不是唯一方式,如果只有一个很小的数据子集被经常改变，建议采用JDO;<br /><br />　　3. 在操作大数据量的时候,直接采用JDBC比Entity Bean更有效;<br /><br />　　4. 避免采用返回很大数据组的finder方法,如 FindAll() 方法，因为它的实现代价太大;<br /><br />　　5. 考虑设置域组field groups,减少没有必要并昂贵的属性加载,如BLOB;<br /><br />　　6. 对于EJB1.1或者BMP,可以设置is-modified-method-name属性,根据isModified()的值来判断是否调用ejbStore()等方法,减少没有必要运算;<br /><br />　　7. 避免连接多个表创建BMP,可以使用视图,存储过程或者O/R Mapping等方式。<a id="1_5_5" name="1_5_5"></a><br /><br /><b>1.5.5 其他的一些小技巧</b><br />　　1. 考虑使用 javax.ejb.SessionSynchronization 接口,提供在Rollback之后恢复数据的方法: afterBegin(), beforeCompletion(), afterCompletion();<br />　　2. 使用完SFSB之后，调用remove()方法释放实例;<br />　　3. 假如你不需要EJB服务的时候,建议使用普通Java类;<br />　　4. 避免EJB之间相互调用;<br />　　5. 使用多读模式。<a id="2" name="2"></a><br /><br /><b>第二章 应用服务器调优<a id="2_1" name="2_1"></a><a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#0">(目录)</a><br />2.1 JVM调优<a id="2_1_1" name="2_1_1"></a><br />2.1.1 垃圾收集和堆大小</b><br />　　垃圾收集(GC)是指JVM释放Java堆中不再使用的对象所占用的内存的过程,而Java堆(Heap)是指Java应用程序对象生存的空间。堆大小决定了GC的频度和时间。堆越大,GC频度低,速度慢。堆越小,GC频度高,速度快。所以GC和堆大小是一组矛盾。为了获取理想的Heap堆大小,需要使用-verbosegc参数(Sun jdk: -Xloggc:&lt;file&gt;)以打开详细的GC输出。分析GC的频度和时间,结合应用最大负载所需内存情况,得出堆的大小。<br />通常情况下,我们建议使用可用内存(除操作系统和其他应用程序占用之外的内存)70-80%,为避免堆大小调整引起的开销,设置内存堆的最小值等于最大值即:-Xms=-Xmx。而为了防止内存溢出,建议在生产环境堆大小至少为256M(Platform至少512M),实际环境中512M~1G左右性能最佳,2G以上是不可取的,在调整内存时可能需要调整核心参数进程的允许最大内存数。对于sun和hp的jvm,永久域太小(默认4M)也可能造成内存溢出,应增加参-XX:MaxPermSize=128m。建议设置临时域-Xmn的大小为-Xmx的1/4~1/3, SurvivorRatio为8。<br /><br />　　为了获得更好的性能,建议在启动文件设置WebLogic为产品模式,此时sun和hp jvm JIT引擎为-server,默认情况下打开JIT编译模式对性能也有帮助。调整Chunk Size和Chunk Pool Size也可能对系统的吞吐量有提高。此外还需关闭显示GC: -XX:+DisableExplicitGC。<br /><br />　　当然在Intel平台上使用jRockit（使用参数-jrockit）无疑大大提高WebLogic性能。<br /><br /><b>2.1.2 jRockit调优</b><br />　　jRockit支持四种垃圾收集器：分代复制收集器、单空间并发收集器、分代并发收集器和并行收集器。默认状态下，JRockit使用分代并发收集器。要改变收集器，可使用-Xgc:&lt;gc-name&gt;,对应四个收集器分其他为gencopy, singlecom, gencon以及parallel。为得到更好的响应性能，应该使用并发垃圾回收器：-Xgc:gencon，可使用-Xms和-Xmx设置堆栈的初始大小和最大值,要设置护理域-Xns为-Xmx的10%。而如果要得到更好的性能，应该选用并行垃圾回收器:-Xgc: parallel，由于并行垃圾回收器不使用nursery，不必设置-Xns。<br /><br />　　如果你的线程大于100或者在linux平台下，可以尝试使用瘦线程模式：-Xthinthread,同时关闭Native IO:-Xallocationtype:global。<br /><br />　　jRockit 还提供了强大的图形化监控工具Jrockit Management Console。欲详细了解JRockit可访问：<a href="http://edocs.bea.com/wljrockit/docs81/index.html" target="_blank">http://edocs.bea.com/wljrockit/docs81/index.html</a>。</p>
		<p align="center">
				<img height="449" src="http://dev2dev.bea.com.cn/images/image2004111689.jpg" width="554" />
		</p>
		<p>
				<a id="2_2" name="2_2">
				</a>
				<br />
				<b>2.2 Server调优</b>
				<br />　　WebLogic Server的核心组件由监听线程,套接字复用器和可执行线程的执行队列组成。当服务器由监听线程接收到连接请求后,将对它的连接控制权交给等待接收请求的套接字复用器。然后套接字复用器读取离开套接字的请求,并将此请求及相关安全信息或事务处理环境一起置入适当的执行队列中(一般为默认的执行队列)。 当有一个请求出现在执行队列中时，就会有一个空闲的执行线程从该队列中取走发来的该<a id="2_2_1" name="2_2_1"></a>请求，并返回应答，然后等待下一次请求。因此要提高WebLogic的性能,就必须从调整核心组件性能出发。<br /><br /><b>2.2.1 尽量使用本地I/O库</b><br />WebLogic Server有两套套接字复用器：Java版和本地库。采用小型本地库更有效,尽量激活Enable Native IO(默认),此时UNIX默认使用CPUs+1个线程,Window下为双倍CPU。如果系统不能加载本地库,将会抛出java.lang.UnsatisfiedLinkException,此时只能使用Java套接字复用器,可以调整socket readers 百分比,默认为33%。该参数可以在Console Server Tuning Configuration配置栏里设置。<a id="2_2_2" name="2_2_2"></a><br /><br /><b>2.2.2 调整默认执行线程数</b><br />　　理想的默认执行线程数是由多方面的因素决定的,比如机器CPU性能、总线体系架构、I/O、操作系统的进程调度机制、JVM的线程调度机制。WebLogic生产环境下默认的线程为25个,随着CPU个数的增加,WebLogic可以近乎线性地提高线程数。线程数越多，花费在线程切换的时间也就越多,线程数越小,CPU可能无法得到充分利用。为获取一个理想的线程数,需要经过反复的测试。在测试中,可以以25*CPUs为基准进行调整。当空闲线程较少,CPU利用率比较低时,可以适当增加线程数的大小(每五个递增)。对于PC Server 和Window 2000，则最好每个CPU小于50个线程, 以CPU利用率为90%左右为佳。由于目前WebLogic执行线程没有缩小线程数的功能,所以应将参数Threads Increase设置为0,同时不应改变优先级的大小。<a id="2_2_3" name="2_2_3"></a><br /><br /><b>2.2.3 调整连接参数</b><br />　　WebLogic Server用Accept Backlog参数规定服务器向操作系统请求的队列大小，默认值为50。当系统重载负荷时,这个值可能过小,日志中报Connection Refused,导致有效连接请求遭到拒绝,此时可以提高Accept Backlog 25%直到连接拒绝错误消失。对于Portal类型的应用,默认值往往是不够的。Login Timeout和SSL Login Timeout参数表示普通连接和SSL连接的超时时间,如果客户连接被服务器中断或者SSL容量大,可以尝试增加该值。这些参数可以在Console Server Tuning Configration配置栏里找到。<a id="2_2_4" name="2_2_4"></a><br /><br /><b>2.2.4 创建新的执行队列</b><br />　　创建新的执行队列有助于解决核心业务优先、避免交叉阻塞、死锁和长时间处理的业务等问题。通常会将自己的执行队列和默认的执行队列设置不同的优先级,这里优先级不应设为9或者10。 定义一个新的执行队列很容易,利用View Excute Queue选项中的Configure a new Excute Queue链接即可定制新的执行队列。创建新的执行队列后，用户需要为应用程序的J2EE组件配置分配策略，以便它可以找到新的队列。举个例子：要将servlet或jsp捆绑到一个特定的执行队列，必须替换web.xml文件项，将wl-dispatch-policy初始化参数设置为自己的执行队列名。<br /><br />&lt;servlet&gt;<br />&lt;servlet-name&gt;servletname&lt;/servlet-name&gt;<br />&lt;jsp-file&gt;/directoryname/deployment.jsp&lt;/jsp-file&gt;<br />&lt;init-param&gt;<br />&lt;param-name&gt;wl-dispatch-policy&lt;/param-name&gt;<br />&lt;param-value&gt;NewExecuteQueueName&lt;/param-value&gt;<br />&lt;/init-param&gt;<br />&lt;/servlet&gt;<br /><br />　　我们可以为一个jsp或者servlet乃至一个WEB应用设置自己的执行队列。同时也可以为EJB设置自己的执行队列。对于执行时间比较长的MDB,建议使用自己的执行队列。<a id="2_3" name="2_3"></a><br /><br /><b>2.3 JDBC调优<a id="2_3_1" name="2_3_1"></a><br />2.3.1 调整连接池配置</b><br />　　JDBC Connection Pool的调优受制于WebLogic Server线程数的设置和数据库进程数,游标的大小。通常我们在一个线程中使用一个连接,所以连接数并不是越多越好,为避免两边的资源消耗，建议设置连接池的最大值等于或者略小于线程数。同时为了减少新建连接的开销,将最小值和最大值设为一致。<br /><br />　　增加Statement Cache Size对于大量使用PreparedStatement对象的应用程序很有帮助,WebLogic能够为每一个连接缓存这些对象,此值默认为10。在保证数据库游标大小足够的前提下,可以根据需要提高Statement Cache Size。比如当你设置连接数为25,Cache Size为10时,数据库可能需要打开25*10=250个游标。不幸的是,当遇到与PreparedStatement Cache有关的应用程序错误时,你需要将Cache Size设置为0。<br /><br />　　尽管JDBC Connection Pool提供了很多高级参数,在开发模式下比较有用,但大部分在生产环境下不需调整。这里建议最好不要设置测试表, 同时Test Reserved Connections和Test Released Connections也无需勾上。 当然如果你的数据库不稳定,时断时续,你就可能需要上述的参数打开。 <br /><br />　　最后提一下驱动程序类型的选择,以Oracle为例,Oracle提供thin驱动和oci驱动,从性能上来讲,oci驱动强于thin驱动,特别是大数据量的操作。但在简单的数据库操作中,性能相差不大,随着thin驱动的不断改进,这一弱势将得到弥补。而thin驱动的移植性明显强于oci驱动。所以在通常情况下建议使用thin驱动。而最新驱动器由于WebLogic server/bin目录下的类包可能不是最新的,请以Oracle网站为准: <a href="http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/htdocs/jdbc9201.html" target="_blank">http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/htdocs/jdbc9201.html</a>。<a id="2_4" name="2_4"></a><br /><br /><b>2.4 WEB调优<a id="2_4_1" name="2_4_1"></a><br />2.4.1 调整WEB应用描述符</b><br />　　WEB应用除代码之外的调优比较简单,仅仅是对一些WEB应用描述符的调整。首先关闭Session Monitoring Enabled,仅仅在Cluster环境下设置Session复制(优先使用内存复制),在保证应用正常运行的情况下,设置较短的Session超时时间。 同时生产环境下无需检查Jsp和servlet：JSPPage Check Secs和Servlet Reload Check Secs均设为-1,关闭JSPKeep Generated 和JSPVerbose对性能也有帮助。此外，还可以对jsp进行预编译,有两种方法：激活precompile选项；使用weblogic.appc事先编译，建议采用后者。<a id="2_5" name="2_5"></a><br /><br /><b>2.5 JMS调优</b><br />　　1. 增加-Dweblogic.JMSThreadPoolSize=n(至少为5),以提高处理JMS的线程数,在jRockit上增加-XXenablefatspin以减少加锁冲突;<br />　　2. 采用文件存储策略,将同步写策略设置为Direct-Write,同时在windows平台上启用磁盘写入缓存;<br />　　3. 使用分布式目的地时,激活连接工厂Load Balancing Enabled ,Server Affinity Enabled;<br />　　4. 为减少服务器不必要的JMS请求路由,如果多个目的地之间存在事务,则部署在同一JMS服务器上,尽量将连接工厂部署到JMS服务器所在的WebLogic实例上,集群环境下，则最好将连接工厂部署到集群中的所有服务器上,而集群中每个JMS服务器和目的地成员尽量使用类似的设置；<br />　　5. 启用消息分页存储功能,以释放内存,可以为JMS服务器和目的地设置, 激活Messages Paging Enabled和Bytes Paging Enabled,同时使用限额防止服务器耗尽接收消息的所有可用内存空间;<br />　　6. 在运行WebLogic Server进程之外的生产者务必使用流控制, 并增大Send Timeout;<br />　　7. 将JMS Server Expiration Scan Interval设很大的值，能禁止主动扫描过期消息;<br />　　8. 使用FIFO或者LIFO方式处理目的地消息;<br />　　9. MDB的max-beans-in-free-pool不应大于最大MDB线程数(默认线程数/2+1)。 <a id="2_6" name="2_6"></a><br /><br /><b>2.6 EJB调优<a id="2_6_1" name="2_6_1"></a><br />2.6.1 调整pool和cache </b><br />　　initial-beans-in-free-pool定义SLSB启动时实例的个数,默认为0,可以调大到正常并发数的大小,以减少初始响应时间。max-beans-in-free-pool为最大个数,默认1000对SLSB来说,在频繁创建和删除实例的情况下很有帮助,一般不用调整,至少设为默认线程数,过大容易造成内存溢出。而对Entity Bean来说,由于是匿名的,所以当频繁使用finder、home和create方法时可以调大。<br /><br />　　对SFSB来说,尽量将max-beans-in-cache参数设置得足够的大，以满足Bean实例对最大并发用户数的要求，可以避免有状态会话Bean过多的钝化行为。而idle-timeout-seconds尽量设置小,如果SFSB不用于存储Web应用会话状态可以设置为0。<br /><br />　　对于Entity Bean来说, max-beans-in-cache同样可以首先采用默认值1000，监控实例缓存和钝化的情况,再做适当调整。<br /><br />　　并行策略concurrency-strategy定义了实体Bean如何管理锁,有四种策略: Exclusive、Databse、ReadOnly、Optimistic。效率依次提高,可靠性依次降低,尽量避免使用互斥策略,如果Bean无需更新操作,使用只读策略,更甚的是,如果Bean的内容不会改变,可设置read-timeout-seconds为0,乐观并行策略时采用事务间缓存策略,在entity-cache描述符中将cache-between-transactions元素设为true。<a id="2_6_2" name="2_6_2"></a><br /><br /><b>2.6.2 优化事务隔离级别和事务属性</b><br />　　对EJB组件来说，有四种事务隔离水平：</p>
		<ul>
				<li>TRANSACTION-SERIALIZABLE：在处理完成之前拒绝其他处理的读入、可扩展性或插入数据操作; 
</li>
				<li>TRANSACTION-REPEATABLE-READ：防止处理修改正在被其他处理调用的数据; 
</li>
				<li>TRANSACTOIN-READ-COMMITTED：防止对正在被其他处理修改的数据执行写锁定； 
</li>
				<li>TRANSACTION-READ-UNCOMMITTED：允许处理读入未受权的数据以及允许在向结果中添加记录时可以忽略处理。 </li>
		</ul>
		<p>　　 以上隔离水平依次降低,效率和性能依次提高。因此,建议选用满足在业务数据完整性要求前提下水平最低的隔离级别。<br /><br />　　对于事务属性的设置也是如此,对于删除、修改和插入操作设置为Required,而对于只读操作设置为Supports或者NotSupports。<a id="2_6_3" name="2_6_3"></a><br /><br /><b>2.6.3 其他一些小技巧</b><br />　　1. 利用finders-load-bean的默认值true，既可以避免“n+1”的查询问题，又可以提高系统的性能;<br />　　2. 使用delay-updates-until-end-of-tx参数的默认值true，除非应用程序对某些变化有特别的要求;<br />　　3. 应用程序在每个业务方法调用后不需要进行存在性检查，将check-exists-on-method设定为false，以提高程序的性能;<br />　　4. 同一应用内, 将enable-call-by-reference设置为 true;<br />　　5. reentrant设置为false,避免事先加载子数据。<a id="3" name="3"></a><br /><br /><b>第三章 数据库调优<a id="3_1_1" name="3_1_1"></a><a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#0">(目录)</a><br />3.1.1 Oracle性能优化</b><br />　　Oracle9i的性能优化除了调整kernal之外就是主要对Oracle启动文件的调整,即调整SGA的参数。注意,不同操作系统不同位数的机器最优的参数不是一样的,这里主要有windows和unix之分,32位和64位之分。<br />首先需要调大进程数和游标数,一般默认的值对实际应用来说都比较小,比如说,进程数可以调到300,游标数可以调到500。<br /><br />　　其次,看一个经验公式: OS 使用内存+ SGA + session*(sort_area_size + hash_area_size +2M)&lt;0.7RAM,通常认为此时的SGA比较合理。这里sort_area_size为64k, hash_area_size为128k(当排序多的时候需要增大sort_area_size,按调整后的值计算),session表示最大并发进程数,假设100个。假如1G内存的机器,OS占用200M,PGA占用200M左右,那么SGA可以设为400-500M，如果2G内存可以1G给SGA，8G可以5G给SGA。不过对于32位数据库来说，通常最多只能使用1.7G内存。<br /><br />　　然后，SGA内参数设置的基本原则是：data buffer 通常可以尽可能的大，shared_pool_size 要适度，log_buffer 通常大到几百K到1M就差不多。具体的：data buffer 1G内存可以设置500M，2G设为1.2G，8G可设为5G 。shared_pool_size不易过大，通常应该控制在200M--300M,如果使用了大量的存储过程，可以根据SGA的值增大到500M，如果增大后命中率得不到提高，则增加是无益的。具体的：1G内存可以设置100M，2G设为150M，8G可设为300M。如不使用Java，java_pool_size 10-20M即可。large_pool_size如果不设置MTS，在20M -30M 即可，假如设置 MTS,可以考虑为 session * (sort_area_size + 2M)。<br /><br />　　最后，关于内存的设置可根据statspack信息和v$system_event,v$sysstat,v$sesstat,v$latch 等view信息来考虑微调。<a id="3_1_2" name="3_1_2"></a><br /><br /><b>3.1.2 Oracle的其他调整</b><br />　　为了Oracle高效率的运行，除了上面提到的内存因素之外，还有就是需要良好的数据库设计：表、视图、索引和日志的合理规划和建立。I/O的性能也是重要因素，应尽量减少页交换和页分配。此外，就是改善检查点的效率。<a id="4" name="4"></a><br /><br /><b>第四章 操作系统调优<a id="4_1" name="4_1"></a><a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#0">(目录)</a><br />4.1 操作系统调整</b><br />　　操作系统影响应用程序运行性能的因素主要有：硬件的配置(CPU、内存、硬盘等),核心参数,TCP/IP参数以及补丁的情况等。这里对操作系统的优化,除了更新最新的补丁程序以保证应用程序正常运行之外,就是调整TCP/IP参数,文件描述符,对于个别操作系统还有其他特别的参数调整。下面将依次介绍不同操作系统的情况,更多的信息请参考各操作系统的文档。<a id="4_1_1" name="4_1_1"></a><br /><br /><b>4.1.1 HP-UX</b><br />　　对于HP-UX,你首先需要安装Java Patch:<br /><a href="http://www.hp.com/products1/unix/java/patches/index.html" target="_blank">http://www.hp.com/products1/unix/java/patches/index.html</a>,然后需要确认下面文档中的核心参数是否满足(可以使用sam命令修改核心参数):<a href="http://e-docs.bea.com/platform/suppconfigs/configs81/hpux11_risc/81sp3.html#80105" target="_blank">http://e-docs.bea.com/platform/suppconfigs/configs81/hpux11_risc/81sp3.html#80105</a>。<br /><br />　　调整TCP参数: ndd -set /dev/tcp tcp_conn_req_max 1024, 将侦听队列的最大允许长度调整到1024。 有时操作系统限制进程使用的最大内存数小于你要配置的内存大小,则需要调整该值。<br /><br />　　读者可以从<a href="http://docs.hp.com/hpux/onlinedocs/TKP-90203/TKP-90203.html" target="_blank">http://docs.hp.com/hpux/onlinedocs/TKP-90203/TKP-90203.html</a>了解更多的HP-UX调整建议。<a id="4_1_2" name="4_1_2"></a><br /><br /><b>4.1.2 Solaris</b><br />　　调整TCP的参数,等待时间间隔tcp-time-wait-interval建议设置为60000ms: /usr/sbin/ndd ?set /dev/tcp tcp_time_wait_interval 60000;<br />其他参数调整如下:<br /><br />tcp_xmit_hiwat/tcp_recv_hiwat 131072<br />tcp_conn_req_max_q/tcp_conn_req_max_q0 16384<br /><br />　　调整一个进程打开的文件描述符的数量:软限制和硬限制以及散列表的大小,修改/etc/system文件:<br /><br />set tcp:tcp_conn_hash_size=32768<br />set rlim_fd_cur=8192<br />set rlim_fd_max=8192<br /><br />更多的调整信息请查阅: <a href="http://docs.sun.com/db/doc/806-7009" target="_blank">http://docs.sun.com/db/doc/806-7009</a>(Solaris9)。<a id="4_1_3" name="4_1_3"></a><br /><br /><b>4.1.3 AIX</b><br />　　AIX用no命令调整TCP参数，等待时间间隔tcp_timewait: no -o tcp_timewait=4,将tcp.timewait参数设置为4个15秒间隔，即1分钟。运行no -a命令将显示网络当前的所有属性值。由于UDP_SENDSPACE默认的缓存大小是8k,为减少I/O异常,需调整为32k:<br /><br />　　no -o udp_sendspace=32768。此外, 当WebLogic HTTP请求忙时,可以调整侦听队列的最大长somaxconn到8192(默认值是1024)。<br /><br />　　更多信息:<a href="http://publib16.boulder.ibmo.com/pseries/en-us/aixbman/prftungd/prftungd.htm" target="_blank">http://publib16.boulder.ibmo.com/pseries/en-us/aixbman/prftungd/prftungd.htm</a>。<a id="4_1_4" name="4_1_4"></a><br /><br /><b>4.1.4 Linux</b><br />　　调整Linux系统使用sysctl命令修改TCP参数等待时间间隔:sysctl -w ip_ct_tcp_timeout_time_wait=60;调整打开文件的最大数:在/etc/sysctl.conf文件中，添加: Fs.file-max=65535,然后运行sysctl -p;调整打开文件描述符最大数为8192:在/etc/security/limits.conf文件，添加:WebLogic hard nofile 8192(仅针对WebLogic用户),然后在WebLogic启动文件里运行ulimit-n 8192激活设置。<br /><br />更多信息请查阅:<a href="http://ipsysctl-tutorial.frozentux.net/ipsysctl-tutorial.html" target="_blank">http://ipsysctl-tutorial.frozentux.net/ipsysctl-tutorial.html</a>。<a id="4_1_5" name="4_1_5"></a><br /><br /><b>4.1.5 Windows</b><br />　　Windows系统的调整通过修改注册表HKEY-LOCAL-MACHINESYSTEMCurrent ControlSetServices文件夹来完成。可以调整TcpipParameters子文件夹中的等待时间间隔时间TcpTimedWaitDelay参数的值。侦听队列最大长度的默认值为15，为修改它，可在InetinfoParameters子目录中创建DWORD条目ListenBackLog。<br />此外,Windows2000的Service Pack(要求sp3以上)也会影响系统稳定性: <a href="http://e-docs.bea.com/platform/suppconfigs/configs81/win2ksvr_as_data_pentium/81sp3.html" target="_blank">http://e-docs.bea.com/platform/suppconfigs/configs81/win2ksvr_as_data_pentium/81sp3.html</a>。<a id="5" name="5"></a><br /><br /><b>第五章 性能监控和性能分析</b><a id="5_1" name="5_1"></a><a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#0">(目录)</a><br /><b>5.1 性能瓶颈</b><br />　　最后,介绍一下实际分析J2EE应用性能的常用命令和工具。对于实现一个高性能的J2EE应用来说,掌握了J2EE调优的理论经验还是不够的。掌握性能监控,发现瓶颈和问题诊断才是保证J2EE系统持续高效运行的关键。<br />瓶颈指的是限值所有吞吐操作以及严重影响反应时间的系统内资源。在分布式系统内寻找并纠正瓶颈是非常困难的，需要有经验的团队来解决。瓶颈会发生在Web服务器上，程序代码中，应用服务器上，数据库，操作系统或者网络，硬件上。经验表明，瓶颈很容易发生在如下地方：数据库连接与队列中；应用服务器的程序代码中；应用服务器和Web服务器硬件上；网络和TCP配置中。实际中可以着力对这些环节进行监控。<br /><br /><b>5.2 操作系统监控</b><br />　　操作系统层面的性能监控主要是对内存、CPU、I/O和交换区的使用情况进行监控分析。windows平台可以通过任务管理器和perfmon工具查看。如果是unix系统可以使用stat系列命令(vmstat, mpstat, iostat)监控内存、CPU和I/O的即时变化,使用swap命令查看交换区的使用情况。如果操作系统安装了top、topas、glance等使用工具,则使用top、topas、glance将能更为方便地看到WebLogic进程对操作系统的内存,CPU和I/O资源使用的即时变化情况。<br /><br />　　而网络方面的性能可以通过ping和netstat等命令来监控,主要几个关键的网络统计值,如数据包再发送、重复数据包和数据包侦听丢失。<br /><br />　　说明:本文提到的unix命令并非适用所有操作系统,仅供参考。<a id="5_3" name="5_3"></a><br /><br /><b>5.3 数据库监控</b><br />　　数据库层面的监控这里为oracle9i为例来说明,可以采用oracle自带的工具Oracle <br />Interprise Manager Console来监控session和sql的执行情况。还有其他专业的数据库监控工具可以使用,比如QUEST的spotlight(<a href="http://www.quest.com/spotlight-portal/" target="_blank">http://www.quest.com/spotlight-portal/</a>)可以非常形象和直观地对Oracle数据库的CPU、内存、I/O、Data Buffer Size、Shared Pool Size、Redo Buffer等参数进行即时监控,并自动对不正常的参数以红色显示。<a id="5_4" name="5_4"></a><br /><br /><b>5.4 WebLogic监控<a id="5_4_1" name="5_4_1"></a><br />5.4.1 JVM监控</b><br />　　采用java参数-verbose:gc 来分析JVM的GC非常繁琐，而且不直观。使用-Xloggc:gc.log 参数将GC日志写入文件,采用GC 工具HPjtune (<a href="http://www.javaperformancetuning.com/tools/hpjtune/index.shtml" target="_blank">http://www.javaperformancetuning.com/tools/hpjtune/index.shtml</a>)进行分析,可以轻松看出当前jvm参数配置是否合理。<br /><br />　　严格意义上来说HPjtune是一个分析工具,不是监控工具。这里不得不提及jRocket,Intel平台上最快的JVM, 在WebLogic启动命令中增加-Xmanagement参数,就可以执行beajrockit81sp3_142_04&#x8;in下console命令监控WebLogic的内存使用和CPU负载情况。设置Tools/Preferences菜单中的Mode of operation属性为developer, jRocket将提供Method Profiler工具，她能够将所有在JRockit Java虚拟机上执行的成员方法的调用次数、执行的总时间和每次调用的执行时间都统计出来，进行代码级调优，这是jRockit的又一大优势。</p>
		<p align="center">
				<img height="567" src="http://dev2dev.bea.com.cn/images/image2004111690.jpg" width="700" />
		</p>
		<p>
				<a id="5_4_2" name="5_4_2">
				</a>
				<br />
				<b>5.4.2 Console监控</b>
				<br />　　WebLogic Console除了管理配置功能之外,提供了丰富的监控功能。通过WebLogic Console，首先我们可以查看服务器的运行情况。<a id="5_4_2_1" name="5_4_2_1"></a><br /><br /><b>5.4.2.1 Server监控</b><br />　　通过使用服务器的Performance Monitoring选项卡，可以查看到请求吞吐量，执行队列积压情况以及JVM栈利用情况。而通过点击Performance Genaral选项卡中” Monitor all Active Queues...”可以查看所以执行线程的当前统计数据。此外Monitoring选项卡还可以监控JTA和JMS等Service的情况。</p>
		<p align="center">
				<img height="636" src="http://dev2dev.bea.com.cn/images/image2004111691.jpg" width="674" />
		</p>
		<p>
				<a id="5_4_2_2" name="5_4_2_2">
				</a>
				<br />
				<b>5.4.2.2 JDBC监控</b>
				<br />　　在连接池Monitoring选项卡中，WebLogic Console为每一个数据库连接池提供了实时统计信息。其中有三个重要参数可以反应WebLogic Server的健康状况：Connections High、Wait Second High和Waiters High。Connection High表示从服务器启动开始后到达池的最大连接数量，如果大于池的最大数量，则需要调整Maxium Capacity。Waiters High表示在没有可用连接的情况下，应用程序等待连接的最大个数。我们可以根据Waiters High的大小调整连接池容量。更多的参数可以通过Customize this view链接添加,参数含义参考:<a href="http://e-docs.bea.com/wls/docs81/ConsoleHelp/domain_jdbcconnectionpool_monitor.html#1104829" target="_blank">http://e-docs.bea.com/wls/docs81/ConsoleHelp/domain_jdbcconnectionpool_monitor.html#1104829</a>。<a id="5_4_2_3" name="5_4_2_3"></a><br /><br /><b>5.4.2.3 WEB监控</b><br />　　Web Application Monitoring选项卡可以监控WEB应用的Session个数,以及Servlet的响应情况,激活Session Monitoring Enabled可以获取所有session的统计情况。更多信息请参考:<br /><a href="http://e-docs.bea.com/wls/docs81/ConsoleHelp/web_applications.html#1106723" target="_blank">http://e-docs.bea.com/wls/docs81/ConsoleHelp/web_applications.html#1106723</a>。<a id="5_4_2_4" name="5_4_2_4"></a><br /><br /><b>5.4.2.4 JMS监控</b><br />　　Welogic Console JMS监控功能比较多,不仅在Server JMS Monitoring选项卡可以监控Active JMS Connections, Pooled JMS Connections和Active JMS Servers的连接和使用情况。还可以监控JMS Session Pool、Active JMS Destinations和Durable Subscribers的消费和生产情况。比如,我们可以监控到JMS Queue的接收和消费消息的数量和字节数。有关JMS监控的详细情况可参见:<a href="http://edocs.bea.com/wls/docs81/ConsoleHelp/jms_monitor.html" target="_blank">http://edocs.bea.com/wls/docs81/ConsoleHelp/jms_monitor.html</a>。<br /><br /><b>5.4.2.5 EJB监控</b><br />　　EJB监控包括对SLSB,SFSB,Entity Bean,MDB四种EJB的监控。本人认为EJB监控提供了非常丰富的运行时统计信息(<a href="http://e-docs.bea.com/wls/docs81/ConsoleHelp/ejb.html#1105036" target="_blank">http://e-docs.bea.com/wls/docs81/ConsoleHelp/ejb.html#1105036</a>),非常有利于我们对EJB进行性能调优。<br /><br />　　SLSB选项卡为用户提供实例池的运行时统计信息。Pool Miss Ratio 表示实例池的Miss率,Pool Waiter Total Count 表示线程等待bean 实例的累计时间,Pool Timeout Total Count表示超时的线程数。当Pool Miss Ratio较大时,可以增加max-beans-free-pool。<br /><br />　　SFSB可以关注Cache Miss Ratio和Activation Count。Cache Miss Ratio过大时,调大max-bean-in-cache未必有帮助,需要尝试不用的max-bean-in-cache以获得最低的Cache Miss Ratio。激活将严重减慢应用程序的速度,如果某一个bean的Activation Count的值过高，那么需要考虑增加max-bean-in-cache的大小。<br />Entity Bean结合了SLSB的free pool和SFSB的cache。可以结合上面的策略进行监控。 <br /><br />　　而MDB仅比SLSB多一个参数JMSConnection Alive,报告EJB是否成功连接到JMS目的地。<br /><br />更多Console监控信息可参见<a href="http://edocs.bea.com/wls/docs81/ConsoleHelp/index.html" target="_blank">http://edocs.bea.com/wls/docs81/ConsoleHelp/index.html</a>。<a id="5_4_3" name="5_4_3"></a><br /><br /><b>5.4.3 实用工具分析</b><br />　　WebLogic除了提供Console进行应用监控之外,用户还可以编写JMX程序或者通过SNMP协议进行监控。而QUEST Spotlight for WebLogic Server提供了类似WebLogic Console类似的监控功能,并对异常情况显红。<br />这里不得不提到实战中经常用来分析性能瓶颈的工具THREAD DUMP,统一的命令是使用 weblogic.Admin 命令 THREAD_DUMP。而在 windows上还可以使用&lt;Ctrl&gt;+&lt;Break&gt; 来创建诊断问题所需的线程转储Thread Dump,而在unix上使用kill -3 &lt;wlspid&gt;命令。我们从中可以看到WebLogic后台线程的运行情况,通常需要每隔10秒左右持续执行几次以助诊断问题。更多信息可以参考BEA实战集锦。<a id="5_5" name="5_5"></a><br /><br /><b>5.5 应用程序分析</b><br />　　应用程序分析除了凭借程序员丰富的经验和敏锐的洞察力去人工检查代码之外,使用厂家的工具也是节省时间的不错选择。目前市场上有Borland Optimizeit Enterprise Suite和QUEST Jprobe两个产品可以用来分析性能瓶颈,垃圾收集,内存泄漏,线程死锁和代码复盖等。Hpjmeter是一个免费的工具,也具有以上类似的性能分析功能。<br /><br />　　而Borland Optimizeit Server Trace,HP OpenView Transaction Analyzer和Mercury LoadRunner J2EE breakdown都可以用来分解J2EE应用从客户端访问到最终数据库操作每一层次花费的时间,甚至精确到每一个方法的执行时间。Server Trace还具有检查内存泄漏，连接泄漏和错误警告等功能,一般在测试环境中使用。而HP OTVA的优势在于运行时监控,LoadRunner优势在于压力测试。<a id="6" name="6"></a><br /><br /><b>总结</b><a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#0">(目录)</a><br />　　J2EE调优是一门实践和经验科学，是一个复杂而往复的过程。其原则是：合理。合理,看似简单,细细品味,意味深长。本文所述的调优策略并不是一成不变的，只是为了给大家一个参考建议，让大家少走弯路，关键是根据实际环境调优。欢迎有兴趣的朋友在论坛上积极讨论和批评指正。<a id="7" name="7"></a></p>
		<p>
				<b>参考文献</b>
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#0">(目录)</a>
				<br />[1]BEA WebLogic Server edocs: <a href="http://e-docs.bea.com/wls/docs81/perform/index.html" target="_blank">http://e-docs.bea.com/wls/docs81/perform/index.html</a><br />[2]Gregory Nyberg &amp; Robert Patrick :Mastering BEA WebLogic Server<br />[3]Jack Shirasi:Java Performance Tuning<a id="8" name="8"></a></p>
		<p>
				<b>关于作者</b>
				<a href="http://dev2dev.bea.com.cn/bbs/jishudata/ArticleShow.jsp?Id=16#0">(目录)</a>
				<br />周海根(dev2dev ID:zhouhg) 合力思软件(中国)有限公司技术顾问，BEA Certified Specialist，BEA dev2dev撰稿人。多年从事J2EE开发工作，目前致力于技术支持工作，主要研究J2EE技术在WebLogic上的应用、调优。有着西电人的务实，喜欢专研技术，是个体育狂热者。<br />联系方式: 010-85251858-1053,<a href="mailto:zhouhaigen@hotmail.com">zhouhaigen@hotmail.com</a></p>
<img src ="http://www.blogjava.net/TrampEagle/aggbug/60947.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-07-31 10:16 <a href="http://www.blogjava.net/TrampEagle/articles/60947.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP连接mysql数据库攻略</title><link>http://www.blogjava.net/TrampEagle/articles/51213.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Wed, 07 Jun 2006 14:37:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/51213.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/51213.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/51213.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/51213.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/51213.html</trackback:ping><description><![CDATA[
		<blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
				<p align="left">引自：<a href="http://www.7880.com/info/Article-83e62ca0.html">http://www.7880.com/info/Article-83e62ca0.html</a><br /><br /><br />　连续几天安装配置和连接Mysql数据库，今天终于成功了，回想这几天，真的是甜酸苦辣都有，单mysql就重装了不下10次，而在eclipse上编写的连接数据库的程序总是报错．我都已经down了oracal准备放弃mysql了，不过．．．就象电视剧演的那样，转机总是在这个时候出现，先是看到了saulzy关于mysql4.1.11版本的安装介绍，接着又找到了一款不错的mysql 界面插件，最后在网友的帮助下把mysql的JDBC驱动配好并连通了．一连5天，日子真不好过阿，不过这个过程中，我也觉得自己学到不少东西，呵呵，反正都撑过来了，就要继续往前走．现在，就这几天弄的总结一下，希望对同是正在学习JAVA技术的同道中人能有帮助．<br /><br />　　(相关链接："配置Eclpise+tomcat并实现JSP的编写与部署")<br /><br /><strong>一． 软件下载<br /></strong>　　Mysql<br />　　下载版本：4.1.11<br />　　<a href="http://dev.mysql.com/downloads/mysql/4.1.html" target="_blank">http://dev.mysql.com/downloads/mysql/4.1.html</a><br /><br />　　JDBC驱动<br />　　下载版本：3.1.8<br />　　<a href="http://dev.mysql.com/downloads/connector/j/3.1.html" target="_blank">http://dev.mysql.com/downloads/connector/j/3.1.html</a><br /><br />　　Mysql界面插件:mysql-front<br />　　下载版本镜像：HongKong（我下回来安装就是中文版了）<br />　　<a href="http://www.mysqlfront.de/download.html" target="_blank">http://www.mysqlfront.de/download.html</a><br /><br /><strong>二． 软件安装<br /></strong>　　1.安装mysql<br />　　请参阅相关文章，推荐文章：<a href="http://blog.csdn.net/saulzy/archive/2005/04/23/359648.aspx" target="_blank">http://blog.csdn.net/saulzy/archive/2005/04/23/359648.aspx</a><br /><br />　　2.JDBC驱动：mysql-connector-java-3.1.8<br />　　这只是一个压缩包，并不需要安装，只要将其解压，我么使用的是文件夹mysql-connector-java-3.1.8里的文件：mysql-connector-java-3.1.8-bin.jar．<br /><br />　　3. Mysql界面插件:mysql-front<br />　　这是一个安装程序，按照提示安装就可以了．<br /><br /><strong>三． 环境配置</strong><br />　首先，我要说明的是我现在tomcat的安装路径是: D:\Program Files\Java\Tomcat；JDK的安装路径是：D:\Program Files\Java\j2sdk。<br /><br />　　在这里，需要配置环境变量的是JDBC驱动．在配置前先要把刚才说到的mysql-connector-java-3.1.8-bin.jar本地硬盘某处（我放的地方：D:\Program Files\Java\mysqlforjdbc），然后根据你放的地方，配置classpath，我的配置是这样的：</p>
				<p>　　D:\Program files\Java\j2sdk\lib\tools.jar;</p>
				<p>　　D:\Program Files\Java\j2sdk\lib\mysql-connector-java-3.1.8-bin-g.jar;</p>
				<p>　　D:\Program Files\Java\mysqlforjdbc\mysql-connector-java-3.1.8-bin.jar<br />　　配置这个的目的是让你的java应用程序找到连接mysql的驱动．<br /><br />　　配置完环境变量后还有很重要一步就是为JSP连接数据库配置驱动，这个其实很简单，就是把mysql-connector-java-3.1.8-bin.jar拷到某些文件夹里就行了，我在网上看了很多资料问了很多人，各种说法都有，我综合了一下，为了保险，我都全做了，呵呵，反正就是拷一个400K的文件而已，现列出要把mysql-connector-java-3.1.8-bin.jar拷进去的文件夹，如下：<br />　　D:\Program Files\Java\Tomcat\common\lib<br />　　D:\Program Files\Java\Tomcat\shared\lib<br /><br /><strong>四． 数据库的使用<br /></strong><br />　　Mysql安装完毕以后，还有一些要注意的地方（推荐文章）：<a href="http://blog.csdn.net/saulzy/archive/2005/04/23/359811.aspx" target="_blank">http://blog.csdn.net/saulzy/archive/2005/04/23/359811.aspx</a></p>
				<p>　　就象在文章提到的，mysql安装好后最重要一样就是要看数据库有没有作为系统服务启动了，所以在大家进行数据库操作前，应要看看，在操作系统的开始－＞运行－＞输入services.msc，确定你在安装时你设置的关于mysql的那个服务已经启动，这样你在操作数据库时不会报连接不上的错误．</p>
				<p>　　上面提到了一个较方便的mysql界面插件，但是这个界面是我在已经开始使用mysql后才找到的，刚开始我是在dos下用命令行进行操作的．虽然那个界面也可以进行建库啊，设定权限等操作，但是，我觉得懂得在使用命令行也是一个很重要的技能，所以我先从命令行开始说，怎样简单使用mysql．到后面会谈及mysql－front的使用．<br /><br />　　现在我想在mysql里建一个数据库shujuku，以及在数据库里建一个表biao．具体的命令如下（假设mysql我是刚安装好的）<br /><br />　　1. 进入dos状态（记住命令行的要运行在mysql的安装目录下的bin目录的）</p>
				<p>　　2. 连接mysql<br />　　输入：mysql –h localhost –u root –p<br />　　输入在安装时已设好的密码，就近入了mysql的命令编辑界面了。<br /><br />　　3. 使用mysql的基本命令(在mysql命令行编辑每输入完命令后最后一定要有分号，不然会报错)<br />　　显示数据库：show databases;<br />　　使用数据库：use 数据库名；<br /><br />　　4．建库<br />　　命令：create database shujuku;<br /><br />　　5.为数据库设置权限（用户和密码）<br />　　命令：grant all privileges on shujuku.* to test@localhost identified by “123456”;<br />　　当你执行完这个命令以后，只要你再以用户名：test,密码：123456登录时你就只可以对shujuku这个数据库操作，这样避开使用root，对数据库的安全有很大帮助．<br /><br />　　6.建表<br />　　命令：create table biao(id int(8) primary key,name varchar(10));<br /><br />　　剩下来的与标准sqsl命令基本上是一样的，具体操作略<br />　　值得一提的是，你在命令行上输入＂？＂，就会有mysql命令的简单帮助，如下：<br /><br />　　呵呵，那样，我们还可以知道退出，就是＂exit＂，呵呵！<br /><br /><strong>五． 关于mysql-front的使用<br /></strong>　　我找了好几个mysql的界面工具，觉得最简洁方便还是mysql-front，可惜的是要收费，不过还好有试用期，呵呵，可以先感受感受一下，最重要一点是mysql-front有简体中文版的，英文不好的我用起来就舒服多了．下面简单说说使用吧．</p>
				<p>　　首先，安装就不用说了，有向导，而且很简单．安装好后第一次运行时会跳出来一个要求添加对话的框，在这里你可以添加例如上面已经设定好的shujuku，过程如下:<br />　　当你在注册的复选框里填上你在上面mysql设定好的用户名和密码后，在选择数据库框里就有shujuku 的数据库了，选上，按确定．进入mysql-fron后，你就会看到下面的界面，这是你就可以进行操作了．<br /><br />　　要说明的是，你还可以把root用户也加进去，这要你在mysql-fron的界面上选设置－＞对话－＞新建，再按上面进行就可以，出了root你还可以加入更多的用户，方法还是一样的，设置不同的用户，是方便对不同数据库进行管理，呵呵，root是权限最高的，可不要随便让别人使用你的root用户，保正你数据库的安全．<br /><br /><strong>六． JSP连接mysql<br /></strong>　　现在就是尝试用jsp连接mysql了<br />　　我在eclipse里建了个test_mysql.jsp页面，代码如下：</p>
				<p class="code">&lt;%@ page contentType="text/html; charset=gb2312" %&gt;<br /><br />&lt;%@ page language="java" %&gt;<br /><br />&lt;%@ page import="com.mysql.jdbc.Driver" %&gt;<br /><br />&lt;%@ page import="java.sql.*" %&gt;<br /><br />&lt;%<br /><br />//驱动程序名<br /><br />String driverName="com.mysql.jdbc.Driver";<br /><br />//数据库用户名<br /><br />String userName="cl41";<br /><br />//密码<br /><br />String userPasswd="123456";<br /><br />//数据库名<br /><br />String dbName="db";<br /><br />//表名<br /><br />String tableName="dbtest";<br /><br />//联结字符串<br /><br />String url="jdbc:mysql://localhost/"+dbName+"?user="+userName+"&amp;password="+userPasswd;<br /><br />Class.forName("com.mysql.jdbc.Driver").newInstance();<br /><br />Connection connection=DriverManager.getConnection(url);<br /><br />Statement statement = connection.createStatement();<br /><br />String sql="SELECT * FROM "+tableName;<br /><br />ResultSet rs = statement.executeQuery(sql); <br /><br />//获得数据结果集合<br /><br />ResultSetMetaData rmeta = rs.getMetaData();<br /><br />//确定数据集的列数，亦字段数<br /><br />int numColumns=rmeta.getColumnCount();<br /><br />// 输出每一个数据值<br /><br />out.print("id"); <br /><br />out.print("|");<br /><br />out.print("num");<br /><br />out.print("&lt;br&gt;");<br /><br />while(rs.next()) {<br /><br />out.print(rs.getString(1)+" "); <br /><br />out.print("|");<br /><br />out.print(rs.getString(2));<br /><br />out.print("&lt;br&gt;"); <br /><br />} <br /><br />out.print("&lt;br&gt;");<br /><br />out.print("数据库操作成功，恭喜你"); <br /><br />rs.close(); <br /><br />statement.close(); <br /><br />connection.close(); <br /><br />%&gt;</p>
				<p align="left">　　然后把test­_mysql.jsp部署到tomcat处，如何部署可参考"配置Eclpise+tomcat并实现JSP的编写与部署"，在浏览器中就可以看到结果了。<br /></p>
		</blockquote>
<img src ="http://www.blogjava.net/TrampEagle/aggbug/51213.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-06-07 22:37 <a href="http://www.blogjava.net/TrampEagle/articles/51213.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>应用OSCache提升J2EE系统运行性能</title><link>http://www.blogjava.net/TrampEagle/articles/49411.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Thu, 01 Jun 2006 01:47:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/49411.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/49411.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/49411.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/49411.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/49411.html</trackback:ping><description><![CDATA[引自：<a href="http://www.3doing.net/forums/dispbbs.asp?boardID=11&amp;ID=322&amp;page=1">http://www.3doing.net/forums/dispbbs.asp?boardID=11&amp;ID=322&amp;page=1</a><br /><br /><blockquote><table class="tablebody2" style="TABLE-LAYOUT: fixed; WORD-BREAK: break-all" width="90%" border="0"><tbody><tr><td style="FONT-SIZE: 9pt; LINE-HEIGHT: 12pt" width="100%"><img alt="发贴心情" src="http://www.3doing.net/forums/Skins/Default/topicface/face1.gif" align="absMiddle" border="0" /> <b>应用OSCache提升J2EE系统运行性能</b><br />Cache是一种用于提高系统响应速度、改善系统运行性能的技术。尤其是在Web应用中，通过缓存页面的输出结果，可以很显著的改善系统运行性能。本文中作者给大家介绍一个实现J2EE框架中Web应用层缓存功能的开放源代码项目----OSCache。通过应用OSCache，我们不但可以实现通常的Cache功能，还能够改善系统的稳定性。<br /><br /><p>关键词： Cache 系统性能</p><p>1面临的问题</p><p>　1.1需要处理的特殊动态内容</p><p>　　在信息系统建设过程中我们通常会遇到这样的问题：</p><p>　　1.基础数据的变更问题</p><p>　　　信息系统中需要处理的基础数据的内容短时间内是不会发生变化的，但是在一个相对长一些的时间里，它却可能是动态增加或者减少的。</p><p>　　　举个例子：电子商务中关于送货区域的定义，可能短时间内不会发生变化，但是随着电子商务企业业务的扩大，系统中需要处理的送货区域就可能增加。所以我们的系统中不得不在每次向客户展示送货区域信息的时候都和数据库（假设送货区域信息保存在数据库中，这也是通常采用的处理方法）进行交互。</p><p>　　2.统计报表（不仅限于统计报表）的问题</p><p>　　　一般来说，统计报表是一个周期性的工作，可能是半个月、一个月或者更长的时间才会需要更新一次，然而统计报表通常是图形显示或者是生成pdf、word、excel等格式的文件，这些图形内容、文件的生成通常需要消耗很多的系统资源，给系统运行造成很大的负担。</p><p>　1.2问题的共同点</p><p>　　通过比较分析，不难发现这两类问题有一些共同点：</p><p>　　1、被处理的内容短时间不变，所以短时间内可以作为静态内容进行处理</p><p>　　2、在一个不太长的时间内，被处理的内容可能或者必定产生变化，所以必须将他们作为动态内容进行处理</p><p>　　3、在合理的时间区段内可以忽略被处理内容变化后带来的影响</p><p>　　4、对这些内容的处理动作比较消耗系统性能，影响系统响应时间</p><p>　1.3 解决方法</p><p>　　缓存技术可以帮助我们很好的解决这个问题：</p><p>　　　1、缓存信息</p><p>　　　当上述的基础数据或者统计报表第一次被访问时，被处理的内容被当作动态信息，基础数库从数据库中获得，统计报表也会被生成符合要求的图形、文件，然后这些信息都会被放入缓存信息中。</p><p>　　　2、响应信息由缓存提供</p><p>　　　当上述的基础数据或者统计报表继续被访问时，系统将会首先检查缓存信息中是否有对应的内容和我们设定的缓存规则，如果符合缓存信息存在而且符合缓存规则，给出的响应将来自于缓存信息，如果没有或者缓存信息已经不符合设定的要求，系统将重复上一步的动作。</p><p>　　　很显然，上面的步骤2中，多数情况下，当用户请求到达时，被处理的内容将来自于缓存，所以大大的减少了与数据库的交互，或者不再需要为每个请求都生成一次报表图形或者文件，这部分工作的减少对于降低系统性能消耗、提高系统稳定性和并发处理能力是非常有益的。</p><p>2　OSCache简介</p><p>　　OSCache是OpenSymphony组织提供的一个J2EE架构中Web应用层的缓存技术实现组件，它的出现解决了我们面临的问题。</p><p>　　OSCache目前最新的稳定版本是2.0，本文中的例子都是基于这个版本的，如果大家运行例子的过程中发生问题，请首先确认是否采用了正确的软件版本。</p><p>　2.1主要特征</p><p>　　1.兼容多种支持JSP的web服务器</p><p>　　　已经通过兼容测试的web服务器包括OrionServer (1.4.0或者以上版本) 、Macromedia JRun (3.0或者以上版本) 、BEA Weblogic (7.x或者以上版本) 、IBM Websphere (5.0版本)、Silverstream (3.7.4版本)、Caucho Resin (1.2.3或者以上版本)、Tomcat (4.0或者以上版本) ，其他支持servlet2.3、jsp1.2的web服务器应该都是完全兼容OSCache的。</p><p>　　2.可选的缓存区</p><p>　　　你可以使用内存、硬盘空间、同时使用内存和硬盘或者提供自己的其他资源（需要自己提供适配器）作为缓存区。</p><p>　　　1)使用内存作为缓存区将可以提供更好的性能</p><p>　　　2)使用硬盘作为缓存区可以在服务器重起后迅速恢复缓存内容</p><p>　　　3)同时使用内存和硬盘作为缓存区则可以减少对内存的占用</p><p>　　3.灵活的缓存系统</p><p>　　　　OSCache支持对部分页面内容或者对页面级的响应内容进行缓存，编程者可以根据不同的需求、不同的环境选择不同的缓存级别。</p><p>　　4.容错</p><p>　　　在一般的web应用中，如果某个页面需要和数据库打交道，而当客户请求到达时，web应用和数据库之间无法进行交互，那么将返回给用户 “系统出错”或者类似的提示信息，如果使用了OSCache的话，你可以使用缓存提供给用户，给自己赢得维护系统或者采取其他补救的时间。</p><p>　　其它特性还包括对集群的支持、缓存主动刷新等特性，大家可以参考OpenSymphony网站上的其他资源获取更多的信息。</p><p>3　OSCache组件的安装</p><p>　　OSCache是一个基于web应用的组件，他的安装工作主要是对web应用进行配置，大概的步骤如下：</p><p>　　1.下载、解压缩OSCache</p><p>　　　请到OSCache的主页<a href="http://www.opensymphony.com/oscache/download.html下载Oscache的最新版本，作者下载的是OSCache的最新稳定版本2.0。" target="_blank"><font color="#000000">http://www.opensymphony.com/oscache/download.html下载Oscache的最新版本，作者下载的是OSCache的最新稳定版本2.0。</font></a></p><p>　　　将下载后的。Zip文件解压缩到c:\oscache（后面的章节中将使用%OSCache_Home%来表示这个目录）目录下</p><p>　　2.新建立一个web应用</p><p>　　3.将主要组件%OSCache_Home%\oscache.jar放入WEB-INF\lib目录</p><p>　　4.commons-logging.jar、commons-collections.jar的处理</p><p>　　l、OSCache组件用Jakarta Commons Logging来处理日志信息，所以需要commons-logging.jar的支持，请将%OSCache_Home%\lib\core\commons-logging.jar放入classpath（通常意味着将这个文件放入WEB-INF\lib目录）</p><p>　　２、如果使用JDK1.3,请将%OSCache_Home%\lib\core\commons-collections.jar放入classpath，如果使用JDK1.4或者以上版本，则不需要了</p><p>　　5.将oscache.properties、oscache.tld放入WEB-INF\class目录</p><p>　　　１、%OSCache_Home%\oscache.properties包含了对OSCache运行特征值的设置信息</p><p>　　　２、%OSCache_Home%\oscache.tld包含了OSCache提供的标签库的定义内容</p><p>　　6.修改web.xml文件</p><p>　　在web.xml文件中增加下面的内容，增加对OSCache提供的taglib的支持：</p><p>　　&lt;taglib&gt;</p><p>　　　&lt;taglib-uri&gt;oscache&lt;/taglib-uri&gt;</p><p>　　　&lt;taglib-location&gt;/WEB-INF/classes/ oscache.tld&lt;/taglib-location&gt;</p><p>　　&lt;/taglib&gt; </p><p>　4　开始使用OSCache中的缓存组件</p><p>　OSCache中按照缓存范围的不同分为两种不同的方式：一种是缓存JSP页面中部分或者全部内容，一种是基于整个页面文件的缓存。</p><p>　　　4.1JSP部分内容缓存</p><p>　　　　4.1.1Cache—OSCache提供的缓存标签</p><p>　　　　　这是OSCache提供的标签库中最重要的一个标签，包括在标签中的内容将应用缓存机制进行处理，处理的方式将取决于编程者对cache标签属性的设置。</p><p>　　　　第一次请求到达时，标签中的内容被处理并且缓存起来，当下一个请求到达时，缓存系统会检查这部分内容的缓存是否已经失效，主要是以下几项：</p><p>　　　　1.缓存时间超过了cache标签设置的time或者duration属性规定的超时时间</p><p>　　　　2.cron属性规定的时间比缓存信息的开始时间更晚</p><p>　　　　3.标签中缓存的内容在缓存后又被重新刷新过</p><p>　　　　4.其他缓存超期设定</p><p>　　　　如果符合上面四项中的任何一项，被缓存的内容视为已经失效，这时被缓存的内容将被重新处理并且返回处理过后的信息，如果被缓存的内容没有失效，那么返回给用户的将是缓存中的信息。</p><p>cache标签的属性说明:</p><p>key – 标识缓存内容的关键词。在指定的作用范围内必须是唯一的。默认的key是被访问页面的URI和后面的请求字符串。</p><p>你可以在同一个页面中使用很多cache标签而不指定他的key属性，这种情况下系统使用该页面的URI和后面的请求字符串，另外再自动给这些key增加一个索引值来区分这些缓存内容。但是不推荐采用这样的方式。</p><p>scope – 缓存发生作用的范围，可以是application或者session </p><p>time – 缓存内容的时间段，单位是秒，默认是3600秒，也就是一个小时，如果设定一个负值，那么这部分被缓存的内容将永远不过期。 </p><p>duration – 指定缓存内容失效的时间，是相对time的另一个选择，可以使用简单日期格式或者符合USO-8601的日期格式。如：duration='PT5M' duration='5s'等</p><p>refresh – false 或者true。</p><p>如果refresh属性设置为true，不管其他的属性是否符合条件，这部分被缓存的内容都将被更新，这给编程者一种选择，决定什么时候必须刷新。 </p><p>mode – 如果编程者不希望被缓存的内容增加到给用户的响应中，可以设置mode属性为“silent”</p><p>其它可用的属性还包括：cron 、groups、language、refreshpolicyclass、refreshpolicyparam。</p><p>上面的这些属性可以单独使用，也可以根据需要组合使用，下面的例子将讲解这些常用属性的使用方式。</p><p>　　　4.1.2Cache标签实例分析:</p><p>　　　　1.最简单的cache标签用法</p><p>　　　　使用默认的关键字来标识cache内容，超时时间是默认的3600秒</p><p>&lt;cache:cache&gt;</p><p>&lt;%</p><p>//自己的JSP代码内容</p><p>%&gt;</p><p>&lt;/cache:cache&gt; </p><p>2.用自己指定的字符串标识缓存内容，并且设定作用范围为session。</p><p>&lt;cache:cache key="foobar" scope="session"&gt;<br />&lt;%</p><p>//自己的JSP代码内容</p><p>%&gt;</p><p>&lt;/cache:cache&gt; </p><p>3.动态设定key值，使用自己指定的time属性设定缓存内容的超时时间，使用动态refresh值决定是否强制内容刷新。</p><p>因为OSCache使用key值来标识缓存内容，使用相同的key值将会被认为使用相同的的缓存内容，所以使用动态的key值可以自由的根据不同的角色、不同的要求决定使用不同的缓存内容。</p><p>&lt;cache:cache key="&lt;%= product.getId() %&gt;" time="1800" refresh="&lt;%= needRefresh %&gt;"&gt;</p><p>&lt;%</p><p>//自己的JSP代码内容</p><p>%&gt;</p><p>&lt;/cache:cache&gt; </p><p>4.设置time属性为负数使缓存内容永不过期</p><p>&lt;cache:cache time="-1"&gt;</p><p>&lt;%</p><p>//自己的JSP代码内容</p><p>%&gt;</p><p>5.使用duration属性设置超期时间</p><p>&lt;cache:cacheduration='PT5M'&gt;</p><p>&lt;%</p><p>//自己的JSP代码内容</p><p>%&gt;</p><p>6.使用mode属性使被缓存的内容不加入给客户的响应中</p><p>&lt;cache:cachemode='silent'&gt;</p><p>&lt;%</p><p>//自己的JSP代码内容</p><p>%&gt;</p><p>4.2用CashFilter实现页面级缓存</p><p>在OSCache组件中提供了一个CacheFilter用于实现页面级的缓存，主要用于对web应用中的某些动态页面进行缓存，尤其是那些需要生成pdf格式文件/报表、图片文件等的页面，不仅减少了数据库的交互、减少数据库服务器的压力，而且对于减少web服务器的性能消耗有很显著的效果。</p><p>这种功能的实现是通过在web.xml中进行配置来决定缓存哪一个或者一组页面，而且还可以设置缓存的相关属性，这种基于配置文件的实现方式对于J2EE来说应该是一种标准的实现方式了。</p><p>[注] 只有客户访问时返回http头信息中代码为200（也就是访问已经成功）的页面信息才能够被缓存</p><p>1.缓存单个文件</p><p>修改web.xml，增加如下内容，确定对/testContent.jsp页面进行缓存。</p><p>&lt;filter&gt;</p><p>&lt;filter-name&gt;CacheFilter&lt;/filter-name&gt;</p><p>&lt;filter-class&gt;com.opensymphony.oscache.web.filter.CacheFilter&lt;/filter-class&gt;</p><p>&lt;/filter&gt;</p><p>&lt;filter-mapping&gt;</p><p>&lt;filter-name&gt;CacheFilter&lt;/filter-name&gt;</p><p>&lt;!—对/testContent.jsp页面内容进行缓存--&gt;</p><p>&lt;url-pattern&gt;/testContent.jsp&lt;/url-pattern&gt;</p><p>&lt;/filter-mapping&gt;</p><p>2.缓存URL pattern</p><p>修改web.xml，增加如下内容，确定对*.jsp页面进行缓存。</p><p>&lt;filter&gt;</p><p>&lt;filter-name&gt;CacheFilter&lt;/filter-name&gt;</p><p>&lt;filter-class&gt;com.opensymphony.oscache.web.filter.CacheFilter&lt;/filter-class&gt;</p><p>&lt;/filter&gt;</p><p>&lt;filter-mapping&gt;</p><p>&lt;filter-name&gt;CacheFilter&lt;/filter-name&gt;</p><p>&lt;!—对所有jsp页面内容进行缓存--&gt;</p><p>&lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;</p><p>&lt;/filter-mapping&gt;</p><p>3.自己设定缓存属性</p><p>在页面级缓存的情况下，可以通过设置CacheFilter的初始属性来决定缓存的一些特性：</p><p>time属性设置缓存的时间段，默认为3600秒，可以根据自己的需要只有的设置</p><p>而scope属性设置，默认为application，可选项包括application、session</p><p>&lt;filter&gt;</p><p>&lt;filter-name&gt;CacheFilter&lt;/filter-name&gt;</p><p>&lt;filter-class&gt;com.opensymphony.oscache.web.filter.CacheFilter&lt;/filter-class&gt;</p><p>&lt;init-param&gt;</p><p>&lt;param-name&gt;time&lt;/param-name&gt;</p><p>&lt;param-value&gt;600&lt;/param-value&gt;</p><p>&lt;/init-param&gt;</p><p>&lt;init-param&gt;</p><p>&lt;param-name&gt;scope&lt;/param-name&gt;</p><p>&lt;param-value&gt;session&lt;/param-value&gt;</p><p>&lt;/init-param&gt;</p><p>&lt;/filter&gt;</p><p>&lt;filter-mapping&gt;</p><p>&lt;filter-name&gt;CacheFilter&lt;/filter-name&gt;</p><p>&lt;!—对所有jsp页面内容进行缓存--&gt;</p><p>&lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;</p><p>&lt;/filter-mapping&gt;</p><p>5性能测试结果</p><p>5.1测试环境</p><p>系统平台：windows 2000 高级服务器/ P3 800 /512M内存</p><p>web服务器：websphere 5.0</p><p>数据库服务器：mysql 4.0.18-nt</p><p>性能测试用工具：apache Jmeter</p><p>5.2测试计划</p><p>l这次性能测试对比方为使用缓存和不使用缓存两种，他们的访问代码都是一样的：通过数据源从本地mysql数据库中获取person表的所有记录，然后显示在页面上。</p><p>l测试中将模仿10个用户，每个用户发起5次请求，然后统计所有访问花费的时间。</p><p>5.3测试结果</p><br /><br /><br /><p>使用缓存后的测试结果</p><p>不使用缓存时的测试结果</p><p>所有请求花费的总时间(毫秒)</p><p>20569</p><p>22870</p><p>性能测试的详细结果请大家查看下载内容中的《不使用cache时的系统性能测试结果.txt》和《使用cache后系统性能测试结果.txt》</p><p>6总结</p><p>在J2EE系统中，我们经常需要处理一些特殊的动态内容，这些内容在一个时间段内的变更非常有限，但是又不得不将他们确定为动态内容进行输出，而且非常消耗数据库系统资源或者web服务器的资源，这时我们就可以采用Cache----一种用于提高系统响应速度、改善系统运行性能的技术----来优化我们的系统。尤其是在Web应用中，这种处理可以很显著的改善系统运行性能。</p><p>本文中作者给大家介绍一个实现J2EE框架中Web应用层缓存功能的开放源代码项目----OSCache。它提供了在J2EE系统中实现缓存需要的丰富的功能。通过应用OSCache，我们不但可以实现通常的Cache功能、自由的设定cache的相关特性比如缓存时间段/缓存内容等，提升系统性能，而且还能有效的改善系统的稳定性。除此之外，OSCache组件还提供了更多的特性比如集群、容错、灵活的缓存区选择等。</p><p>作者根据自己的使用经验给大家提供了一些简单的例子，他们部分演示了如何使用OSCache组件提供的丰富特性，OSCache提供的特性远不止这些，需要大家在今后的时间里深入的研究，同时也希望大家通过E-mail和作者贡献研究成果。</p><p>参考资料</p><p>1.OpenSymphony网站中关于OSCache的部分 <a href="http://www.opensymphony.com/oscache/" target="_blank"><font color="#000000">http://www.opensymphony.com/oscache/</font></a></p><p>下载内容</p><p>1.OSCache下载地址 <a href="http://www.opensymphony.com/oscache/download.html" target="_blank"><font color="#000000">http://www.opensymphony.com/oscache/download.html</font></a></p><p>2.性能测试结果.rar</p><p>作者信息：</p><p>肖菁，软件工程师，IBM developerWorks/Bea dev2dev/sun 技术开发者撰稿人，主要研究J2EE、web services以及他们在websphere、weblogic平台上的实现，拥有IBM的 Developing With Websphere Studio证书。您可以通过E_mail和作者取得联系，或者查看作者的主页获取更多信息</p></td></tr></tbody></table></blockquote>我们在开发web应用的时候，经常会碰到数据列表的功能开发，有的数据列表所显示的数据的变化并不是很频繁，也有的时候用户并不需要一定看到当前最新的数据信息，因此每一次都从数据库取出列表数据显然不是一种理想的方式。<br />接下来我们通过研究petstore－WAF(web层开发框架)提供的缓存机制来学会如何给自己应用显示页面加上一个缓存。<br />我写过一篇有关WAF的介绍，大家可以在论坛里找找。<br /><br />  首先要声明的是WAF提供的是jsp页面缓存的技术(利用了jsp-tag技术)，缓存方式是在jsp页面上直接利用tag技术对页面的输出内容进行缓存，在petstore当中，可以看到在category.jsp(列出某项分类的所有产品)和product.jsp(列出某个产品的所有项目)，都采用了缓存技术对产品列表信息和项目列表信息进行了缓存，并设置了缓存时间为300000毫秒，这样任何用户在首次访问这俩个页面时，页面将从数据库中读取出信息，在第一次开始到5分钟之内任何用户再次访问时得到的列表显示信息是从缓存(内存)中取得的，如果此时更新数据库数据将不会影响到页面。<br />下面看看petstore是如何利用这一缓存技术的：<br /><br />&lt;waf:cache/&gt; 标签<br />waf:cache标签是由WAF提供的，专门对jsp显示内容进行缓存，标签body中的内容将被缓存起来，再次访问时只要缓存内容没有过期，则从缓存取出内容返回给显示页面。<br />waf:cache包括3个属性：<br />1.“scope” <br />缓存内容的限定范围，值包括” context”、” session”、” request”、” page”，根据被缓存内容的使用者范围可以有不同的选择。<br />2.“name”<br />给缓存内容起个名字，在同一页面上不要重复。这样你可以在同一个页面上进行多处缓存，只要起不同的名字就行了。<br />3.“duration”<br />缓存内容的过期时间，以毫秒为单位。<br /><br />我们来看看petstore当中是如何应用的：<br />category.jsp<br />&lt;waf:cache name="page" scope="context" duration="300000"&gt;<br />**************缓存部分开始(body start)*************<br />&lt;jsp:useBean<br />  id="catalog"<br />  class="com.sun.j2ee.blueprints.catalog.client.CatalogHelper"<br />  scope="session"<br />/&gt;<br />&lt;c:choose&gt;<br />&lt;c:when test="${param.count != null}"&gt;<br />  &lt;c:set value="${param.start}" target="${catalog}" property="start"/&gt;<br />...<br />&lt;table border="0"<br />       width="100%"<br />...<br />**************缓存部分结束(body end)*************<br />&lt;/waf:cache&gt;<br /><br />  前面提到过这个页面将显示指定分类的所有产品信息，属于列表页面并对对于列表部分的内容进行了缓存，给它起了个名字” page”，范围是” context”整个应用，过期时间是5分钟。<br /><br />那么这个神奇的标签到底干了什么呢？我们看下一部分。<br />CacheTag实现类<br />  查看jsp的taglib引用，我们找到/WEB-INF/waftags.tld文件，里面定义了waf标签库中的cache标签的实现类是CacheTag。这是一个标准tag实现类，继承自BodyTagSupport，说明这个tag类要对标签包括的内容进行操作(缓存)。<br />查看这个类的源代码(WAF是提供源代码的)：<br />1.缓存池<br />  WAF直接使用了jsp提供的内存对象当做不同要求的缓存池，如下：<br />ServletContext 、Session、Request、page，我想这些对象大家再熟悉不过了，可以通过jsp提供给我们的PageContext对象得到这些对象。<br />看看源码实现，这里是获取提供缓存的jsp对象：<br />if ("context".equals(scope)) {<br />  return (Entry)pageContext.getServletContext().getAttribute(key);<br />} else if ("session".equals(scope)) {<br />  return (Entry)pageContext.getSession().getAttribute(key);<br />} else if ("request".equals(scope)) {<br />return (Entry)pageContext.getRequest().getAttribute(key);<br />} else if ("page".equals(scope)) {<br />  return (Entry)pageContext.getAttribute(key);<br />}<br />  缓存池是对页面某一部分的内容进行缓存，因此被缓存信息的主键由以下几个部分构成，包括当前页面的访问url，url后面跟着的参数(?以后的部分)，缓存部分的名称(页面中name属性定义)。<br /><br />源码中是这样写的：<br />req.getRequestURL().toString() + '#' + name + '?' + req.getQueryString()<br /><br />2.doStartTag()方法(可以在J2EE的api文档里面查看这些方法的定义)<br />方法被调用时相应的属性已经被附过值，此时表示标签开始执行，下面对其源码进行分析：<br />// 根据我们定义的缓存范围查找当前缓存部分<br />entry = getEntry();<br />//是否已经存在并且尚未过期<br />    if ((entry != null) &amp;&amp; entry.isExpired()) {<br />      entry = null;<br />//过期则从缓存中删除<br />      removeEntry();<br />}<br />//如果缓存不存在或者过期返回EVAL_BODY_BUFFERED表示要重新对tag包含的缓存部分进行处理(由jsp对象完成)；如果缓存内容已经存在则不必再进行处理<br />return (entry == null) ? EVAL_BODY_BUFFERED : SKIP_BODY;<br /><br />3.doEndTag()<br />  doStartTag执行完成后执行，此时body部分应当已经被处理过(除非已经进行了缓存，总之tag已经得到了body部分返回给客户端的数据)，下面看源码：<br /><br />//没有被缓存或者已过期<br />if (entry == null) {<br />//得到钢材解析过的body部分内容<br />BodyContent bc = getBodyContent();<br />    if (bc != null) {<br />      String content = bc.getString();<br />//新建一个缓存对象<br />      entry = new Entry(content, duration);<br />//根据设定的缓存范围进行缓存<br />        if ("context".equals(scope)) {<br />          pageContext.getServletContext().setAttribute(getKey(), entry);<br />        }else if ("session".equals(scope)) {<br />                pageContext.getSession().setAttribute(getKey(), entry);<br />        } else if ("request".equals(scope)) {<br />          pageContext.getRequest().setAttribute(getKey(), entry);<br />        } else if ("page".equals(scope)) {<br />          pageContext.setAttribute(getKey(), entry);<br />        }<br />//输出到页面<br />        try {<br />           JspWriter out = bc.getEnclosingWriter();<br />           out.print(content);<br />           }<br />           catch (IOException ioe) {<br />           System.err.println("ChacheTag: Problems with writing...");<br />           }<br />           }<br />        } else {  //如果已经缓存过直接输出到页面<br />            try {<br />                JspWriter out = pageContext.getOut();<br />                out.print(entry.getContent());<br />            } catch (IOException ioe) {<br />                System.err.println("CacheTag: Problems with writing...");<br />            }<br />        }<br /><br />  &lt;waf:cache&gt;实际就是将其body部分的内容(静态内容)当做字符串存到内存里，用的时候再取。<br />  好了工作原理到这里讲完了，怎么样还不赶快动手把它应用到你的项目里！^_^<br />  别忘了在web.xml里面声明jsp tag的定义文件啊！<br /><img src ="http://www.blogjava.net/TrampEagle/aggbug/49411.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-06-01 09:47 <a href="http://www.blogjava.net/TrampEagle/articles/49411.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 用缓冲技术提高JSP应用的性能和稳定性</title><link>http://www.blogjava.net/TrampEagle/articles/49339.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Wed, 31 May 2006 14:00:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/49339.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/49339.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/49339.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/49339.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/49339.html</trackback:ping><description><![CDATA[用缓冲技术提高JSP应用的性能和稳定性<br />原文引自：<a href="http://www.3doing.net/forums/dispbbs.asp?boardID=57&amp;ID=591&amp;page=1">http://www.3doing.net/forums/dispbbs.asp?boardID=57&amp;ID=591&amp;page=1</a><br /><br /><h3><b>一、概述</b></h3><p>在Web应用中，有些报表的生成可能需要数据库花很长时间才能计算出来；有的网站提供天气信息，它需要访问远程服务器进行SOAP调用才能得到温度信息。所有这一切都属于复杂信息的例子。在Web页面中加入过多的复杂信息可能导致Web服务器、数据库服务器负荷过重。JSP代码块缓冲为开发者带来了随意地增加各种复杂信息的自由。</p><p>JSP能够在标记库内封装和运行复杂的Java代码，它使得JSP页面文件更容易维护，使得非专业开发人员使用JSP页面文件更加方便。现在已经有许多标记库，它们或者是商业产品，或者是源代码开放产品。但这些产品中的大多数都只是用标记库的形式实现原本可以用一个简单的Java Scriptlet实现的功能，很少有产品以某种创造性的方式使用定制标记，提供在出现JSP定制标记库之前几乎不可能实现的用法。</p><p>OSCache标记库由<a href="http://www.opensymphony.com/oscache/" target="_blank"><font color="#000000">OpenSymphony</font></a>设计，它是一种开创性的JSP定制标记应用，提供了在现有JSP页面之内实现快速内存缓冲的功能。虽然已经有一些供应商在提供各种形式的缓存产品，但是，它们都属于面向特定供应商的产品。OSCache能够在任何JSP 1.1兼容的服务器上运行，它不仅能够为所有用户缓冲现有JSP代码块，而且能够以用户为单位进行缓冲。OSCache还包含一些提高可伸缩性的高级特性，比如：缓冲到磁盘，可编程的缓冲刷新，异常控制，等等。另外，正如OpenSymphony的其他产品，OSCache的代码也在一个开放源代码许可协议之下免费发行。</p><p>本文以一个假想的拍卖网站设计过程为例，介绍OSCache的工作过程。这个假想的Web网站将包含：一个报告最近拍卖活动的管理页面；一个功能完整、带有各种宣传信息的主页；一个特殊的导航条，它包含了用户所有尚未成交的拍卖活动信息。</p><h3><b>二、管理页面</b></h3><p>拍卖网站包含一个管理报表，数据库服务器需要数秒时间才能创建这样一个报表。报表生成时间长这一点很重要，因为我们可能让多个管理员监视系统运行情况，同时又想避免管理员每次访问时都重新生成这个报表。为了实现这一点，我们将把整个页面封装到一个应用级的缓冲标记之内，这个缓冲标记每隔1小时刷新。其他供应商提供的一些产品也具有类似的功能，只是OSCache比它们做得更好。</p><p>为简单计，我们将不过多地关注格式问题。在编写管理页面时，我们首先把标记库声明加入到页面：</p><table bordercolor="#111111" cellspacing="0" cellpadding="5" width="80%" bgcolor="#e9e9e9" border="1"><tbody><tr><td class="code">&lt;%@ taglib uri="cachetags" prefix="cache" %&gt;</td></tr></tbody></table><p>接下来我们要用cache标记来包围整个页面。cache标记的默认缓冲时间是1小时。</p><table bordercolor="#111111" cellspacing="0" cellpadding="5" width="80%" bgcolor="#e9e9e9" border="1"><tbody><tr><td class="code">&lt;cache:cache&gt; .... 复杂的管理报表 .... &lt;/cache:cache&gt;</td></tr></tbody></table><p>现在管理页面已经被缓冲。如果管理员在页面生成后的一个小时之内再次访问同一页面，他看到的将是以前缓存的页面，不需要由数据库服务器再次生成这个报表。</p><h3><b>三、主页</b></h3><p>拍卖网站的主页显示网站活动情况，宣传那些即将结束的拍卖活动。我们希望显示出正在进行的拍卖活动数量，当前登录用户数量，在短期内就要结束的拍卖活动的清单，以及当前时间。这些信息有着不同的时间精确度要求。网站上的拍卖活动通常持续数天，因此我们可以把缓冲有效拍卖活动数量的时间定为6个小时。用户数量的变化显然要频繁一些，但这里我们将把这个数值每次缓冲15分钟。最后，我们希望页面中显示的当前时间总是精确的页面访问时间。</p><p>在主页中声明标记库之后，我们首先以不带缓冲的方式直接输出当前日期：</p><table bordercolor="#111111" cellspacing="0" cellpadding="5" width="80%" bgcolor="#e9e9e9" border="1"><tbody><tr><td class="code">现在是：&lt;%=new java.util.Date()%&gt;</td></tr></tbody></table><p>接下来，我们要显示一个清单，列出那些将在短期内结束的拍卖活动：</p><table bordercolor="#111111" cellspacing="0" cellpadding="5" width="80%" bgcolor="#e9e9e9" border="1"><tbody><tr><td class="code">&lt;cache:cache&gt; &lt;ul&gt; &lt;% // 构造一个包含最近拍卖活动的Iterator Iterator auctions = .... while (auctions.hasMore()) { Auction auction = (Auction)auctions.next(); %&gt;&lt;li&gt;&lt;%=auction%&gt;&lt;/li%&lt; } %&gt; &lt;/ul&gt; &lt;/cache:cache&gt;</td></tr></tbody></table><p>最后，我们希望显示出正在进行的拍卖活动的数量，这个数字需要缓冲6小时。由于cache标记需要的是缓冲数据的秒数，我们把6小时转换成21600秒：</p><table bordercolor="#111111" cellspacing="0" cellpadding="5" width="80%" bgcolor="#e9e9e9" border="1"><tbody><tr><td class="code">&lt;cache:cache time="21600"&gt; &lt;% //查询数据库得到拍卖活动总数 int auctionCount = .... %&gt; 本网站正在进行的拍卖活动有&lt;%=auctionCount%&gt;个! &lt;/cache&gt;</td></tr></tbody></table><p>可以看到，我们只用少量的代码就构造出了一个带有复杂缓冲系统的主页。这个缓冲系统对页面各个部分分别进行缓冲，而且各个部分的缓冲时间完全符合它们各自的信息变化频繁程度。由于有了缓冲，现在我们可以在主页中放入更多的内容；而在以前没有缓冲的情况下，主页中放入过多的内容会导致页面访问速度变慢，甚至可能给数据库服务器带来过重的负载。</p><h3><b>四、导航条</b></h3><p>假设在规划网站的时候，我们决定在左边导航条的下方显示购物车内容。我们将显示出用户所拍卖的每一种商品的出价次数和当前报价，以及所有那些当前用户出价最高的商品的清单。</p><p>我们利用会话级的缓冲能力在导航条中构造上述功能。把下面的代码放入模板或者包含文件，以便网站中的其他页面引用这个导航条：</p><table bordercolor="#111111" cellspacing="0" cellpadding="5" width="80%" bgcolor="#e9e9e9" border="1"><tbody><tr><td class="code">&lt;cache:cache key="navbar" scope="session" time="300"&gt; &lt;% //提取并显示当前的出价信息 %&gt; &lt;/cache:cache&gt;</td></tr></tbody></table><p>在这里我们引入了两个重要的属性，即key和scope。在本文前面的代码中，由于cache标记能够自动为代码块创建唯一的key，所以我们不需要手工设置这个key属性。但在这里，我们想要从网站的其余部分引用这个被缓冲的代码块，因此我们显式定义了该cache标记的key属性。第二，scope属性用来告诉cache标记当前代码块必须以用户为单位缓冲，而不是为所有用户缓冲一次。</p><p>在使用会话级缓冲时应该非常小心，应该清楚：虽然我们可以让复杂的导航条减少5倍或10倍的服务器负载，但它将极大地增加每个会话所需要的内存空间。在CPU能力方面增加可能的并发用户数量无疑很理想，但是，一旦在内存支持能力方面让并发用户数量降低到了CPU的限制之下，这个方案就不再理想。</p><p>正如本文前面所提到的，我们希望从网站的其余部分引用这个缓冲的代码块。这是因为，当一个用户增加了一个供拍卖的商品、或者出价竞购其他用户拍卖的商品时，我们希望刷新缓冲，使得导航条下一次被读取时具有最新的内容。虽然这些数据可能因为其他用户的活动而改变，但如果用户在网站上执行某个动作之后看到自己的清单仍未改变，他可能会感到非常困惑。</p><p>OSCache库提供的flush标记能够刷新缓冲内容。我们可以把下面的代码加入到处理用户动作且可能影响这一区域的页面之中：</p><table bordercolor="#111111" cellspacing="0" cellpadding="5" width="80%" bgcolor="#e9e9e9" border="1"><tbody><tr><td class="code">&lt;cache:flush key="navbar" scope="session" /&gt;</td></tr></tbody></table><p>当用户下次访问它时，navbar缓冲块将被刷新。</p><p>至此为止，我们这个示例网站的构造工作已经完成且可以开始运行。下面我们来看看OSCache的异常处理能力。即使缓冲的内容已经作废，比如在缓冲块内出现了Java异常，OSCache标记库仍旧允许我们用编程的方法显示这些内容。有了这种异常控制功能，我们可以拆除数据库服务器和Web服务器之间的连接，而网站仍能够继续运行。JSP 1.2规范引入了TryCatchFinally接口，这个接口允许标记本身检测和处理Java异常。因此，标记可以结合这种异常处理代码，使得JSP页面更简单、更富有条理。</p><p>OpenSymphony正在计划实现其他的缓冲机制以及一个可管理性更好的主系统，它将使我们能够对缓冲使用的RAM和磁盘空间进行管理。一旦有了这些功能，我们就能够进一步提高网站的响应速度和可*性。</p><p><font color="#008080">【结束语】</font>OSCache能够帮助我们构造出更丰富多彩、具有更高性能的网站。有了OSCache标记库的帮助，现在我们能够用它解决一些影响网站响应能力的问题，比如访问量高峰期、数据库服务器负荷过重等。</p><img src ="http://www.blogjava.net/TrampEagle/aggbug/49339.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-05-31 22:00 <a href="http://www.blogjava.net/TrampEagle/articles/49339.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用javascript放大图片局部</title><link>http://www.blogjava.net/TrampEagle/articles/49284.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Wed, 31 May 2006 08:19:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/49284.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/49284.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/49284.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/49284.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/49284.html</trackback:ping><description><![CDATA[原文引自：<a href="http://blog.donews.com/lveyo/archive/2006/03/15/769093.aspx">http://blog.donews.com/lveyo/archive/2006/03/15/769093.aspx</a><br /><br /><p>&lt;html&gt;<br />&lt;head&gt;<br />&lt;title&gt;emu&lt;/title&gt;<br />&lt;/head&gt;<br />&lt;body&gt;<br />&lt;BR&gt;<br />&lt;BR&gt;<br />&lt;img src="<a href="http://img.pconline.com.cn/images/photo2/839980/1118509777696.JPG" _fcksavedurl="http://img.pconline.com.cn/images/photo2/839980/1118509777696.JPG">http://img.pconline.com.cn/images/photo2/839980/1118509777696.JPG</a>" onmousemove="zoom()" id=srcImg&gt;<br />&lt;BR&gt;<br />&lt;BR&gt;<br />&lt;div style="overflow:hidden"&gt;&lt;img id=zoomImg&gt;&lt;/div&gt;</p><p>&lt;SCRIPT LANGUAGE="JavaScript"&gt;<br />&lt;!--<br />zoomImg.src = srcImg.src;<br />srcImg.height = srcImg.height/2;<br />var zoomRate = 5;<br />zoomImg.height = srcImg.height*zoomRate;<br />zoomImg.parentNode.style.width = srcImg.width;<br />zoomImg.parentNode.style.height = srcImg.height;<br />function zoom(){<br />var elm = event.srcElement;<br />h = elm.offsetHeight/zoomRate/2;<br />w = elm.offsetWidth/zoomRate/2;<br />var x = event.x-elm.offsetLeft;<br />x=x&lt;(elm.offsetWidth-w)?x&lt;w?w:x:elm.offsetWidth-w;<br />zoomImg.style.marginLeft=(w-x)*zoomRate;<br />var y = event.y-elm.offsetTop;<br />y=y&lt;(elm.offsetHeight-h)?y&lt;h?h:y:elm.offsetHeight-h;<br />zoomImg.style.marginTop=(h-y)*zoomRate;<br />}<br />//--&gt;<br />&lt;/SCRIPT&gt;<br />&lt;/body&gt;<br />&lt;/html&gt;</p><br /><br /><p id="TBPingURL">Trackback: http://tb.donews.net/TrackBack.aspx?PostId=769093</p><img src ="http://www.blogjava.net/TrampEagle/aggbug/49284.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-05-31 16:19 <a href="http://www.blogjava.net/TrampEagle/articles/49284.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源项目论坛 mvnForum 安装简介</title><link>http://www.blogjava.net/TrampEagle/articles/48982.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Tue, 30 May 2006 06:25:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/48982.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/48982.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/48982.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/48982.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/48982.html</trackback:ping><description><![CDATA[引自：<a href="http://www.3doing.net/forums/dispbbs.asp?boardID=57&amp;ID=232&amp;page=2">http://www.3doing.net/forums/dispbbs.asp?boardID=57&amp;ID=232&amp;page=2</a><br /><br />于 Java 开发的论坛，最有名的当属 Jive ，国产的 Jute 也很不错。好是好，但需要花费银子才能用。对于企业，应该考虑使用Jute，因为其提高良好的技术支持。对于个人，或许就不值得了。这里推荐开源项目 mvnForum， 基于 J2EE technology (Jsp/Servlet). <br /><br /><b>mvnFourm</b> is free, opensource and released under the terms of the GNU General Public License. It means that you could use it free of charge to build your own discussion communities. <br /><br /><p>一、简介</p><table cellspacing="1" cellpadding="4" border="0"><tbody><tr><td>mvnForum 基于Jsp/Servlet开发，支持Jsp 1.2 和 Servlet 2.3，安装和使用都非常简单。</td></tr><tr><td><ul><p><b>主要特征:</b><br /></p><li>基于 MVC 架构 <br /></li><li>内建数据库连接池 <br /></li><li>多种数据库 (DB2, MySQL, Oracle 8i/9i, Sql Server, postgreSQL, hsqldb, Interbase/Firebird, SAPDB) <br /></li><li>国际化 (支持14种语言: English, 简体, 繁体等等) <br /></li><li>Jakarta Common Logging </li></ul><a href="http://www.mvnforum.com/mvnforumweb/feature.jsp" target="_blank"><font color="#000000">这里可以查看论坛功能和全部特征。</font></a></td></tr></tbody></table><p>二、安装环境</p><table cellspacing="1" cellpadding="4" width="100%" border="1"><tbody><tr><td></td><td>参考</td></tr><tr><td>服务器：tomcat 4.1.27</td><td>http://jakarta.apache.org/tomcat/index.html</td></tr><tr><td>数据库：PostgreSQL 7.3.3</td><td>http://www.postgresql.org</td></tr></tbody></table><p>三、安装</p><table cellspacing="1" cellpadding="8"><tbody><tr><td>1、下载<a href="http://www.mvnforum.com/download/mvnforum-1.0.0-rc1.zip" target="_blank"><font color="#000000">mvnForum 1.0.0 RC 1</font></a>，如果需要源码，可以下载<a href="http://www.mvnforum.com/download/mvnforum-1.0.0-rc1-src.zip" target="_blank"><font color="#000000">mvnForum 1.0.0 RC 1 Source</font></a></td></tr><tr><td>2、将mvnforum-1.0.0-rc1.zip截压缩到mvnforum-1.0.0-rc1目录。把mvnforum-1.0.0-rc1/webapp目录复制到tomcat/webapps/目录下，然后将webapp改名为mvnforum（可根据需要改成任意的名称）。接着把mvnforum-1.0.0-rc1/driver/postgresql.jar复制到tomcat/webapps/mvnforum/WEB-INF/lib/目录下。</td></tr><tr><td>3、建立论坛数据库表。首先在PostgreSQL创建一数据库mvnForum,执行命令如下：<br />CREATEDB -E unicode mvnForum<br />接着执行mvnforum-1.0.0-rc1/sql/mvnForum_postgresql.sql文件，创建表，执行命令如下：<br />#psql mvnForum<br />mvnForum=#\i mvnForum_postgresql.sql</td></tr><tr><td>4、修改tomcat/webapps/mvnforum/WEB-INF/class/mvncore_db_DBOptions.properties文件，这个文件配置与数据库相关的资料。设置内容如下：<br />DRIVER_CLASS_NAME = org.postgresql.Driver<br />DATABASE_URL = jdbc:postgresql://192.168.0.10:5432/mvnForum<br />DATABASE_USER = postgres<br />DATABASE_PASSWORD = <br /></td></tr><tr><td>5、基本安装完成，启动Tomcat，通过<a href="http://localhost:8080/mvnforum/index.jsp就可以访问论坛了。" target="_blank"><font color="#000000">http://localhost:8080/mvnforum/index.jsp就可以访问论坛了。 </font></a></td></tr><tr><td>6、管理员管理，<a href="http://localhost:8080/mvnforum/mvnforumadmin/index。用户名和密码都是admin，管理员登陆后可以增加版面和管理用户了。" target="_blank"><font color="#000000">http://localhost:8080/mvnforum/mvnforumadmin/index。用户名和密码都是admin，管理员登陆后可以增加版面和管理用户了。 </font></a></td></tr></tbody></table><a href="http://www.mvnforum.com/mvnforumweb/index.jsp" target="_blank"><font color="#000000">http://www.mvnforum.com/mvnforumweb/index.jsp</font></a><img src ="http://www.blogjava.net/TrampEagle/aggbug/48982.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-05-30 14:25 <a href="http://www.blogjava.net/TrampEagle/articles/48982.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP内建对象</title><link>http://www.blogjava.net/TrampEagle/articles/46595.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Wed, 17 May 2006 03:46:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/46595.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/46595.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/46595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/46595.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/46595.html</trackback:ping><description><![CDATA[
		<div class="postcontent">JSP内建对象- -                                       
<p></p><p><font face="Courier New"><strong>① out - javax.servlet.jsp.jspWriter</strong><br />   out对象用于把结果输出到网页上。</font></p><p><font face="Courier New">方法：<br />1. void clear() ;<br />   清除输出缓冲区的内容，但是不输出到客户端。</font></p><p><font face="Courier New">2. void clearBuffer() ;<br />   清除输出缓冲区的内容，并输出到客户端。</font></p><p><font face="Courier New">3. void close() ;<br />   关闭输出流，清除所有内容。</font></p><p><font face="Courier New">4. void flush() ;<br />   输出缓冲区里面的数据。</font></p><p><font face="Courier New">5. int getBufferSize() ;<br />   获取以kb为单位的目前缓冲区大小。</font></p><p><font face="Courier New">6. int getRemaining() ;<br />   获取以kb为单位的缓冲区中未被占用的空间大小。</font></p><p><font face="Courier New">7. boolean isAutoFlush() ;<br />   是否自动刷新缓冲区。</font></p><p><font face="Courier New">8. void newLine() ;<br />   输出一个换行字符。</font></p><p><font face="Courier New">9. void print( boolean b ) ;<br />   void print( char c ) ;<br />   void print( char[] s ) ;<br />   void print( double d ) ;<br />   void print( float f ) ;<br />   void print( int i ) ;<br />   void print( long l ) ;<br />   void print( Object obj ) ;<br />   void print( String s ) ;<br />   将指定类型的数据输出到Http流，不换行。</font></p><p><font face="Courier New">10. void println( boolean b ) ;<br />    void println( char c ) ;<br />    void println( char[] s ) ;<br />    void println( double d ) ;<br />    void println( float f ) ;<br />    void println( int i ) ;<br />    void println( long l ) ;<br />    void println( Object obj ) ;<br />    void println( String s ) ;<br />    将指定类型的数据输出到Http流，并输出一个换行符。<br />    <br />11. Appendable append( char c ) ;<br />    Appendable append( CharSequence cxq, int start, int end ) ;<br />    Appendable append( CharSequence cxq ) ;<br />    将一个字符或者实现了CharSequence接口的对象添加到输出流的后面。</font></p><p><font face="Courier New">成员：<br />int DEFAULT_BUFFER = 0    - 缺省缓冲区大小<br />int NO_BUFFER = -1        - writer是否处于缓冲输出状态<br />int UNBOUNDED_BUFFER = -2 - 是否限制缓冲区大小</font></p><p><br /><font face="Courier New"><strong>② request - javax.servlet.http.HttpServletRequest<br /></strong>   request对象包含所有请求的信息，如请求的来源、标头、cookies和请求相关的参数值等。</font></p><p><font face="Courier New">方法：<br />1. Object getAttribute( String name ) ;<br />   返回由name指定的属性值，该属性不存在时返回null。</font></p><p><font face="Courier New">2. Enumeration getAttributeNames() ;<br />   返回request对象的所有属性名称的集合。</font></p><p><font face="Courier New">3. String getAuthType() ;<br />   返回用来保护servlet的认证方法的名称，未受保护时返回null。</font></p><p><font face="Courier New">4. String getCharacterEncoding() ;<br />   返回请求中的字符编码方法，可以在response对象中设置。</font></p><p><font face="Courier New">5. int getContentLength() ;<br />   返回请求的BODY的长度，不能确定长度时返回-1。可以在response中设置。</font></p><p><font face="Courier New">6. String getContentType() ;<br />   返回在response中定义的内容类型。</font></p><p><font face="Courier New">7. String getContentPath() ;<br />   返回请求的路径。</font></p><p><font face="Courier New">8. Cookie[] getCookies() ;<br />   返回客户端所有的Cookie的数组。</font></p><p><font face="Courier New">9. Enumeration getHeaderNames() ;<br />   返回所有HTTP头的名称的集合。</font></p><p><font face="Courier New">10. Enumeration getHeaders( String name ) ;<br />    返回指定HTTP头的所有值的集合。</font></p><p><font face="Courier New">11. String getHeader( String name ) ;<br />    返回指定名称的HTTP头的信息。</font></p><p><font face="Courier New">12. long getDateHeader( String name ) ;<br />    返回指定名称的Data类型的HTTP头的信息。</font></p><p><font face="Courier New">13. int getIntHeader( String name ) ;<br />    返回指定名称的Int类型的HTTP头的信息。</font></p><p><font face="Courier New">14. ServletInputStream getInputStream() ;<br />    返回请求的输入流。</font></p><p><font face="Courier New">15. Locale getLocale() ;<br />    返回当前页的Locale对象，可以在response中设定。</font></p><p><font face="Courier New">16. Enumeration getLocales() ;<br />    返回请求中所有的Locale对象的集合。</font></p><p><font face="Courier New">17. String getLocalName() ;<br />    获取响应请求的服务器端主机名。</font></p><p><font face="Courier New">18. String getLocalAddr() ;<br />    获取响应请求的服务器端地址。</font></p><p><font face="Courier New">19. int getLocalPort() ;<br />    获取响应请求的服务器端端口</font></p><p><font face="Courier New">20. String getMethod() ;<br />    获取客户端向服务器端发送请求的方法(GET、POST)。</font></p><p><font face="Courier New">21. String getParameter( String name ) ;<br />    获取客户端发送给服务器端的参数值。</font></p><p><font face="Courier New">22. Map getParameterMap() ;<br />    该方法返回包含请求中所有参数的一个Map对象。</font></p><p><font face="Courier New">23. Enumeration getParameterNames() ;<br />    返回请求中所有参数的集合。</font></p><p><font face="Courier New">24. String[] getParameterValues( String name ) ;<br />    获得请求中指定参数的所有值。</font></p><p><font face="Courier New">25. String getQueryString() ;<br />    返回get方法传递的参数字符串，该方法不分解出单独的参数。</font></p><p><font face="Courier New">26. String getPathInfo() ;<br />    取出请求中处于ServletPath和QueryString之间的额外信息。</font></p><p><font face="Courier New">27. String getPathTranslated() ;<br />    返回用getPathInfo()方法取得的路径信息的实际路径。</font></p><p><font face="Courier New">28. String getProtocol() ;<br />    返回请求使用的协议。可以是HTTP1.1或者HTTP1.0。</font></p><p><font face="Courier New">29. BufferedReader getReader() ;<br />    返回请求的输入流对应的Reader对象，该方法和getInputStream()方法在一个页面中只能调用一个。</font></p><p><font face="Courier New">30. String getRemoteAddr() ;<br />    获取发出请求的客户端IP地址。</font></p><p><font face="Courier New">31. String getRemoteHost() ;<br />    获取发出请求的客户端主机名</font></p><p><font face="Courier New">32. String getRemoteUser() ;<br />    返回经过客户端验证的用户名，未经验证返回null。</font></p><p><font face="Courier New">33. int getRemotePort() ;<br />    返回发出请求的客户端主机端口。</font></p><p><font face="Courier New">34. String getRealPath( String path ) ;<br />    返回给定虚拟路径的物理路径。</font></p><p><font face="Courier New">35. RequestDispatcher getRequestDispatcher( String path ) ;<br />    按给定的路径生成资源转向处理适配器对象。</font></p><p><font face="Courier New">36. String getRequestedSessionId() ;<br />    返回请求的session的标识。</font></p><p><font face="Courier New">37. String RequestURI() ;<br />    返回发出请求的客户端地址，但是不包括请求的参数字符串。</font></p><p><font face="Courier New">38. StringBuffer getRequestURI() ;<br />    返回响应请求的服务器端地址</font></p><p><font face="Courier New">39. String getScheme() ;<br />    获取协议名称，缺省值为HTTP协议。</font></p><p><font face="Courier New">40. String getServerName() ;<br />    返回响应请求的服务器名称。</font></p><p><font face="Courier New">41. String getServletPath() ;<br />    获取客户端所请求的脚本文件的文件路径。</font></p><p><font face="Courier New">42. int getServerPort() ;<br />    获取响应请求的服务器端主机端口号。</font></p><p><font face="Courier New">43. void removeAttribute( String name ) ;<br />    在属性列表中删除指定名称的属性。</font></p><p><font face="Courier New">44. void setAttribute( String name, Object value ) ;<br />    在属性列表中添加/删除指定的属性。</font></p><p><font face="Courier New">45. void setCharacterEncoding( String name ) ;<br />    设置请求的字符编码格式。</font></p><p><font face="Courier New">46. HttpSession getSession() ;<br />    HttpSession getSession( boolean create ) ;<br />    获取session，如果create为true，在无session的情况下创建一个。<br />    <br />47. boolean isRequestedSessionIdFromCookie() ;<br />    检查请求的会话ID是否为通过Cookie传入。</font></p><p><font face="Courier New">48. boolean isRequestedSessionIdFromURL() ;<br />    检查请求的会话ID是否为通过URL传入。</font></p><p><font face="Courier New">49. boolean isRequestedSessionIdValid() ;<br />    检查请求的会话ID是否仍然有效。</font></p><p><font face="Courier New">50. boolean isSecure() ;<br />    检查请求是否使用安全链接，如果HTTPS等。</font></p><p><font face="Courier New">51. boolean isUserInRole( String role ) ;<br />    检查已经通过验证的用户是否在是role所指定的角色。</font></p><p><font face="Courier New">52. Principal getUserPrincipal() ;<br />    返回包含用户登陆名的一个java.security.Principal对象。</font></p><p><font face="Courier New">成员：<br />String BASIC_AUTH = "BASIC"             - <br />String CLIENT_CERT_AUTH = "CLIENT_CERT" - <br />String DIGEST_AUTH = "DIGEST"           - <br />String FORM_AUTH = "FORM"               - </font></p><p><br /><font face="Courier New"><strong>③ response - javax.servlet.http.HttpServletResponse</strong><br />   response对象主要将JSP容器处理后的结果传回到客户端。</font></p><p><font face="Courier New">方法：<br />1. void addCookie( Cookie cookie ) ;<br />   添加一个Cookie对象，保存客户端信息。</font></p><p><font face="Courier New">2. void addDateHeader( String name, long value ) ;<br />   添加一个日期类型的HTTP头信息，覆盖同名的HTTP头信息。</font></p><p><font face="Courier New">3. void addHeader( String name, String value ) ;<br />   添加一个HTTP头，覆盖同名的旧HTTP头。</font></p><p><font face="Courier New">4. void addIntHeader( String name, int value ) ;<br />   添加一个整型的HTTP头，覆盖同名的旧HTTP头。</font></p><p><font face="Courier New">5. boolean containsHeader( String name ) ;<br />   判断指定的HTTP头是否存在。</font></p><p><font face="Courier New">6. String encodeRedirectURL( String url ) ;<br />   对sendRedirect()方法使用的URL进行编码。</font></p><p><font face="Courier New">7. String encodeURL( String url ) ;<br />   将URL予以编码，回传包含session ID的URL。<br />   <br />8. void flushBuffer() ;<br />   强制把当前缓冲区的内容发送到客户端。</font></p><p><font face="Courier New">9. int getBufferSize() ;<br />   取得以kb为单位的缓冲区大小。</font></p><p><font face="Courier New">10. String getCharacterEncoding() ;<br />    获取响应的字符编码格式。</font></p><p><font face="Courier New">11. String getContentType() ;<br />    获取响应的类型。</font></p><p><font face="Courier New">12. Locale getLocale() ;<br />    获取响应的Locale对象。</font></p><p><font face="Courier New">13. ServletOutputStream getOutputStream() ;<br />    返回客户端的输出流对象。</font></p><p><font face="Courier New">14. PrintWriter getWriter() ;<br />    获取输出流对应的writer对象。</font></p><p><font face="Courier New">15. boolean isCommitted() ;<br />    判断服务器端是否已经将数据输出到客户端。</font></p><p><font face="Courier New">16. void reset() ;<br />    清空buffer中的所有内容。</font></p><p><font face="Courier New">17. void resetBuffer() ;<br />    情况buffer中所有的内容，但是保留HTTP头和状态信息。</font></p><p><font face="Courier New">18. void sendError( int xc, String msg ) ;<br />    void sendError( int xc ) ;<br />    发送错误，包括状态码和错误信息。</font></p><p><font face="Courier New">19. void sendRedirect( String locationg ) ;<br />    把响应发送到另外一个位置进行处理。</font></p><p><font face="Courier New">20. void setBufferSize( int size ) ;<br />    设置以kb为单位的缓冲区大小。</font></p><p><font face="Courier New">21. void setCharacterEncoding( String charset ) ;<br />    设置响应使用的字符编码格式。</font></p><p><font face="Courier New">22. void setContentLength( int length ) ;<br />    设置响应的BODY长度。</font></p><p><font face="Courier New">23. void setContentType( String type ) ;<br />    设置响应的类型。</font></p><p><font face="Courier New">24. void setDateHeader( String name, long value ) ;<br />    设置指定名称的Data类型的HTTP头的值。</font></p><p><font face="Courier New">25. void setHeader( String name, String value ) ;<br />    设置指定名称的HTTP头的值。</font></p><p><font face="Courier New">26. void setIntHeader( String name, int value ) ;<br />    设置指定名称的int类型的HTTP头的值。</font></p><p><font face="Courier New">27. void setStatus( int xc ) ;<br />    设置响应状态码，新值会覆盖当前值。</font></p><p><font face="Courier New">成员(HTTP状态码)：<br />int SC_CONTINUE = 100                      int SC_SWITCHING_PROTOCOLS = 101<br />int SC_OK = 200                            int SC_NON_AUTHORITATIVE_INFORMATION = 203<br />int SC_ACCEPTED = 202                      int SC_CREATED = 201<br />int SC_NO_CONTENT = 204                    int SC_RESET_CONTENT = 205<br />int SC_PARTIAL_CONTENT = 206               int SC_MULTIPLE_CHOICES = 300<br />int SC_MOVED_PERMANENTLY = 301             int SC_MOVED_TEMPORARILY = 302<br />int SC_FOUND = 302                         int SC_SEE_OTHER = 303<br />int SC_NOT_MODIFIED = 304                  int SC_USE_PROXY = 305<br />int SC_TEMPORARY_REDIRECT = 307            int SC_BAD_REQUEST = 400<br />int SC_UNAUTHORIZED = 401                  int SC_PAYMENT_REQUIRED = 402<br />int SC_FORBIDDEN = 403                     int SC_NOT_FOUND = 404<br />int SC_METHOD_NOT_ALLOWED = 405            int SC_NOT_ACCEPTABLE = 406<br />int SC_PROXY_AUTHENTICATION_REQUIRED = 407 int SC_REQUEST_TIMEOUT = 408<br />int SC_CONFLICT = 409                      int SC_GONE = 410<br />int SC_LENGTH_REQUIRED = 411               int SC_PRECONDITION_FAILED = 412<br />int SC_REQUEST_ENTITY_TOO_LARGE = 413      int SC_REQUEST_URI_TOO_LONG = 414<br />int SC_UNSUPPORTED_MEDIA_TYPE = 415        int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416<br />int SC_EXPECTATION_FAILED = 417            int SC_INTERNAL_SERVER_ERROR = 500<br />int SC_NOT_IMPLEMENTED = 501               int SC_BAD_GATEWAY = 502<br />int SC_SERVICE_UNAVAILABLE = 503           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 />   session对象表示目前个别用户的会话状态，用来识别每个用户。</font></p><p><font face="Courier New">方法：<br />1. Object getAttribute( String name ) ;<br />   获取与指定名字相关联的session属性值。</font></p><p><font face="Courier New">2. Enumeration getAttributeNames() ;<br />   取得session内所有属性的集合。</font></p><p><font face="Courier New">3. long getCreationTime() ;<br />   返回session的创建时间，最小单位千分之一秒。</font></p><p><font face="Courier New">4. String getId() ;<br />   取得session标识。</font></p><p><font face="Courier New">5. long getLastAccessedTime() ;<br />   返回与当前session相关的客户端最后一次访问的时间，由1970-01-01算起，单位毫秒。</font></p><p><font face="Courier New">6. int getMaxInactiveInterval( int interval ) ;<br />   返回总时间，以秒为单位，表示session的有效时间(session不活动时间)。-1为永不过期。</font></p><p><font face="Courier New">7. ServletContext getServletContext() ;<br />   返回一个该JSP页面对应的ServletContext对象实例。</font></p><p><font face="Courier New">8. HttpSessionContext getSessionContext() ;<br />   </font></p><p><font face="Courier New">9. Object getValue( String name ) ;<br />   取得指定名称的session变量值，不推荐使用。</font></p><p><font face="Courier New">10. String[] getValueNames() ;<br />    取得所有session变量的名称的集合，不推荐使用。</font></p><p><font face="Courier New">11. void invalidate() ;<br />    销毁这个session对象。</font></p><p><font face="Courier New">12. boolean isNew() ;<br />    判断一个session是否由服务器产生，但是客户端并没有使用。</font></p><p><font face="Courier New">13. void pubValue( String name, Object value ) ;<br />    添加一个session变量，不推荐使用。</font></p><p><font face="Courier New">14. void removeValue( String name ) ;<br />    移除一个session变量的值，不推荐使用。</font></p><p><font face="Courier New">15. void setAttribute( String name, String value ) ;<br />    设置指定名称的session属性值。</font></p><p><font face="Courier New">16. void setMaxInactiveInterval( int interval ) ;<br />    设置session的有效期。</font></p><p><font face="Courier New">17. void removeAttribute( String name ) ;<br />    移除指定名称的session属性。</font></p><p><br /><font face="Courier New"><strong>⑤ pageContext - javax.servlet.jsp.PageContext</strong><br />   pageContext对象存储本JSP页面相关信息，如属性、内建对象等。</font></p><p><font face="Courier New">方法：<br />1. void setAttribute( String name, Object value, int scope ) ;<br />   void setAttribute( String name, Object value ) ;<br />   在指定的共享范围内设置属性。</font></p><p><font face="Courier New">2. Object getAttribute( String name, int scope ) ;<br />   Object getAttribute( String name ) ;<br />   取得指定共享范围内以name为名字的属性值。</font></p><p><font face="Courier New">3. Object findAttribute( String name ) ;<br />   按页面、请求、会话和应用程序共享范围搜索已命名的属性。</font></p><p><font face="Courier New">4. void removeAttribute( String name, int scope ) ;<br />   void removeAttribute( String name ) ;<br />   移除指定名称和共享范围的属性。</font></p><p><font face="Courier New">5. void forward( String url ) ;<br />   将页面导航到指定的URL。</font></p><p><font face="Courier New">6. Enumeration getAttributeNamesScope( int scope ) ;<br />   取得指定共享范围内的所有属性名称的集合。</font></p><p><font face="Courier New">7. int getAttributeScope( String name ) ;<br />   取得指定属性的共享范围。</font></p><p><font face="Courier New">8. ErrorData getErrorDate() ;<br />   取得页面的errorData对象。</font></p><p><font face="Courier New">9. Exception getException() ;<br />   取得页面的exception对象。</font></p><p><font face="Courier New">10. ExpressionEvaluator getExpressionEvaluator() ;<br />    取得页面的expressionEvaluator对象。</font></p><p><font face="Courier New">11. JspWriter getOut() ;<br />    取得页面的out对象。</font></p><p><font face="Courier New">12. Object getPage() ;<br />    取得页面的page对象。</font></p><p><font face="Courier New">13. ServletRequest getRequest() ;<br />    取得页面的request对象。</font></p><p><font face="Courier New">14. ServletResponse getResponse() ;<br />    取得页面的response对象。</font></p><p><font face="Courier New">15. ServletConfig getConfig() ;<br />    取得页面的config对象。</font></p><p><font face="Courier New">16. ServletContext getServletContext() ;<br />    取得页面的servletContext对象。</font></p><p><font face="Courier New">17. HttpSession getSession() ;<br />    取得页面的session对象。</font></p><p><font face="Courier New">18. VariableResolver getVariableResolver() ;<br />    取得页面的variableResolver对象。</font></p><p><font face="Courier New">19. void include( String url, boolean flush ) ;<br />    void include( String url ) ;<br />    包含其他的资源，并指定是否自动刷新。</font></p><p><font face="Courier New">20. void release() ;<br />    重置pageContext内部状态，释放所有内部引用。</font></p><p><font face="Courier New">21. void initialize( Servlet servlet, ServletRequest request, ServletResponse response,<br />                     String errorPageURL, boolean needSession, int bufferSize, boolean autoFlush ) ;<br />    初始化未经初始化的pageContext对象。</font></p><p><font face="Courier New">22. BodyContext pushBody() ;<br />    BodyContext pushBody( Writer writer ) ;<br />    保存当前的out对象，并更新pageContext中page范围内的out对象。</font></p><p><font face="Courier New">23. JspWrite popBody() ;<br />    取出由pushBody()方法保存的out对象。</font></p><p><font face="Courier New">24. void handlePageException( Exception e ) ;<br />    void handlePageException( Thrwoable t ) ;<br />    </font></p><p><font face="Courier New">成员：<br />int PAGE_SCOPE = 1        - 页面共享范围<br />int REQUEST_SCOPE = 2     - 请求共享范围<br />int SESSION_SCOPE = 3     - 会话共享范围<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 />   application主要功用在于取得或更改Servlet的设定。</font></p><p><font face="Courier New">方法：<br />1. Object getAttribute( String name ) ;<br />   返回由name指定的application属性。</font></p><p><font face="Courier New">2. Enumeration getAttributes() ;<br />   返回所有的application属性。</font></p><p><font face="Courier New">3. ServletContext getContext( String uripath ) ;<br />   取得当前应用的ServletContext对象。</font></p><p><font face="Courier New">4. String getInitParameter( String name ) ;<br />   返回由name指定的application属性的初始值。</font></p><p><font face="Courier New">5. Enumeration getInitParameters() ;<br />   返回所有的application属性的初始值的集合。</font></p><p><font face="Courier New">6. int getMajorVersion() ;<br />   返回servlet容器支持的Servlet API的版本号。</font></p><p><font face="Courier New">7. String getMimeType( String file ) ;<br />   返回指定文件的类型，未知类型返回null。一般为"text/html"和"image/gif"。</font></p><p><font face="Courier New">8. int getMinorVersion() ;<br />   返回servlet容器支持的Servlet API的副版本号。</font></p><p><font face="Courier New">9. String getRealPath( String path ) ;<br />   返回给定虚拟路径所对应物理路径。</font></p><p><font face="Courier New">10. RequestDispatcher getNamedDispatcher( String name ) ;<br />    为指定名字的Servlet对象返回一个RequestDispatcher对象的实例。</font></p><p><font face="Courier New">11. RequestDispatcher getRequestDispatcher( String path ) ;<br />    返回一个RequestDispatcher对象的实例。</font></p><p><font face="Courier New">12. URL getResource( String path ) ;<br />    返回指定的资源路径对应的一个URL对象实例，参数要以"/"开头。</font></p><p><font face="Courier New">13. InputStream getResourceAsStream( String path ) ;<br />    返回一个由path指定位置的资源的InputStream对象实例。</font></p><p><font face="Courier New">14. Set getResourcePaths( String path ) ;<br />    返回存储在web-app中所有资源路径的集合。</font></p><p><font face="Courier New">15. String getServerInfo() ;<br />    取得应用服务器版本信息。</font></p><p><font face="Courier New">16. Servlet getServlet( String name ) ;<br />    在ServletContext中检索指定名称的servlet。</font></p><p><font face="Courier New">17. Enumeration getServlets() ;<br />    返回ServletContext中所有servlet的集合。</font></p><p><font face="Courier New">18. String getServletContextName() ;<br />    返回本web应用的名称。</font></p><p><font face="Courier New">19. Enumeration getServletContextNames() ;<br />    返回ServletContext中所有servlet的名称集合。</font></p><p><font face="Courier New">20. void log( Exception ex, String msg ) ;<br />    void log( String msg, Throwable t ) ;<br />    void log( String msg ) ;<br />    把指定的信息写入servlet log文件。</font></p><p><font face="Courier New">21. void removeAttribute( String name ) ;<br />    移除指定名称的application属性。</font></p><p><font face="Courier New">22. void setAttribute( String name, Object value ) ;<br />    设定指定的application属性的值。</font></p><p><br /><font face="Courier New"><strong>⑦ config - javax.servlet.ServletConfig<br /></strong>   config对象用来存放Servlet初始的数据结构。</font></p><p><font face="Courier New">方法：<br />1. String getInitParameter( String name ) ;<br />   返回名称为name的促使参数的值。</font></p><p><font face="Courier New">2. Enumeration getInitParameters() ;<br />   返回这个JSP所有的促使参数的名称集合。</font></p><p><font face="Courier New">3. ServletContext getContext() ;<br />   返回执行者的servlet上下文。</font></p><p><font face="Courier New">4. String getServletName() ;<br />   返回servlet的名称。</font></p><p><br /><font face="Courier New"><strong>⑧ exception - java.lang.Throwable</strong><br />   错误对象，只有在JSP页面的page指令中指定isErrorPage="true"后，才可以在本页面使用exception对象。</font></p><p><font face="Courier New">方法：<br />1. Throwable fillInStackTrace() ;<br />   将当前stack信息记录到exception对象中。</font></p><p><font face="Courier New">2. String getLocalizedMessage() ;<br />   取得本地语系的错误提示信息。</font></p><p><font face="Courier New">3. String getMessage()<br />   取得错误提示信息。</font></p><p><font face="Courier New">4. StackTrackElement[] getStackTrace() ;<br />   返回对象中记录的call stack track信息。</font></p><p><font face="Courier New">5. Throwable initCause( Throwable cause ) ;<br />   将另外一个异常对象嵌套进当前异常对象中。<br />   <br />6. Throwable getCause() ;<br />   取出嵌套在当前异常对象中的异常。</font></p><p><font face="Courier New">7. void printStackTrace() ;<br />   void printStackTrace( printStream s ) ;<br />   void printStackTrace( printWriter s ) ;<br />   打印出Throwable及其call stack trace信息。</font></p><p><font face="Courier New">8. void setStackTrace( StackTraceElement[] stackTrace )<br />   设置对象的call stack trace信息。</font></p><p><br /><font face="Courier New"><strong>⑨ page - javax.servlet.jsp.HttpJspPage</strong><br />   page对象代表JSP对象本身，或者说代表编译后的servlet对象，<br />   可以用( (javax.servlet.jsp.HttpJspPage)page )来取用它的方法和属性。</font></p></div>
<img src ="http://www.blogjava.net/TrampEagle/aggbug/46595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-05-17 11:46 <a href="http://www.blogjava.net/TrampEagle/articles/46595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSTL 入门,第4部分: 访问SQL和XML内容</title><link>http://www.blogjava.net/TrampEagle/articles/46373.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Tue, 16 May 2006 04:40:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/46373.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/46373.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/46373.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/46373.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/46373.html</trackback:ping><description><![CDATA[原文引自：<a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/index.html">http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/index.html</a><br /><br /><br /><blockquote>Web应用程序的标志是多个子系统的集成。SQL和XML是在这类子系统之间交换数据的两种最通用的机制。在本文中，Mark Kolb介绍访问JSP页面数据库和XML内容的sql和xml库并对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>Web应用程序的模板式（stereotypical）架构分为三层：处理请求的Web服务器、实施业务逻辑的应用程序服务器以及管理永久性数据的数据库。应用程序和数据库层之间的联接通常采用关系数据库中的SQL调用格式。当业务逻辑被写入到Java语言中时，JDBC用于实现这些调用。 </p><p>如果应用程序调用与其它服务器(本地或远程)的集成，我们将需要用于在不同子系统之间交换数据的更深层次的机制。在Web应用程序内部和应用程序之间传送数据采用的越来越普遍的一种方法是XML文件的交换。 </p><p>迄今为止，在我们的JSTL之旅中，我们讨论了JSTL <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0211/"><font color="#5c81a7">表达式语言（expression language</font></a>，EL）和 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/"><font color="#5c81a7">core</font></a>和 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/"><font color="#5c81a7">fmt</font></a>标记库。在最后一部分，我们将考虑sql和xml库--正如它们的名字表示的一样 -- 提供定制标记来接入和管理从SQL数据库和XML文件检索到的数据。 </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="IDA4CQ3E"><b>不要遗漏本系列的其它部分</b></a><br /><p>第1部分,“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0211/"><font color="#5c81a7">表达式语言</font></a>” (2003年2月) </p><p>第2部分，“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/"><font color="#5c81a7">探讨核心</font></a>”(2003年3月) </p><p>第3部分，“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/"><font color="#5c81a7">表示就是一切（Presentation is everything</font></a>）” (2003年4月) </p></td></tr></tbody></table></td></tr></tbody></table><p><a name="1"><span class="atitle"><font face="Arial" size="4">xml库</font></span></a></p><p>根据设计，XML提供灵活的方式来表示结构化数据，这些数据同时准备进行验证，因此它尤其适应于在松散联合的系统之间交换数据。这反过来使其成为Web应用程序极具吸引力的集成技术。 </p><p>与使用XML表示的数据进行交互的第一步是把数据作为一个XML文件，对其进行检索并进行分解，以创建数据结构来接入该文件中的内容。在分解文件后，您可以有选择的对其进行转换以创建新的XML文件，您可以对新的XML文件进行相同的操作。最终，文件中的数据可以被提取，然后显示或使用作为输入数据来运行其它操作。</p><p>这些步骤都在用于控制XML的JSTL标记中反映出。根据我们在第2部分 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/"><font color="#5c81a7">探讨核心</font></a>中所讨论的，我们使用core库中的&lt;c:import&gt;标记来检索XML文件。然后使用&lt;x:parse&gt;标记来分解该文件，支持标准的XML分解技术，如文件对象模式（Document Object Model，DOM)和简单XML API（Simple API for XML，SAX)。&lt;x:transform&gt;标记可用于转换XML文件并依赖标准技术来转换XML数据：扩展样式表语言（ <i>Extensible Stylesheet Language，</i>XSL)。最后，我们提供多个标记来接入和控制分解后的XML数据，但是所有这一切都依赖于另一种标准- <i>XML路径语言（XML Path Language，</i>XPath)，以引用分解后的XML文件中的内容。 </p><p><a name="N10094"><span class="smalltitle"><strong><font face="Arial">分解XML</font></strong></span></a></p><p>&lt;x:parse&gt;标记有多种格式，取决于用户希望的分解类型。这一项操作最基本的格式使用以下语法：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;x:parse xml="
        <i>expression</i>" var="
        <i>name</i>" scope="
        <i>scope</i>"
    filter="
        <i>expression</i>" systemId="
        <i>expression</i>"/&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>在这五种属性中，只有xml属性是需要的，其值应该是包含要分解的XML文件的字符串，或者是java.io.Reader实例，通过它可以读取要被分解的文件。此外，您可以使用以下语法，根据&lt;x:parse&gt;标记的主体内容来规定要被分解的文件：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;x:parse var="
        <i>name</i>" scope="
        <i>scope</i>"
    filter="
        <i>expression</i>" systemId="
        <i>expression</i>"&gt;
  
        <i>body content</i>
&lt;/x:parse&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>var和scope属性规定存储分解后的文件的scoped变量。然后xml库中的其它标记可以使用这一变量来运行其它操作。注意，当var和 scope 属性存在时，JSTL用于表示分解后的文件的数据结构类型以实施为导向，从而厂商可以对其进行优化。 </p><p>如果应用程序需要对JSTL提供的分解后的文件进行处理，它可以使用另一种格式的&lt;x:parse&gt;，它要求分解后的文件坚持使用一个标准接口。在这种情况下，该标记的语法如下： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;x:parse xml="
        <i>expression</i>" varDom="
        <i>name</i>" scopeDom="
        <i>scope</i>"
    filter="
        <i>expression</i>" systemId="
        <i>expression</i>"/&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>当您使用&lt;x:parse&gt;的这一版本时，表示分解后的XML文件的对象必须使用org.w3c.dom.Document接口。当根据&lt;x:parse&gt;中的主体内容来规定XML文件时，您还可以使用varDom和scopeDom属性来代替var 和 scope属性，语法如下：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;x:parse varDom="
        <i>name</i>" scopeDom="
        <i>scope</i>"
    filter="
        <i>expression</i>" systemId="
        <i>expression</i>"&gt;
  
        <i>body content</i>
&lt;/x:parse&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>其它两个属性filter 和 systemId 可以实现对分解流程的精确控制。filter 属性规定org.xml.sax.XMLFilter类的一个实例，以在分解之前对文件进行过滤。如果要被分解的文件非常大，但目前的工作只需要处理一小部分内容时这一属性尤其有用。systemId属性表示要被分解的文件的URI并解析文件中出现的任何相关的路径。当被分解的XML文件使用相关的URL来引用分解流程中需要接入的其它文件或资源时需要这种属性</p><p>清单1展示了&lt;x:parse&gt; 标记的使用，包括与 &lt;c:import&gt;的交互。此处&lt;c:import&gt; 标记用于检索众所周知的Slashdot Web 网站的RDF Site Summary (RSS)反馈，然后使用&lt;x:parse&gt;分解表示RSS 反馈的XML文件，表示分解后的文件的以实施为导向的数据结构被保存到名为rss的变量（带有page 范围）中。 </p><br /><a name="IDA2SQ3E"><b>清单1：&lt;x:parse&gt;与&lt;c:import&gt;的交互</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/&gt;
&lt;x:parse var="rss" xml="${rssFeed}"/&gt;
</font></code></pre></td></tr></tbody></table><br /><p><a name="N10105"><span class="smalltitle"><strong><font face="Arial">转换XML</font></strong></span></a></p><p>XML通过XSL样式表来转换。JSTL使用&lt;x:transform&gt;标记来支持这一操作。与&lt;x:parse&gt;的情况一样，&lt;x:transform&gt; 标记支持多种不同的格式。&lt;x:transform&gt; 最基本的格式的语法是： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;x:transform xml="
        <i>expression</i>" xslt="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"
    xmlSystemId="
        <i>expression</i>" xsltSystemId="
        <i>expression</i>"&gt;
  &lt;x:param name="
        <i>expression</i>" value="
        <i>expression</i>"/&gt;
  ...
&lt;/x:transform&gt;

      </font></code></pre></td></tr></tbody></table><br /><table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"><tbody><tr><td width="10"><font face="Lucida Console"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></font></td><td><table cellspacing="0" cellpadding="5" width="100%" border="1"><tbody><tr><td bgcolor="#eeeeee"><a name="IDATUQ3E"><b>关于 RSS</b></a><br /><p>RDF Site Summary (RSS) 是许多以新闻为导向的网站公布的XML文件格式，它列出它们当前的标题，提供链接到相关文章的URL。同样，它提供在Web上联合新闻的简单机制。关于RSS的更详细信息，请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/index.html#resources"><font color="#996699">参考资料</font></a>。 </p></td></tr></tbody></table></td></tr></tbody></table><p>此处，xml 属性规定要被转换的文件，xslt 属性规定定义这次转换的样式表。这两种属性是必要的，其它属性为可选。 </p><p>与&lt;x:parse&gt;的xml属性一样，&lt;x:transform&gt;的xml 属性值可以是包含XML文件的字符串，或者是接入这类文件的Reader。此外，它还可以采用 org.w3c.dom.Document 类或javax.xml.transform.Source 类的实例格式。最后，它还可以是使用&lt;x:parse&gt; 操作的var或varDom属性分配的变量值。 </p><p>而且，您可以根据&lt;x:transform&gt; 操作的主体内容来包含要被转换的XML文件。在这种情况下，&lt;x:transform&gt; 的语法是： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;x:transform xslt="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"
    xmlSystemId="
        <i>expression</i>" xsltSystemId="
        <i>expression</i>"&gt;
  
        <i>body content</i>
  &lt;x:param name="
        <i>expression</i>" value="
        <i>expression</i>"/&gt;
  ...
&lt;/x:transform&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>在这两种情况下，规定XSL 样式表的xslt 属性应是字符串、Reader或javax.xml.transform.Source实例。 </p><p>如果var 属性存在，转换后的XML文件将分配给相应的scoped变量，作为org.w3c.dom.Document 类的一个实例。通常，scope属性规定这类变量分配的范围。 </p><p>&lt;x:transform&gt; 标记还支持将转换结果存储到javax.xml.transform.Result 类的一个实例中，而不是作为org.w3c.dom.Document的一个实例。如果var 和 scope 属性被省略，result对象规定作为result属性的值，&lt;x:transform&gt;标记将使用该对象来保存应用该样式表的结果。清单2中介绍了使用&lt;x:transform&gt; 的result属性的这两种语法的变化： </p><br /><a name="IDAC0Q3E"><b>清单2：使用result属性来提供javax.xml.transform.Result实例时，&lt;x:transform&gt;操作的语法变化</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;x:transform xml="
        <i>expression</i>" xslt="
        <i>expression</i>"
    result="
        <i>expression</i>"
    xmlSystemId="
        <i>expression</i>" xsltSystemId="
        <i>expression</i>"&gt;
  &lt;x:param name="
        <i>expression</i>" value="
        <i>expression</i>"/&gt;
  ...
&lt;/x:transform&gt;

&lt;x:transform xslt="
        <i>expression</i>"
    result="
        <i>expression</i>"
    xmlSystemId="
        <i>expression</i>" xsltSystemId="
        <i>expression</i>"&gt;
  
        <i>body content</i>
  &lt;x:param name="
        <i>expression</i>" value="
        <i>expression</i>"/&gt;
  ...
&lt;/x:transform&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>无论您采用这两种&lt;x:transform&gt;格式中的那一种，您都必须从定制标记单独创建javax.xml.transform.Result对象。该对象自身作为result属性的值提供。 </p><p>如果既不存在var 属性，也不存在result属性，转换的结果将简单地插入到JSP页面，作为处理&lt;x:transform&gt; 操作的结果。当样式表用于将数据从XML转换成HTML时尤其有用，如清单3所示： </p><br /><a name="listing3"><b>清单3：在JSP页面直接显示转换的XML数据</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/&gt;
&lt;c:import var="rssToHtml" url="/WEB-INF/xslt/rss2html.xsl"/&gt;
&lt;x:transform xml="${rssFeed}" xslt="${rssToHtml}"/&gt;
</font></code></pre></td></tr></tbody></table><br /><p>在本例中，使用 &lt;c:import&gt; 标记来读取RSS反馈和适当的样式表。样式表的输出结果是HTML，通过忽略&lt;x:transform&gt;的var和result 属性来直接显示。图1显示了实例结果： </p><br /><a name="IDAB3Q3E"><b>图1：清单3的输出结果 </b></a><br /><img height="273" alt="Output of Listing 3" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/images/transformXML.jpg" width="543" /><br /><p>与&lt;x:parse&gt;的systemId 属性一样，&lt;x:transform&gt;的xmlSystemId 和 xsltSystemId 属性用于解析XML文件中相关的路径。在这种情况下，xmlSystemId 属性应用于根据标记的 xml属性值提供的文件，而xsltSystemId 属性用于解析根据标记的xslt属性规定的样式表中的相关路径。 </p><p>如果正在推动文件转换的样式表使用了参数，我们使用&lt;x:param&gt; 标记来规定这些参数。如果参数存在，那么这些标记必须在&lt;x:transform&gt; 标记主体内显示。如果根据主体内容规定了要被转换的XML文件，那么它必须先于任何 &lt;x:param&gt; 标记。 </p><p>&lt;x:param&gt; 标记有两种必要的属性 -- name 和 value -- 就象本系列 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/"><font color="#5c81a7">第2部分</font></a> 和 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/"><font color="#5c81a7">第3部分</font></a>中讨论的&lt;c:param&gt; 和 &lt;fmt:param&gt; 标记一样。 </p><p><a name="N101CF"><span class="smalltitle"><strong><font face="Arial">处理XML内容</font></strong></span></a></p><p>XML文件的分解和转换操作都是基于整个文件来进行。但是，在您将文件转换成一种可用的格式之后，一项应用程序通常只对文件中包含的一部分数据感兴趣。鉴于这一原因，xml 库包括多个标记来接入和控制XML文件内容的各个部分。 </p><p>如果您已经阅读了本系列第2部分( <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/"><font color="#5c81a7">探讨核心</font></a>)，您将对这些xml 标记的名字非常熟悉。它们都基于JSTL core 库相应的标记。但是，这些core 库标记使用EL表达式，通过它们的value属性来接入JSP容器中的数据，而它们在xml 库中的副本使用XPath表达式，通过select属性接入XML文件中的数据。 </p><p>XPath是引用XML文件中元素及它们的属性值和主体内容的标准化符号。正如其名字代表的一样，这种符号与文件系统路径的表示方法类似，使用短斜线来分开XPath语句的组分。这些组分对映于XML文件的节点，连续的组分匹配嵌套的Element。此外，星号可以用于作为通配符来匹配多个节点，括号内的表达式可以用于匹配属性值和规定索引。有多种在线参考资料介绍XPath和它的使用(见 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/index.html#resources"><font color="#996699">参考资料</font></a>)。 </p><p>要显示XML文件的数据的一个Element，使用&lt;x:out&gt; 操作，它与core 库的&lt;c:out&gt; 标记类似。 但是，&lt;c:out&gt; 使用名为value 和escapeXml的属性，&lt;x:out&gt; 的属性为select 和escapeXml： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;x:out select="
        <i>XPathExpression</i>" escapeXml="
        <i>boolean</i>"/&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>当然，两者的区别在于&lt;x:out&gt; 的select 属性值必须是XPath表达式，而&lt;c:out&gt; 的value 属性必须是EL表达式。两种标记的escapeXml 属性的意义是相同的。 </p><p>清单4显示了&lt;x:out&gt; 操作的使用。注意，规定用于select 属性的XPath表达式由一个EL表达式规定为scoped变量，尤其是$rss。这一EL表达式根据将被求值的XPath语句来识别分解后的XML文件。该语句在此处查找名为title且父节点名为channel的Element，从而选择它找到的第一个Element(根据表达式尾部[1]索引规定)。这一&lt;x:out&gt; 操作的结果是显示这一Element的主体内容，关闭正在转义（Escaping）的XML字符。 </p><br /><a name="IDAQER3E"><b>清单4：使用&lt;x:out&gt;操作来显示XML Element的主体内容</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/&gt;
&lt;x:parse var="rss" xml="${rssFeed}"/&gt;

&lt;x:out select="$rss//*[name()='channel']/*[name()='title'][1]" 
  escapeXml="false"/&gt;
</font></code></pre></td></tr></tbody></table><br /><p>除了&lt;x:out&gt;之外，JSTL xml 库包括以下控制XML数据的标记： </p><ul><li>&lt;x:set&gt; ，向JSTL scoped 变量分配XPath表达式的值 
</li><li>&lt;x:if&gt; ，根据XPath表达式的布尔值来条件化内容 
</li><li>&lt;x:choose&gt;、&lt;x:when&gt;和&lt;x:otherwise&gt;，根据XPath表达式来实施互斥的条件化 
</li><li>&lt;x:forEach&gt; ，迭代根据XPath表达式匹配的多个Elements </li></ul><p>每个这些标记的操作与core库中相应的标记类似。例如，清单5中显示的&lt;x:forEach&gt;的使用， &lt;x:forEach&gt; 操作用于迭代XML文件中表示RSS反馈的所有名为item 的Element。注意，&lt;x:forEach&gt;主体内容中嵌套的两个&lt;x:out&gt; 操作中的XPath表达式与&lt;x:forEach&gt;标记正在迭代的节点相关。它们用于检索每个item element的子节点link 和 title。 </p><br /><a name="IDALHR3E"><b>清单5：使用&lt;x:out&gt; 和&lt;x:forEach&gt;操作来选择和显示XML数据</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/&gt;
&lt;x:parse var="rss" xml="${rssFeed}"/&gt;

&lt;a href="&lt;x:out select="$rss//*[name()='channel']/*[name()='link'][1]"/&gt;"
  &gt;&lt;x:out select="$rss//*[name()='channel']/*[name()='title'][1]" 
    escapeXml="false"/&gt;&lt;/a&gt;

&lt;x:forEach select="$rss//*[name()='item']"&gt;
  &lt;li&gt; &lt;a href="&lt;x:out select="./*[name()='link']"/&gt;"
        &gt;&lt;x:out select="./*[name()='title']" escapeXml="false"/&gt;&lt;/a&gt;
&lt;/x:forEach&gt;
</font></code></pre></td></tr></tbody></table><br /><p>清单5中JSP程序代码的输出结果与 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/index.html#listing3"><font color="#996699">清单3</font></a>类似，它在 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/index.html#fig1"><font color="#996699">图1</font></a>中显示。xml 库以XPath为导向的标记提供备选的样式表来转换XML内容，尤其是当最后的输出结果是HTML的情况。 </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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="2"><span class="atitle"><font face="Arial" size="4">sql库</font></span></a></p><p>JSTL第4个也是最后一个操作是sql定制标记库。正如其名字代表的一样，该库提供与关系数据库交互的标记。尤其是sql 库定义规定数据源、发布查询和更新以及将查询和更新编组到事务处理中的标记。 </p><p>Datasource <br />Datasource是获得数据库连接的工厂。它们经常实施某些格式的连接库来最大限度地降低与创建和初始化连接相关的开销。Java 2 Enterprise Edition (J2EE)应用程序服务器通常内置了Datasource支持，通过 Java命名和目录接口（ Java Naming and Directory Interface，JNDI)它可用于J2EE应用程序。 </p><p>JSTL的sql 标记依赖于Datasource来获得连接。实际上包括可选的dataSource 属性以明确规定它们的连接工厂作为 javax.sql.DataSource 接口实例，或作为JNDI名。 </p><p>您可以使用&lt;sql:setDataSource&gt; 标记来获得javax.sql.DataSource 实例，它采用以下两种格式： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;sql:setDataSource dataSource="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"/&gt;

&lt;sql:setDataSource url="
        <i>expression</i>" driver="
        <i>expression</i>"
    user="
        <i>expression</i>" password="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"/&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>第一种格式只需要dataSource 属性，而第二种格式只需要url 属性。 </p><p>通过提供JNDI名作为dataSource属性值，您可以使用第一种格式来接入与JNDI名相关的datasource。第二种格式将创建新的datasource，使用作为url属性值提供的JDBC URL。可选的driver 属性规定实施数据库driver的类的名称，同时需要时user 和 password 属性提供接入数据库的登录证书。 </p><p>对于&lt;sql:setDataSource&gt;的任何一种格式而言，可选的var 和 scope 属性向scoped变量分配特定的datasource。如果var属性不存在，那么 &lt;sql:setDataSource&gt; 操作设置供sql 标记使用的缺省 datasource，它们没有规定明确的datasource。 </p><p>您还可以使用javax.servlet.jsp.jstl.sql.dataSource 参数来配置sql 库的缺省datasource。在实践中，在应用程序的Web.xml文件中添加与清单6中显示的类似的程序代码是规定缺省datasource最方便的方式。使用&lt;sql:setDataSource&gt; 来完成这一操作要求使用JSP页面来初始化该应用程序，因此可以以某种方式自动运行这一页面。 </p><br /><a name="IDAUMR3E"><b>清单6：使用JNDI名来设置JSTL在web.xml部署描述符中的缺省datasource</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;context-param&gt;
  &lt;param-name&gt;javax.servlet.jsp.jstl.sql.dataSource&lt;/param-name&gt;
  &lt;param-value&gt;jdbc/blog&lt;/param-value&gt;
&lt;/context-param&gt;
</font></code></pre></td></tr></tbody></table><br /><p><a name="N10276"><span class="smalltitle"><strong><font face="Arial">提交查询和更新</font></strong></span></a></p><p>在建立了datasource接入之后，您可以使用&lt;sql:query&gt; 操作来执行查询，同时使用&lt;sql:update&gt; 操作来执行数据库更新。查询和更新使用SQL语句来规定，它可以是使用基于JDBC的java.sql.PreparedStatement 接口的方法来实现参数化。参数值使用嵌套的&lt;sql:param&gt; 和 &lt;sql:dateParam&gt; 标记来规定。 </p><p>支持以下三种&lt;sql:query&gt; 操作： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;sql:query sql="
        <i>expression</i>" dataSource="
        <i>expression</i>" 
    var="
        <i>name</i>" scope="
        <i>scope</i>"
    maxRows="
        <i>expression</i>" startRow="
        <i>expression</i>"/&gt;

&lt;sql:query sql="
        <i>expression</i>" dataSource="
        <i>expression</i>" 
    var="
        <i>name</i>" scope="
        <i>scope</i>"
    maxRows="
        <i>expression</i>" startRow="
        <i>expression</i>"&gt;
  &lt;sql:param value="
        <i>expression</i>"/&gt;
  ...
&lt;/sql:query&gt;

&lt;sql:query dataSource="
        <i>expression</i>" 
    var="
        <i>name</i>" scope="
        <i>scope</i>"
    maxRows="
        <i>expression</i>" startRow="
        <i>expression</i>"&gt;
  
        <i>SQL statement</i>
  &lt;sql:param value="
        <i>expression</i>"/&gt;
  ...
&lt;/sql:query&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>前两种格式只要求sql 和 var 属性，第三种格式只要求var 属性。 </p><p>var 和 scope 属性规定存储查询结果的scoped 变量。maxRows 属性可以用于限制查询返回的行数，startRow 属性允许忽略一些最开始的行数(如当结果集（Result set）由数据库来构建时忽略)。 </p><p>在执行了查询之后，结果集被分配给scoped变量，作为javax.servlet.jsp.jstl.sql.Result 接口的一个实例。这一对象提供接入行、列名称和查询的结果集大小的属性，如表1所示： </p><p><a name="table1"><span class="smalltitle"><strong><font face="Arial">表1：javax.servlet.jsp.jstl.sql.Result 接口定义的属性</font></strong></span></a></p><p></p><table cellspacing="0" cellpadding="3" width="100%" border="1"><tbody><tr><td><strong>属性</strong></td><td><b>说明</b></td></tr><tr><td>rows</td><td>一排SortedMap 对象，每个对象对映列名和结果集中的单行</td></tr><tr><td>rowsByIndex</td><td>一排数组，每个对应于结果集中的单行</td></tr><tr><td>columnNames</td><td>一排对结果集中的列命名的字符串，采用与rowsByIndex属性相同的顺序</td></tr><tr><td>rowCount</td><td>查询结果中总行数</td></tr><tr><td>limitedByMaxRows</td><td>如果查询受限于maxRows 属性值为真</td></tr></tbody></table><p>在这些属性中，rows 尤其方便，因为您可以使用它来在整个结果集中进行迭代和根据名字访问列数据。我们在 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/index.html#listing7"><font color="#996699">清单7</font></a>中阐述了这一操作，查询的结果被分配到名为queryResults的scoped变量中，然后使用core 库中的&lt;c:forEach&gt;标记来迭代那些行。嵌套的&lt;c:out&gt; 标记利用EL内置的Map 收集支持来查找与列名称相对应的行数据。(记得在 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0211/"><font color="#5c81a7">第1部分</font></a> ，${row.title}和${row["title"]} 是相等的表达式。) </p><p>清单7还展示了使用&lt;sql:setDataSource&gt; 来关联datasource 和scoped变量，它由&lt;sql:query&gt; 操作通过其dataSource 属性随后接入。 </p><br /><a name="listing7"><b>清单7：使用&lt;sql:query&gt;来查询数据库，使用&lt;c:forEach&gt;来迭代整个结果集</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;sql:setDataSource var="dataSrc"
    url="jdbc:mysql:///taglib" driver="org.gjt.mm.mysql.Driver"
    user="admin" password="secret"/&gt;
    &lt;sql:query var="queryResults" dataSource="${dataSrc}"&gt;
  select * from blog group by created desc limit ?
  &lt;sql:param value="${6}"/&gt;&lt;/sql:query&gt;

&lt;table border="1"&gt;
  &lt;tr&gt;
    &lt;th&gt;ID&lt;/th&gt;
    &lt;th&gt;Created&lt;/th&gt;
    &lt;th&gt;Title&lt;/th&gt;
    &lt;th&gt;Author&lt;/th&gt;
  &lt;/tr&gt;
&lt;c:forEach var="row" items="${queryResults.rows}"&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;c:out value="${row.id}"/&gt;&lt;/td&gt;
    &lt;td&gt;&lt;c:out value="${row.created}"/&gt;&lt;/td&gt;
    &lt;td&gt;&lt;c:out value="${row.title}"/&gt;&lt;/td&gt;
    &lt;td&gt;&lt;c:out value="${row.author}"/&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/c:forEach&gt;
&lt;/table&gt;
</font></code></pre></td></tr></tbody></table><br /><p>图2显示了清单7中JSTL程序代码的实例页面输出结果。注意：清单7中&lt;sql:query&gt;操作主体中出现的SQL语句为参数化语句。 </p><br /><a name="IDATUR3E"><b>图2：清单7的输出</b></a><br /><img height="308" alt="Output of Listing 7" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/images/query.jpg" width="482" /><br /><p>在&lt;sql:query&gt; 操作中，SQL语句根据主体内容来规定，或者使用？字符，通过sql 属性实现参数化。对于SQL语句中每个这样的参数来说，应有相应的&lt;sql:param&gt; 或 &lt;sql:dateParam&gt; 操作嵌套到&lt;sql:query&gt; 标记的主体中。&lt;sql:param&gt; 标记只采用一种属性 -- value --来规定参数值。此外，当参数值为字符串时，您可以忽略value 属性并根据&lt;sql:param&gt; 标记的主体内容来提供参数值。 </p><p>表示日期、时间或时间戳的参数值使用&lt;sql:dateParam&gt; 标记来规定，使用以下语法： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;sql:dateParam value="
        <i>expression</i>" type="
        <i>type</i>"/&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>对于&lt;sql:dateParam&gt;来说，value 属性的表达式必须求 java.util.Date 类实例的值，同时type 属性值必须是date、time或timestamp，由SQL语句需要那类与时间相关的值来决定。 </p><p>与&lt;sql:query&gt; 一样，&lt;sql:update&gt; 操作支持三种格式： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;sql:update sql="
        <i>expression</i>" dataSource="
        <i>expression</i>" 
    var="
        <i>name</i>" scope="
        <i>scope</i>"/&gt;

&lt;sql:update sql="
        <i>expression</i>" dataSource="
        <i>expression</i>" 
    var="
        <i>name</i>" scope="
        <i>scope</i>"&gt;
  &lt;sql:param value="
        <i>expression</i>"/&gt;
  ...
&lt;/sql:update&gt;

&lt;sql:update dataSource="
        <i>expression</i>" 
    var="
        <i>name</i>" scope="
        <i>scope</i>"&gt;
  
        <i>SQL statement</i>
  &lt;sql:param value="
        <i>expression</i>"/&gt;
  ...
&lt;/sql:update&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>sql 和dataSource 属性有与&lt;sql:query&gt;相同的&lt;sql:update&gt; 语义。同样，var 和 scope 属性可以用于规定scoped变量，但在这种情况下，分配给scoped变量的值将是java.lang.Integer 的一个实例，显示作为数据库更新结果而更改的行数。 </p><p><a name="N10388"><span class="smalltitle"><strong><font face="Arial">管理事务处理</font></strong></span></a></p><p>事务处理用于保护作为一个组必须成功或失败的一系列数据库操作。事务处理支持已经嵌入到JSTL的sql 库中，通过将相应的&lt;sql:query&gt;和&lt;sql:update&gt;操作嵌套到&lt;sql:transaction&gt;标记的主体内容中，从而将一系列查询和更新操作打包到一个事务处理中也就显得微不足道了。 </p><p>&lt;sql:transaction&gt; 语法如下： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;sql:transaction dataSource="
        <i>expression</i>" isolation="
        <i>isolationLevel</i>"&gt;
  &lt;sql:query .../&gt; 
        <i>or</i>  &lt;sql:update .../&gt;
  ...

      </font></code></pre></td></tr></tbody></table><br /><p>&lt;sql:transaction&gt; 操作没有必需的属性。如果您忽略了dataSource 属性，那么使用JSTL的缺省datasource。isolation 属性用于规定事务处理的隔离级别，它可以是read_committed、read_uncommitted、repeatable_read或serializable。如果您未规定这一属性，事务处理将使用datasource的缺省隔离级别。 </p><p>您可能希望所有嵌套的查询和更新必须使用与事务处理相同的datasource。实际上，嵌套到&lt;sql:transaction&gt;操作中的&lt;sql:query&gt; 或 &lt;sql:update&gt; 不能用于规定dataSource 属性。它将自动使用与周围的&lt;sql:transaction&gt;标记相关的datasource (显性或隐性)。 </p><p>清单8显示了如何使用&lt;sql:transaction&gt; 的一个实例： </p><br /><a name="IDAA3R3E"><b>清单：使用&lt;sql:transaction&gt;来将数据库更新联合到事务处理中</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;sql:transaction&gt;
  &lt;sql:update sql="update blog set title = ? where id = ?"&gt;
    &lt;sql:param value="New Title"/&gt;
    &lt;sql:param value="${23}"/&gt;
  &lt;/sql:update&gt;
  &lt;sql:update sql="update blog set last_modified = now() where id = ?"&gt;
    &lt;sql:param value="${23}"/&gt;
  &lt;/sql:update&gt;
&lt;/sql:transaction&gt;
</font></code></pre></td></tr></tbody></table><br /><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><font face="Lucida Console"><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" /></font></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><font face="Lucida Console"><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /></font><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><font face="Lucida Console"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></font></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="3"><span class="atitle"><font face="Arial" size="4">注意事项</font></span></a></p><p>JSTL的xml 和 sql 库使用定制标记，从而能够在JSP页面上实施复杂的功能，但是在您的表示层实施这类功能可能不是最好的方法。 </p><p>对于多位开发人员长期编写的大型应用程序来说，实践证明，用户接口、基本的业务逻辑和数据仓库之间的严格分离能够长期简化软件维护。广泛流行的模式/视图/控制器（ Model-View-Controller，MVC）设计模板是这一“最佳实践”的公式化。在J2EE Web应用程序领域中，模式是应用程序的业务逻辑，视图是包含表示层的JSP页面。(控制器是form handlers和其它服务器端机制，使浏览器操作能够开始更改模式并随后更新视图。) MVC规定应用程序的三个主要elements--模式、视图和控制器 --相互之间有最小的相关性，从而限制相互之间的交互到统一、精心定义的接口。 </p><p>应用程序依赖XML文件来进行数据交换以及关系数据库来提供数据永久性都是应用程序业务逻辑（也就是其模式）的特征。因此，使用MVC设计模板建议无需在应用程序的表示层（也就是其视图）反映这些实施细节。如果JSP用于实施表示层，那么使用 xml 和 sql 库将违反MVC，因为它们的使用将意味着在表示层内暴露基本业务逻辑的elements。 </p><p>鉴于这一原因，xml 和 sql 库最适用于小型项目和原型工作。应用程序服务器对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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="4"><span class="atitle"><font face="Arial" size="4">结束语</font></span></a></p><p>在本系列中，我们讨论了4个JSTL定制标记库的功能及它们的使用。在 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0211/"><font color="#5c81a7">第1部分</font></a> 和 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/"><font color="#5c81a7">第2部分</font></a>，我们讨论通过El和core 库标记的使用，您如何在许多常见情况下避免JSP脚本程序。 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/"><font color="#5c81a7">第3部分</font></a> 关注使用fmt 库来本地化Web内容。 </p><p>在最后一部分，我们讨论了xml 和 sql 库的功能。如果您愿意接受将业务逻辑包含到表示层的结果，这两个库中的标记都使其能够非常轻松地将XML文件和关系数据库中的内容结合到JSP页面。这两个库还展示了当集成&lt;sql:query&gt; 和&lt;c:forEach&gt;时，JSTL库如何构建和集成，以及xml 库利用&lt;c:import&gt; 操作的能力。 </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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="resources"><span class="atitle"><font face="Arial" size="4">参考资料 </font></span></a></p><ul><li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/library/j-jstl0520/index.html"><font color="#5c81a7">英文原文</font></a>. <br /><br /></li><li>下载Weblog实例应用程序的 <a href="ftp://www6.software.ibm.com/software/developer/library/j-jstl0520.jar"><font color="#5c81a7">源代码</font></a>。 <br /><br /><br /></li><li><a href="http://java.sun.com/products/jsp/jstl/index.html"><font color="#5c81a7">JSTL Web site</font></a> 是深入了解JSTL不错的起点。 <br /><br /><br /></li><li><a href="http://jcp.org/aboutJava/communityprocess/final/jsr052/"><font color="#996699">JSTL 1.0 Specification</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，2002 年）出色地讨论了由参考实现领导编写的全部 JSTL 功能。 <br /><br /><br /></li><li>David Geary 是一位很受欢迎的 Java 编程方面的作者，他还著有一部关于 JSTL 的书籍，名为 <a href="http://www.core-jstl.com/"><font color="#5c81a7"><i>Core JSTL</i></font></a>(Prentice-Hall and Sun Microsystems Press, 2002)。 <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>阅读James Lewin的“ <a href="http://www.ibm.com/developerworks/web/library/w-rss.html"><font color="#5c81a7">RSS新闻反馈简介</font></a>”( <i>developerWorks</i>, 2000年11月)以了解更多关于RSS的信息。 <br /><br /><br /></li><li>Mark Colan 在“ <a href="http://www.ibm.com/developerworks/xml/library/x-xsltwork/"><font color="#5c81a7">Putting XSL transformations to work</font></a>” ( <i>developerWorks</i>, 2001年10月)提供了XSL的介绍性概述。 <br /><br /><br /></li><li>参阅Parand Tony Darugar撰写的“ <a href="http://www.ibm.com/developerworks/xml/library/x-domjava/"><font color="#5c81a7">Effective XML processing with DOM and XPath in Java</font></a>”( <i>developerWorks</i>, 2002年5月)以更好地了解XPath及其与文件对象模式（ Document Object Model，DOM)的关系. <br /><br /><br /></li><li>通过动手实践指南“ <a href="http://www.ibm.com/developerworks/cn/views/java/tutorials.jsp?cv_doc_id=85038"><font color="#5c81a7">使用 JDBC 构建基于 Web 的应用程序</font></a>”( <i>developerWorks</i>, 2001年12月)来全面了解JDBC。 <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 Developer Domain</font></a>) ，动手实践 WBOnline，这篇文章演示了如何使用 servlet、JSP 页面及定制标记库 <br /><br /><br /></li><li>通过Jeff Wilson的优秀文章“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-taglib/"><font color="#5c81a7">使用定制标记控制 JSP 页面</font></a>” ( <i>developerWorks</i>，2002 年 1 月）来学习关于定制标记库的全部内容。 <br /><br /><br /></li><li>Noel Bergman 的文章“ <a href="http://www-128.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>在 <a href="http://www-128.ibm.com/developerworks/cn/java/"><font color="#5c81a7"><i>developerWorks</i> Java 技术专区 </font></a>可以找到数百篇有关 Java 技术的参考资料。 <br /><br /></li></ul><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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0520/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="author"><span class="atitle"><font face="Arial" size="4">关于作者</font></span></a></p><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td colspan="3"><font face="Arial" size="4"><img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /></font></td></tr><tr valign="top" align="left"><td><p><font face="Arial" size="4"></font></p></td><td><font face="Arial" size="4"><img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="4" /></font></td><td width="100%"><p>Mark Kolb 是一位在德克萨斯州奥斯汀市（Austin）工作的软件工程师。他常就服务器端 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"><font color="#5c81a7">mak@taglib.com</font></a>与 Mark联系。 </p></td></tr></tbody></table><img src ="http://www.blogjava.net/TrampEagle/aggbug/46373.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-05-16 12:40 <a href="http://www.blogjava.net/TrampEagle/articles/46373.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSTL 入门: 表示就是一切</title><link>http://www.blogjava.net/TrampEagle/articles/46372.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Tue, 16 May 2006 04:39:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/46372.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/46372.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/46372.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/46372.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/46372.html</trackback:ping><description><![CDATA[原文引自：<a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.html">http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.html</a><br /><br /><br /><blockquote>JSP 标准标记库（JSP Standard Tag Library，JSTL）fmt 库通过一组颇受关注的定制标记提供了用于访问所有 Java 编程语言国际化功能的便利方式。Mark Kolb 研究了用于对数据进行格式化和国际化的 fmt 标记。</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>在本系列的前几篇文章中，我们讨论了 JSTL 及其表达式语言（EL）。我们还研究了由 <code>core</code> 库定义的定制标记。具体而言，在“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0211/index.html"><font color="#996699">JSTL 入门：表达式语言</font></a>”中我们指出 EL 提供了一种简化语言，用于在 JSP 应用程序中访问和操作数据并使该数据可被 JSTL 定制标记用作动态属性值。 <code>core</code> 库包含了一些定制标记，用于管理限定了作用域的变量、显示 EL 值、实现迭代内容和条件内容以及与 URL 进行交互，这是“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html"><font color="#996699">JSTL 入门：探讨 core</font></a>”的主题。 </p><p>我们接下来将讨论的 JSTL 库是 <code>fmt</code> 库。 <code>fmt</code> 库中的定制标记支持通过资源束对文本内容进行本地化，并支持对数字和日期的显示和解析。这些标记利用在 <code>java.util</code> 和 <code>java.text</code> 包中实现的 Java 语言的国际化 API，因此如果您已经很熟悉诸如 <code>ResourceBundle</code> 、 <code>Locale</code> 、 <code>MessageFormat</code> 和 <code>DateFormat</code> 这样的类，那么您将发现 <code>fmt</code> 库中有很多方面值得称道。如果您不熟悉这些类，那么 <code>fmt</code> 库的标记用直观的方式来封装国际化 API，这种方式使您能够很容易将本地化功能合并到 JSP 应用程序中。 </p><p><a name="1"><span class="atitle"><font face="Arial" size="4">本地化</font></span></a></p><p>在 Java 语言国际化 API 中，影响数据本地化方式的因素主要有两个。一个是用户的 <i>语言环境</i>，另一个是用户的 <i>时区</i>。语言环境表示某一特定区域或文化的语言习惯，包括日期、数字和货币金额的格式。一个语言环境始终会有一种相关联的语言，在许多情况下这种语言是由多个语言环境共享的某种语言的方言。例如，美国英语、英国英语、澳大利亚英语和加拿大英语都具有不同的英语语言环境，而法国、比利时、瑞士和加拿大所用的法语方言则都具有不同的法语语言环境。 </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="IDAHE22F"><b>别错过了本系列的其它文章</b></a><br /><p>第 1 部分，“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0211/index.html"><font color="#996699">JSTL 入门：表达式语言</font></a>”（2003 年 2 月） </p><p>第 2 部分，“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html"><font color="#996699">JSTL 入门：探讨 core</font></a>”（2003 年 3 月） </p></td></tr></tbody></table></td></tr></tbody></table><p>时区是数据本地化中的第二个因素，这仅仅是因为一些语言环境分布的地理区域很广。当您显示有关跨洲语言环境（比如澳大利亚英语）的时间信息时，针对用户时区定制数据与对其进行正确格式化一样重要。</p><p>但是这就有了一个问题：应用程序如何确定用户的语言环境和时区？在 Java 应用程序的情况下，JVM 能够通过与本地操作系统进行交互来设置缺省语言环境和时区。虽然这种方法对于桌面应用程序而言可以正常工作，但是它实际上并不适合于服务器端的 Java 应用程序，因为这种应用程序所处理的请求，可能来自于距离该应用程序所驻留的服务器万里之遥的地方。</p><p>幸运的是，HTTP 协议通过 <code>Accept-Language</code> 请求头将本地化信息从浏览器传递至服务器。许多 Web 浏览器允许用户定制他们的语言首选项，如图 1 所示。通常，那些没有为一种或多种首选语言环境提供显式设置的浏览器会询问操作系统以确定在 <code>Accept-Language</code> 头中发送哪个值（或哪些值）。servlet 规范通过 <code>javax.servlet.ServletRequest</code> 类的 <code>getLocale()</code> 和 <code>getLocales()</code> 方法自动地利用 HTTP 协议的这一功能。JSTL <code>fmt</code> 库中的定制标记又会利用这些方法来自动地确定用户的语言环境，从而相应地调整它们的输出。 </p><br /><a name="IDAXF22F"><b>图 1. 通过设置浏览器的语言首选项来选择语言环境 </b></a><br /><img height="502" alt="设置浏览器语言首选项" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/browserPrefs.jpg" width="600" /><br /><p>但遗憾的是，不存在将用户的时区从浏览器传输到服务器的标准 HTTP 请求头。因此，那些希望自己的 Web 应用程序对时间数据进行本地化的用户，将需要实现他们自己的机制，用来确定和跟踪特定于用户的时区。例如，在本系列文章第 2 部分“ <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html"><font color="#996699">JSTL 入门：探讨 core</font></a>”中所介绍的 Weblog 应用程序包含了一种将用户的时区首选项存储在 cookie 中的方式。 </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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="2"><span class="atitle"><font face="Arial" size="4">fmt 库</font></span></a></p><p>JSTL <code>fmt</code> 库中的定制标记主要分成四组。第一组允许您设置本地化上下文，其它标记将在其中进行操作。换句话说，这组标记允许页面作者显式地设置其它 <code>fmt</code> 标记在格式化数据时将要使用的语言环境和时区。第二组和第三组标记分别支持对日期和数字进行格式化和解析。最后一组标记侧重于对文本消息进行本地化。 </p><p>既然我们已经有了些基本了解，那就让我们集中精力逐个研究这四组标记，并演示其用法。</p><p><a name="N100F7"><span class="smalltitle"><strong><font face="Arial">本地化上下文标记</font></strong></span></a></p><p>正如我们已经讨论过的那样，JSTL 标记在格式化数据时所使用的语言环境往往是通过查看用户浏览器发送的每个 HTTP 请求所包含的 <code>Accept-Language</code> 头来确定的。如果没有提供这样的头，那么 JSTL 提供一组 JSP 配置变量，您可以设置这些变量以指定缺省的语言环境。如果尚未设置这些配置变量，那么就使用 JVM 的缺省语言环境，该缺省语言环境是从 JSP 容器所运行的操作系统中获取的。 </p><p><code>fmt</code> 库提供了其自身的定制标记，以覆盖这个确定用户语言环境的过程： <code>&lt;fmt:setLocale&gt;</code> 。正如下面的代码片段所示， <code>&lt;fmt:setLocale&gt;</code> 操作支持三个属性： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:setLocale value="
        <i>expression</i>"
    scope="
        <i>scope</i>" variant="
        <i>expression</i>"/&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>其中只有一个属性是必需的： <code>value</code> 属性。该属性的值应当是命名该语言环境的一个字符串或者是 <code>java.util.Locale</code> 类的一个实例。语言环境名称是这样组成的：小写的两字母 ISO 语言代码，可选地，后面可以跟下划线或连字符以及大写的两字母 ISO 国家或地区代码。 </p><p>例如， <code>en</code> 是英语的语言代码， <code>US</code> 是美国的国家或地区代码，因此 <code>en_US</code> （或 <code>en-US</code> ）将是美式英语的语言环境名称。类似的， <code>fr</code> 是法语的语言代码， <code>CA</code> 是加拿大的国家或地区代码，因此 <code>fr_CA</code> （或 <code>fr-CA</code> ）是加拿大法语的语言环境名称（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.html#3"><font color="#996699">参考资料</font></a>以获取所有有效的 ISO 语言和国家或地区代码的链接）。当然，由于国家或地区代码是可选的，因此 <code>en</code> 和 <code>fr</code> 本身就是有效的语言环境名称，适用于不区别这些相应语言特定方言的应用程序。 </p><p><code>&lt;fmt:setLocale&gt;</code> 的可选属性 <code>scope</code> 用来指定语言环境的作用域。 <code>page</code> 作用域指出这项设置只适用于当前页，而 <code>request</code> 作用域将它应用于请求期间访问的所有 JSP 页面。如果将 <code>scope</code> 属性设置成 <code>session</code> ，那么指定的语言环境被用于用户会话期间访问的所有 JSP 页面。值 <code>application</code> 指出该语言环境适用于该 Web 应用程序所有 JSP 页面的全部请求和该应用程序所有用户的全部请求。 </p><p><code>variant</code> 属性（也是可选的）允许您进一步针对特定的 Web 浏览器平台或供应商定制语言环境。例如， <code>MAC</code> 和 <code>WIN</code> 分别是 Apple Macintosh 和 Microsoft Windows 平台的变体名。 </p><p>下面的代码片段说明了如何使用 <code>&lt;fmt:setLocale&gt;</code> 标记来显式指定用户会话的语言环境设置： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:setLocale value="fr_CA" scope="session"/&gt;
</font></code></pre></td></tr></tbody></table><br /><p>JSP 容器处理完该 JSP 代码段之后，将忽略用户浏览器设置中所指定的语言首选项。</p><p><code>&lt;fmt:setTimeZone&gt;</code> 操作像 <code>&lt;fmt:setLocale&gt;</code> 一样，可以用来设置其它 <code>fmt</code> 定制标记所使用的缺省时区值。它的语法如下所示： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:setTimeZone value="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"/&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>和 <code>&lt;fmt:setLocale&gt;</code> 一样，只有 <code>value</code> 属性是必需的，但是在本例中它应当是时区名或 <code>java.util.TimeZone</code> 类的实例。 </p><p>遗憾的是，对于时区命名目前还没有任何被广泛接受的标准。因此您可以用于 <code>&lt;fmt:setTimezone&gt;</code> 标记的 <code>value</code> 属性的时区名是特定于 Java 平台的。您可以通过调用 <code>java.util.TimeZone</code> 类的 <code>getAvailableIDs()</code> 静态方法来检索有效的时区名列表。示例包括 <code>US/Eastern</code> 、 <code>GMT+8</code> 和 <code>Pacific/Guam</code> 。 </p><p>和 <code>&lt;fmt:setLocale&gt;</code> 的情况一样，您可以使用可选的 <code>scope</code> 属性来指出时区设置的作用域。下面的代码演示了 <code>&lt;fmt:setTimeZone&gt;</code> 的用法，它用来指定适用于单个用户会话的时区： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:setTimeZone value="Australia/Brisbane" scope="session"/&gt;
</font></code></pre></td></tr></tbody></table><br /><p>您还可以使用 <code>&lt;fmt:setTimeZone&gt;</code> 操作将 <code>TimeZone</code> 实例的值存储在限定了作用域的变量中。在本例中，您可以使用 <code>var</code> 属性来命名限定了作用域的变量，用 <code>scope</code> 属性来指定该变量的作用域（例如，就象这两个属性用在 <code>&lt;c:set&gt;</code> 和 <code>&lt;c:if&gt;</code> 操作中）。请注意，当您以这种方式使用 <code>&lt;fmt:setTimeZone&gt;</code> 操作时，它唯一的副作用就是设置指定的变量。当指定 <code>var</code> 属性时，对于任何其它 JSTL 标记使用什么时区，不会对 JSP 环境作任何更改。 </p><p>这组中的最后一个标记是 <code>&lt;fmt:timeZone&gt;</code> 操作： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:timeZone value="
        <i>expression</i>"&gt;
  
        <i>body content</i>
&lt;/fmt:timeZone&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>和 <code>&lt;fmt:setTimeZone&gt;</code> 一样，您可以使用该标记来指定将由其它 JSTL 标记使用的时区。但是， <code>&lt;fmt:timeZone&gt;</code> 操作的作用域仅限于其标记体内容。在 <code>&lt;fmt:timeZone&gt;</code> 标记体中，由标记的 <code>value</code> 属性指定的时区覆盖了 JSP 环境中现有的任何其它时区设置。 </p><p>和 <code>&lt;fmt:setTimeZone&gt;</code> 的情况一样， <code>&lt;fmt:timeZone&gt;</code> 标记的 <code>value</code> 属性应当是时区名或者是 <code>java.util.TimeZone</code> 实例。后面的 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.html#listing1"><font color="#996699">清单 1</font></a> 中提供了一个如何使用 <code>&lt;fmt:timeZone&gt;</code> 的示例。 </p><p><a name="N10255"><span class="smalltitle"><strong><font face="Arial">日期标记</font></strong></span></a></p><p><code>fmt</code> 库包含了用来与日期和时间进行交互的两个标记： <code>&lt;fmt:formatDate&gt;</code> 和 <code>&lt;fmt:parseDate&gt;</code> 。顾名思义， <code>&lt;fmt:formatDate&gt;</code> 用来格式化和显示日期和时间（数据 <i>输出</i>），而 <code>&lt;fmt:parseDate&gt;</code> 用来解析日期和时间值（数据 <i>输入</i>）。 </p><p><code>&lt;fmt:formatDate&gt;</code> 的语法如下所示： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:formatDate value="
        <i>expression</i>"
    timeZone="
        <i>expression</i>"
    type="
        <i>field</i>" dateStyle="
        <i>style</i>"
    timeStyle="
        <i>style</i>"
    pattern="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"/&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>只有 <code>value</code> 属性才是必需的。其值应当是 <code>java.util.Date</code> 类的实例，指定要进行格式化和显示的日期和／或时间数据。 </p><p>可选的 <code>timeZone</code> 属性指出将要显示哪个时区的日期和／或时间。如果没有显式地指定 <code>timeZone</code> 属性，那么就使用周围任何 <code>&lt;fmt:timeZone&gt;</code> 标记所指定的时区。如果 <code>&lt;fmt:timeZone&gt;</code> 标记的主体部分没有包含 <code>&lt;fmt:formatDate&gt;</code> 操作，那么就使用任何适用的 <code>&lt;fmt:setTimeZone&gt;</code> 操作所设置的时区。如果没有相关的 <code>&lt;fmt:setTimeZone&gt;</code> 操作，那么就使用 JVM 的缺省时区（也就是，专为本地操作系统而设置的时区）。 </p><p><code>type</code> 属性指出要显示指定的 <code>Date</code> 实例的哪些字段，应当是 <code>time</code> 、 <code>date</code> 或 <code>both</code> 。该属性的缺省值是 <code>date</code> ，因此如果没有给出 <code>type</code> 属性，那么 <code>&lt;fmt:formatDate&gt;</code> 标记（名符其实）将只显示与 <code>Date</code> 实例相关的日期信息，这个信息用该标记的 <code>value</code> 属性指定。 </p><p><code>dateStyle</code> 和 <code>timeStyle</code> 属性分别指出应当如何格式化日期和时间信息。有效的样式有 <code>default</code> 、 <code>short</code> 、 <code>medium</code> 、 <code>long</code> 和 <code>full</code> 。缺省值自然是 <code>default</code> ，指出应当使用特定于语言环境的样式。其它四个样式值的语义与 <code>java.text.DateFormat</code> 类定义的一样。 </p><p>可以使用 <code>pattern</code> 属性来指定定制样式，而不必依赖于内置样式。给出定制样式后，该模式属性的值应当是符合 <code>java.text.SimpleDateFormat</code> 类约定的模式字符串。这些模式基于用对应的日期和时间字段代替模式内指定的字符。例如，模式 <code>MM/dd/yyyy</code> 表明应当显示用正斜杠分隔的两位数的月份和日期值以及四位数的年份值。 </p><p>如果指定了 <code>var</code> 属性，那就把包含格式化日期的 <code>String</code> 值指派给指定的变量。否则， <code>&lt;fmt:formatDate&gt;</code> 标记将写出格式化结果。当指定了 <code>var</code> 属性后， <code>scope</code> 属性指定所生成变量的作用域。 </p><p>清单 1（它是本系列 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html"><font color="#996699">第 2 部分</font></a>清单 8 的扩展）包含了 <code>&lt;fmt:formatDate&gt;</code> 标记的两种用法。在第一种用法中， <code>&lt;fmt:formatDate&gt;</code> 只用来显示第一个 weblog 项的创建时间戳记的日期部分。此外，为 <code>dateStyle</code> 属性指定了一个 <code>full</code> 值，这样一来所有的日期字段就将用一种特定于语言环境的格式进行显示。 </p><br /><a name="listing1"><b>清单 1. 使用 &lt;fmt:formatDate&gt; 标记来显示日期和时间值</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;table&gt;
&lt;fmt:timeZone value="US/Eastern"&gt;
&lt;c:forEach items="${entryList}" var="blogEntry" varStatus="status"&gt;
&lt;c:if test="${status.first}"&gt;
        &lt;tr&gt;&lt;td align="left" class="blogDate"&gt;
          &lt;fmt:formatDate value=
              "${blogEntry.created}" dateStyle="full"/&gt;
        &lt;/td&gt;&lt;/tr&gt;
      &lt;/c:if&gt;
      &lt;tr&gt;&lt;td align="left" class="blogTitle"&gt;
        &lt;c:out value="${blogEntry.title}" escapeXml="false"/&gt;
      &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td align="left" class="blogText"&gt;
      &lt;c:out value="${blogEntry.text}" escapeXml="false"/&gt;
      &lt;font class="blogPosted"&gt;
        [Posted &lt;fmt:formatDate value="${blogEntry.created}"
                                pattern="h:mm a zz"/&gt;]
      &lt;/font&gt;
    &lt;/td&gt;&lt;/tr&gt;
  &lt;/c:forEach&gt;
  &lt;/fmt:timeZone&gt;
&lt;/table&gt;
</font></code></pre></td></tr></tbody></table><br /><p>在 <code>&lt;c:forEach&gt;</code> 循环体中，第二个 <code>&lt;fmt:formatDate&gt;</code> 操作只用来显示每个项的创建日期的时间部分。在本例中， <code>pattern</code> 属性用来控制时间值的格式化、并控制指定一位数的小时显示（如果可能的话）、12 小时的时钟和缩写时区的输出。输出如图 2 所示： </p><br /><a name="IDA3I32F"><b>图 2. 清单 1 中 en_US 语言环境的输出 </b></a><br /><img height="381" alt="清单 1 中 en_US 语言环境的输出" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/blog4_en_US.jpg" width="600" /><br /><p>更准确地说，用户浏览器设置指定首选项是英语时，就会产生图 2 中所示的输出。但是由于 <code>&lt;fmt:formatDate&gt;</code> 对用户语言环境敏感，所以浏览器首选项的改变将导致生成不同的内容。例如，当给定的首选项是法语语言环境时，则结果会如图 3 所示： </p><br /><a name="IDAPJ32F"><b>图 3. 清单 1 中 fr_CA 语言环境的输出 </b></a><br /><img height="381" alt="清单 1 中 fr_CA 语言环境的输出" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/blog4_fr_CA.jpg" width="600" /><br /><p><code>&lt;fmt:formatDate&gt;</code> 生成了 <code>java.util.Date</code> 实例的本地化字符串表示，而 <code>&lt;fmt:parseDate&gt;</code> 操作执行相反的操作：给定一个表示日期和／或时间的字符串，它将生成相应的 <code>Date</code> 对象。 <code>&lt;fmt:parseDate&gt;</code> 操作有两种格式，如下所示： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:parseDate value="
        <i>expression</i>"
    type="
        <i>field</i>" dateStyle="
        <i>style</i>" timeStyle="
        <i>style</i>"
    pattern="
        <i>expression</i>"
    timeZone="
        <i>expression</i>" parseLocale="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"/&gt;

&lt;fmt:parseDate
    type="
        <i>field</i>" dateStyle="
        <i>style</i>" timeStyle="
        <i>style</i>"
    pattern="
        <i>expression</i>"
    timeZone="
        <i>expression</i>" parseLocale="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"&gt;
  
        <i>body content</i>
&lt;/fmt:parseDate&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>对于第一种格式，只有 <code>value</code> 属性才是必需的，它的值应当是指定日期、时间或这两者组合的字符串。对于第二种格式，没有必需的属性，表示要解析的值的字符串被指定为 <code>&lt;fmt:parseDate&gt;</code> 标记必需的标记体内容。 </p><p><code>type</code> 、 <code>dateStyle</code> 、 <code>timeStyle</code> 、 <code>pattern</code> 和 <code>timeZone</code> 属性对 <code>&lt;fmt:parseDate&gt;</code> 和对 <code>&lt;fmt:formatDate&gt;</code> 起一样的作用，不同之处仅在于对于前者，它们控制日期值的解析而非显示。 <code>parseLocale</code> 属性用来指定一种语言环境，将根据这种语言环境来解析该标记的值，它应当是语言环境的名称或 <code>Locale</code> 类的实例。 </p><p><code>var</code> 和 <code>scope</code> 属性用来指定限定了作用域的变量（作为 <code>&lt;fmt:parseDate&gt;</code> 的结果），将把 <code>Date</code> 对象赋给该变量。如果没有给出 <code>var</code> 属性，则使用 <code>Date</code> 类的 <code>toString()</code> 方法将结果写到 JSP 页面中。清单 2 显示了 <code>&lt;fmt:parseDate&gt;</code> 操作的一个示例： </p><br /><a name="IDAHO32F"><b>清单 2. 使用 &lt;fmt:parseDate&gt; 标记来解析日期和时间</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:set var="usDateString"&gt;4/1/03 7:03 PM&lt;/c:set&gt;
&lt;fmt:parseDate value="${usDateString}" parseLocale="en_US"
               type="both" dateStyle="short" timeStyle="short"
	       var="usDate"/&gt;

&lt;c:set var="gbDateString"&gt;4/1/03 19:03&lt;/c:set&gt;
&lt;fmt:parseDate value="${gbDateString}" parseLocale="en_GB"
               type="both" dateStyle="short" timeStyle="short"
	       var="gbDate"/&gt;

&lt;ul&gt;
&lt;li&gt; Parsing &lt;c:out value="${usDateString}"/&gt; against the
U.S. English
     locale yields a date of &lt;c:out value="${usDate}"/&gt;.&lt;/li&gt;

&lt;li&gt; Parsing &lt;c:out value="${gbDateString}"/&gt; against the
British English
     locale yields a date of &lt;c:out value="${gbDate}"/&gt;.&lt;/li&gt;
&lt;/ul&gt;
</font></code></pre></td></tr></tbody></table><br /><p>清单 2 的输出如图 4 所示。</p><br /><a name="IDATO32F"><b>图 4. 清单 2 的输出 </b></a><br /><img height="228" alt="清单 2 的输出" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/parseDate.jpg" width="457" /><br /><p>由 <code>&lt;fmt:parseDate&gt;</code> 所执行的解析非常严格，注意这一点很重要。正如清单 2 所暗示的那样，要解析的值必须严格符合特定（特定于语言环境）的样式或模式。这当然更加受限制。另一方面，数据的解析并不是一个非常适合于表示层的任务。对于生产代码，文本输入的验证和转换最好由后端代码（比如 servlet）来处理，而不是通过 JSP 定制标记来处理。 </p><p><a name="N1045B"><span class="smalltitle"><strong><font face="Arial">数字标记</font></strong></span></a></p><p>就象 <code>&lt;fmt:formatDate&gt;</code> 和 <code>&lt;fmt:parseDate&gt;</code> 标记用于格式化和解析日期一样， <code>&lt;fmt:formatNumber&gt;</code> 和 <code>&lt;fmt:parseNumber&gt;</code> 标记对数字数据执行类似的功能。 </p><p><code>&lt;fmt:formatNumber&gt;</code> 标记用来以特定于语言环境的方式显示数字数据，包括货币和百分数。 <code>&lt;fmt:formatNumber&gt;</code> 操作由语言环境确定，例如，使用句点还是使用逗号来定界数字的整数和小数部分。下面是它的语法： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:formatNumber value="
        <i>expression</i>"
    type="
        <i>type</i>" pattern="
        <i>expression</i>"
    currencyCode="
        <i>expression</i>" currencySymbol="
        <i>expression</i>"
    maxIntegerDigits="
        <i>expression</i>" minIntegerDigits="
        <i>expression</i>"
    maxFractionDigits="
        <i>expression</i>" minFractionDigits="
        <i>expression</i>"
    groupingUsed="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"/&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>如 <code>&lt;fmt:formatDate&gt;</code> 的情况一样，只有 <code>value</code> 属性才是必需的。它用来指定将被格式化的数值。 <code>var</code> 和 <code>scope</code> 属性对 <code>&lt;fmt:formatNumber&gt;</code> 操作所起的作用，如它们在 <code>&lt;fmt:formatDate&gt;</code> 中所起的作用一样。 </p><p><code>type</code> 属性的值应当是 <code>number</code> 、 <code>currency</code> 或 <code>percentage</code> ，并指明要对哪种类型的数值进行格式化。该属性的缺省值是 <code>number</code> 。 <code>pattern</code> 属性优先于 <code>type</code> 属性，允许对遵循 <code>java.text.DecimalFormat</code> 类模式约定的数值进行更精确的格式化。 </p><p>当 <code>type</code> 属性的值为 <code>currency</code> 时， <code>currencyCode</code> 属性可以用来显式地指定所显示的数值的货币单位。与语言和国家或地区代码一样，货币代码也是由 ISO 标准管理的（请参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.html#3"><font color="#996699">参考资料</font></a>以获取所有有效的 ISO 货币符号代码的链接）。该代码用来确定作为已格式化值的一部分显示的货币符号。 </p><p>另外，您可以使用 <code>currencySymbol</code> 属性来显式地指定货币符号。请注意，由于 JDK 1.4 和相关的 <code>java.util.Currency</code> 类的引入， <code>&lt;fmt:formatNumber&gt;</code> 操作的 <code>currencyCode</code> 属性优先权超过 <code>currencySymbol</code> 属性。但是对于较老版本的 JDK 而言， <code>currencySymbol</code> 属性具有优先权。 </p><p><code>maxIntegerDigits</code> 、 <code>minIntegerDigits</code> 、 <code>maxFractionDigits</code> 和 <code>minFractionDigits</code> 属性用来控制小数点前后所显示的有效数字的个数。这些属性要求是整数值。 </p><p><code>groupingUsed</code> 属性带有布尔值并控制是否要对小数点前面的数字分组。例如，在英语语言环境中，将较大数的每三个数字分为一组，每组用逗号定界。其它语言环境用句点或空格来定界这样的分组。该属性的缺省值为 <code>true</code> 。 </p><p>清单 3 显示了一个简单的货币示例，它本身是 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.html#listing1"><font color="#996699">清单 1</font></a> 的扩展。在本例中，不指定 <code>currencyCode</code> 或 <code>currencySymbol</code> 属性。而货币是由语言环境设置确定的。 </p><br /><a name="IDAPV32F"><b>清单 3. 使用 &lt;fmt:formatNumber&gt; 标记显示货币值</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;table&gt;
&lt;fmt:timeZone value="US/Eastern"&gt;
&lt;c:forEach items="${entryList}" var="blogEntry"
varStatus="status"&gt;
&lt;c:if test="${status.first}"&gt;
        &lt;tr&gt;&lt;td align="left" class="blogDate"&gt;
          &lt;fmt:formatDate value=
              "${blogEntry.created}" dateStyle="full"/&gt;
        &lt;/td&gt;&lt;/tr&gt;
      &lt;/c:if&gt;
      &lt;tr&gt;&lt;td align="left" class="blogTitle"&gt;
        &lt;c:out value="${blogEntry.title}" escapeXml="false"/&gt;
      &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td align="left" class="blogText"&gt;
      &lt;c:out value="${blogEntry.text}" escapeXml="false"/&gt;
      &lt;font class="blogPosted"&gt;
        [My &lt;fmt:formatNumber value="0.02" type="currency"/&gt;
         posted at &lt;fmt:formatDate value="${blogEntry.created}"
                                   pattern="h:mm a zz"/&gt;]
      &lt;/font&gt;
    &lt;/td&gt;&lt;/tr&gt;
  &lt;/c:forEach&gt;
  &lt;/fmt:timeZone&gt;
&lt;/table&gt;
</font></code></pre></td></tr></tbody></table><br /><p><code>en_US</code> 语言环境的输出如图 5 所示： </p><br /><a name="IDAPW32F"><b>图 5. 清单 3 的 en_US 语言环境的输出 </b></a><br /><img height="381" alt="清单 3 的 en_US 语言环境的输出" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/blog5_en_US.jpg" width="600" /><br /><p><code>fr_CA</code> 语言环境的输出如图 6 所示： </p><br /><a name="IDABX32F"><b>图 6. 清单 3 的 fr_CA 语言环境的输出 </b></a><br /><img height="381" alt="清单 3 的 fr_CA 语言环境的输出" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/blog5_fr_CA.jpg" width="600" /><br /><p>如下所示， <code>&lt;fmt:parseNumber&gt;</code> 操作解析了一个数值，该数值是通过 <code>value</code> 属性或该操作的标记体内容以特定于语言环境的方式提供的，将结果作为 <code>java.lang.Number</code> 类的实例返回。 <code>type</code> 和 <code>pattern</code> 属性对 <code>&lt;fmt:parseNumber&gt;</code> 和对 <code>&lt;fmt:formatNumber&gt;</code> 起一样的作用。同样， <code>parseLocale</code> 、 <code>var</code> 和 <code>scope</code> 属性对 <code>&lt;fmt:parseNumber&gt;</code> 起与 <code>&lt;fmt:parseDate&gt;</code> 一样的作用。 </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:parseNumber value="
        <i>expression</i>"
    type="
        <i>type</i>" pattern="
        <i>expression</i>"
    parseLocale="
        <i>expression</i>"
    integerOnly="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"/&gt;

&lt;fmt:parseNumber
    type="
        <i>type</i>" pattern="
        <i>expression</i>"
    parseLocale="
        <i>expression</i>"
    integerOnly="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"&gt;
  
        <i>body content</i>
&lt;/fmt:parseNumber&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>先前有关 <code>&lt;fmt:parseDate&gt;</code> 的说明同样适用于 <code>&lt;fmt:parseNumber&gt;</code> ：解析数据并不是一项非常适合于表示层的任务。如果解析和验证数据作为应用程序业务逻辑的一部分实现，那么软件维护将会得到简化。由于这个原因，通常建议大家在产品 JSP 页面中避免同时使用 <code>&lt;fmt:parseDate&gt;</code> 和 <code>&lt;fmt:parseNumber&gt;</code> 。 </p><p>只有 <code>integerOnly</code> 属性才是 <code>&lt;fmt:parseNumber&gt;</code> 所独有的。该属性获取一个布尔值，指出是否应当只解析所给值的整数部分。如果该属性的值为 <code>true</code> ，那么就忽略要被解析的字符串中跟在小数点后面的任何数字。该属性的缺省值为 <code>false</code> 。 </p><p><a name="N105FD"><span class="smalltitle"><strong><font face="Arial">消息标记</font></strong></span></a></p><p>在 JSTL 中用 <code>&lt;fmt:message&gt;</code> 标记实现文本的本地化。该标记允许您从特定于语言环境的资源束中检索文本消息并显示在 JSP 页面上。而且，由于该操作利用 <code>java.text.MessageFormat</code> 类所提供的功能，所以可以将参数化的值替换进这样的文本消息，以便动态地定制本地化内容。 </p><p>用于存储特定于语言环境消息的资源束采用类或特性文件的形式，这些类或特性文件符合标准命名约定，在这种命名约定中基名和语言环境名组合在一起。例如，请研究名为 <code>Greeting.properties</code> 的特性文件，它驻留在我们的 weblog 应用程序的类路径中，该类路径位于与 <code>com.taglib.weblog</code> 包相对应的子目录中。您可以通过在同一目录下指定两个新的特性文件，从而将该特性文件所描述的资源束本地化为英语和法语，通过追加相应的语言代码来命名。具体而言，这两个文件应当分别命名为 <code>Greeting_en.properties</code> 和 <code>Greeting_fr.properties</code> 。如果希望另一个本地化为加拿大法语，您可以引入第三个特性文件，在其名称中包含了相应的国家或地区代码（比如 <code>Greeting_fr_CA.properties</code> ）。 </p><p>这些文件都可以定义相同的特性，但是应当将这些特性的值定制成对应的语言或方言。这种方法如清单 4 和清单 5 所示，它们给出了 <code>Greeting_en.properties</code> 和 <code>Greeting_fr.properties</code> 文件的样本内容。在这些示例中，定义了两个已本地化的消息。它们可以通过 <code>com.taglib.weblog.Greeting.greeting</code> 和 <code>com.taglib.weblog.Greeting.return</code> 键识别。但是已经将与这些键相关联的值本地化为文件名中所确定的语言。请注意，出现在 <code>com.taglib.weblog.Greeting.greeting</code> 消息的两个值中的 <code>{0}</code> 模式使已参数化的值能够在内容生成期间动态地插入到消息中。 </p><br /><a name="listing4"><b>清单 4. Greeting_en.properties 本地化资源束的内容</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">com.taglib.weblog.Greeting.greeting=Hello {0}, and welcome to the JSTL Blog.
com.taglib.weblog.Greeting.return=Return
</font></code></pre></td></tr></tbody></table><br /><br /><br /><a name="listing5"><b>清单 5. Greeting_fr.properties 本地化资源束的内容</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">com.taglib.weblog.Greeting.greeting=Bonjour {0}, et bienvenue au JSTL Blog.
com.taglib.weblog.Greeting.return=Retournez
</font></code></pre></td></tr></tbody></table><br /><p>用 JSTL 显示这样的本地化内容，第一步就是指定资源束。 <code>fmt</code> 库为完成这一任务提供了两个定制标记： <code>&lt;fmt:setBundle&gt;</code> 和 <code>&lt;fmt:bundle&gt;</code> ，它们的行为和前面介绍的 <code>&lt;fmt:setTimeZone&gt;</code> 和 <code>&lt;fmt:timeZone&gt;</code> 标记相似。 <code>&lt;fmt:setBundle&gt;</code> 操作设置了一个缺省资源束，供 <code>&lt;fmt:message&gt;</code> 标记在特定作用域内使用，而 <code>&lt;fmt:bundle&gt;</code> 指定了为嵌套在其标记体内容中的全部和任意 <code>&lt;fmt:message&gt;</code> 操作所用的资源束。 </p><p>下面的代码片段显示了 <code>&lt;fmt:setBundle&gt;</code> 标记的语法。 <code>basename</code> 属性是必需的，它标识了设为缺省值的资源束。请注意， <code>basename</code> 属性的值不应当包含任何本地化后缀或文件扩展名。清单 4 和清单 5 中给出的示例资源束的基名为 <code>com.taglib.weblog.Greeting</code> 。 </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:setBundle basename="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"/&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>可选的 <code>scope</code> 属性指明缺省资源束设置所应用的 JSP 作用域。如果没有显式地指定该属性，就假定为 <code>page</code> 作用域。 </p><p>如果指定了可选的 <code>var</code> 属性，那么将把由 <code>basename</code> 属性所标识的资源束赋给该属性值所命名的变量。在这种情况下， <code>scope</code> 属性指定变量的作用域；没有将缺省资源束赋给相应的 JSP 作用域。 </p><p>您使用 <code>&lt;fmt:bundle&gt;</code> 标记（其语法如下所示）在其标记体内容的作用域内设置缺省资源束。和 <code>&lt;fmt:setBundle&gt;</code> 一样，只有 <code>basename</code> 属性才是必需的。您可以使用可选的 <code>prefix</code> 属性来为任何嵌套的 <code>&lt;fmt:message&gt;</code> 操作的 <code>key</code> 值指定缺省前缀。 </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:bundle basename="
        <i>expression</i>"
prefix="
        <i>expression</i>"&gt;
  
        <i>body content</i>
&lt;/fmt:bundle&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>一旦设置了资源束，真正起到显示本地化消息作用的是 <code>&lt;fmt:message&gt;</code> 标记。该操作支持两种不同的语法，这取决于是否需要任何嵌套的 <code>&lt;fmt:param&gt;</code> 标记： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:message key="
        <i>expression</i>" bundle="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"/&gt;

&lt;fmt:message key="
        <i>expression</i>" bundle="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"&gt;
  &lt;fmt:param value="
        <i>expression</i>"/&gt;
  ...
&lt;/fmt:message&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>对于 <code>&lt;fmt:message&gt;</code> ，只有 <code>key</code> 属性才是必需的。 <code>key</code> 属性的值用来确定要显示在资源束中定义的哪些消息。 </p><p>您可以使用 <code>bundle</code> 属性来指定一个显式的资源束，用来查找由 <code>key</code> 属性标识的消息。请注意，该属性的值必须是实际的资源束，比如当指定 <code>&lt;fmt:setBundle&gt;</code> 操作的 <code>var</code> 属性时由该操作所赋予的资源束。 <code>&lt;fmt:message&gt;</code> 的 <code>bundle</code> 属性不支持字符串值（比如 <code>&lt;fmt:bundle&gt;</code> 和 <code>&lt;fmt:setBundle&gt;</code> 的 <code>basename</code> 属性）。 </p><p>如果指定了 <code>&lt;fmt:message&gt;</code> 的 <code>var</code> 属性，那么将由该标记所生成的文本消息赋给指定的变量，而不是写到 JSP 页面。通常，可选的 <code>scope</code> 属性用来指定由 <code>var</code> 属性指定的变量的作用域。 </p><p>需要的时候您可以通过使用 <code>&lt;fmt:param&gt;</code> 标记的 <code>value</code> 属性来提供文本消息的参数化值。或者，可以将该值指定为 <code>&lt;fmt:param&gt;</code> 标记体内容，在这种情况下省略该属性。无论参数化值模式出现在消息文本中的什么地方，由 <code>&lt;fmt:param&gt;</code> 标记指定的值都将合并到从资源束检索的消息，这与 <code>java.text.MessageFormat</code> 类的行为一致。因为参数化值可以通过其下标进行标识，因此嵌套的 <code>&lt;fmt:param&gt;</code> 标记的顺序很重要。 </p><p><code>&lt;fmt:bundle&gt;</code> 、 <code>&lt;fmt:message&gt;</code> 和 <code>&lt;fmt:param&gt;</code> 标记的交互作用如清单 6 所示。此处， <code>&lt;fmt:bundle&gt;</code> 标记通过两个嵌套的 <code>&lt;fmt:message&gt;</code> 标记指定了要在其中检索本地化消息的资源束。这两个 <code>&lt;fmt:message&gt;</code> 标记的第一个对应于带有一个参数化值的消息，还出现了对应的用于该值的 <code>&lt;fmt:param&gt;</code> 标记。 </p><br /><a name="IDALG42F"><b>清单 6. 使用 &lt;fmt:message&gt; 标记显示本地化消息</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:bundle basename="com.taglib.weblog.Greeting"&gt;
&lt;fmt:message key="com.taglib.weblog.Greeting.greeting"&gt;
&lt;fmt:param value="${user.fullName}"/&gt;
&lt;/fmt:message&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;center&gt;
    &lt;a href=
      "&lt;c:url value='/index.jsp'/&gt;"&gt;&lt;fmt:message
          key="com.taglib.weblog.Greeting.return"/&gt;&lt;/a&gt;
  &lt;/center&gt;
&lt;/fmt:bundle&gt;</font></code></pre></td></tr></tbody></table><br /><p>清单 7 演示了 <code>&lt;fmt:bundle&gt;</code> 的 <code>prefix</code> 属性的用法；为 <code>prefix</code> 属性提供的值在嵌套的 <code>&lt;fmt:message&gt;</code> 操作中自动地预先添加到所有 <code>key</code> 值上。因此清单 7 相当于清单 6，只是清单 7 利用了这一便利的特性，使得能够在两个 <code>&lt;fmt:message&gt;</code> 标记中使用缩略的 <code>key</code> 值。 </p><br /><a name="IDAYH42F"><b>清单 7. &lt;fmt:bundle&gt; 的 prefix 属性对 &lt;fmt:message&gt; 标记的影响</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;fmt:bundle basename="com.taglib.weblog.Greeting"
            prefix="com.taglib.weblog.Greeting."&gt;
&lt;fmt:message key="greeting"&gt;
&lt;fmt:param value="${user.fullName}"/&gt;
&lt;/fmt:message&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;center&gt;
    &lt;a href="&lt;c:url value='/index.jsp'/&gt;"&gt;&lt;fmt:message key="return"/&gt;&lt;/a&gt;
  &lt;/center&gt;
&lt;/fmt:bundle&gt;</font></code></pre></td></tr></tbody></table><br /><p>图 7 和图 8 演示了正在工作的 <code>fmt</code> 库与消息相关的标记，显示了由清单 7 中代码所产生的输出，以及 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.html#listing4"><font color="#996699">清单 4</font></a>和 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.html#listing5"><font color="#996699">清单 5</font></a>中的本地化资源束。图 7 显示了当浏览器首选项为英语语言环境时的结果。 </p><br /><a name="IDAZI42F"><b>图 7. 清单 7 中 en_US 语言环境的输出 </b></a><br /><img height="245" alt="清单 7 的 en_US 语言环境的输出" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/greeting_en_US.jpg" width="600" /><br /><p>图 8 显示了指定法语的语言环境的输出。</p><br /><a name="IDAHJ42F"><b>图 8. 清单 7 的 fr_CA 语言环境的输出 </b></a><br /><img height="245" alt="清单 7 的 fr_CA 语言环境的输出" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/greeting_fr_CA.jpg" width="600" /><br /><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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="3"><span class="atitle"><font face="Arial" size="4">结束语</font></span></a></p><p>JSTL <code>fmt</code> 库的定制标记为 JSP 开发人员提供了一种对 Java 平台的国际化 API 的简单访问。文本消息、数值和日期都可以用对语言环境敏感的方式进行显示，还可以将时间调整到特定的时区。可以从用户的浏览器设置自动确定特定用户的语言环境，或者由页面作者显式指定特定用户的语言环境。最后，除了提供用于生成和显示格式化数据的操作之外， <code>fmt</code> 库还包含了用于解析面向数字和时间数据的定制标记。 </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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="resources"><span class="atitle"><font face="Arial" size="4">参考资料 </font></span></a></p><ul><li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/library/j-jstl0415/index.html"><font color="#5c81a7">英文原文</font></a>. <br /><br /></li><li>下载 Weblog 示例应用程序的 <a href="ftp://www6.software.ibm.com/software/developer/library/j-jstl0415.jar"><font color="#5c81a7">源代码</font></a>。 <br /><br /><br /></li><li>Sun 的 JSP 标准标记库 <a href="http://java.sun.com/products/jsp/jstl/index.html"><font color="#5c81a7">产品页</font></a>是学习有关 JSTL 的更多内容的良好起点。 <br /><br /><br /></li><li><a href="http://jcp.org/aboutJava/communityprocess/final/jsr052/"><font color="#996699">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，2002）精彩地概述了所有的 JSTL 特性，作者是参考实现的主管。 <br /><br /><br /></li><li>广受欢迎的 Java 编程作者 David Geary 也撰写了有关 JSTL 的书籍，书名为 <a href="http://www.core-jstl.com/"><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>Mark Davis 和 Helena Shih 在“ <a href="http://www.ibm.com/developerworks/library/j-intljava.html"><font color="#5c81a7">The Java International API: Beyond JDK 1.1</font></a>”（ <i>developerWorks</i>，1998 年 10 月）中广泛地概述了 Java 平台的国际化特性。 <br /><br /><br /></li><li>如果您对国际化感兴趣，您可能不希望错过 Joe Sam Shirah 的综合性教程： <a href="http://www.ibm.com/developerworks/cn/views/java/tutorials.jsp?cv_doc_id=84886"><font color="#5c81a7">java国际化基础知识 </font></a>（ <i>developerWorks</i>，2002 年 4 月）。 <br /><br /><br /></li><li><a href="http://www.loc.gov/standards/iso639-2/englangn.html"><font color="#5c81a7">ISO 639 规范</font></a>定义了有效的语言代码，而 <a href="http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html"><font color="#5c81a7">ISO 3166 规范</font></a>定义了有效的国家或地区代码。 <br /><br /><br /></li><li>与此类似， <a href="http://www.xe.com/iso4217.htm"><font color="#5c81a7">ISO 4217 规范</font></a>定义了货币代码。 <br /><br /><br /></li><li>“ <a href="http://www-128.ibm.com/developerworks/cn/websphere/library/tutorials/vajwebsph353/Part-I/index.html"><font color="#5c81a7">VisualAge for Java 版本 3.5.3/WebSphere Studio 3.5.2 ― JSP 1.1 开发</font></a>”（ <a href="http://www-128.ibm.com/developerworks/cn/websphere/"><font color="#5c81a7">WebSphere 开发者园地</font></a>）是 WBOnline 实战篇，它演示了 servlet、JSP 页面和定制标记库的用法。 <br /><br /><br /></li><li>通过 Jeff Wilson 的优秀论文“ <a href="http://www-128.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-128.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>请在 <a href="http://www-128.ibm.com/developerworks/cn/java/"><font color="#5c81a7"><i>developerWorks</i>Java 技术专区 </font></a>查找大量的 Java 技术参考资料。 <br /><br /></li></ul><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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0415/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="author"><span class="atitle"><font face="Arial" size="4">关于作者</font></span></a></p><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td colspan="3"><font face="Arial" size="4"><img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /></font></td></tr><tr valign="top" align="left"><td><p><font face="Arial" size="4"></font></p></td><td><font face="Arial" size="4"><img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="4" /></font></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"><font color="#5c81a7">mak@taglib.com</font></a>与 Mark 联系。 </p></td></tr></tbody></table><img src ="http://www.blogjava.net/TrampEagle/aggbug/46372.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-05-16 12:39 <a href="http://www.blogjava.net/TrampEagle/articles/46372.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSTL 入门: 探讨 core</title><link>http://www.blogjava.net/TrampEagle/articles/46371.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Tue, 16 May 2006 04:33:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/46371.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/46371.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/46371.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/46371.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/46371.html</trackback:ping><description><![CDATA[原文引自：<a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html">http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html</a><br /><br /><blockquote>顾名思义，JSP 标准标记库（JSP Standard Tag Library，JSTL） <code>core</code> 库为一些基本功能（如，管理限定了作用域的变量和与 URL 交互等）和基本操作（如，迭代和条件化）提供了定制标记。这些标记不仅可以由页面设计人员直接利用，而且还为与其它 JSTL 库相结合从而提供更复杂的表示逻辑奠定了基础。Mark Kolb 在本文中继续对 JSTL 和 <code>core</code> 库进行探讨，研究用标记来协助流控制和 URL 管理。 </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>通过阅读本系列的 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0211/index.html"><font color="#996699">第一篇文章</font></a>，您对 JSTL 有了初步的了解。我们描述了使用其 <i>表达式语言</i>（EL）来访问数据和操作数据。正如您所了解的那样，EL 用来为 JSTL 定制标记的属性赋予动态值，因此，它所起的作用与 JSP 表达式一样，为内置操作及其它定制标记库指定请求时的属性值。 </p><p>为了演示 EL 的用法，我们介绍了 <code>core</code> 库中的三个标记： <code>&lt;c:set&gt;</code> 、 <code>&lt;c:remove&gt;</code> 和 <code>&lt;c:out&gt;</code> 。 <code>&lt;c:set&gt;</code> 和 <code>&lt;c:remove&gt;</code> 用于管理限定了作用域的变量；而 <code>&lt;c:out&gt;</code> 用于显示数据，尤其是显示用 EL 计算出的值。在此基础上，接下来本文把注意力集中在 <code>core</code> 库的其余标记上，这些标记可以大致归为两大类别：流控制和 URL 管理。 </p><p><a name="1"><span class="atitle"><font face="Arial" size="4">示例应用程序</font></span></a></p><p>为了演示 JSTL 标记，我们将使用来自一个工作应用程序的示例，本系列中余下的文章都将使用此应用程序。由于基于 Java 的 Weblog 日渐流行及为人们所熟悉，因此我们将出于此目的使用一个简单的基于 Java 的 Weblog；参阅 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html#resources"><font color="#996699">参考资料</font></a>以下载该应用程序的 JSP 页面和源代码。Weblog（也称为 blog）是一种基于 Web 的简短注释的日志，这些注释是有关 Weblog 的作者所感兴趣的主题，通常带有与 Web 上其它地方的相关文章及讨论的链接。图 1 中显示了该应用程序正在运行时的抓屏。 </p><br /><a name="N400089"><b>图 1. Weblog 应用程序 </b></a><br /><img height="644" alt="Weblog 示例应用程序的抓屏" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/weblog.jpg" width="600" /><br /><p>虽然完整的实现需要二十四个 Java 类，但在表示层中却只涉及 Weblog 应用程序中的两个类， <code>Entry</code> 和 <code>UserBean</code> 。这样，对于理解 JSTL 示例而言，只有这两个类比较重要。图 2 显示了 <code>Entry</code> 和 <code>UserBean</code> 的类图。 </p><br /><a name="N4000AB"><b>图 2. Weblog 应用程序的类图 </b></a><br /><img height="153" alt="Weblog 示例应用程序的类图" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/Classes.jpg" width="428" /><br /><p><code>Entry</code> 类表示 Weblog 中一个标有日期的项。其 <code>id</code> 属性用于在数据库中存储及检索该项，而 <code>title</code> 和 <code>text</code> 属性则表示该项的实际内容。 <code>created</code> 和 <code>lastModified</code> 属性引用了 Java 语言中 <code>Date</code> 类的两个实例，分别用来表示最初创建该项的时间和最后编辑该项的时间。 <code>author</code> 属性引用了标识该项的创建者的 <code>UserBean</code> 实例。 </p><p><code>UserBean</code> 类存储了有关应用程序的已认证用户的信息，如用户名、全名和电子邮件地址。该类还包含一个用于与相关数据库进行交互的 <code>id</code> 属性。其最后一个属性 <code>roles</code> 引用一列 <code>String</code> 值，这列值标识与相应用户相关的、特定于应用程序的角色。对于 Weblog 应用程序，相关的角色是“User”（所有应用程序用户常用的缺省角色）和“Author”（该角色指定可以创建和编辑 Weblog 项的用户）。 </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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="2"><span class="atitle"><font face="Arial" size="4">流控制</font></span></a></p><p>由于可以用 EL 替代 JSP 表达式来指定动态属性值，因此页面创作人员无需使用脚本编制元素。因为脚本编制元素可能是引起 JSP 页面中维护问题的主要原因，所以 JSTL 的主要优点就在于提供了这样简单（且标准）的替代方法。</p><p>EL 从 JSP 容器检索数据，遍历对象层次结构，然后对结果执行简单的操作。不过，除了访问和操作数据之外，JSP 脚本编制元素的另一个常见用法是流控制。尤其是，页面创作人员常借助 scriptlet 来实现迭代或条件内容。然而，因为这样的操作超出了 EL 的能力，所以 <code>core</code> 库提供了几个定制操作来管理流控制，其形式有 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html#2.1"><font color="#996699">迭代</font></a>、 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html#2.2"><font color="#996699">条件化</font></a>和 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html#2.3"><font color="#996699">异常处理</font></a>。 </p><p><a name="2.1"><span class="smalltitle"><strong><font face="Arial">迭代</font></strong></span></a></p><p>在 Web 应用程序环境中，迭代主要用于访存和显示数据集，通常是以列表或表中的一系列行的形式显示。实现迭代内容的主要 JSTL 操作是 <code>&lt;c:forEach&gt;</code> 定制标记。该标记支持两种不同样式的迭代：整数范围上的迭代（类似 Java 语言的 <code>for</code> 语句）和集合上的迭代（类似 Java 语言的 <code>Iterator</code> 和 <code>Enumeration</code> 类）。 </p><p>进行整数范围迭代用到了清单 1 中所示的 <code>&lt;c:forEach&gt;</code> 标记的语法。 <code>begin</code> 和 <code>end</code> 属性要么是静态整数值，要么是可以得出整数值的表达式。它们分别指定迭代索引的初始值以及迭代索引的终止值。当使用 <code>&lt;c:forEach&gt;</code> 在整数范围内进行迭代时，这两个属性是必需的，而其它所有属性都是可选的。 </p><br /><a name="N40013D"><b>清单 1. 通过 &lt;c:forEach&gt; 操作进行数字迭代的语法</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:forEach var="
        <i>name</i>" varStatus="
        <i>name</i>"
    begin="
        <i>expression</i>" end="
        <i>expression</i>" step="
        <i>expression</i>"&gt;
  
        <i>body content</i>
&lt;/c:forEach&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>当出现 <code>step</code> 时，它也必须是整数值。它指定每次迭代后索引的增量。这样，迭代索引从 <code>begin</code> 属性的值开始，以 <code>step</code> 属性的值为增量进行递增，在迭代索引超过 <code>end</code> 属性的值时停止迭代。注：如果省略了 <code>step</code> 属性，那么步长缺省为 1。 </p><p>如果指定了 <code>var</code> 属性，那么将会创建一个带有指定名称的并限定了作用域的变量，并将每次迭代的当前索引值赋给该变量。这一限定了作用域的变量具有嵌套式可视性 ― 只可以在 <code>&lt;c:forEach&gt;</code> 标记体内对其进行访问。（我们很快将讨论可选属性 <code>varStatus</code> 的用法。）清单 2 显示了对一组固定整数值进行迭代的 <code>&lt;c:forEach&gt;</code> 操作示例。 </p><br /><a name="N400186"><b>清单 2. 使用 &lt;c:forEach&gt; 标记来生成表列数据，这些数据对应于某一范围内的数值</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;table&gt;
&lt;tr&gt;&lt;th&gt;Value&lt;/th&gt;
    &lt;th&gt;Square&lt;/th&gt;&lt;/tr&gt;
&lt;c:forEach var="x" begin="0" end="10" step="2"&gt;
  &lt;tr&gt;&lt;td&gt;&lt;c:out value="${x}"/&gt;&lt;/td&gt;
      &lt;td&gt;&lt;c:out value="${x * x}"/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/c:forEach&gt;
&lt;/table&gt;
</font></code></pre></td></tr></tbody></table><br /><p>如图 3 中所示，上面的示例代码生成了一张表，显示前五个偶数及其平方。这是通过将 <code>begin</code> 和 <code>step</code> 属性值指定为 2，而将 <code>end</code> 属性值指定为 10 实现的。此外，用 <code>var</code> 属性创建用于存储索引值的限定了作用域的变量， <code>&lt;c:forEach&gt;</code> 标记体内引用了该变量。尤其是，使用了一对 <code>&lt;c:out&gt;</code> 操作来显示索引及其平方，其中索引的平方是使用一个简单的表达式计算得来的。 </p><br /><a name="N4001BB"><b>图 3. 清单 2 的输出 </b></a><br /><img height="267" alt="清单 2 的输出" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/forEach.jpg" width="467" /><br /><p>在对集合的成员进行迭代时，用到了 <code>&lt;c:forEach&gt;</code> 标记的另一个属性： <code>items</code> 属性，清单 3 中显示了该属性。当使用这种形式的 <code>&lt;c:forEach&gt;</code> 标记时， <code>items</code> 属性是唯一必需的属性。 <code>items</code> 属性的值应该是一个集合，对该集合的成员进行迭代，通常使用 EL 表达式指定值。如果变量名称是通过 <code>&lt;c:forEach&gt;</code> 标记的 <code>item</code> 属性指定的，那么对于每次迭代该已命名变量都将被绑定到集合后续元素上。 </p><br /><a name="N4001E8"><b>清单 3. 通过 &lt;c:forEach&gt; 操作对集合进行迭代的语法</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:forEach var="
        <i>name</i>" items="
        <i>expression</i>" varStatus="
        <i>name</i>"
    begin="
        <i>expression</i>" end="
        <i>expression</i>" step="
        <i>expression</i>"&gt;
  
        <i>body content</i>
&lt;/c:forEach&gt;

      </font></code></pre></td></tr></tbody></table><br /><p><code>&lt;c:forEach&gt;</code> 标记支持 Java 平台所提供的所有标准集合类型。此外，您可以使用该操作来迭代数组（包括基本类型数组）中的元素。表 1 列出了 <code>items</code> 属性所支持的所有值。正如表的最后一行所指出的那样，JSTL 定义了它自己的接口 <code>javax.servlet.jsp.jstl.sql.Result</code> ，用来迭代 SQL 查询的结果。（我们将在本系列后面的文章中详细讨论这一功能。） </p><p><a name="N10207"><span class="smalltitle"><strong><font face="Arial">表 1. &lt;c:forEach&gt; 标记的 items 属性所支持的集合 </font></strong></span></a></p><p></p><table cellspacing="0" cellpadding="3" width="100%" border="1"><tbody><tr valign="top"><td><strong><code>items</code> 的值 </strong></td><td><b>所产生的 <code>item</code> 值 </b></td></tr><tr valign="top"><td><code>java.util.Collection</code></td><td>调用 <code>iterator()</code> 所获得的元素 </td></tr><tr valign="top"><td><code>java.util.Map</code></td><td><code>java.util.Map.Entry</code> 的实例 </td></tr><tr valign="top"><td><code>java.util.Iterator</code></td><td>迭代器元素</td></tr><tr valign="top"><td><code>java.util.Enumeration</code></td><td>枚举元素</td></tr><tr valign="top"><td><code>Object</code> 实例数组 </td><td>数组元素</td></tr><tr valign="top"><td>基本类型值数组</td><td>经过包装的数组元素</td></tr><tr valign="top"><td>用逗号定界的 <code>String</code></td><td>子字符串</td></tr><tr valign="top"><td><code>javax.servlet.jsp.jstl.sql.Result</code></td><td>SQL 查询所获得的行</td></tr></tbody></table><p>可以使用 <code>begin</code> 、 <code>end</code> 和 <code>step</code> 属性来限定在迭代中包含集合中哪些元素。和通过 <code>&lt;c:forEach&gt;</code> 进行数字迭代的情形一样，在迭代集合中的元素时同样要维护一个迭代索引。 <code>&lt;c:forEach&gt;</code> 标记实际上只处理那些与索引值相对应的元素，这些索引值与指定的 <code>begin</code> 、 <code>end</code> 和 <code>step</code> 值相匹配。 </p><p>清单 4 显示了用来迭代集合的 <code>&lt;c:forEach&gt;</code> 标记。对于该 JSP 代码段， <code>entryList</code> 这一限定了作用域的变量被设置成了 <code>Entry</code> 对象列表（确切的说， <code>ArrayList</code> ）。 <code>&lt;c:forEach&gt;</code> 标记依次处理列表中的每个元素，将其赋给一个限定了作用域的变量 <code>blogEntry</code> ，然后生成两个表行 ― 一个用于 Weblog 项的 <code>title</code> ，另一个则用于该项 <code>text</code> 。这些特性是通过一对带有相应 EL 表达式的 <code>&lt;c:out&gt;</code> 操作从 <code>blogEntry</code> 变量检索得到的。注：由于 Weblog 项的标题和文本都可能包含 HTML 标记，因此这两个 <code>&lt;c:out&gt;</code> 标记的 <code>escapeXml</code> 属性都被设置成了 false。图 4 显示了结果。 </p><br /><a name="N4002FA"><b>清单 4. 使用 &lt;c:forEach&gt; 标记显示表示给定日期的 Weblog 项</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;table&gt;
  &lt;c:forEach items="${entryList}" var="blogEntry"&gt;
    &lt;tr&gt;&lt;td align="left" class="blogTitle"&gt;
      &lt;c:out value="${blogEntry.title}" escapeXml="false"/&gt;
    &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td align="left" class="blogText"&gt;
      &lt;c:out value="${blogEntry.text}" escapeXml="false"/&gt;
    &lt;/td&gt;&lt;/tr&gt;
  &lt;/c:forEach&gt;
&lt;/table&gt;
</font></code></pre></td></tr></tbody></table><br /><br /><a name="N400314"><b>图 4. 清单 4 的输出 </b></a><br /><img height="312" alt="清单 4 的输出" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/blog1.jpg" width="590" /><br /><p>不论是对整数还是对集合进行迭代， <code>&lt;c:forEach&gt;</code> 剩余的属性 <code>varStatus</code> 所起的作用相同。和 <code>var</code> 属性一样， <code>varStatus</code> 用于创建限定了作用域的变量。不过，由 <code>varStatus</code> 属性命名的变量并不存储当前索引值或当前元素，而是赋予 <code>javax.servlet.jsp.jstl.core.LoopTagStatus</code> 类的实例。该类定义了一组特性，它们描述了迭代的当前状态，表 2 中列出了这些特性。 </p><p><a name="table1"><span class="smalltitle"><strong><font face="Arial">表 2. LoopTagStatus 对象的特性</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>Getter</b></td><td><b>描述</b></td></tr><tr valign="top"><td>current</td><td><code>getCurrent()</code></td><td>当前这次迭代的（集合中的）项</td></tr><tr valign="top"><td>index</td><td><code>getIndex()</code></td><td>当前这次迭代从 0 开始的迭代索引</td></tr><tr valign="top"><td>count</td><td><code>getCount()</code></td><td>当前这次迭代从 1 开始的迭代计数</td></tr><tr valign="top"><td>first</td><td><code>isFirst()</code></td><td>用来表明当前这轮迭代是否为第一次迭代的标志</td></tr><tr valign="top"><td>last</td><td><code>isLast()</code></td><td>用来表明当前这轮迭代是否为最后一次迭代的标志</td></tr><tr valign="top"><td>begin</td><td><code>getBegin()</code></td><td><code>begin</code> 属性值 </td></tr><tr valign="top"><td>end</td><td><code>getEnd()</code></td><td><code>end</code> 属性值 </td></tr><tr valign="top"><td>step</td><td><code>getStep()</code></td><td><code>step</code> 属性值 </td></tr></tbody></table><p>清单 5 显示了关于如何使用 <code>varStatus</code> 属性的一个示例。这个示例修改了清单 4 中的代码，将 Weblog 项的编号添加到显示 Weblog 标题（title）的表行。它是通过为 <code>varStatus</code> 属性指定一个值，然后访问所生成的限定了作用域的变量的 <code>count</code> 特性来实现这一点的。结果显示在图 5 中。 </p><br /><a name="N4003ED"><b>清单 5. 使用 varStatus 属性来显示 Weblog 项的数目</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;table&gt;
  &lt;c:forEach items=
    "${entryList}" var="blogEntry" varStatus="status"&gt;
    &lt;tr&gt;&lt;td align="left" class="blogTitle"&gt;
      &lt;c:out value="${status.count}"/&gt;.
      &lt;c:out value="${blogEntry.title}" escapeXml="false"/&gt;
    &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td align="left" class="blogText"&gt;
      &lt;c:out value="${blogEntry.text}" escapeXml="false"/&gt;
    &lt;/td&gt;&lt;/tr&gt;
  &lt;/c:forEach&gt;
&lt;/table&gt;
</font></code></pre></td></tr></tbody></table><br /><br /><a name="N400407"><b>图 5. 清单 5 的输出 </b></a><br /><img height="312" alt="清单 5 的输出" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/blog2.jpg" width="590" /><br /><p>除 <code>&lt;c:forEach&gt;</code> 以外， <code>core</code> 库还提供了另一个迭代标记： <code>&lt;c:forTokens&gt;</code> 。JSTL 的这个定制操作与 Java 语言的 <code>StringTokenizer</code> 类的作用相似。清单 6 中显示的 <code>&lt;c:forTokens&gt;</code> 标记除了比 <code>&lt;c:forEach&gt;</code> 的面向集合版本多一个属性之外，其它属性都相同。对于 <code>&lt;c:forTokens&gt;</code> 而言，通过 <code>items</code> 属性指定要标记化的字符串，而通过 <code>delims</code> 属性提供用于生成标记的一组定界符。和 <code>&lt;c:forEach&gt;</code> 的情形一样，可以使用 <code>begin</code> 、 <code>end</code> 和 <code>step</code> 属性将要处理的标记限定为那些与相应索引值相匹配的标记。 </p><br /><a name="N40044C"><b>清单 6. 使用 &lt;c:forTokens&gt; 操作来迭代字符串标记的语法</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:forTokens var="
        <i>name</i>" items="
        <i>expression</i>"
    delims="
        <i>expression</i>" varStatus="
        <i>name</i>"
    begin="
        <i>expression</i>" end="
        <i>expression</i>" step="
        <i>expression</i>"&gt;
  
        <i>body content</i>
&lt;/c:forTokens&gt;

      </font></code></pre></td></tr></tbody></table><br /><p><a name="2.2"><span class="smalltitle"><strong><font face="Arial">条件化</font></strong></span></a></p><p>对于包含动态内容的 Web 页面，您可能希望不同类别的用户看到不同形式的内容。例如，在我们的 Weblog 中，访问者应该能够阅读各项，也许还应该能够提交反馈，但只有经过授权的用户才能公布新项，或编辑已有内容。</p><p>在同一个 JSP 页面内实现这样的功能，然后使用条件逻辑来根据每条请求控制所显示的内容，这样做常常能够改善实用性和软件维护。 <code>core</code> 库提供了两个不同的条件化标记 ― <code>&lt;c:if&gt;</code> 和 <code>&lt;c:choose&gt;</code> ― 来实现这些功能。 </p><p><code>&lt;c:if&gt;</code> 是这两个操作中较简单的一个，它简单地对单个测试表达式进行求值，接下来，仅当对表达式求出的值为 <code>true</code> 时，它才处理标记的主体内容。如果求出的值不为 <code>true</code> ，就忽略该标记的主体内容。如清单 7 所示， <code>&lt;c:if&gt;</code> 可以通过其 <code>var</code> 和 <code>scope</code> 属性（它们所起的作用和在 <code>&lt;c:set&gt;</code> 中所起的作用一样）选择将测试结果赋给限定了作用域的变量。当测试代价非常高昂时，这种能力尤为有用：可以将结果高速缓存在限定了作用域的变量中，然后在随后对 <code>&lt;c:if&gt;</code> 或其它 JSTL 标记的调用中检索该结果。 </p><br /><a name="N4004A9"><b>清单 7. &lt;c:if&gt; 条件操作的语法</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:if test="
        <i>expression</i>" var="
        <i>name</i>" scope="
        <i>scope</i>"&gt;
  
        <i>body content</i>
&lt;/c:if&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>清单 8 显示了与 <code>&lt;c:forEach&gt;</code> 标记的 <code>LoopTagStatus</code> 对象的 <code>first</code> 特性一起使用的 <code>&lt;c:if&gt;</code> 。如图 6 中所示，在这种情况下，只在 Weblog 项的第一项上显示这组项的创建日期，而不在任何其它项前面重复该日期。 </p><br /><a name="N4004D5"><b>清单 8. 使用 &lt;c:if&gt; 来为 Weblog 项显示日期</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;table&gt;
  &lt;c:forEach items=
    "${entryList}" var="blogEntry" varStatus="status"&gt;
    &lt;c:if test="${status.first}"&gt;
      &lt;tr&gt;&lt;td align="left" class="blogDate"&gt;
            &lt;c:out value="${blogEntry.created}"/&gt;
      &lt;/td&gt;&lt;/tr&gt;
    &lt;/c:if&gt;
    &lt;tr&gt;&lt;td align="left" class="blogTitle"&gt;
      &lt;c:out value="${blogEntry.title}" escapeXml="false"/&gt;
    &lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td align="left" class="blogText"&gt;
      &lt;c:out value="${blogEntry.text}" escapeXml="false"/&gt;
    &lt;/td&gt;&lt;/tr&gt;
  &lt;/c:forEach&gt;
&lt;/table&gt;
</font></code></pre></td></tr></tbody></table><br /><br /><a name="N4004F5"><b>图 6. 清单 8 的输出 </b></a><br /><img height="341" alt="清单 8 的输出" src="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/blog3.jpg" width="590" /><br /><p>如清单 8 所示， <code>&lt;c:if&gt;</code> 标记为条件化内容的一些简单情形提供了一种非常简洁的表示法。对于需要进行互斥测试来确定应该显示什么内容的情况下，JSTL <code>core</code> 库还提供了 <code>&lt;c:choose&gt;</code> 操作。清单 9 中显示了 <code>&lt;c:choose&gt;</code> 的语法。 </p><br /><a name="N400516"><b>清单 9. &lt;c:choose&gt; 操作的语法</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:choose&gt;
  &lt;c:when test="
        <i>expression</i>"&gt;
    
        <i>body content</i>
  &lt;/c:when&gt;
  ...
  &lt;c:otherwise&gt;
    
        <i>body content</i>
  &lt;/c:otherwise&gt;
&lt;/c:choose&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>每个要测试的条件都由相应的 <code>&lt;c:when&gt;</code> 标记来表示，至少要有一个 <code>&lt;c:when&gt;</code> 标记。只会处理第一个其 <code>test</code> 值为 <code>true</code> 的 <code>&lt;c:when&gt;</code> 标记体内的内容。如果没有一个 <code>&lt;c:when&gt;</code> 测试返回 <code>true</code> ，那么会处理 <code>&lt;c:otherwise&gt;</code> 标记的主体内容。注：尽管如此， <code>&lt;c:otherwise&gt;</code> 标记却是可选的； <code>&lt;c:choose&gt;</code> 标记至多可有一个嵌套的 <code>&lt;c:otherwise&gt;</code> 标记。如果所有 <code>&lt;c:when&gt;</code> 测试都为 <code>false</code> ，而且又没有给出 <code>&lt;c:otherwise&gt;</code> 操作，那么不会处理任何 <code>&lt;c:choose&gt;</code> 标记的主体内容。 </p><p>清单 10 显示了运用 <code>&lt;c:choose&gt;</code> 标记的示例。在这里，检索请求对象而获得协议信息（通过 EL 的 <code>pageContext</code> 隐式对象），并用简单的字符串比较对协议信息进行测试。根据这些测试的结果，会显示相应的文本消息。 </p><br /><a name="N400572"><b>清单 10. 使用 &lt;c:choose&gt; 进行内容条件化</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:choose&gt;
  &lt;c:when test="${pageContext.request.scheme eq 'http'}"&gt;
    This is an insecure Web session.
  &lt;/c:when&gt;
  &lt;c:when test="${pageContext.request.scheme eq 'https'}"&gt;
    This is a secure Web session.
  &lt;/c:when&gt;
  &lt;c:otherwise&gt;
    You are using an unrecognized Web protocol. How did this happen?!
  &lt;/c:otherwise&gt;
&lt;/c:choose&gt;
</font></code></pre></td></tr></tbody></table><br /><p><a name="2.3"><span class="smalltitle"><strong><font face="Arial">异常处理</font></strong></span></a></p><p>最后一个流控制标记是 <code>&lt;c:catch&gt;</code> ，它允许在 JSP 页面内进行初级的异常处理。更确切地说，在该标记的主体内容中产生的任何异常都会被捕获并被忽略（即，不会调用标准的 JSP 错误处理机制）。然而，如果产生了一个异常并且已经指定了 <code>&lt;c:catch&gt;</code> 标记的可选属性 <code>var</code> ，那么会将异常赋给（具有页面作用域的）指定的变量，这使得能够在页面自身内部进行定制错误处理。清单 11 显示了 <code>&lt;c:catch&gt;</code> 的语法（稍后在 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html#listing18"><font color="#996699">清单 18</font></a>中给出一个示例）。 </p><br /><a name="N40059D"><b>清单 11. &lt;c:catch&gt; 操作的语法</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:catch var="
        <i>name</i>"&gt;
  
        <i>body content</i>
&lt;/c:catch&gt;

      </font></code></pre></td></tr></tbody></table><br /><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><font face="Lucida Console"><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" /></font></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><font face="Lucida Console"><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /></font><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><font face="Lucida Console"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></font></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="3"><span class="atitle"><font face="Arial" size="4">URL 操作</font></span></a></p><p>JSTL <code>core</code> 库中的其余标记主要是关于 URL。这些标记中的第一个被适当地命名为 <code>&lt;c:url&gt;</code> 标记，用于生成 URL。尤其是， <code>&lt;c:url&gt;</code> 提供了三个功能元素，它们在为 J2EE Web 应用程序构造 URL 时特别有用： </p><ul><li>在前面附加当前 servlet 上下文的名称 
</li><li>为会话管理重写 URL 
</li><li>请求参数名称和值的 URL 编码 </li></ul><p>清单 12 显示了 <code>&lt;c:url&gt;</code> 标记的语法。 <code>value</code> 属性用来指定基本 URL，然后在必要时标记对其进行转换。如果这个基本 URL 以一个斜杠开始，那么会在它前面加上 servlet 的上下文名称。可以使用 <code>context</code> 属性提供显式的上下文名称。如果省略该属性，那么就使用当前 servlet 上下文的名称。这一点特别有用，因为 servlet 上下文名称是在部署期间而不是开发期间决定的。（如果这个基本 URL 不是以斜杠开始的，那么就认为它是一个相对 URL，这时就不必添加上下文名称。） </p><br /><a name="N4005E1"><b>清单 12. &lt;c:url&gt; 操作的语法</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:url value="
        <i>expression</i>" context="
        <i>expression</i>"
    var="
        <i>name</i>" scope="
        <i>scope</i>"&gt;
  &lt;c:param name="
        <i>expression</i>" value="
        <i>expression</i>"/&gt;
  ...
&lt;/c:url&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>URL 重写是由 <code>&lt;c:url&gt;</code> 操作自动执行的。如果 JSP 容器检测到一个存储用户当前会话标识的 cookie，那么就不必进行重写。但是，如果不存在这样的 cookie，那么 <code>&lt;c:url&gt;</code> 生成的所有 URL 都会被重写以编码会话标识。注：如果在随后的请求中存在适当的 cookie，那么 <code>&lt;c:url&gt;</code> 将停止重写 URL 以包含该标识。 </p><p>如果为 <code>var</code> 属性提供了一个值（还可以同时为 <code>scope</code> 属性提供一个相应的值，这是可选的），那么将生成的 URL 赋值给这个限定了作用域的指定变量。否则，将使用当前的 <code>JspWriter</code> 输出生成的 URL。这种直接输出其结果的能力允许 <code>&lt;c:url&gt;</code> 标记作为值出现，例如，作为 HTML <code>&lt;a&gt;</code> 标记的 <code>href</code> 属性的值，如清单 13 中所示。 </p><br /><a name="N40062A"><b>清单 13. 生成 URL 作为 HTML 标记的属性值</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;a href="&lt;c:url value='/content/sitemap.jsp'/&gt;"&gt;View sitemap&lt;/a&gt;
</font></code></pre></td></tr></tbody></table><br /><p>最后，如果通过嵌套 <code>&lt;c:param&gt;</code> 标记指定了任何请求参数，那么将会使用 HTTP GET 请求的标准表示法将它们的名称和值添加到生成的 URL 后面。此外，还进行 URL 编码：为了生成有效的 URL，将对这些参数的名称或值中出现的任何字符适当地进行转换。清单 14 演示了 <code>&lt;c:url&gt;</code> 的这种行为。 </p><br /><a name="N400645"><b>清单 14. 生成带请求参数的 URL</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:url value="/content/search.jsp"&gt;
  &lt;c:param name="keyword" value="${searchTerm}"/&gt;
  &lt;c:param name="month" value="02/2003"/&gt;
&lt;/c:url&gt;
</font></code></pre></td></tr></tbody></table><br /><p>清单 14 中的 JSP 代码被部署到一个名为 <code>blog</code> 的 servlet 上下文，限定了作用域的变量 <code>searchTerm</code> 的值被设置为 <code>"core library"</code> 。如果检测到了会话 cookie，那么清单 14 生成的 URL 将类似于清单 15 中的 URL。注：在前面添加上下文名称，而在后面附加请求参数。此外， <code>keyword</code> 参数值中的空格和 <code>month</code> 参数值中的斜杠都被按照 HTTP GET 参数的需要进行了编码（确切地说，空格被转换成了 <code>+</code> ，而斜杠被转换成了 <code>%2F</code> 序列）。 </p><br /><a name="N400671"><b>清单 15. 有会话 cookie 时生成的 URL</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">/blog/content/search.jsp?keyword=foo+bar&amp;month=02%2F2003
</font></code></pre></td></tr></tbody></table><br /><p>当没有会话 cookie 时，生成的结果如清单 16 中所示。同样，servlet 上下文被添加到了前面，而 URL 编码的请求参数被附加到了后面。不过，除此以外还重写了基本 URL 以包含指定的会话标识。当浏览器发送用这种方式重写的 URL 请求时，JSP 容器自动抽取会话标识，并将请求与相应的会话进行关联。这样，需要会话管理的 J2EE 应用程序就无需依赖由应用程序用户启用的 cookie 了。</p><br /><a name="N400681"><b>清单 16. 没有会话 cookie 时生成的 URL</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">/blog/content/search.jsp;jsessionid=233379C7CD2D0ED2E9F3963906DB4290
  ?keyword=foo+bar&amp;month=02%2F2003
</font></code></pre></td></tr></tbody></table><br /><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><font face="Lucida Console"><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" /></font></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><font face="Lucida Console"><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /></font><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><font face="Lucida Console"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></font></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="4"><span class="atitle"><font face="Arial" size="4">导入内容</font></span></a></p><p>JSP 有两种内置机制可以将来自不同 URL 的内容合并到一个 JSP 页面： <code>include</code> 伪指令和 <code>&lt;jsp:include&gt;</code> 操作。不过，不管是哪种机制，要包含的内容都必须属于与页面本身相同的 Web 应用程序（或 servlet 上下文）。两个标记之间的主要区别在于： <code>include</code> 伪指令在页面编译期间合并被包含的内容，而 <code>&lt;jsp:include&gt;</code> 操作却在请求处理 JSP 页面时进行。 </p><p>从本质上讲， <code>core</code> 库的 <code>&lt;c:import&gt;</code> 操作是更通用、功能更强大的 <code>&lt;jsp:include&gt;</code> 版本（好像是 <code>&lt;jsp:include&gt;</code> “服用了兴奋剂”的）。和 <code>&lt;jsp:include&gt;</code> 一样， <code>&lt;c:import&gt;</code> 也是一种请求时操作，它的基本任务就是将其它一些 Web 资源的内容插入 JSP 页面中。如清单 17 中所示，它的语法非常类似于 <code>&lt;c:url&gt;</code> 的语法。 </p><br /><a name="N4006C7"><b>清单 17. &lt;c:import&gt; 操作的语法</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:import url="
        <i>expression</i>" context="
        <i>expression</i>"
    charEncoding="
        <i>expression</i>" var="
        <i>name</i>" scope="
        <i>scope</i>"&gt;
  &lt;c:param name="
        <i>expression</i>" value="
        <i>expression</i>"/&gt;
  ...
&lt;/c:import&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>通过 <code>url</code> 属性指定将要导入内容的 URL，这个属性是 <code>&lt;c:import&gt;</code> 的唯一一个必选属性。这里允许使用相对 URL，并且根据当前页面的 URL 来解析这个相对 URL。但是，如果 <code>url</code> 属性的值以斜杠开始，那么它就被解释成本地 JSP 容器内的绝对 URL。如果没有为 <code>context</code> 属性指定值，那么就认为这样的绝对 URL 引用当前 servlet 上下文内的资源。如果通过 <code>context</code> 属性显式地指定了上下文，那么就根据指定的 servlet 上下文解析绝对（本地）URL。 </p><p>但 <code>&lt;c:import&gt;</code> 操作并不仅仅限于访问本地内容。也可以将包含协议和主机名的完整 URI 指定为 <code>url</code> 属性的值。实际上，协议甚至不仅局限于 HTTP。 <code>&lt;c:import&gt;</code> 的 <code>url</code> 属性值可以使用 <code>java.net.URL</code> 类所支持的任何协议。清单 18 中显示了这种能力。 </p><p>其中， <code>&lt;c:import&gt;</code> 操作用来包含通过 FTP 协议访问的文档内容。此外，还使用了 <code>&lt;c:catch&gt;</code> 操作，以便在本地处理 FTP 文件传送期间可能发生的任何错误。错误处理是这样实现的：使用 <code>&lt;c:catch&gt;</code> 的 <code>var</code> 属性为异常指定一个限定了作用域的变量，然后使用 <code>&lt;c:if&gt;</code> 检查其值。如果产生了异常，那么就会对那个限定了作用域的变量进行赋值：如清单 18 中的 EL 表达式所显示的那样，该变量的值将 <i>不</i>会为空。由于 FTP 文档的检索将会失败，因此会显示有关这种情况的错误消息。 </p><br /><a name="listing18"><b>清单 18. 将 &lt;c:import&gt; 与 &lt;c:catch&gt; 相结合的示例</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:catch var="exception"&gt;
  &lt;c:import url="ftp://ftp.example.com/package/README"/&gt;
&lt;/c:catch&gt;
&lt;c:if test="${not empty exception}"&gt;
  Sorry, the remote content is not currently available.
&lt;/c:if&gt;
</font></code></pre></td></tr></tbody></table><br /><p><code>&lt;c:import&gt;</code> 操作的最后两个（可选的）属性是 <code>var</code> 和 <code>scope</code> 。 <code>var</code> 属性会导致从指定 URL 获取的内容（作为 <code>String</code> 值）被存储在一个限定了作用域的变量中，而不是包含在当前 JSP 页面中。 <code>scope</code> 属性控制该变量的作用域，缺省情况下是页面作用域。如同我们在今后的文章中将要看到的那样，JSTL <code>xml</code> 库中的标记利用了 <code>&lt;c:import&gt;</code> 这种能力，即将整个文档存储在一个限定了作用域的变量中。 </p><p>还要注意的是，可以使用（可选的）嵌套的 <code>&lt;c:param&gt;</code> 标记来为正在导入的 URL 指定请求参数。与在 <code>&lt;c:url&gt;</code> 中嵌套 <code>&lt;c:param&gt;</code> 标记一样，必要时也要对参数名称和参数值进行 URL 编码。 </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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="5"><span class="atitle"><font face="Arial" size="4">请求重定向</font></span></a></p><p>最后一个 <code>core</code> 库标记是 <code>&lt;c:redirect&gt;</code> 。该操作用于向用户的浏览器发送 HTTP 重定向响应，它是 JSTL 中与 <code>javax.servlet.http.HttpServletResponse</code> 的 <code>sendRedirect()</code> 方法功能相当的标记。清单 19 中显示了该标记的 <code>url</code> 和 <code>context</code> 属性，它们的行为分别等同于 <code>&lt;c:import&gt;</code> 的 <code>url</code> 和 <code>context</code> 属性的行为，是嵌套任何 <code>&lt;c:param&gt;</code> 标记的结果。 </p><br /><a name="N4007A2"><b>清单 19. &lt;c:redirect&gt; 操作的语法</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:redirect url="
        <i>expression</i>" context="
        <i>expression</i>"&gt;
  &lt;c:param name="
        <i>expression</i>" value="
        <i>expression</i>"/&gt;
  ...
&lt;/c:redirect&gt;

      </font></code></pre></td></tr></tbody></table><br /><p>清单 20 显示了 <code>&lt;c:redirect&gt;</code> 操作，它用一个到指定错误页面的重定向代替了清单 18 中的错误消息。在该示例中， <code>&lt;c:redirect&gt;</code> 标记的用法与标准 <code>&lt;jsp:forward&gt;</code> 操作的用法类似。不过请回忆一下：通过请求分派器进行转发是在服务器端实现的，而重定向却是由浏览器来执行的。从开发人员的角度来讲，转发比重定向更有效率，但 <code>&lt;c:redirect&gt;</code> 操作却更灵活一些，因为 <code>&lt;jsp:forward&gt;</code> 只能分派到当前 servlet 上下文内的其它 JSP 页面。 </p><br /><a name="N4007D2"><b>清单 20. 响应异常的重定向</b></a><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;c:catch var="exception"&gt;
  &lt;c:import url="ftp://ftp.example.com/package/README"/&gt;
&lt;/c:catch&gt;
&lt;c:if test="${not empty exception}"&gt;
  &lt;c:redirect url="/errors/remote.jsp"/&gt;
&lt;/c:if&gt;
</font></code></pre></td></tr></tbody></table><br /><p>从用户的角度来看，主要区别在于重定向会更新浏览器所显示的 URL，并因此影响书签的设置。转发却不这样，它对最终用户是透明的。这样，选择 <code>&lt;c:redirect&gt;</code> 还是 <code>&lt;jsp:forward&gt;</code> 还取决于所期望的用户体验。 </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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="6"><span class="atitle"><font face="Arial" size="4">结束语</font></span></a></p><p>JSTL <code>core</code> 库含有多种通用的定制标记，广大的 JSP 开发人员都会使用这些标记。例如，URL 和异常处理标记很好地补充了现有的 JSP 功能，如 <code>&lt;jsp:include&gt;</code> 和 <code>&lt;jsp:forward&gt;</code> 操作、 <code>include</code> 伪指令以及 <code>page</code> 伪指令的 <code>errorpage</code> 属性。迭代和条件操作使得无需脚本编制元素就能够实现复杂的表示逻辑，尤其在将变量标记（ <code>&lt;c:set&gt;</code> 和 <code>&lt;c:remove&gt;</code> ）与 EL 相结合使用时更是如此。 </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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="resources"><span class="atitle"><font face="Arial" size="4">参考资料 </font></span></a></p><ul><li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/library/j-jstl0318/index.html"><font color="#5c81a7">英文原文</font></a>. <br /><br /></li><li>本系列的第一篇文章 <a href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0211/index.html"><font color="#996699">JSTL 入门：表达式语言</font></a>（ <i>developerWorks</i>，2003 年 2 月）介绍了 JSTL，并详细讨论了表达式语言及 <code>core</code> 库中的几个标记。 <br /><br /><br /></li><li>下载 Weblog 示例应用程序的 <a href="ftp://www6.software.ibm.com/software/developer/library/j-jstl0318.jar"><font color="#5c81a7">源代码</font></a>。 <br /><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="#996699">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，2002 年）出色地讨论了由参考实现领导编写的全部 JSTL 功能。 <br /><br /><br /></li><li>David Geary 是一位很受欢迎的 Java 编程方面的作者，他还著有一部关于 JSTL 的书籍，名为 <a href="http://www.core-jstl.com/"><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-128.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-128.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>在 <a href="http://www-128.ibm.com/developerworks/cn/java/"><font color="#5c81a7"><i>developerWorks</i>Java 技术专区 </font></a>可以找到数百篇有关 Java 技术的参考资料。 <br /><br /></li></ul><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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/java/j-jstl0318/index.html#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="author"><span class="atitle"><font face="Arial" size="4">关于作者</font></span></a></p><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td colspan="3"><font face="Arial" size="4"><img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /></font></td></tr><tr valign="top" align="left"><td><p><font face="Arial" size="4"></font></p></td><td><font face="Arial" size="4"><img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="4" /></font></td><td width="100%"><p>Mark Kolb 是一位在德克萨斯州奥斯汀市（Austin）工作的软件工程师。他常就服务器端 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"><font color="#5c81a7">mak@taglib.com</font></a>与 Mark 联系。 </p></td></tr></tbody></table><img src ="http://www.blogjava.net/TrampEagle/aggbug/46371.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-05-16 12:33 <a href="http://www.blogjava.net/TrampEagle/articles/46371.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSTL 入门: 表达式语言</title><link>http://www.blogjava.net/TrampEagle/articles/46366.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Tue, 16 May 2006 03:34:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/46366.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/46366.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/46366.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/46366.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/46366.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 原文引自：http://www-128.ibm.com/developerworks/cn/java/j-jstl0211/index.html		JSP 标准标记库（JSP Standard Tag Library，JSTL）是一个实现 Web 应用程序中常见的通用功能的定制标记库集，这些功能包括迭代和条件判断、数据管理格式化、XML 操作以及数据库访问。在 developerWorks 上...&nbsp;&nbsp;<a href='http://www.blogjava.net/TrampEagle/articles/46366.html'>阅读全文</a><img src ="http://www.blogjava.net/TrampEagle/aggbug/46366.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-05-16 11:34 <a href="http://www.blogjava.net/TrampEagle/articles/46366.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AXIS实现Web服务深入篇</title><link>http://www.blogjava.net/TrampEagle/articles/45561.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Wed, 10 May 2006 15:16:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/45561.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/45561.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/45561.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/45561.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/45561.html</trackback:ping><description><![CDATA[原文引自：<a href="http://www-128.ibm.com/developerworks/cn/webservices/ws-deepaxis/">http://www-128.ibm.com/developerworks/cn/webservices/ws-deepaxis/</a><br /><br />作者：刘东<br /><br /><blockquote>本文主要介绍使用service方式实现Web服务、复杂类型参数或者返回值以及面向消息/文档的服务类型，同时还会简单提及Web服务的会话管理以及安全问题等等。</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>前段时间我的一篇文章《应用AXIS开始Web服务之旅》介绍了如何通过AXIS这个项目来实现Web服务的功能。该文章主要介绍AXIS的结构、如何使用jws文件的方式开发一个简单的Web服务，并用了比较大的篇幅来介绍Web服务的客户端编程，应该说是使用AXIS开发Web服务的入门篇，本文假设你已经看过《应用AXIS开始Web服务之旅》并对AXIS有一定的基础，在这个基础上我们将要介绍的内容有几个方面包括使用service方式实现Web服务、复杂类型参数或者返回值以及面向消息/文档的服务类型，同时还会简单提及Web服务的会话管理以及安全问题等等。</p><p>在开始我们的文章之前，我们还需要搭建一个环境，我们需要一个支持Web服务的web应用程序并假设名字为axis，如何建立请参照《应用AXIS开始Web服务之旅》文章中的介绍。</p><p><a name="0"><span class="atitle"><font face="Arial" size="4">使用定制发布编写Web服务</font></span></a></p><p><font face="Arial" size="4"></font></p><p>使用jws文件的方式编写Web服务具有方便、快捷的优点，它可以很快的将你已有的类发布成Web服务。但是更多的时候这并不是一个好的主意，因为这种做法引发的问题是我们必须要将已有类的源码发布出来，因为更多的时候我们并不想这样做；另外虽然你可以先用工具开发并调试完毕一个java文件后再改名为jws，但是这多少有些便扭，而且并不是类中的所有方法你都想发布成可通过Web服务来访问的，这时候你就必须将这些方法的修饰符改为不是public的，这就跟你原有的类不同步，以后的修改将会更加的麻烦。</p><p>在这里我把定制发布方式称为service方式，就好像JSP的出现不会使Servlet失宠的道理一样，有了jws，service方式还是有它的用武之地，而且是大放异彩。发布一个service方式的Web服务需要两部分内容：类文件以及Web服务发布描述文件。下面我们使用一个简单的例子来讲述这个过程。</p><p>首先我们需要一个service类，这个类跟普通的类没有任何区别，下面是我们实现一个城市便民服务的类，我们需要将CityService类的两个方法getZip和getTel发布成Web服务，编译该文件并把class文件拷贝到&lt;webapp&gt;/WEB-INF/classes对应目录下。</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">Package lius.axis.demo;
/** 
  * 该类实现了城市服务，用于发布成Web服务 
  * @author Liudong 
  */
  
  public class CityService {
  /**     
    * 获取指定城市的邮编     
    * @param city     
    * @return     
    */
    public String getZip(String city) { 
 return "510630";
    }
    
    /**     
      * 获取指定城市的长途区号     
      * @param city     
      * @return     
      */ 
    
    public String getTel(String city) {
 return "020"; 
    }
}
</font></code></pre></td></tr></tbody></table><br /><p>程序已经完成，下面是发布这个Web服务。打开&lt;webapp&gt;/WEB-INF/server-config.wsdd如果这个文件不存在则创建一个新的文件，内容如下：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;deployment xmlns="http://xml.apache.org/axis/wsdd/" 
	xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"&gt; 
 &lt;globalConfiguration&gt;  
  &lt;parameter name="adminPassword" value="admin"/&gt;  
  &lt;parameter name="attachments.implementation" 
  	value="org.apache.axis.attachments.AttachmentsImpl"/&gt;  
  &lt;parameter name="sendXsiTypes" value="true"/&gt;  
  &lt;parameter name="sendMultiRefs" value="true"/&gt;  
  &lt;parameter name="sendXMLDeclaration" value="true"/&gt;  
  &lt;parameter name="axis.sendMinimizedElements" value="true"/&gt;  
  &lt;requestFlow&gt;   
   &lt;handler type="java:org.apache.axis.handlers.JWSHandler"&gt;    
    &lt;parameter name="scope" value="session"/&gt;   
   &lt;/handler&gt;   
   &lt;handler type="java:org.apache.axis.handlers.JWSHandler"&gt;    
    &lt;parameter name="scope" value="request"/&gt;    
    &lt;parameter name="extension" value=".jwr"/&gt;   
   &lt;/handler&gt;  
  &lt;/requestFlow&gt; 
 &lt;/globalConfiguration&gt; 
 &lt;handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/&gt; 
 &lt;handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/&gt; 
 &lt;handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/&gt;   

 &lt;service name="city" provider="java:RPC"&gt;  
  &lt;!-- 服务类名 --&gt;   
  &lt;parameter name="className" value="lius.axis.demo.CityService"/&gt;  
  &lt;!-- 允许访问所有方法 --&gt;  
  &lt;parameter name="allowedMethods" value="*"/&gt; 
 &lt;/service&gt;  
 &lt;transport name="http"&gt;  
  &lt;requestFlow&gt;   
   &lt;handler type="URLMapper"/&gt;   
   &lt;handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/&gt;  
  &lt;/requestFlow&gt; 
 &lt;/transport&gt; 
 &lt;transport name="local"&gt;  
  &lt;responseFlow&gt;   
   &lt;handler type="LocalResponder"/&gt;  
  &lt;/responseFlow&gt; 
 &lt;/transport&gt;
&lt;/deployment&gt;
</font></code></pre></td></tr></tbody></table><br /><p>其中粗斜体的部分是我们服务的配置信息，启动Tomcat并打开浏览求访问地址： http://localhost:8080/axis/services/city?wsdl ，下面是浏览器显示我们Web服务的WDSL数据。</p><br /><img alt="" src="http://www-128.ibm.com/developerworks/cn/webservices/ws-deepaxis/image001.jpg" /><br /><p>当然了，这个过程比起jws方式来说是稍微麻烦一点，你可以把它想象成你发布一个servlet一样，创建servlet类然后在web.xml中加入配置信息。</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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-deepaxis/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="1"><span class="atitle"><font face="Arial" size="4">处理复杂类型参数和返回值</font></span></a></p><p><font face="Arial" size="4"></font></p><p>之前我们做的演示程序都很简单，方法的参数和返回值都是简单类型的数据，但是在实际应用过程中往往没有这么简单。在使用面向对象的编程语言时，我们会希望数据类型可以是某个对象，比如我们提供一个接口用来发送短信息，那么我们希望接口的参数是一个消息对象，这个消息对象封装了一条信息的所有内容包括发送者、接收者、发送时间、优先级、信息内容等等，如果我们把每个内容都做成一个参数，那这个接口的参数可能会非常的多。因此封装成对象是很有必要的。</p><p>在使用Axis来编写Web服务时对复杂类型数据的处理同样也是非常简单。Axis要求复杂类型对象的编写必须符合JavaBean的规范，简单的说就是对象的属性是通过getter/setter方法来访问的。来看看下面这个简单的例子所输出的WSDL信息有何特殊的地方。为了简便，我们还是使用jws来编写，需要编写三个文件：sms.jws,Message.java,Response.java。</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">//文件名：sms.jws
import lius.axis.demo.*;

public class sms{  

/**  
  * 短信息发送Web服务接口  
  */
  
  public Response send(Message msg) throws Exception{
 System.out.println("CONTENT:"+msg.getContent());
 Response res = new Response();
 res.setMessage(msg);
 res.setCode(0);
 res.setErrorText("");
 return res;    
  } 
}
</font></code></pre></td></tr></tbody></table><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">//Message.javapackage lius.axis.demo;

/** 
  * 欲发送的信息 
  * @author Liudong 
  */
  
public class Message {
 private String from;
 private String to;
 private String content;
 private int priority;
 
 public String getContent() {
  return content;
 }
 
 public void setContent(String content) {
  this.content = content;
 } 
 
 public String getFrom() { 
  return from;
 }
 
 public void setFrom(String from) { 
  this.from = from;
 }    
 
 public int getPriority() {
  return priority;
 }
 
 public void setPriority(int priority) {
  this.priority = priority;
 } 
 
 public String getTo() {
  return to;
 } 
 
 public void setTo(String to) {
  this.to = to;
 }
}
</font></code></pre></td></tr></tbody></table><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">//Response.javapackage lius.axis.demo;

/** 
  * 信息发送回应，在这里我们做了一个对Message 类的引用 
  * @author Liudong 
  */
  
public class Response {
 private int code; 
 
 //发送结果代码 
 private String errorText;
 private Message message;
 
 //发送的原始信息  
 public int getCode() {
  return code;
 } 
 
 public void setCode(int code) {
  this.code = code;
 } 
 
 public String getErrorText() { 
  return errorText;
 } 
 
 public void setErrorText(String errorText) {   
  this.errorText = errorText;
 } 
 
 public Message getMessage() {
  return message;
 } 

 
 public void setMessage(Message message) { 
  this.message = message;
 }
}
</font></code></pre></td></tr></tbody></table><br /><p>编译Message.java和Response.java并将编译后的类文件拷贝到axis/WEB-INF/classes对应包的目录下，sms.jws拷贝到axis目录，访问http://localhost:8080/axis/sms.jws?wsdl即可看到WSDL信息，这些信息与之前不同的在于下面列出的内容(注意粗斜体部分内容)：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;wsdl:types&gt;
&lt;schema targetNamespace="http://demo.axis.lius" xmlns="http://www.w3.org/2001/XMLSchema"&gt;
  &lt;import namespace="http://schemas.xmlsoap.org/soap/encoding/" /&gt;
  &lt;complexType name="Message"&gt;
    &lt;sequence&gt;
      &lt;element name="content" nillable="true" type="xsd:string" /&gt;
      &lt;element name="from" nillable="true" type="xsd:string" /&gt;
      &lt;element name="priority" type="xsd:int" /&gt;
      &lt;element name="to" nillable="true" type="xsd:string" /&gt;
    &lt;/sequence&gt;
  &lt;/complexType&gt;
  &lt;complexType name="Response"&gt;
    &lt;sequence&gt;
      &lt;element name="code" type="xsd:int" /&gt;
      &lt;element name="errorText" nillable="true" type="xsd:string" /&gt;
      &lt;element name="message" nillable="true" type="tns1:Message" /&gt;
    &lt;/sequence&gt;
  &lt;/complexType&gt;
&lt;/schema&gt;
&lt;/wsdl:types&gt;
</font></code></pre></td></tr></tbody></table><br /><p>这里定义了两个类型Message和Response，就是我们接口的参数类型以及返回值的类型。现在再使用WSDL2Java工具来生成客户端Helper类看看Axis帮我们做了什么？它会自动帮我们生成两个类Message和Response，包名与类名都跟我们刚才定义的一致，你可以打开看看跟我们刚才编写的类差别多大？这两个类添加了很多方法例如getTypeDesc、getSerializer、getDeserializer等等。现在你就可以随便写个小程序测试一下了，我们就不在累赘了。Service方式Web服务的处理跟jws是类似的，不同在于service方式需要在server-config.wsdd添加类型的映射配置，下面给出一个配置的示例，读者可以根据实际情况进行修改。</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;service name="SmsService" provider="java:RPC"&gt;
 &lt;parameter name="className" value="lius.axis.demo.SmsService"/&gt;
 &lt;parameter name="allowedMethods" value="send"/&gt;
 &lt;operation name="send" returnType="ns:Response"&gt;
  &lt;parameter name="msg" type="ns:Message"/&gt;
 &lt;/operation&gt;
 
&lt;!-- 这里定义了方法的参数以及返回值 --&gt;

 &lt;typeMapping deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"   
 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
 qname="ns:Message"
 serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
 type="java:lius.axis.demo.Message" xmlns:ns="SmsService"/&gt;
 
 &lt;typeMapping
 deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"    
 	encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
 qname="ns:Response"    
 serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"    
 type="java:lius.axis.demo.Response" xmlns:ns="SmsService"/&gt;
 &lt;/service&gt;

</font></code></pre></td></tr></tbody></table><br /><p>其他编程语言也都可以借助语言本身所附带的工具来生成这些复杂类型，如果你嫌麻烦的话可以使用XML来描述这些复杂类型，这样就简单很多。</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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-deepaxis/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="2"><span class="atitle"><font face="Arial" size="4">面向消息/文档的Web服务类型</font></span></a></p><p><font face="Arial" size="4"></font></p><p>我们前面介绍的服务方式是基于RPC(远程过程调用)方式，这也是Web服务最常用的方式。面向消息/文档的的类型跟RPC不同的是它提供了一个更底层的抽象，要求更多的编程工作。客户端可以传入任何的XML文档，得到的响应不一定是SOAPEnvelope，可以返回任何它所需要的东西，甚至不返回。虽然这对开发者来说非常的灵活，但是这种通讯类型在实际的应用中并不常见。面向消息/文档的Web服务主要适合于下面几种情况，比如批量处理，基于表单的数据导入，有需要返回非XML数据时，Web服务器实现中要求直接访问传输层等等。</p><p>对于RPC类型的服务需要在全局配置文件server-config.wsdd中设置一行&lt;service ... provider="java:RPC"&gt;，其中RPC就是服务的方式，而对于面向消息/文档的服务类型那java:RPC就要替换成为Message，并且面向消息/文档的服务类型必须通过WSDD配置来发表。对于完成面向消息服务的类，其方法必须具有以下的格式：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">public Element[] methodName(Element [] elems)
</font></code></pre></td></tr></tbody></table><br /><p>其中methodName为你自定义的方法名。在Axis的目录下可以找到MessageService.java，这就是一个完成了该类型的服务类，该服务的在WSDD中的配置如下：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;deployment name="test" xmlns="http://xml.apache.org/axis/wsdd/"      
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"&gt;
 &lt;service name="MessageService" style="message"&gt;
  &lt;parameter name="className" value="samples.message.MessageService"/&gt;
  &lt;parameter name="allowedMethods" value="methodName"/&gt; 
 &lt;/service&gt;
&lt;/deployment&gt;
</font></code></pre></td></tr></tbody></table><br /><p>不管是什么内容的Web服务，对客户端来说都是一样的，使用WSDL2Java来生成的客户端Helper类的MessageService接口如下：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">/** 
  * MessageService.java 
  * 
  * This file was auto-generated from WSDL 
  * by the Apache Axis WSDL2Java emitter. 
  */
  
package liudong.axis.services.MessageService;

public interface MessageService extends java.rmi.Remote {
 public java.lang.Object echoElements(java.lang.Object part) throws java.rmi.RemoteException;
}
</font></code></pre></td></tr></tbody></table><br /><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><font face="Lucida Console"><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" /></font></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><font face="Lucida Console"><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /></font><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><font face="Lucida Console"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></font></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-deepaxis/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="3"><span class="atitle"><font face="Arial" size="4">我从哪里可以获得…</font></span></a></p><p><font face="Arial" size="4"></font></p><p>Axis文档中有一句话很有意思，对于绝大多数类似于"我从哪里可以获得…"的问题，答案都在MessageContext类中。通过MessageContext类你可以获取下面几个内容，一个AxisEngine实例的引用；请求以及回应的信息；验证信息以及对于Servlet规范中的实例引用等等。例如当我们需要客户端的IP地址时我们可以通过下面代码片段获取：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">/**      
  * 获取客户端请求     
  * @return     
  */
  
private HttpServletRequest getRequest() throws Exception{
 MessageContext context = MessageContext.getCurrentContext();
 HttpServletRequest req = (HttpServletRequest)context.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);        
 return req.getRemoteHost();
}
</font></code></pre></td></tr></tbody></table><br /><p>在类HTTPConstants中，所有以MC_开头的常量就是你所可以获取到的信息，例如上面通过MC_HTTP_SERVLETREQUEST获取对应Servlet规范中的HTTP请求。更详细的信息可以通过查询API文档获取。</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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-deepaxis/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="4"><span class="atitle"><font face="Arial" size="4">Web服务会话管理</font></span></a></p><p><font face="Arial" size="4"></font></p><p>在Web服务中我们可以借助HTTP以及HTTP Cookie来处理会话信息。前面我们介绍了大多数对Axis的管理都是通过MessageContext实例来完成的。下面的例子首先验证用户的登录帐号与口令如果正确则在会话中保存用户的登录信息，并提供接口供客户端获取密码。</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">import org.apache.axis.MessageContext;
import org.apache.axis.session.Session;

public class login{ 
 public boolean login(String user, String pass){ 
  MessageContext mc = MessageContext.getCurrentContext();
  Session session = mc.getSession();
  session.set("user",user);
  
  //保存用户名与口令
  session.set("pass",pass);
  return true;
 }
 
 public String getPassword(String user){
  MessageContext mc = MessageContext.getCurrentContext();
  Session session = mc.getSession();
  if(user.equals(session.get("user"))) 
   return (String)session.get("pass");
  return null;
 }
}
</font></code></pre></td></tr></tbody></table><br /><p>对于服务器端来讲只需要通过MessageContext实例获取Session对象即可进行会话级的数据保存或者读取，而对于通过Axis的WSDL2Java工具生成的客户端来讲还需要做一个特殊的设置，请看下面客户端代码片段。</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">public static void main(String[] args) throws Exception {
 LoginServiceLocator lsl = new LoginServiceLocator();
        lsl.setMaintainSession(true);
        Login login = lsl.getlogin();
        if(login.login("ld","haha")) 
  System.out.println("PWD:"+login.getPassword("ld"));
        else  
  System.out.println("Login failed.");
}
</font></code></pre></td></tr></tbody></table><br /><p>代码中的粗体部分就是让Axis帮助我们自动处理服务器返回的Cookie信息以保证会话正常工作。</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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-deepaxis/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="5"><span class="atitle"><font face="Arial" size="4">保护Web服务</font></span></a></p><p><font face="Arial" size="4"></font></p><p>网络的安全问题永远是需要最先考虑的问题，可是怎么能让我们的Web服务更加安全呢？为此Axis建议可以根据实际的需要采取以下的几种方法。</p><ol><li>使用HTTPS传输方式 该方式需要在Web服务器上进行配置同时需要客户端的支持。该措施有效的防止数据在网络传输过程中被窥视。 
</li><li>重命名Axis已有的一些名字，例如AdminService、AxisServlet，删除Axis目录下一些无用的程序，例如happyaxis.jsp以及一些无用的jar包等。 
</li><li>通过设置axis.enableListQuery的值为false来停止AxisServlet列出所有服务的功能。 
</li><li>禁止自动生成WSDL的功能 
</li><li>使用过滤器来增加一些验证功能，例如客户端的地址等。 </li></ol><p>最常用的不外乎上面几个，至于更详细的资料可以参考Axis解压目录下的docs/reference.html文件的详细介绍。</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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-deepaxis/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="resources"><span class="atitle"><font face="Arial" size="4">参考资料 </font></span></a></p><ul><li>《应用AXIS开始Web服务之旅》 <br /><a href="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/index.html"><font color="#5c81a7">http://www.ibm.com/developerworks/cn/webservices/ws-startaxis/index.shtml</font></a><br /><br /></li><li>IBM开发者站点Web服务专区 <br /><a href="http://www-128.ibm.com/developerworks/cn/webservices"><font color="#5c81a7">http://www.ibm.com/developerworks/cn/webservices</font></a><br /><br /></li><li>Apache网站AXIS项目 <br /><a href="http://ws.apache.org/axis/"><font color="#5c81a7">http://ws.apache.org/axis/</font></a><br /><br /></li><li>W3C之Web服务 <br /><a href="http://www.w3.org/2002/ws/"><font color="#5c81a7">http://www.w3.org/2002/ws/</font></a><br /></li></ul><br /><img src ="http://www.blogjava.net/TrampEagle/aggbug/45561.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-05-10 23:16 <a href="http://www.blogjava.net/TrampEagle/articles/45561.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>应用AXIS开始Web 服务之旅</title><link>http://www.blogjava.net/TrampEagle/articles/45560.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Wed, 10 May 2006 15:13:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/45560.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/45560.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/45560.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/45560.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/45560.html</trackback:ping><description><![CDATA[原文引自：<a href="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/">http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/</a><br /><br />作者：刘东<br /><blockquote>本文介绍使用AXIS作为开发环境来体会Web服务的开发过程。</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><a name="1"><span class="atitle"><font face="Arial" size="4">一． 介绍</font></span></a></p><p><br />本文并不是想介绍Web服务的原理、系统架构等，我们假设您已经了解了关于Web服务的一些基本的概念、原理等知识。本文主要是针对那些已经了解Web服务概念，但是还没有亲身体会Web服务所带来令人欢欣鼓舞的特征的开发人员。在此我们认为你已经具备了Java、XML等基础知识，如果你还有其他开发环境的经验例如VB、VC那是再好不过的了。 </p><p><a name="N1004B"><span class="smalltitle"><strong><font face="Arial">1．Web服务</font></strong></span></a></p><p><br />虽然我们并不想详细讲述Web服务的体系结构，但是大概的介绍一下还是有必要的。Web服务是一种新型的Web应用程序。不同于其他Web应用程序，它是自适应、自我描述、模块化的应用程序，并可以跨越Web进行发布、定位以及调用。简单的Web服务可以提供例如天气预报或者航班信息的服务。一旦部署了Web服务，其他的应用程序就可以发现和调用所部署的服务。 </p><p><a name="N10056"><span class="smalltitle"><strong><font face="Arial">2．AXIS项目</font></strong></span></a></p><p><br />Axis框架来自 Apache 开放源代码组织，它是基于JAVA语言的最新的 SOAP 规范（SOAP 1.2）和 SOAP with Attachments 规范（来自 Apache Group ）的开放源代码实现。有很多流行的开发工具都使用AXIS作为其实现支持Web服务的功能，例如JBuilder以及著名的Eclipse J2EE插件Lomboz。AXIS的最新版本是1.1，可以从 <a href="http://ws.apache.org/axis/index.html" target="_blank"><font color="#5c81a7">http://ws.apache.org/axis/index.html</font></a>下载。下图是AXIS核心引擎的体系结构图： </p><br /><img alt="" src="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/1_axis_engine.jpg" /><br /><p><b>图1</b></p><p>整个AXIS项目包括以下几个部分：</p><ol><li>消息流子系统 <br />消息流子系统提供了灵活的消息传递框架，这个消息传递框架包括处理程序、链、序列化程序和反序列化程序。处理程序是一个处理请求、响应和故障流的对象。处理程序可被组合在一起成为链，而且可以使用一个灵活的部署描述符来配置这些处理程序的顺序。 
</li><li>传输框架子系统 <br />提供了一个传输框架，这个传输框架可以帮助您创建自己的可插式传输发送器和传输侦听器。 
</li><li>数据编码子系统 <br />AXIS完全按照 XML Schema 规范提供各种数据类型的自动序列化，并且提供功能扩展接口来使用您自己定制的序列化器和反序列化器。 
</li><li>其他 <br />AXIS完全支持 WSDL 以及日志记录、出错以及故障处理机制。它同时提供一些工具用来讲WSDL文档转换成客户端的调用框架以及根据类来产生WSDL定义文档。 </li></ol><p>AXIS目前版本支持的标准是：W3C SOAP 1.1 和 1.2；WSDL 1.1；SAAJ 1.1（SUN公司：SOAP with Attachments API for Java）；JAX-RPC（SUN公司：Java API for XML-Based RPC）1.0。 </p><p>除了前面介绍的AXIS外，本文中还将会用到TOMCAT，这里不再另行介绍。另外为了演示Web服务真正与开发环境无关以及AXIS产生的是标准的、符合规范的Web服务，我们还将用到微软公司的SOAP TOOLKIT以及微软的开发环境VB和VC来做为Web服务的客户端。 </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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="2"><span class="atitle"><font face="Arial" size="4">二. 环境搭建</font></span></a></p><p><br />由于AXIS本身是基于JAVA语言开发的项目，并且是以Web应用形式发布的，因此它运行时需要一个应用服务器作为支撑。为了方便我们这里选用的是Tomcat。由于AXIS本身需要用到处理XML信息的包，所以我们建议使用JDK1.4并安装Tomcat 4.1.24。下面是环境搭建步骤，读取根据自身情况进行安装。 </p><ol><li>安装JDK1.4.1 
</li><li>安装Tomcat 4.1.24到C:\Tomcat并验证安装是否成功 
</li><li>下载AXIS项目打包文件axis-1_1.zip解压缩后将目录中的webapps目录下的axis子目录拷贝到C:\Tomcat\webapps下。 
</li><li>验证AXIS的安装：重新启动Tomcat服务器后打开浏览器输入网址http://localhost:8080/axis 后应该出现如下图所示页面，点击链接"Validate"来验证Axis所需的几个JAVA包是否齐全。 </li></ol><br /><img alt="" src="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/2_axis_home.jpg" /><br /><p><b>图2</b></p><p>点击超链接Validate后，AXIS会自动检查所需的每一个JAVA组件，这协组件分为：必需组件以及可选组件，必须保证所有必需组件都存在，如下图所示即为验证成功。 </p><br /><img alt="" src="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/3_axis_verify.jpg" /><br /><p><b>图3</b></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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="3"><span class="atitle"><font face="Arial" size="4">三． Web Service服务端开发</font></span></a></p><p><br />经过了前两步之后我们就可以开始Web服务之旅了！大多数人在学习一种编程语言的第一步都是从Hello world程序开始的，我们也不例外。我们将提供这样一个Web服务，通过给它传入姓名，服务返回：你好[姓名]，欢迎来到Web服务的世界。这就是我们的需求。我们将马上根据AXIS的要求完成我们的需求，你就会发现原来Web服务可以这么简单！ </p><p>编写JAVA类Hello.java，内容如下：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">public class Hello{
 public String hello(String name){
  if(name==null)
   name = "";
  return "你好"+name+"，欢迎来到Web服务的世界！";
}
}
</font></code></pre></td></tr></tbody></table><br /><p>仅此而已，无需编译，将该文件改名为Hello.jws并拷贝到AXIS应用目录C:\Tomcat\webapps\axis下。 </p><p>下面我们就可以测试该Web服务了，打开浏览器并输入刚刚创建的文件名对应的URL地址 <a href="http://localhost:8080/axis/Hello.jws" target="_blank"><font color="#5c81a7">http://localhost:8080/axis/Hello.jws</font></a> 浏览器显示如下结果： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">There is a Web Service here

        
        </font><a href="http://localhost:8080/axis/Hello.jws?wsdl" target="_blank"><font face="Lucida Console" color="#5c81a7">Click to see the WSDL </font></a><font face="Lucida Console"></font></code></pre></td></tr></tbody></table><br /><p>点击页面上的链接查看该Web服务对应的WSDL信息如下所示（我们将在下一小节简单介绍WSDL） </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
-&lt;wsdl:definitions
 targetNamespace="http://localhost:8080/axis/Hello.jws"
 xmlns="http://schemas.xmlsoap.org/wsdl/"
 xmlns="http://www.w3.org/2000/xmlns/"
 xmlns:apachesoap="http://xml.apache.org/xml-soap" 
 xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
 xmlns:impl="http://localhost:8080/axis/Hello.jws" 
 xmlns:intf="http://localhost:8080/axis/Hello.jws"
 xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"&gt;
 - &lt;wsdl:message name="helloRequest"&gt;
 &lt;wsdl:part name="name" type="xsd:string" /&gt; 
 &lt;/wsdl:message&gt;
 + &lt;wsdl:message name="helloResponse"&gt;
 - &lt;wsdl:portType name="Hello"&gt;
 - &lt;wsdl:operation name="hello" parameterOrder="name"&gt;
 &lt;wsdl:input name="helloRequest" message="intf:helloRequest" /&gt; 
 &lt;wsdl:output name="helloResponse" message="intf:helloResponse" /&gt;
 &lt;/wsdl:operation&gt; 
 &lt;/wsdl:portType&gt;
 - &lt;wsdl:binding name="HelloSoapBinding" type="intf:Hello"&gt; 
 &lt;wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /&gt;
 - &lt;wsdl:operation name="hello"&gt; 
 &lt;wsdlsoap:operation soapAction="" /&gt;
 - &lt;wsdl:input name="helloRequest"&gt;
 &lt;wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
  namespace="http://DefaultNamespace" /&gt;  
 &lt;/wsdl:input&gt;- &lt;wsdl:output name="helloResponse"&gt;  
 &lt;wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  namespace="http://localhost:8080/axis/Hello.jws" /&gt;   
 &lt;/wsdl:output&gt; 
 &lt;/wsdl:operation&gt; 
 &lt;/wsdl:binding&gt;
 - &lt;wsdl:service name="HelloService"&gt;
 - &lt;wsdl:port name="Hello" binding="intf:HelloSoapBinding"&gt;
 &lt;wsdlsoap:address location="http://localhost:8080/axis/Hello.jws" /&gt; 
 &lt;/wsdl:port&gt;  
 &lt;/wsdl:service&gt; 
 &lt;/wsdl:definitions&gt;
</font></code></pre></td></tr></tbody></table><br /><p>到此我们已经完成了hello的Web服务了，那我们怎么告诉用户如何来使用该服务呢？我们只需要告诉用户我们的Web服务的URL地址： <a href="http://localhost:8080/axis/Hello.jws?wsdl" target="_blank"><font color="#5c81a7">http://localhost:8080/axis/Hello.jws?wsdl</font></a> 就可以了！下一节我们将介绍如何通过这个地址来访问对应的Web服务。 </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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="4"><span class="atitle"><font face="Arial" size="4">四． Web Service客户端开发</font></span></a></p><p><br />在这一节中我们将使用三种不同的语言来访问刚刚创建的Web服务，分别是JAVA、VB、VC。为了使用VB和VC访问Web服务，我们需要安装微软公司的Soap Toolkit 开发工具包，这个工具包可以从微软公司的主页 </p><p><a href="http://download.microsoft.com/download/xml/soap/2.0/W98NT42KMe/EN-US/SoapToolkit20.exe" target="_blank"><font color="#5c81a7">http://download.microsoft.com/download/xml/soap/2.0/W98NT42KMe/EN-US/SoapToolkit20.exe</font></a></p><p>下载，下载该软件包并使用默认方式安装即可。 </p><p>在开始客户端开发之前有两个概念我们必须先粗略的介绍一下。 </p><p>SOAP：简单对象访问协议。这是一种在松散的、分布的环境中使用XML对等地交换结构化的和类型化的信息提供了一个简单且轻量级的机制，它是一个基于XML的协议。它包括四个部分：SOAP封装（envelop），封装定义了一个描述消息中的内容是什么，是谁发送的，谁应当接受并处理它以及如何处理它们的框架；SOAP编码规则（encoding rules），用于表示应用程序需要使用的数据类型的实例; SOAP RPC表示(RPC representation)，表示远程过程调用和应答的协定;SOAP绑定（binding），使用底层协议交换信息。 </p><p>虽然这四个部分都作为SOAP的一部分，作为一个整体定义的，但他们在功能上是相交的、彼此独立的。特别的，信封和编码规则是被定义在不同的XML命名空间(namespace)中，这样使得定义更加简单。 </p><p>SOAP的主要设计目标是简明性和可扩展性。这就意味着有一些传统消息系统或分布式对象系统中的特性将不包含在SOAP的核心规范中。这些特性包括：分布式垃圾收集；批量消息传输/处理；对象引用；对象激活。 </p><p>WSDL：Web Service描述语言。使用了WSDL，我们就可以通过这种跨平台和跨语言的方法使Web Service代理的产生自动化。就像COM和CORBA的IDL文件，WSDL文件由客户和服务器约定。由于WSDL设计成可以绑定除SOAP以外的其他协议，这里我们主要关注WSDL在HTTP上和SOAP的关系。同样，由于SOAP目前主要用来调用远程的过程和函数，WSDL支持SOAP传输的文档规范。 </p><p>WSDL文档可以分为两部分。顶部分由抽象定义组成，而底部分则由具体描述组成。抽象部分以独立于平台和语言的方式定义SOAP消息，它们并不包含任何随机器或语言而变的元素。这就定义了一系列服务，截然不同的网站都可以实现。 </p><p><a name="N1013F"><span class="smalltitle"><strong><font face="Arial">1. JAVA客户端</font></strong></span></a></p><p><br />使用AXIS的工具将使Web服务的访问和我们之前介绍的创建一个Web服务一样的简单。我们前面安装的AXIS环境中已经包含着这样的工具，它是一个JAVA类，类名为：org.apache.axis.wsdl.WSDL2Java。打开命令行窗口，转到AXIS目录下的WEB-INF子目录。确保Tomcat服务已经处于启动状态，键入命令 ： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">Java -Djava.ext.dirs=lib org.apache.axis.wsdl.WSDL2Java http://localhost:8080/axis/Hello.jws?wsdl
</font></code></pre></td></tr></tbody></table><br /><p>该命令执行的结果是在当前所在目录下产生一个子目录 localhost/axis/Hello_jws，该目录下有四个JAVA源文件，它们分别是： </p><p>Hello.java 定义了Web服务接口，此例中只有一个hello方法。 </p><p>HelloService.java 定义了用于获取Web服务接口的方法。 </p><p>HelloServiceLocator.java 接口HelloService的具体实现。 </p><p>HelloSoapBindingStub.java Web服务客户端桩，通过该类与服务器交互。 </p><p>这四个JAVA类帮我们处理了大部分的逻辑，我们需要的仅仅是把这些类加到我们的项目然后创建一个我们自己的类来调用它们即可。为此我们新加一个类Main.java，为了方便，让这个类与刚产生的四个类都在同一个包下。内容如下： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">//Main.java
package localhost.axis.Hello_jws;
public class Main{
public static void main(String[] args) throws Exception{
 HelloService service = new HelloServiceLocator();
 Hello hello = service.getHello(); 
 System.out.println("Response:"+hello.hello("罐头")); 
 }
}
</font></code></pre></td></tr></tbody></table><br /><p>使用以下命令进行编译： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">javac -classpath lib\axis.jar;lib\jaxrpc.jar localhost\axis\Hello_jws\*.java
</font></code></pre></td></tr></tbody></table><br /><p>如果编译没有问题的话执行该测试程序：</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">java -Djava.ext.dirs=lib -cp . localhost.axis.Hello_jws.Main//运行结果：Response:你好罐头，欢迎来到Web服务的世界！
</font></code></pre></td></tr></tbody></table><br /><p>在WSDL2Java工具自动产生的几个类中，类HelloServiceLocator中保存这一些跟服务器相关的信息，例如URL地址等，当服务器的地址更改后但是服务并没有改动的时候直接修改该文件中的字符串定义，而无需重新生成这几个类。具体需要修改的内容，打开该文件便可一目了然。 </p><p><a name="N10175"><span class="smalltitle"><strong><font face="Arial">2. VB客户端</font></strong></span></a></p><p><br />有了微软SOAP toolkit，用VB调用Web服务也是一件令人愉快的事情。 </p><p>打开VB开发环境新建一个标准EXE项目，打开工程(Project)菜单并选择引用打开组件引用对话框如下图所示：找到并选中Microsoft Soap Type Library。 </p><br /><img alt="" src="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/image008.jpg" /><br /><p><b>图 4</b></p><p>新建并编辑窗体如下图所示：</p><br /><img alt="" src="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/4_vbclient.jpg" /><br /><p><b>图 5</b></p><p>编辑按钮Call的点击事件处理程序如下：（注意窗体的控件名称要与程序中的名称对应）</p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">Private Sub callBtn_Click()    
'这种做法需要在工程中引用Soap Type Library  
'Dim soap As MSSOAPLib.SoapClient  
'Set soap = New MSSOAPLib.SoapClient
Dim soap  
Set soap = CreateObject("MSSOAP.SoapClient")   
On Error Resume Next
'soap.mssoapinit urlText.Text 
Call soap.mssoapinit(urlText.Text)   
If Err &lt;&gt; 0 Then   
 MsgBox "初始化SOAP失败： " + Err.Description       
 urlText.SetFocus 
Else       
 If Len(Trim(nameText.Text)) = 0 Then       
  MsgBox "请输入您的姓名！"          
  nameText.SetFocus    
 Else          
  responseText.Text = soap.hello(nameText.Text) 
 End If 
 End If
End Sub
</font></code></pre></td></tr></tbody></table><br /><p>保存项目并运行，输入姓名并点击按钮Call。 </p><p><a name="N101BA"><span class="smalltitle"><strong><font face="Arial">3. VC客户端</font></strong></span></a></p><p><br />打开VC开发环境，新建项目HelloClient，项目类型为 Win32 Console Application的空项目。新建C++ Source File文件名为：HelloSoap.cpp，编辑文件内容如下： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">//#include "stdafx.h"
#include &lt;stdio.h&gt;
#import "msxml3.dll"
using namespace MSXML2;
//根据自己机器的情况修改下面语句中指定的路径

#import "C:\Program Files\Common Files\MSSoap\Binaries\mssoap1.dll" \ 
 exclude("IStream", "ISequentialStream", "_LARGE_INTEGER", \ 
 "_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")
using namespace MSSOAPLib;

void Hello(){ 
 ISoapSerializerPtr Serializer;
 ISoapReaderPtr Reader; 
 ISoapConnectorPtr Connector;
 // Connect to the service 
 Connector.CreateInstance(__uuidof(HttpConnector));
 Connector-&gt;Property["EndPointURL"] = "http://localhost:8080/axis/Hello.jws?wsdl";
 Connector-&gt;Connect(); 
 // Begin message
 Connector-&gt;BeginMessage(); 
 // Create the SoapSerializer 
 Serializer.CreateInstance(__uuidof(SoapSerializer)); 
 // Connect the serializer to the input stream of the connector
 Serializer-&gt;Init(_variant_t((IUnknown*)Connector-&gt;InputStream)); 

 // Build the SOAP Message 

 Serializer-&gt;startEnvelope("","",""); 
 Serializer-&gt;startBody(""); 
 Serializer-&gt;startElement("hello","","",""); 
 Serializer-&gt;startElement("name","","","");
 Serializer-&gt;writeString("罐头"); 
 Serializer-&gt;endElement(); 
 Serializer-&gt;endElement();
 Serializer-&gt;endBody(); 
 Serializer-&gt;endEnvelope();  
 
 // Send the message to the web service 
 Connector-&gt;EndMessage();   
 
 // Let us read the response
 Reader.CreateInstance(__uuidof(SoapReader)); 
 // Connect the reader to the output stream of the connector
 Reader-&gt;Load(_variant_t((IUnknown*)Connector-&gt;OutputStream), ""); 

 // Display the result 
 printf("Response: %s\n", (const char*)Reader-&gt;RPCResult-&gt;text);  
}

int main()
{
 CoInitialize(NULL);
 Hello(); 
 CoUninitialize(); 
 
 return 0; 
}
</font></code></pre></td></tr></tbody></table><br /><p>编译并运行该项目。</p><p>本节只是为了演示如果通过VC来访问使用AXIS创建的Web服务，至于Soap toolkit的具体使用请参照soap toolkit的帮助手册，其他语言的访问请查阅相关的文档。 </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"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="5"><span class="atitle"><font face="Arial" size="4">五. AXIS集成</font></span></a></p><p><font face="Arial" size="4"></font></p><p>为了让我们的WEB应用程序支持Web服务功能，我们需要将AXIS集成到我们的应用程序中。集成AXIS很简单，首先需要拷贝AXIS用到的几个JAR包文件，这些文件都在[AXIS]\WEB-INF\lib目录下，将这些文件拷贝到我们自己的应用目录下的WEB-INF\lib。另外如果你用的不是TOMCAT服务器那就需要拷贝activation.jar，这个JAR文件可以在[TOMCAT]\common\lib目录下找到！ </p><p>拷贝完JAR文件后就是web.xml的配置了，只需要把AXIS中的web.xml中的配置信息添加到我们自己应用程序中的web.xml中即可。最重要的是下面的内容： </p><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section"><font face="Lucida Console">&lt;servlet&gt;  
 &lt;servlet-name&gt;AxisServlet&lt;/servlet-name&gt;  
 &lt;display-name&gt;Apache-Axis Servlet&lt;/display-name&gt;   
 &lt;servlet-class&gt; 
  org.apache.axis.transport.http.AxisServlet  
 &lt;/servlet-class&gt;
&lt;/servlet&gt;

&lt;servlet-mapping&gt;   
 &lt;servlet-name&gt;AxisServlet&lt;/servlet-name&gt;  
 &lt;url-pattern&gt;*.jws&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;

&lt;mime-mapping&gt;    
 &lt;extension&gt;wsdl&lt;/extension&gt;  
 &lt;mime-type&gt;text/xml&lt;/mime-type&gt;
&lt;/mime-mapping&gt;

&lt;mime-mapping&gt;   
 &lt;extension&gt;xsd&lt;/extension&gt;   
 &lt;mime-type&gt;text/xml&lt;/mime-type&gt;
&lt;/mime-mapping&gt;
</font></code></pre></td></tr></tbody></table><br /><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><font face="Lucida Console"><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" /></font></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><font face="Lucida Console"><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /></font><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="center"><font face="Lucida Console"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></font></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/webservices/ws-startaxis/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="6"><span class="atitle"><font face="Arial" size="4">六 总结</font></span></a></p><p><br />到此文章告一段落，通过以上的演练，我相信你已经对Web服务有一个感性的认识，但是这个仅仅是开始，我们也只是很简单的介绍了Web服务的一些基本概念并演示了一个无法再简单的例子。Web服务还有很多其他高级的内容例如复杂类型、数据安全等没有涉及到，不过没有关系，万事开头难，希望本文能够促进大家理解和应用下一代的应用模式并给还没有动手试验的开发人员开一个好头。 </p><img src ="http://www.blogjava.net/TrampEagle/aggbug/45560.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-05-10 23:13 <a href="http://www.blogjava.net/TrampEagle/articles/45560.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MyEclipse+struts+Hibernate配置开发</title><link>http://www.blogjava.net/TrampEagle/articles/45395.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Wed, 10 May 2006 03:03:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/45395.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/45395.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/45395.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/45395.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/45395.html</trackback:ping><description><![CDATA[
		<p>原文引自：<a href="http://dev.yesky.com/39/2239039.shtml">http://dev.yesky.com/39/2239039.shtml</a><br /><br />说明：<br /><br />　　这个手册只是为初学者制作的环境配置和快速开发的一些基本方法，为的是广大爱好者能快速上手，少走我走过的弯路，里面没有任何关于java模式和其他相关的说明。本人水平有限，也没有能力去讨论关于模式设计和开发细节的一些内容。 </p>
		<p>
		</p>
		<p>
		</p>
		<p>　　建议：<br /><br />　　如果你还不清楚struts和hibernate的一些基本原理，希望能先去了解一下这方面的相关内容。</p>
		<p>　　推荐：<br /><br />　　Hibernate中文手册》作者认为要学Hibernate看这个就足够了，里面几乎包括了所有的细节，不过可能不太适合快速入门。<br /><br />　　地址：<a href="http://www.hibernate.org/hib_docs/v3/reference/zh-%20cn/html_single/">http://www.hibernate.org/hib_docs/v3/reference/zh- cn/html_single/</a><br /><br />　　关于struts的资料就很多了，这里推荐一个可以下载一些入门教程的网站。<br /><br />　　地址：<a href="http://www.wnetw.com/jclub/index.jsp">http://www.wnetw.com/jclub/index.jsp</a><br /><br />　　强烈建议入门的朋友先了解一下基本的原理！否则本文可能对你没有任何帮助。</p>
		<p>　　相关工具下载：（注意版本）<br /><br />　　mysql5.0 <a href="http://www.mysql.org/">http://www.mysql.org</a><br />　　eclipse 3.1.1 <a href="http://www.eclipse.org/" target="_blank">http://www.eclipse.org</a><br />　　myeclipse4.0.3 <a href="http://www.myeclipseide.com/">http://www.myeclipseide.com</a><br />　　tomcat5.5</p>
		<p>　　安装：<br /><br />　　关于tomcat和mysql的安装就不多说了，需要注意的是最好保证你的 jdk是1.5的版本，并配置好你的环境变量，不然可能会遇到一些问题。<br /><br />　　把eclipse解开，再去安装刚下载的myeclipse，在安装的时候需要把路径指定到刚才解开的eclipse上，由于myeclipse是个收费软件，所以需要注册。不过一般按照Chinese的习惯，去google一个注册码就可以了:}</p>
		<p>　　开发环境部署：<br /><br />　　好了，现在保证你的mysql和tomcat服务能够正常启动，myeclipse能够正常打开（如果不能，可以去找一下相关的说明或者给作者留言）。下面我们就要开始真正的开始部署一个传说中的tomcat+struts+hibernate+mysql结构的工程了！（faint!前言就写的我好累）<br /><br />　　首先，在myeclipse里新建一个工程。在左边的Package Exporler面版里点右键选择new-&gt;project… <br /><br />　　在跳出菜单里选择MyEclipse-&gt;J2EE Projects-&gt;Web Project。<br /><br />　　点击next后进入如下画面：</p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/3dv4s4cjwa2l.cn/pic/3fa10d830200006m" />
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/1.JPG" target="_blank">
				</a>
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/1.JPG" target="_blank">
				</a>
		</p>
		<p>
				<br />　　工程名为：test<br /><br />　　结束后点击Finish。<br /><br />　　好了，如果成功的话你就会在 Package Exporler里看到一个新的test工程！现在我们先配置一下数据库方面的东西。首先在你的mysql 里建立一个数据库webases，再在里面新建一个表admin，里面三个字段分别为id,<a class="bluekey" href="http://www.yesky.com/key/99/160099.html" target="_blank">name</a>,password其中id为自动取值的主键（mysql具体的操作可以自己找资料，不是本文涉及范围）。<br /><br />　　再回到myeclipse ，选中window-&gt;Open Perspective-&gt;Other…<br /><br />　　可以看到现在跳出一个名为Select Perspective的菜单，在里面选中MyEclipse Databases Exporler，可以看到现在到了下面的页面。</p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/2s5d31zdm346.cn/pic/3fa10d830200006n" />
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/2.JPG" target="_blank">
				</a>
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/2.JPG" target="_blank">
				</a>
		</p>
		<p>　　按以上图示输入相关字段后点击Finish便建立了一个数据库连接，在新出现的JDBC for Mysql上点右键，选择Open connection…，确认用户名和密码正确后点OK，如果一切顺利的话你会看到下面的画面： </p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/0g601v5hykhy.cn/pic/3fa10d830200006o" />
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/3.JPG" target="_blank">
				</a>
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/3.JPG" target="_blank">
				</a>
		</p>
		<p>　　这说明你已经和数据库建立了正确的连接。现在我们再回到window-&gt;Open Perspective- &gt;Other…里的MyEclipse，也就是我们刚进来的时候看到的画面。<br /><br />　　右键点击你刚建立的工程 test并选择MyEclipse-&gt;Add struts Capabilities…在跳出的菜单里按照如下输入并确定：</p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/r8rfzry4u70v.cn/pic/3fa10d830200006p" />
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/4.JPG" target="_blank">
				</a>
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/4.JPG" target="_blank">
				</a>
		</p>
		<p>　　好了，现在你已经为你的工程增加了struts，接下来和上面一样在右键工程后选择MyEclipse- &gt;Add Hibernate Capabilities…一路确定下来为你的工程添加Hibernate。（为方便起见我们在选择路径时把HibernateSessionFactory.java放在了src/com下面，其实最好建立个单独的目录如 src/com/hibernate）<br /><br />　　为了更好的演示我们不建立通常的登陆页面而是建立个注册页面。选择 src目录下的hibernate.cfg.xml文件。照如下填写并保存。这样hibernate就为你建立了数据库的连接池。</p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/w9r22908kj35.cn/pic/3fa10d830200006q" />
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/5.JPG" target="_blank">
				</a>
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/5.JPG" target="_blank">
				</a>
		</p>
		<p>　　下面我们再选择WebRoot/WEB-INF/struts-config.xml文件，在画面中点击右键选择new- &gt;Form, Action and JSP。如下填写</p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/w0cu77s737rz.cn/pic/3fa10d830200006r" />
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/6.JPG" target="_blank">
				</a>
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/6.JPG" target="_blank">
				</a>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/5.JPG" target="_blank">
				</a>
		</p>
		<p>　　再选择JSP选项，如下</p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/1x6mi889p265.cn/pic/3fa10d830200006s" />
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/7.JPG" target="_blank">
				</a>
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/7.JPG" target="_blank">
				</a>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/6.JPG" target="_blank">
				</a>
		</p>
		<p>　　最后选择Finish。<br /><br />　　再新建一个一个success.jsp的页面，<br /><br />　　在刚才struts- config.xml文件里右键<a class="bluekey" href="http://www.yesky.com/key/1712/156712.html" target="_blank">选择a</a>ddAdmin选择Properties，在菜单里选择Forwords，再点add，如下图填写 </p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/55rct6wh32c3.cn/pic/3fa10d830200006t" />
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/8.JPG" target="_blank">
				</a>
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/8.JPG" target="_blank">
				</a>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/7.JPG" target="_blank">
				</a>
		</p>
		<p>　　最后你的struts-config.xml就是下面这个样子：</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/9.JPG" target="_blank">
				</a>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/8.JPG" target="_blank">
				</a>
		</p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/17nf5q9p44y5.cn/pic/3fa10d830200006u" />
		</p>
		<p>
				<br />　　下面我们转到hibernate。换到刚才我们建立数据库的页面，选择你的admin的表点右键选择Create Hibernate Mapping。选择好打包路径后选择Finish。如图：</p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/k8h07y72ok59.cn/pic/3fa10d830200006v" />
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/10.JPG" target="_blank">
				</a>
		</p>
		<p>　　在你刚才选择的路径下（我为方便是src/com/yourcompanyname/）下新建立的文件 AdminDAOFactory.java文件并输入以下内容：</p>
		<p>package com.yourcompanyname;</p>
		<p>import java.util.Iterator;</p>
		<p>import org.hibernate.HibernateException;<br />import org.hibernate.Query;<br />import org.hibernate.Session;<br />import org.hibernate.Transaction;</p>
		<p>import com.hibernate.SessionFactory;</p>
		<p>public class AdminDAOFactory {<br /> Session session;<br /> Transaction tx;<br /> public void add(Admin admin) throws HibernateException {<br />  /**<br />   * Creation Date: 11-17-2005<br />   * TODO Add a new admin user.<br />   * @param An object of Admin<br />   * @return void<br />   * @author Coder Guo<br />   */<br />  try {<br />   session = SessionFactory.currentSession();<br />   tx = session.beginTransaction();<br />   //Add a new admin<br />   session.save(admin);<br />   tx.commit ();<br />  }catch(HibernateException e){<br />   throw e;<br />  }finally{<br />   if (tx!=null) {<br />    tx.rollback();<br />   } <br />   SessionFactory.closeSession();<br />  }<br /> }<br />}</p>
		<p> 再打开com.yourcompany.struts.action下的AddAdminAction.java添加（其中如果有错误选中好按ctrl+shift+o自动添加包）</p>
		<p>public class AddAdminAction extends Action {</p>
		<p> // --------------------------------------------------------- Instance Variables</p>
		<p> // --------------------------------------------------------- Methods</p>
		<p> /** <br />  * Method execute<br />  * @param mapping<br />  * @param form<br />  * @param request<br />  * @param response<br />  * @return ActionForward<br />  * @author Coder Guo<br />  */<br /> public ActionForward execute(<br />  ActionMapping mapping,<br />  ActionForm form,<br />  HttpServletRequest request,<br />  HttpServletResponse response) {<br />  AddAdminForm addAdminForm = (AddAdminForm) form;<br />  <br />  // TODO Add a new admin<br />  Admin admin = new Admin();<br />  admin.setName(addAdminForm.getName ());<br />  admin.setPassword(addAdminForm.getPassword ());<br />  AdminDAOFactory adminDAO = new AdminDAOFactory ();<br />  adminDAO.add(admin);<br />  <br />  return mapping.findForward("success");<br /> }</p>
		<p>}</p>
		<p> 再打开com.yourcompanyname.struts.form下的AddAdminForm.java，修改（如果有错误按照上面说的方法导入包）<br /> public ActionErrors validate(<br />  ActionMapping mapping,<br />  HttpServletRequest request) {</p>
		<p>  // TODO Auto-generated method stub<br />  ActionErrors errors = new ActionErrors();<br />  <br />  Session session = SessionFactory.currentSession();<br />  Transaction tx = session.beginTransaction ();<br />  Query query = session.createQuery("select admin from Admin as admin where admin.name = '" + this.name + "'");<br />  Iterator it = query.iterate ();<br />  if (it.hasNext()){<br />   errors.add ("addAdmin.err.name",new ActionMessage("form.addAdmin.err.name"));<br />  } <br />  tx.commit();<br />  SessionFactory.closeSession ();<br />  return errors;<br /> }</p>
		<p> public void reset(ActionMapping mapping, HttpServletRequest request) {</p>
		<p>  // TODO Auto-generated method stub<br />  this.name=null;<br />  this.password=null;<br /> }</p>
		<p>　　再打开com\yourcompanyname\struts下的ApplicationResource.properties在这里面添加错误信息： <br /><br />Form.addAdmin.err.name=err</p>
		<p>　　最后，（汗，好累啊-_-!）打开addAdmin.jsp修改成如下：<br /><br />&lt;%@ page contentType="text/html; charset=utf-8"%&gt; <br />&lt;%@ page language="java"%&gt;<br />&lt;%@ taglib uri="<a href="http://jakarta.apache.org/struts/tags-bean">http://jakarta.apache.org/struts/tags-bean</a>" prefix="bean"%&gt; <br />&lt;%@ taglib uri="<a href="http://jakarta.apache.org/struts/tags-html">http://jakarta.apache.org/struts/tags-html</a>" prefix="html"%&gt;</p>
		<p>&lt;script language = "javascript"&gt;<br />&lt;!--<br />function <a class="bluekey" href="http://www.yesky.com/key/4908/159908.html" target="_blank">check</a>(){<br /> if (loginForm.userName.value == "" || loginForm.password.value == ""){<br />  alert("请输入完整的信息！");<br />  loginForm.userName.focus();<br />  return false;<br /> }<br />}<br />//--&gt;<br />&lt;/script&gt;<br /> <br /> &lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;<br />&lt;html:html&gt;<br />  &lt;head&gt;<br />    &lt;html:base /&gt;<br />    <br />    &lt;title&gt;login.jsp&lt;/title&gt;<br />    &lt;link href="css/webcss.css" rel="stylesheet" type="text/css"&gt;<br />    <br />    &lt;<a class="bluekey" href="http://www.yesky.com/key/4816/159816.html" target="_blank">meta</a> http-equiv="pragma" content="no- cache"&gt;<br />    &lt;meta http-equiv="cache-control" content="no- cache"&gt;<br />    &lt;meta http-equiv="expires" content="0"&gt;    <br />    &lt;meta http-equiv="keywords" content="keyword1,keyword2,keyword3"&gt;<br />    &lt;meta http- equiv="description" content="This is my page"&gt;<br />  &lt;/head&gt;<br />  </p>
		<p>  &lt;body&gt;<br />  &lt;center&gt;<br />   &lt;p&gt;&amp;nbsp;&lt;/p&gt;<br />   &lt;p&gt;&amp;nbsp;&lt;/p&gt;<br />   &lt;table width="<a class="bluekey" href="http://www.yesky.com/key/636/160636.html" target="_blank">30</a>0" border="0" cellpadding="0" cellspacing="0"&gt;<br />   &lt;html:form action="/addAdmin" focus="name" method="GET"&gt;<br />     &lt;tr align="center" valign="middle"&gt;<br />       &lt;td colspan="2" class="typt_normal"&gt;新增管理员&lt;/td&gt;<br />     &lt;/tr&gt;<br />     &lt;tr&gt;<br />       &lt;td width="100" align="center" valign="middle" class="typt_normal"&gt;名称： &lt;/td&gt;<br />       &lt;td width="200" align="left"&gt;&lt;html:text property="name" styleClass="text_s"/&gt;&lt;html:errors property="addAdmin.err.name"/&gt;&lt;/td&gt;<br />     &lt;/tr&gt;<br />     &lt;tr&gt;<br />       &lt;td width="100" align="center" valign="middle" class="typt_normal"&gt;密码： &lt;/td&gt;<br />       &lt;td width="200" align="left"&gt;&lt;html:password property="password" styleClass="text_s"/&gt;&lt;/td&gt;<br />     &lt;/tr&gt;<br />     &lt;tr&gt; <br />       &lt;td colspan="2" align="center" valign="middle"&gt;&lt;html:submit value="提交" onclick="return check ();"/&gt;&lt;html:reset value="重置"&gt;&lt;/html:reset&gt;&lt;/td&gt;<br />       &lt;/tr&gt;<br /> &lt;/html:form&gt;<br />   &lt;/table&gt;<br /> &lt;/center&gt;<br /> &lt;/body&gt;</p>
		<p>&lt;/html:html&gt;<br /><br />　　其中可以看到如何在struts的标签中使用javascript的方法。<br /><br />　　配置好myeclipse于tomcat的连接。在window-&gt;Preferences做如下设定：</p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/rfe9mz6n6877.cn/pic/3fa10d830200006w" />
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/11.JPG" target="_blank">
				</a>
		</p>
		<p>　　在项目文件点右键－&gt;“myeclipse”－&gt;“Add and remove project deployment”，如下图：</p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/4el6k0a08339.cn/pic/3fa10d830200006x" />
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/12.JPG" target="_blank">
				</a>
		</p>
		<p>　　好了，我们的配置工作基本结束了,在myeclipse上开启tomcat服务</p>
		<p align="center">
				<img src="http://dev.yesky.com/imagelist/05/12/a597a7j21uhi.cn/pic/3fa10d830200006y" />
		</p>
		<p>
				<a href="file:///E:/我的文章/MyEclipse+TomCat+struts+Hibernate+Mysql环境配置手册和快速开发实例/pic/13.JPG" target="_blank">
				</a>
		</p>
		<p>　　现在打开浏览器，输入<br /><br />　　<a href="http://127.0.0.1:8080/test/addAdmin.jsp">http://127.0.0.1:8080/test/addAdmin.jsp</a><b r="">就可以看到你的jsp页面了！</b></p>
<img src ="http://www.blogjava.net/TrampEagle/aggbug/45395.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-05-10 11:03 <a href="http://www.blogjava.net/TrampEagle/articles/45395.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BPEL 实例教程</title><link>http://www.blogjava.net/TrampEagle/articles/40560.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Wed, 12 Apr 2006 01:56:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/40560.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/40560.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/40560.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/40560.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/40560.html</trackback:ping><description><![CDATA[
		<span class="topstoryhead">原文引自：<a href="http://www.oracle.com/technology/global/cn/pub/articles/matjaz_bpel1.html">http://www.oracle.com/technology/global/cn/pub/articles/matjaz_bpel1.html</a><br /><br />                                                                            BPEL 实例教程<br /><br /><span class="boldbodycopy"><font color="#666666">开发人员：J2EE 和 Web 服务</font></span><p><span class="topstoryhead">BPEL 实例教程</span><br /><span class="italicbodycopy">作者：Matjaz Juric</span></p><p><span class="boldbodycopy">了解如何创建一个将一系列虚拟的、与旅行相关的 web 服务结合起来的示例业务流程，然后将其部署到 Oracle BPEL Process Manager 运行时环境。</span></p><p></p><table cellspacing="0" cellpadding="1" width="42%" bgcolor="#cccccc" border="0"><tbody><tr><td><table cellspacing="0" cellpadding="2" width="100%" bgcolor="#ffffff" border="0"><tbody><tr><td><span class="boldbodycopy">本文相关下载</span><br /><span class="boldbodycopy"><img height="5" src="http://oracleimg.com/admin/images/ocom/bullet_5x5.gif" width="5" align="baseline" border="0" /></span><a href="http://www.oracle.com/technology/pub/files/matjaz_bpel1_sample.tar"><span class="bodylink">示例代码</span></a><br /><span class="boldbodycopy"><img height="5" src="http://oracleimg.com/admin/images/ocom/bullet_5x5.gif" width="5" align="baseline" border="0" /></span><a href="http://www.oracle.com/technology/software/htdocs/devlic.html?/technology/software/products/ias/bpel/index.html" target="_blank"><span class="bodylink">Oracle BPEL Process Manager 和 Designer</span></a></td></tr></tbody></table></td></tr></tbody></table><p><span class="bodycopy"><a class="bodylink" href="http://www-128.ibm.com/developerworks/library/ws-bpel/" target="_blank">面向 Web 服务的业务流程执行语言</a>（BPEL 或 BPEL4WS）是一种使用 Web 服务定义和执行业务流程的语言。BPEL 使您可以通过组合、编排和协调 Web 服务自上而下地实现面向服务的体系结构 (SOA)。BPEL 提供了一种相对简单易懂的方法，可将多个 Web 服务组合到一个新的复合服务（称作</span><span class="italicbodycopy">业务流程</span>）中。 </p><p><span class="bodycopy">本文将介绍如何创建一个将一系列虚拟的、与旅行相关的 web 服务结合起来的示例业务流程，然后将其部署到 Oracle BPEL Process Manager 运行时环境。</span></p><p><span class="parahead1">BPEL 背景知识</span></p><p><span class="bodycopy">首先，介绍一些背景知识。BPEL 基于 XML 和 Web 服务构建；它使用一种基于 Web 的语言，该语言支持 web 服务技术系列，包括 SOAP、WSDL、UDDI、Web 服务可靠性消息、Web 服务寻址、Web 服务协调以及 Web 服务事务。 </span></p><p><span class="bodycopy">BPEL 代表了两种早期工作流语言 - Web 服务流语言 (WSFL) 和 XLANG 的交汇。WSFL 由 IBM 基于有向图概念设计。XLANG 是一种由 Microsoft 设计的块结构化语言。BPEL 组合了这两种方法，并提供了丰富的词汇来描述业务流程。</span></p><p><span class="bodycopy">BPEL 的第一个版本诞生于 2002 年 8 月。此后，随着许多主要供应商（包括 Oracle）的纷纷加入了，催生了多项修改和改进，并于 2003 年 3 月推出了 1.1 版。2003 年 4 月，BPEL 提交结构化信息标准促进组织 (OASIS) 以实现标准化，并组建了 Web 服务业务流程执行语言技术委员会 (<a href="http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wsbpel" target="_blank"><span class="bodylink">WSBPEL TC</span></a>)。该努力使 BPEL 在业界获得更广范围的认可。</span></p><p><span class="bodycopy">在企业内部，BPEL 用于标准化企业应用程序集成以及将此集成扩展到先前孤立的系统。在企业之间，BPEL 使与业务合作伙伴的集成变得更容易、更高效。BPEL 激发企业进一步定义它们的业务流程，从而导致业务流程的优化、重新设计以及选择最合适的流程，进而实现了组织的进一步优化。BPEL 中描述的业务流程定义并不影响现有系统，因此对升级产生了促进作用。在已经或将要通过 Web 服务公开功能的环境中，BPEL 是一项重要的技术。随着 Web 服务的不断普及，BPEL 的重要性也随之提高。 </span></p><p><span class="parahead1">编制与编排</span></p><p><span class="bodycopy">Web 服务通常公开某些应用程序或信息系统的操作。因此，组合多个 Web 服务实际上涉及基础应用程序及其功能的集成。 </span></p><p><span class="bodycopy">可以用两种方式组合 Web 服务：</span></p><p></p><ul><li><span class="bodycopy">编制</span></li><li><span class="bodycopy">编排</span></li></ul><p><span class="bodycopy">在编制（通常用于专用业务流程）中，一个中央流程（可以是另一个 Web 服务）控制相关的 Web 服务并协调对操作所涉及 Web 服务的不同操作的执行。相关的 Web 服务并不“知道”（也无需知道）它们参与了组合流程并在参与更高级别的业务流程。只有编制的中央协调员知道此目标，因此编制主要集中于操作的显式定义以及 Web 服务的调用顺序。（见图 1。）</span></p><p></p><table width="100%" align="center"><tbody><tr><td align="middle"><img height="104" alt="图 1" src="http://www.oracle.com/technology/pub/images/matjaz_bpel1_f1.gif" width="315" border="0" /></td></tr><tr><td align="middle"><span class="bodycopy">图 1：通过编制组合 Web 服务</span></td></tr></tbody></table><p><span class="bodycopy">而编排并不依赖某个中央协调员。相反，编排所涉及的每个 Web 服务完全知道执行其操作的时间以及交互对象。编排是一种强调在公共业务流程中交换消息的协作方式。编排的所有参与者都需要知道业务流程、要执行的操作、要交换的消息以及消息交换的时间。（见图 2。）</span></p><p></p><table width="100%" align="center"><tbody><tr><td align="middle"><img height="140" alt="图 2" src="http://www.oracle.com/technology/pub/images/matjaz_bpel1_f2.gif" width="290" border="0" /></td></tr><tr><td align="middle"><span class="bodycopy">图 2：通过编排组合 Web 服务</span></td></tr></tbody></table><p><span class="bodycopy">从组合 Web 服务以执行业务流程的角度而言，编制是一个更灵活的范例，它相对于编排而言具有以下优点：</span></p><p></p><ul><li><span class="bodycopy">元件流程的协调由某个已知的协调员集中管理</span></li><li><span class="bodycopy">可以组合 Web 服务而不必使它们知道它们正在参与更大的业务流程</span></li><li><span class="bodycopy">可以准备其他方案以防发生故障。</span></li></ul><p><span class="bodycopy">BPEL 支持两种不同的业务流程描述方法（支持编制和编排）：</span></p><p></p><ul><li><span class="boldbodycopy">可执行流程</span><span class="bodycopy">允许指定业务流程的准确细节。它们遵循编制范例，并可由编制引擎执行。 </span></li><li><span class="boldbodycopy">抽象业务协议</span><span class="bodycopy">允许只指定双方之间的公共消息交换。它们不包含流程的内部细节并且无法执行。它们遵循编排范例。</span></li></ul><p><span class="bodycopy">现在，我们来逐步演示如何创建可执行的 BPEL 业务流程；可以下载它的代码并将其部署到 <a class="bodylink" href="http://www.oracle.com/technology/global/cn/products/ias/bpel/index.html" target="_blank">Oracle BPEL Process Manager</a>。我们将假设已经按照安装指导成功安装了 Oracle BPEL Process Manager，并假设它使用缺省端口 9700。如果在安装过程中选择了其他端口，则必须相应地修改示例。</span></p><p><span class="parahead1">构建业务流程</span></p><p><span class="bodycopy">BPEL 流程指定参与的 Web 服务的确切调用顺序 - 顺序地或并行地。使用 BPEL，您可以表述条件行为。例如，某个 Web 服务的调用可以取决于上次调用的值。还可以构造循环、声明变量、复制和赋予值、定义故障处理程序等。通过组合所有这些构造，您可以以算法的形式定义复杂业务流程。实际上，由于业务流程本质上属于活动图，因此使用统一建模语言 (UML) 活动图表示它们可能很有用。</span></p><p><span class="bodycopy">通常情况下，BPEL 业务流程接收请求。为了满足请求，该流程调用相关的 Web 服务，然后响应原始调用方。由于 BPEL 流程与其他 Web 服务通信，因此它在很大程度上依赖于复合型 Web 服务调用的 Web 服务 的 WSDL 描述。</span></p><p><span class="bodycopy">我们来看一个示例。一个 BPEL 流程由多个步骤组成，每个步骤称作“活动”。BPEL 支持基元活动和结构活动。</span><span class="italicbodycopy">基元</span><span class="bodycopy">活动表示基本构造，用于如下所示的常见任务：</span></p><p></p><ul><li><span class="bodycopy">使用 </span><tt>&lt;invoke&gt;</tt> 调用其他 Web 服务 
</li><li><span class="bodycopy">使用 </span><tt>&lt;receive&gt;</tt><span class="bodycopy">（接收请求）等待客户端通过发送消息调用业务流程</span></li><li><span class="bodycopy">使用 </span><tt>&lt;reply&gt;</tt> 生成同步操作的响应 
</li><li><span class="bodycopy">使用 </span><tt>&lt;assign&gt;</tt> 操作数据变量 
</li><li><span class="bodycopy">使用 </span><tt>&lt;throw&gt;</tt> 指示故障和异常 
</li><li><span class="bodycopy">使用 </span><tt>&lt;wait&gt;</tt> 等待一段时间 
</li><li><span class="bodycopy">使用 </span><tt>&lt;terminate&gt;</tt> 终止整个流程。 </li></ul><span class="bodycopy">然后，我们可以组合这些基元活动以及其他基元活动，以定义准确指定业务流程步骤的复杂算法。为组合基元活动，BPEL 支持几个</span><span class="italicbodycopy">结构</span><span class="bodycopy">活动。其中最重要的是：</span><p></p><ul><li><span class="bodycopy">顺序 (</span><tt>&lt;sequence&gt;</tt><span class="bodycopy">)，它允许定义一组将按顺序调用的活动。</span></li><li><span class="bodycopy">流 (</span><tt>&lt;flow&gt;</tt><span class="bodycopy">)，用于定义一组将并行调用的活动</span></li><li><span class="bodycopy">Case-switch 构造 (</span><tt>&lt;switch&gt;</tt><span class="bodycopy">)，用于实现分支</span></li><li><span class="bodycopy">While (</span><tt>&lt;while&gt;</tt><span class="bodycopy">)，用于定义循环</span></li><li><span class="bodycopy">使用 </span><tt>&lt;pick&gt;</tt> 能够选择多个替换路径之一。 </li></ul><p><span class="bodycopy">每个 BPEL 业务还将使用 &lt;partnerLink&gt; 定义合作伙伴链接，使用 &lt;variable&gt; 声明变量。</span></p><p><span class="bodycopy">为了理解 BPEL 是如何描述业务流程的，我们将定义雇员出差安排的简化业务流程：客户端调用此业务流程，指定雇员姓名、目的地、出发日期以及返回日期。此 BPEL 业务流程首先检查雇员出差状态。我们将假设存在一个可用于进行此类检查的 Web 服务。然后，此 BPEL 流程将检查以下两家航空公司的机票价格：美国航空公司和达美航空公司。我们将再次假设这两家航空公司均提供了可用于进行此类检查的 Web 服务。最后，此 BPEL 流程将选择较低的价格并将出差计划返回给客户端。 </span></p><p><span class="bodycopy">然后，我们将构建一个异步 BPEL 流程。我们将假设用于检查雇员出差状态的 Web 服务是同步的。由于可以立即获取此数据并将其返回给调用方，因此这是一个合理的方法。为了获取机票价格，我们使用异步调用。由于确认飞机航班时刻表可能需要稍长的时间，因此这也是一个合理的方法。为简化示例，我们假设以上两家航空公司均提供了 Web 服务，且这两个 Web 服务完全相同（即提供相同的端口类型和操作）。 </span></p><p><span class="bodycopy">在实际情形下，您通常无法选择 Web 服务，而是必须使用您的合作伙伴提供的服务。如果您有幸能够同时设计 Web 服务和 BPEL 流程，则应考虑用哪个接口更好。通常，您将对持续时间较长的操作使用异步服务，而对在相对较短的时间内返回结果的操作使用同步服务。如果使用异步 Web 服务，则 BPEL 流程通常也是异步的。 </span></p><p><span class="bodycopy">当您用 BPEL 定义业务流程时，您实际上定义了一个由现有服务组成的新 Web 服务。该新 BPEL 复合 Web 服务的接口使用一组端口类型来提供类似任何其他 Web 服务的操作。要调用用 BPEL 描述的业务流程，则必须调用生成的复合 Web 服务。图 3 是我们流程的示意图。</span></p><p></p><table width="100%" align="center"><tbody><tr><td align="middle"><img height="397" alt="图 3" src="http://www.oracle.com/technology/pub/images/matjaz_bpel1_f3.gif" width="681" border="0" /></td></tr><tr><td align="middle"><span class="bodycopy">图 3：出差安排示例 BPEL 流程</span></td></tr></tbody></table><p><span class="bodycopy">在开发此示例 BPEL 流程的过程中，您将经历下列步骤：</span></p><p></p><ul><li><span class="bodycopy">熟悉相关的 Web 服务</span></li><li><span class="bodycopy">为此 BPEL 流程定义 WSDL </span></li><li><span class="bodycopy">定义合作伙伴链接类型</span></li><li><span class="bodycopy">开发此 BPEL 流程： </span><ul><li><span class="bodycopy">定义合作伙伴链接</span></li><li><span class="bodycopy">声明变量</span></li><li><span class="bodycopy">编写流程逻辑定义。 </span></li></ul></li></ul><p><span class="parahead1">第 1 步：列出相关 Web 服务的清单</span></p><p><span class="bodycopy">在您开始编写 BPEL 流程定义之前，必须先熟悉从业务流程中调用的 Web 服务。这些服务称作</span><span class="italicbodycopy">合作伙伴 Web 服务</span><span class="bodycopy">。本示例使用雇员出差状态 Web 服务以及美国航空公司和达美航空公司 Web 服务（这两个 Web 服务具有相同的 WSDL 描述）。（同样，本示例中使用的 Web 服务是虚构的。）</span></p><p><span class="boldbodycopy">雇员出差状态 Web 服务</span><span class="bodycopy">雇员出差状态 Web 服务提供 </span><tt>EmployeeTravelStatusPT</tt><span class="bodycopy"> 端口类型，通过它可以使用 </span><tt>EmployeeTravelStatus</tt><span class="bodycopy"> 操作检查雇员出差状态。此操作将返回雇员可以使用的乘机标准（可能为经济舱、商务舱或头等舱）。（见图 4。）</span></p><p></p><table width="100%" align="center"><tbody><tr><td align="middle"><img height="91" alt="图 4" src="http://www.oracle.com/technology/pub/images/matjaz_bpel1_f4.gif" width="344" border="0" /></td></tr><tr><td align="middle"><span class="bodycopy">图 4：雇员出差状态 Web 服务</span></td></tr></tbody></table><p><span class="boldbodycopy">航空公司 Web 服务</span><span class="bodycopy">航空公司 Web 服务是异步的；因此它指定了两个端口类型：第一个端口类型 </span><tt>FlightAvailabilityPT</tt><span class="bodycopy"> 用于使用 </span><tt>FlightAvailability</tt><span class="bodycopy"> 操作检查航班可用性。为返回结果，该 Web 服务指定了第二个端口类型 </span><tt>FlightCallbackPT</tt><span class="bodycopy">。此端口类型指定 </span><tt>FlightTicketCallback</tt><span class="bodycopy"> 操作。 </span></p><p><span class="bodycopy">尽管航空公司 Web 服务定义了两个端口类型，但它只实现 </span><tt>FlightAvailabilityPT。FlightCallbackPT</tt><span class="bodycopy"> 则由作为 Web 服务客户端的 BPEL 流程实现。图 5 是此 Web 服务体系结构的示意图：</span></p><p></p><table width="100%" align="center"><tbody><tr><td align="middle"><img height="91" alt="图 5" src="http://www.oracle.com/technology/pub/images/matjaz_bpel1_f5.gif" width="343" border="0" /></td></tr><tr><td align="middle"><span class="bodycopy">图 5：航空公司 Web 服务</span></td></tr></tbody></table><p><span class="parahead1">第 2 步：为 BPEL 流程定义 WSDL</span></p><p><span class="bodycopy">接下来，我们必须将此业务出差 BPEL 公开为 Web 服务。因此，第二步是为它定义 WSDL。此流程将必须从它的客户端接收消息并返回结果。它必须公开 </span><tt>TravelApprovalPT</tt><span class="bodycopy"> 端口类型，后者将指定一个输入消息。它还必须声明 </span><tt>ClientCallbackPT</tt><span class="bodycopy"> 端口类型（用于使用回调将结果异步返回给客户端）。图 6 说明了此流程。</span></p><p></p><table width="100%" align="center"><tbody><tr><td align="middle"><img height="91" alt="图 6" src="http://www.oracle.com/technology/pub/images/matjaz_bpel1_f6.gif" width="343" border="0" /></td></tr><tr><td align="middle"><span class="bodycopy">图 6：此 BPEL 流程的 WSDL</span></td></tr></tbody></table><p><span class="parahead1">第 3 步：定义合作伙伴链接类型</span></p><p><span class="bodycopy">第三步是定义合作伙伴链接类型。合作伙伴链接类型表示 BPEL 流程与相关方（包括 BPEL 流程调用的 Web 服务以及调用 BPEL 流程的客户端）之间的交互。 </span></p><p><span class="bodycopy">本示例包含三个不同的合作伙伴：客户端、雇员出差状态服务和航空公司服务。理想情况下，每个 Web 服务都应在 WSDL 中定义相应的合作伙伴链接类型。（实际情形可能不是这样的。）然后，我们可以使用 WSDL 包装合作伙伴 Web 服务（导入 Web 服务的 WSDL 并定义合作伙伴链接类型）。或者，我们可以在 BPEL 流程的 WSDL 中定义所有合作伙伴链接。但由于此方法违反了封装原则，因此不建议使用。 </span></p><p><span class="bodycopy">对于本示例，我们定义了三个合作伙伴链接类型（每个类型位于 Web 服务的相应 WSDL 中）：</span></p><p></p><ul><li><tt>travelLT</tt><span class="bodycopy">：用于描述此 BPEL 流程客户端与此 BPEL 流程本身之间的交互。此交互是异步交互。此合作伙伴链接类型在此 BPEL 流程的 WSDL 中定义。</span></li><li><tt>employeeLT</tt><span class="bodycopy">：用于描述此 BPEL 流程与雇员出差状态 Web 服务之间的交互。此交互是同步交互。此合作伙伴链接类型在雇员 Web 服务的 WSDL 中定义。</span></li><li><tt>flightLT</tt><span class="bodycopy">：描述此 BPEL 流程与航空公司 Web 服务之间的交互。此交互是异步交互，且航空公司 Web 服务对此 BPEL 流程调用一个回调。此合作伙伴链接类型在航空公司 Web 服务的 WSDL 中定义。</span></li></ul><p><span class="bodycopy">每个合作伙伴链接可以拥有一个或两个角色，我们必须为每个角色指定它使用的 </span><tt>portType</tt><span class="bodycopy">。对于同步操作，由于操作只是单向调用，因此每个合作伙伴链接类型仅有一个角色。例如，此 BPEL 流程对雇员出差状态 Web 服务调用 </span><tt>EmployeeTravelStatus</tt><span class="bodycopy"> 操作。由于它是同步操作，因此此 BPEL 流程等待完成并仅在完成操作后取得响应。 </span></p><p><span class="bodycopy">对于异步回调操作，我们必须指定两个角色。第一个角色描述客户端操作调用。第二个角色描述回调操作调用。在本示例中，BPEL 流程与航空公司 Web 服务之间存在一个异步关系。 </span></p><p><span class="bodycopy">正如我们已经指出的，我们需要三个合作伙伴链接类型：两个链接类型指定两个角色（因为它们是异步的），一个链接类型指定一个角色（因为它是同步的）。 </span></p><p><span class="bodycopy">合作伙伴链接类型在特殊命名空间<a href="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" target="_blank"><span class="bodylink">http://schemas.xmlsoap.org/ws/2003/05/partner-link/</span></a> 的 WSDL 定义。首先，我们在客户端使用的 BPEL 流程 WSDL 中定义 </span><tt>travelLT</tt><span class="bodycopy"> 链接类型以调用此 BPEL 流程。所需的第一个角色是出差服务（即，我们的 BPEL 流程）的角色。客户端使用 </span><tt>TravelApprovalPT</tt><span class="bodycopy"> 端口类型与此 BPEL 服务通信。第二个角色 </span><tt>travelServiceCustomer</tt><span class="bodycopy"> 描述了此 BPEL 流程将在 </span><tt>ClientCallbackPT</tt><span class="bodycopy"> 端口类型中对其执行回调的客户端的特征：</span></p><p></p><pre>&lt;plnk:partnerLinkType name="travelLT"&gt;

&lt;plnk:role name="travelService"&gt;
&lt;plnk:portType name="tns:TravelApprovalPT" /&gt;
&lt;/plnk:role&gt;

&lt;plnk:role name="travelServiceCustomer"&gt;
&lt;plnk:portType name="tns:ClientCallbackPT" /&gt;
&lt;/plnk:role&gt;

&lt;/plnk:partnerLinkType&gt;
</pre><p><span class="bodycopy">第二个链接类型是 </span><tt>employeeLT</tt><span class="bodycopy">。它用于描述此 BPEL 流程与雇员出差状态 Web 服务之间的通信，并在此雇员 Web 服务的 WSDL 中定义。此交互是同步交互，因此我们需要一个名为 </span><tt>employeeTravelStatusService</tt><span class="bodycopy"> 的角色。此 BPEL 流程使用雇员 Web 服务上的 </span><tt>EmployeeTravelStatusPT</tt><span class="bodycopy">：</span></p><p></p><pre>&lt;plnk:partnerLinkType name="employeeLT"&gt;

&lt;plnk:role name="employeeTravelStatusService"&gt;
&lt;plnk:portType name="tns:EmployeeTravelStatusPT" /&gt;
&lt;/plnk:role&gt;

&lt;/plnk:partnerLinkType&gt;
</pre><p><span class="bodycopy">最后一个合作伙伴链接类型 </span><tt>flightLT</tt><span class="bodycopy"> 用于描述此 BPEL 流程与航空公司 Web 服务之间的通信。此通信是异步通信。此 BPEL 流程对航空公司 Web 服务调用一个异步操作。此 Web 服务在完成请求后对此 BPEL 流程调用一个回调。因此，我们需要两个角色。第一个角色描述航空公司 Web 服务对于此 BPEL 流程服务的角色，即航空公司服务 (</span><tt>airlineService</tt><span class="bodycopy">)。此 BPEL 流程使用 </span><tt>FlightAvailabilityPT</tt><span class="bodycopy"> 端口类型进行异步调用。第二个角色描述了此 BPEL 流程对于航空公司 Web 服务的角色。对于航空公司 Web 服务而言，此 BPEL 流程是一个航空公司客户，因此角色名称为 </span><tt>airlineCustomer</tt><span class="bodycopy">。航空公司 Web 服务使用 </span><tt>FlightCallbackPT</tt><span class="bodycopy"> 端口类型进行回调。此合作伙伴链接类型在航空公司 Web 服务的 WSDL 中定义：</span></p><p></p><pre>&lt;plnk:partnerLinkType name="flightLT"&gt;

&lt;plnk:role name="airlineService"&gt;
&lt;plnk:portType name="tns:FlightAvailabilityPT" /&gt;
&lt;/plnk:role&gt;

&lt;plnk:role name="airlineCustomer"&gt;
&lt;plnk:portType name="tns:FlightCallbackPT" /&gt;
&lt;/plnk:role&gt;

&lt;/plnk:partnerLinkType&gt;
</pre><p><span class="bodycopy">了解合作伙伴链接类型对于开发 BPEL 流程规范至关重要。有时，它可以帮助生成所有交互的图表。定义合作伙伴链接类型后，我们已经完成了准备阶段，并准备开始编写业务流程定义。</span></p><p><span class="parahead1">第 4 步：创建业务流程</span></p><p><span class="bodycopy">现在，您就可以开始编写 BPEL 流程了。通常，BPEL 流程等待客户端传入的消息，以启动业务流程的执行。在本示例中，客户端通过发送输入消息</span>TravelRequest<span class="bodycopy"> 启动此 BPEL 流程。然后，此 BPEL 流程通过发送 </span><tt>EmployeeTravelStatusRequest</tt><span class="bodycopy"> 消息调用雇员出差状态 Web 服务。由于此调用是同步调用，因此它等待 </span><tt>EmployeeTravelStatusResponse</tt><span class="bodycopy"> 消息。然后，此 BPEL 流程通过向上述两家航空公司 Web 服务发送 </span><tt>FlightTicketRequest</tt><span class="bodycopy"> 消息对它们进行并发异步调用。每个航空公司 Web 服务通过发送 </span><tt>TravelReponse</tt><span class="bodycopy"> 消息进行回调。然后，此 BPEL 流程选择较合适的航空公司并使用 </span><tt>TravelResponse</tt><span class="bodycopy"> 消息对客户端进行回调。 </span></p><p><span class="bodycopy">我们首先编写一个空的 BPEL 流程提纲，它展示了每个 BPEL 流程定义文档的基本结构：</span></p><p></p><pre>&lt;process name="BusinessTravelProcess" ... &gt;
   
&lt;partnerLinks&gt;
&lt;!-- The declaration of partner links --&gt;
&lt;/partnerLinks&gt;

&lt;variables&gt;
&lt;!-- The declaration of variables --&gt;
&lt;/variables&gt;

&lt;sequence&gt;
&lt;!-- The definition of the BPEL business process main body --&gt;
&lt;/sequence&gt;

&lt;/process&gt;
</pre><p><span class="bodycopy">我们首先添加所需的命名空间。此处，我们必须定义目标命名空间以及用于访问雇员和航空公司 WSDL 以及此 BPEL 流程 WSDL 的命名空间。我们还必须为所有 BPEL 活动标记声明命名空间（此处采用缺省命名空间，以便不必限定每个 BPEL 标记名）。BPEL 活动命名空间必须为 http://schemas.xmlsoap.org/ws/2003/03/business-process/：</span></p><p></p><pre>&lt;process name="BusinessTravelProcess" 
targetNamespace="http://packtpub.com/bpel/travel/" 
xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
xmlns:trv="http://packtpub.com/bpel/travel/"
xmlns:emp="http://packtpub.com/service/employee/"
xmlns:aln="http://packtpub.com/service/airline/" &gt;
...
</pre><p><span class="boldbodycopy">合作伙伴链接</span><span class="bodycopy">接下来，我们必须定义</span><span class="italicbodycopy">合作伙伴链接</span><span class="bodycopy">，它们定义与此 BPEL 流程交互的不同方。每个合作伙伴链接都与描述其特性的特定 </span><tt>partnerLinkType</tt><span class="bodycopy"> 相关。每个合作伙伴链接还最多指定两个属性：</span></p><p></p><ul><li><tt>myRole</tt><span class="bodycopy">：表明业务流程本身的角色。</span></li><li><tt>partnerRole</tt><span class="bodycopy">：表明合作伙伴的角色。</span></li></ul><p><span class="bodycopy">合作伙伴链接仅可以指定一个角色，通常同步请求/响应操作也仅能指定一个角色。对于异步操作，它指定两个角色。在本示例中，我们定义四个角色。第一个合作伙伴链接称作客户端，由 </span><tt>travelLT</tt><span class="bodycopy"> 合作伙伴链接类型描述其特性。此客户端调用该业务流程。我们需要指定 </span><tt>myRole</tt><span class="bodycopy"> 属性以描述此 BPEL 流程 (</span><tt>travelService</tt><span class="bodycopy">) 的角色。我们必须指定第二个角色：</span><tt>partnerRole</tt><span class="bodycopy">。此处，该角色为 </span><tt>travelServiceCustomer</tt><span class="bodycopy">，它描述 BPEL 流程客户端的特性。</span></p><p><span class="bodycopy">第二个合作伙伴链接称作 </span><tt>employeeTravelStatus</tt><span class="bodycopy">，由 </span><tt>employeeLT</tt><span class="bodycopy"> 合作伙伴链接类型描述其特性。它是 BPEL 流程与 Web 服务之间的一个同步请求/响应关系；我们再次仅指定一个角色。此时，该角色为 </span><tt>partnerRole</tt><span class="bodycopy">，这是因为我们描述了 Web 服务（它是此 BPEL 流程的合作伙伴）的角色：</span></p><p><span class="bodycopy">最后两个合作伙伴链接对应于航空公司 Web 服务。由于它们使用同一类型的 Web 服务，因此我们基于一个合作伙伴链接类型 </span><tt>flightLT</tt><span class="bodycopy"> 指定两个合作伙伴链接。此处，由于我们使用异步回调通信，因此需要两个角色。此 BPEL 流程 (</span><tt>myRole</tt><span class="bodycopy">) 对于航空公司 Web 服务的角色为 </span><tt>airlineCustomer</tt><span class="bodycopy">，而航空公司 (</span><tt>partnerRole</tt><span class="bodycopy">) 的角色为 </span><tt>airlineService</tt><span class="bodycopy">：</span></p><p></p><pre>&lt;partnerLinks&gt;
&lt;partnerLink name="client" 
partnerLinkType="trv:travelLT"
myRole="travelService"
partnerRole="travelServiceCustomer"/&gt;

&lt;partnerLink name="employeeTravelStatus" 
partnerLinkType="emp:employeeLT"
partnerRole="employeeTravelStatusService"/&gt;

&lt;partnerLink name="AmericanAirlines" 
partnerLinkType="aln:flightLT"
myRole="airlineCustomer"
partnerRole="airlineService"/&gt;
                   
&lt;partnerLink name="DeltaAirlines" 
partnerLinkType="aln:flightLT"
myRole="airlineCustomer"
partnerRole="airlineService"/&gt;
&lt;/partnerLinks&gt;
</pre><p><span class="boldbodycopy">变量</span><span class="bodycopy"> BPEL 流程中的变量用于存储消息以及对这些消息进行重新格式化和转换。您通常需要为发送到合作伙伴以及从合作伙伴收到的每个消息定义一个变量。就我们的流程而言，我们需要七个变量。我们将它们命名为 </span><tt>TravelRequest、EmployeeTravelStatusRequest、EmployeeTravelStatusResponse、FlightDetails、FlightResponseAA、FlightResponseDA</tt><span class="bodycopy"> 和 </span><tt>TravelResponse</tt>。 </p><p><span class="bodycopy">我们必须为每个变量指定类型。可以使用 WSDL 消息类型、XML 模式简单类型或 XML 模式元素。在我们的示例中，我们对所有变量使用 WSDL 消息类型：</span></p><p></p><pre>&lt;variables&gt;
&lt;!-- input for this process --&gt;      
&lt;variable name="TravelRequest" 
messageType="trv:TravelRequestMessage"/&gt;
&lt;!-- input for the Employee Travel Status web service --&gt;
&lt;variable name="EmployeeTravelStatusRequest" 
messageType="emp:EmployeeTravelStatusRequestMessage"/&gt;
&lt;!-- output from the Employee Travel Status web service --&gt;
&lt;variable name="EmployeeTravelStatusResponse" 
messageType="emp:EmployeeTravelStatusResponseMessage"/&gt;
&lt;!-- input for American and Delta web services --&gt;
&lt;variable name="FlightDetails" 
messageType="aln:FlightTicketRequestMessage"/&gt;
&lt;!-- output from American Airlines --&gt;
&lt;variable name="FlightResponseAA" 
messageType="aln:TravelResponseMessage"/&gt;
&lt;!-- output from Delta Airlines --&gt;
&lt;variable name="FlightResponseDA" 
messageType="aln:TravelResponseMessage"/&gt;
&lt;!-- output from BPEL process --&gt;
&lt;variable name="TravelResponse" 
messageType="aln:TravelResponseMessage"/&gt;
&lt;/variables&gt;
</pre><p><span class="boldbodycopy">BPEL 流程主体</span><span class="bodycopy">流程主体指定调用合作伙伴 Web 服务的顺序。它通常以 </span><tt>&lt;sequence&gt;</tt><span class="bodycopy">（用于定义多个将按顺序执行的操作）开始。在顺序中，我们首先指定启动业务流程的输入消息。我们使用 </span><tt>&lt;receive&gt;</tt><span class="bodycopy"> 构造（它等待匹配消息，在本示例中为 </span><tt>TravelRequest</tt><span class="bodycopy"> 消息）实现此目的。在 </span><tt>&lt;receive&gt;</tt><span class="bodycopy"> 构造中，我们不直接指定消息。而是指定合作伙伴链接、端口类型、操作名称以及可选变量（用于保存收到的消息以用于随后的操作）。</span></p><p><span class="bodycopy">我们将消息接收与客户端合作伙伴链接在一起，并等待对端口类型 </span><tt>TravelApprovalPT</tt><span class="bodycopy"> 调用 </span><tt>TravelApproval</tt><span class="bodycopy"> 操作。我们将收到的消息存储到 </span><tt>TravelRequest</tt><span class="bodycopy"> 变量中：</span></p><p></p><pre>&lt;sequence&gt;

&lt;!-- Receive the initial request for business travel from client --&gt;
&lt;receive partnerLink="client" 
portType="trv:TravelApprovalPT" 
operation="TravelApproval" 
variable="TravelRequest"
createInstance="yes" /&gt;
...
</pre><p><tt>&lt;receive&gt;</tt><span class="bodycopy"> 等待客户端调用 </span><tt>TravelApproval</tt><span class="bodycopy"> 操作，并将传入的消息以及有关业务出差的参数存储到 </span><tt>TravelRequest</tt><span class="bodycopy"> 变量中。此处，此变量名与消息名相同，但并不一定要相同。 </span></p><p><span class="bodycopy">接下来，我们需要调用雇员出差状态 Web 服务。但在调用之前，我们必须为此 Web 服务准备输入。查看雇员 Web 服务的 WSDL，可以看到我们必须发送由雇员部分组成的消息。我们可以通过复制客户端发送的消息的雇员部分来构造此消息。编写相应的赋值语句：</span></p><p></p><pre>...
&lt;!-- Prepare the input for the Employee Travel Status Web Service --&gt;
&lt;assign&gt;
&lt;copy&gt;
&lt;from variable="TravelRequest" part="employee"/&gt;
&lt;to variable="EmployeeTravelStatusRequest" part="employee"/&gt;
&lt;/copy&gt;
&lt;/assign&gt;
...
</pre><p><span class="bodycopy">现在，我们就可以调用雇员出差状态 Web 服务了。为了进行同步调用，我们使用 </span><tt>&lt;invoke&gt;</tt><span class="bodycopy"> 活动。我们使用 </span><tt>employeeTravelStatus</tt><span class="bodycopy"> 合作伙伴链接，并对 </span><tt>EmployeeTravelStatusPT</tt><span class="bodycopy"> 端口类型调用 </span><tt>EmployeeTravelStatus</tt><span class="bodycopy"> 操作。我们已经在 </span><tt>EmployeeTravelStatusRequest</tt><span class="bodycopy"> 变量中准备了输入消息。由于它是同步调用，因此该调用等待回应并将其存储在 </span><tt>EmployeeTravelStatusResponse</tt><span class="bodycopy"> 变量中：</span></p><p></p><pre>...
&lt;!-- Synchronously invoke the Employee Travel Status Web Service --&gt;
&lt;invoke partnerLink="employeeTravelStatus" 
portType="emp:EmployeeTravelStatusPT" 
operation="EmployeeTravelStatus"
inputVariable="EmployeeTravelStatusRequest" 
outputVariable="EmployeeTravelStatusResponse" /&gt;
...
</pre><p><span class="bodycopy">下一步是调用上述两个航空公司 Web 服务。同样，我们先准备所需的输入消息（这两个 Web 服务的输入消息相同）。</span><tt>FlightTicketRequest</tt><span class="bodycopy"> 消息包含两部分： </span></p><p></p><ul><li><tt>flightData</tt><span class="bodycopy">：它从客户端消息 (</span><tt>TravelRequest</tt><span class="bodycopy">) 中检索而得。</span></li><li><tt>travelClass</tt><span class="bodycopy">：它从 </span><tt>EmployeeTravelStatusResponse</tt><span class="bodycopy"> 变量中检索而得。 </span></li></ul><p><span class="bodycopy">因此，我们编写一个包含两个 copy 元素的赋值： </span></p><p></p><pre>...
&lt;!-- Prepare the input for AA and DA --&gt;
&lt;assign&gt;
&lt;copy&gt;
&lt;from variable="TravelRequest" part="flightData"/&gt;
&lt;to variable="FlightDetails" part="flightData"/&gt;
&lt;/copy&gt;
&lt;copy&gt;
&lt;from variable="EmployeeTravelStatusResponse" part="travelClass"/&gt;
&lt;to variable="FlightDetails" part="travelClass"/&gt;
&lt;/copy&gt;
&lt;/assign&gt;
...
</pre><p><span class="bodycopy">输入数据包含需要传递给航空公司 Web 服务的数据。由于格式相同，因此我们可以使用一个简单复制直接传递它。在实际情况下，通常需要执行转换。为此，可以使用具有 </span><tt>&lt;assign&gt;</tt><span class="bodycopy"> 的 XPath 表达式、使用转换服务（如 XSLT 引擎）或使用由特定 BPEL 服务器提供的转换功能。</span></p><p><span class="bodycopy">现在，我们准备调用这两个航空公司 Web 服务。我们将进行并发的异步调用。为表述并发，BPEL 提供了 </span><tt>&lt;flow&gt;</tt><span class="bodycopy"> 活动。对每个 Web 服务的调用将包含两个步骤：</span></p><p></p><ul><li><span class="bodycopy">使用 </span><tt>&lt;invoke&gt;</tt><span class="bodycopy"> 活动进行异步调用。</span></li><li><span class="bodycopy">使用 </span><tt>&lt;receive&gt;</tt><span class="bodycopy"> 活动等待回调。</span></li></ul><p><span class="bodycopy">我们使用 </span><tt>&lt;sequence&gt;</tt><span class="bodycopy"> 对这两个活动进行分组。这两个调用只在合作伙伴链接名称上存在差别。我们对一个调用使用 </span><tt>AmericanAirlines</tt><span class="bodycopy">，对另一个调用使用 </span><tt>DeltaAirlines</tt><span class="bodycopy">。两者均对 </span><tt>FlightAvailabilityPT</tt><span class="bodycopy"> 端口类型调用 </span><tt>FlightAvailability</tt><span class="bodycopy"> 操作，发送 </span><tt>FlightDetails</tt><span class="bodycopy"> 变量中的消息。 </span></p><p><span class="bodycopy">使用 </span><tt>&lt;receive&gt; </tt><span class="bodycopy">活动接收回调。我们再次使用这两个合作伙伴链接名。</span><tt>&lt;receive&gt;</tt><span class="bodycopy"> 等待对 </span><tt>FlightCallbackPT</tt><span class="bodycopy"> 端口类型调用 </span><tt>FlightTicketCallback</tt><span class="bodycopy"> 操作。我们将结果消息分别存储到 </span><tt>FlightResponseAA</tt><span class="bodycopy"> 和 </span><tt>FlightResponseDA</tt><span class="bodycopy"> 变量中：</span></p><p></p><pre>...
&lt;!-- Make a concurrent invocation to AA in DA --&gt;
&lt;flow&gt;
      
&lt;sequence&gt;
&lt;!-- Async invoke of the AA web service and wait for the callback--&gt;
        
&lt;invoke partnerLink="AmericanAirlines" 
portType="aln:FlightAvailabilityPT" 
operation="FlightAvailability"
inputVariable="FlightDetails" /&gt;

&lt;receive partnerLink="AmericanAirlines" 
portType="aln:FlightCallbackPT" 
operation="FlightTicketCallback"
variable="FlightResponseAA" /&gt;

&lt;/sequence&gt;

&lt;sequence&gt;
&lt;!-- Async invoke of the DA web service and wait for the callback--&gt;
        
&lt;invoke partnerLink="DeltaAirlines" 
portType="aln:FlightAvailabilityPT" 
operation="FlightAvailability"
inputVariable="FlightDetails" /&gt;

&lt;receive partnerLink="DeltaAirlines" 
portType="aln:FlightCallbackPT" 
operation="FlightTicketCallback"
variable="FlightResponseDA" /&gt;

&lt;/sequence&gt;

&lt;/flow&gt;
...
</pre><p><span class="bodycopy">在该流程的这个阶段，我们收到两个机票报价。在下一步中，我们必须选择一个机票报价。为此，我们使用 </span><tt>&lt;switch&gt;</tt><span class="bodycopy"> 活动。 </span></p><p></p><pre>...
&lt;!-- Select the best offer and construct the TravelResponse --&gt;
&lt;switch&gt;
              
&lt;case condition="bpws:getVariableData('FlightResponseAA',
'confirmationData','/confirmationData/Price') 
&lt;= bpws:getVariableData('FlightResponseDA',
'confirmationData','/confirmationData/Price')"&gt;
                    
&lt;!-- Select American Airlines --&gt;
&lt;assign&gt;
&lt;copy&gt;
&lt;from variable="FlightResponseAA" /&gt;
&lt;to variable="TravelResponse" /&gt;
&lt;/copy&gt;
&lt;/assign&gt;
&lt;/case&gt;
                    
&lt;otherwise&gt;
&lt;!-- Select Delta Airlines --&gt;
&lt;assign&gt;
&lt;copy&gt;
&lt;from variable="FlightResponseDA" /&gt;
&lt;to variable="TravelResponse" /&gt;
&lt;/copy&gt;
&lt;/assign&gt;
&lt;/otherwise&gt;
&lt;/switch&gt;
...
</pre><p><span class="bodycopy">在 </span><tt>&lt;case&gt;</tt><span class="bodycopy"> 元素中，我们检查美国航空公司的机票报价 (</span><tt>FlightResponseAA</tt><span class="bodycopy">) 是等于还是低于达美航空公司的机票报价 (</span><tt>FlightResponseDA</tt><span class="bodycopy">)。为此，我们使用 BPEL 函数 </span><tt>getVariableData</tt><span class="bodycopy"> 并指定变量名。价格位于 </span><tt>confirmationData</tt><span class="bodycopy"> 消息的内部，虽然它是唯一的消息部分，但我们仍必须指定它。我们还必须指定查询表达式以找到价格元素。此处，我们采用简单的 XPath 1.0 表达式。 </span></p><p><span class="bodycopy">如果美国航空公司的机票报价低于达美航空公司的机票报价，则将 </span><tt>FlightResponseAA</tt><span class="bodycopy"> 变量复制到 </span><tt>TravelResponse</tt><span class="bodycopy"> 变量（我们最终将此变量返回给客户端）。否则，我们将复制 </span><tt>FlightResponseDA</tt><span class="bodycopy"> 变量。</span></p><p><span class="bodycopy">我们已经到达此 BPEL 业务流程的最后一步 — 使用 </span><tt>&lt;invoke&gt;</tt><span class="bodycopy"> 活动将回调返回给客户端。对于此回调，我们使用客户端合作伙伴链接并对 </span><tt>ClientCallbackPT</tt><span class="bodycopy"> 端口类型调用 </span><tt>ClientCallback</tt><span class="bodycopy"> 操作。保存答复消息的变量为 </span><tt>TravelResponse</tt><span class="bodycopy">：</span></p><p></p><pre>...
&lt;!-- Make a callback to the client --&gt;
&lt;invoke partnerLink="client" 
portType="trv:ClientCallbackPT" 
operation="ClientCallback"
inputVariable="TravelResponse" /&gt;
&lt;/sequence&gt;

&lt;/process&gt;
</pre><p></p><table cellpadding="5" width="40%" align="right" bgcolor="#dddddd" border="1" vspace="5" hspace="5"><tbody><tr><td><center><a name="next"><span class="parahead1">后续步骤</span></a></center><p><span class="boldbodycopy">下载<a href="http://www.oracle.com/technology/books/pdfs/1183_BPEL_Preview_Ch4.zip"><span class="bodylink"><i>用于 Web 服务的业务流程执行语言</i></span></a> 一书中的示例章节。</span></p><p><span class="boldbodycopy"><a href="http://www.oracle.com/technology/global/cn/tech/webservices/index.html" target="_blank"><span class="bodylink">访问 Web 服务技术中心</span></a></span></p></td></tr></tbody></table><span class="bodycopy">到此，我们已经完成了我们的第一个 BPEL 业务流程规范。您可以看到，BPEL 并不是很复杂，并允许相对简单和自然的业务流程规范。 </span><p><span class="parahead1">第 5 步：部署和测试</span></p><p><span class="bodycopy">我们部署到 Oracle BPEL Process Manager 的每个 BPEL 流程都需要一个流程描述符。BPEL 标准不包括此流程描述符，且它特定于 BPEL 服务器。部署流程描述符是流程在给定平台上的唯一实现部分，必须重写它才能在不同 BPEL 引擎上运行该流程。Oracle 流程描述符是一个 XML 文件，它指定有关 BPEL 流程的以下细节：BPEL 源文件名、BPEL 流程名 (ID)、所有合作伙伴链接 WSDL Web 服务的 WSDL 位置以及可选的配置属性。流程描述符的默认文件名为 </span><tt>bpel.xml</tt><span class="bodycopy">，但我们可以使用任何其他名称：</span></p><p></p><pre>&lt;BPELSuitcase&gt;

&lt;BPELProcess src="Travel.bpel" id="TravelProcessCh4"&gt;
&lt;partnerLinkBindings&gt;

&lt;partnerLinkBinding name="client"&gt;
&lt;property name="wsdlLocation"&gt;
Travel.wsdl
&lt;/property&gt;
&lt;/partnerLinkBinding&gt;

&lt;partnerLinkBinding name="employeeTravelStatus"&gt;
&lt;property name="wsdlLocation"&gt;
http://localhost:9700/orabpel/default/Employee/Employee?wsdl
&lt;/property&gt;
&lt;/partnerLinkBinding&gt;

&lt;partnerLinkBinding name="AmericanAirlines"&gt;
&lt;property name="wsdlLocation"&gt;
http://localhost:9700/orabpel/default/AmericanAirline/AmericanAirline?wsdl
&lt;/property&gt;
&lt;/partnerLinkBinding&gt;

&lt;partnerLinkBinding name="DeltaAirlines"&gt;
&lt;property name="wsdlLocation"&gt;
http://localhost:9700/orabpel/default/DeltaAirline/DeltaAirline?wsdl
&lt;/property&gt;
&lt;/partnerLinkBinding&gt;

&lt;/partnerLinkBindings&gt;
&lt;/BPELProcess&gt;
&lt;/BPELSuitcase&gt;
</pre><p><span class="bodycopy">我们现在准备启动 BPEL Process Manager。可以从</span><tt>开始</tt><span class="bodycopy">菜单（如果使用 Windows）或通过执行 </span><tt>c:\orabpel\bin</tt><span class="bodycopy"> 目录中的 </span><tt>startOraBPEL</tt><span class="bodycopy"> 脚本（假设 Oracle BPEL Process Manager 已经安装到 </span><tt>c:\orabpel</tt><span class="bodycopy"> 中）来执行此操作。为便于访问，建议将此目录包含在 PATH 中。</span></p><p><span class="bodycopy">Oracle BPEL Process Manager 包含一个名为 obant 的 Ant 实用程序，用于配置复杂的编译和部署方案。obant 只是一个围绕标准 Ant 的包装程序，用于设置环境，然后调用标准 Ant Java 任务。要使用它，我们必须准备相应的项目文件（通常名为 </span><tt>build.xml</tt><span class="bodycopy">）。以下是出差示例流程的项目文件：</span></p><p></p><pre>&lt;?xml version="1.0"?&gt;
&lt;project name="TravelProcessCh4" default="main" basedir="."&gt;

&lt;property name="deploy" value="default"/&gt;
&lt;property name="rev" value="1.0"/&gt;
       
&lt;target name="main"&gt;
&lt;bpelc home="${home}" rev="${rev}" deploy="${deploy}"/&gt;        
&lt;/target&gt;

&lt;/project&gt;
</pre><p><span class="bodycopy">要编译和部署此 BPEL 流程，我们只需从命令行启动 obant。 </span></p><p><span class="bodycopy">既然我们已经在 Oracle BPEL 服务器上成功部署了 BPEL 流程，那我们就执行它。Oracle BPEL Process Manager 提供了一个 BPEL 控制台，通过它可以在 BPEL 服务器域中执行、监视、管理和调试 BPEL 流程。可以通过 http://localhost:9700/BPELConsole/ 访问 BPEL 控制台。我们必须单击流程名、填写以下表单并按 </span><tt>Post XML Message</tt><span class="bodycopy"> 按钮：</span></p><p></p><table width="100%" align="center"><tbody><tr><td align="middle"><img height="522" alt="图 7" src="http://www.oracle.com/technology/pub/images/matjaz_bpel1_f7.gif" width="650" border="0" /></td></tr><tr><td align="middle"><span class="bodycopy">图 7：BPEL 控制台</span></td></tr></tbody></table><p><span class="bodycopy">我们现在看到一个屏幕，通知我们正在异步处理流程实例。我们可以选择执行、实例审计或实例调试的可视化流。实例的可视化流以图形方式显示了 BPEL 流程实例的执行。我们可以监视流程的执行及其状态（正在运行、已完成、已取消或过时）： </span></p><p></p><table width="100%" align="center"><tbody><tr><td align="middle"><img height="632" alt="图 8" src="http://www.oracle.com/technology/pub/images/matjaz_bpel1_f8.gif" width="650" border="0" /></td></tr><tr><td align="middle"><span class="bodycopy">图 8：实例流的图形视图</span></td></tr></tbody></table><p><span class="bodycopy">Oracle BPEL Process Manager 提供了多个用于审计、管理、调试和部署 BPEL 流程的选项。有关更多信息，请查看<a class="bodylink" href="http://www.oracle.com/technology/global/cn/products/ias/bpel/index.html">产品文档</a>。 </span></p><p><span class="parahead1">结论</span></p><p><span class="bodycopy">现在，您已经熟悉了使用 BPEL 组合 Web 服务的基本概念，您可以更深入地研究更高级的概念。我的下一篇文章将介绍一些高级 BPEL 特性，如故障处理、范围、补偿、并发活动以及事件处理。</span><br /><br /><span class="boldbodycopy">Matjaz B. Juric</span><span class="bodycopy"> 拥有计算机与信息科学的博士学位。他是<a href="http://www.amazon.com/exec/obidos/tg/detail/-/1904811183/qid=1106325670/sr=1-5/ref=sr_1_5/102-8657616-9037757?v=glance&amp;s=books" target="_blank"><span class="bodylink"><i>用于 Web 服务的业务流程执行语言</i></span></a>一书 (Packt Publishing) 的作者。Matjaz 还是</span><span class="italicbodycopy">专家级 J2EE EAI、专家级 EJB、应用的 J2EE 设计模式</span><span class="bodycopy">以及</span><span class="italicbodycopy">VB.NET 序列化指南</span><span class="bodycopy">（全部由 Wrox Press 出版）的合著者。Matjaz 还曾为 </span><span class="italicbodycopy">Java Developer's Journal、Java Report、Java World</span><span class="bodycopy"> 以及其他出版物撰写过文章。 </span><br /></p></span>
<img src ="http://www.blogjava.net/TrampEagle/aggbug/40560.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-04-12 09:56 <a href="http://www.blogjava.net/TrampEagle/articles/40560.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jsp中request的一些方法返回值</title><link>http://www.blogjava.net/TrampEagle/articles/37225.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Fri, 24 Mar 2006 07:19:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/37225.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/37225.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/37225.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/37225.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/37225.html</trackback:ping><description><![CDATA[在页面上打印如下内容，通过服务器本地和客户端异地调用的结果如下<br />&lt;%<br />  String url111 = request.getRequestURI();<br />  System.out.println("url111============"+url111);<br />  String url222 = request.getRemoteHost();<br />  System.out.println("url222============"+url222);<br />  String url333 = request.getRemoteAddr();<br />  System.out.println("url333============"+url333);<br />  String url555 = request.getServerName();<br />  System.out.println("url555============"+url555);<br />  int url666 = request.getServerPort();<br />  System.out.println("url666============"+url666);<br />  String url777 = request.getRemoteAddr();<br />  System.out.println("url777============"+url777);<br />  String url888 = request.getRemoteUser();<br />  String url999 = request.getProtocol();<br />  System.out.println("url999============"+url999);<br />  System.out.println("url888============"+url888);<br />  String url444 = request.getRequestURL().toString();<br />  System.out.println("url444============"+url444);<br />  String url000 = request.getPathInfo();<br />  System.out.println("url000============"+url000);<br />  <br />%&gt;<br /><br />本地服务器端调用：<br />url111============/TestWEB/index.jsp<br />url222============localhost<br />url333============127.0.0.1<br />url555============127.0.0.1<br />url666============7001<br />url777============127.0.0.1<br />url999============HTTP/1.1<br />url888============null<br />url444============http://127.0.0.1:7001/TestWEB/index.jsp<br />url000============null<br />异地客户端调用如下：<br />url111============/TestWEB/index.jsp<br />url222============DX<br />url333============192.168.0.24<br />url555============192.168.0.254<br />url666============7001<br />url777============192.168.0.24<br />url999============HTTP/1.1<br />url888============null<br />url444============http://192.168.0.254:7001/TestWEB/index.jsp<br />url000============null<img src ="http://www.blogjava.net/TrampEagle/aggbug/37225.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-03-24 15:19 <a href="http://www.blogjava.net/TrampEagle/articles/37225.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Weblogic服务器性能调优[转] </title><link>http://www.blogjava.net/TrampEagle/articles/27901.html</link><dc:creator>TrampEagle</dc:creator><author>TrampEagle</author><pubDate>Fri, 13 Jan 2006 04:47:00 GMT</pubDate><guid>http://www.blogjava.net/TrampEagle/articles/27901.html</guid><wfw:comment>http://www.blogjava.net/TrampEagle/comments/27901.html</wfw:comment><comments>http://www.blogjava.net/TrampEagle/articles/27901.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/TrampEagle/comments/commentRss/27901.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/TrampEagle/services/trackbacks/27901.html</trackback:ping><description><![CDATA[引自：<a href="/zyb9114/articles/26113.html">http://www.blogjava.net/zyb9114/articles/26113.html</a><br /><br /><div class="postbody"><h2 style="MARGIN: 13pt 0cm"><a name="_Toc123696092"><span lang="EN-US"><font face="Arial" color="#1d58d1">Weblogic</font></span></a>服务器性能调优</h2><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><span style="mso-tab-count: 1"><font face="Arial">       </font></span></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">注：在下面做的介绍都是以</span><span lang="EN-US"><font face="Arial">Weblogic8.1</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">为例的，其它版本的</span><span lang="EN-US"><font face="Arial">Weblogic</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">可能会有些许不同。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><font face="Arial"><span style="mso-tab-count: 1">       </span>1) </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">设置</span><span lang="EN-US"><font face="Arial">JAVA</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">参数；</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><font face="Arial"><span style="mso-tab-count: 1">       </span>a) </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">编辑</span><span lang="EN-US"><font face="Arial">Weblogic Server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">启动脚本文件；</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l1 level2 lfo1; tab-stops: list 42.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'">         </span></span></span><span lang="EN-US"><font face="Arial">BEA_HOME\user_projects\domains\domain-name\startWebLogic.cmd(startWebLogic.sh on Unix)</font></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l1 level2 lfo1; tab-stops: list 42.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'">         </span></span></span><span lang="EN-US"><font face="Arial">BEA_HOME\user_projects\domains\domain-name\startManagedWebLogic.cmd(startManagedWebLogic.sh on Unix)</font></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span lang="EN-US"><font face="Arial">b) </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">编辑</span><span lang="EN-US"><font face="Arial">set JAVA_OPTIONS</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">命令，如：</span><span lang="EN-US"><font face="Arial">set JAVA_OPTIONS=-Xms<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /?><st1:chmetcnv tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="256" unitname="m" w:st="on">256m</st1:chmetcnv> –Xmx<st1:chmetcnv tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="256" unitname="m" w:st="on">256m</st1:chmetcnv></font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">；</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span lang="EN-US"><font face="Arial">c) </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">保存，重启即可。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span style="COLOR: blue; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">注：在</span><span lang="EN-US" style="COLOR: blue"><font face="Arial">WebLogic</font></span><span style="COLOR: blue; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">中，为了获得更好的性能，</span><span lang="EN-US" style="COLOR: blue"><font face="Arial">BEA</font></span><span style="COLOR: blue; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">公司推荐最小</span><span lang="EN-US" style="COLOR: blue"><font face="Arial">Java</font></span><span style="COLOR: blue; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">堆等于最大</span><span lang="EN-US" style="COLOR: blue"><font face="Arial">Java</font></span><span style="COLOR: blue; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">堆。</span><span lang="EN-US" style="COLOR: blue"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?><o:p></o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span lang="EN-US"><font face="Arial">2) </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">开发模式</span><span lang="EN-US"><font face="Arial"> vs. </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">产品模式；</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">开发模式和产品模式的一些参数的默认值不同，可能会对性能造成影响，下面是对性能有影响的参数列表：</span></p><table class="MsoTableGrid" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse; mso-border-alt: solid windowtext .5pt; mso-yfti-tbllook: 480; mso-padding-alt: 0cm 5.4pt 0cm 5.4pt; mso-border-insideh: .5pt solid windowtext; mso-border-insidev: .5pt solid windowtext" cellspacing="0" cellpadding="0" border="1"><tbody><tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes"><td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 194.4pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt" valign="top" width="259"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">参数</span></p></td><td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #e0dfe3; WIDTH: 134.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt" valign="top" width="179"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">开发模式默认值</span></p></td><td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #e0dfe3; WIDTH: 164.25pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt" valign="top" width="219"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">产品模式默认值</span></p></td></tr><tr style="mso-yfti-irow: 1"><td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #e0dfe3; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 194.4pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" valign="top" width="259"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><font face="Arial">Execute Queue: Thread Count</font></span></p></td><td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #e0dfe3; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #e0dfe3; WIDTH: 134.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" valign="top" width="179"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><font face="Arial">15 threads</font></span></p></td><td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #e0dfe3; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #e0dfe3; WIDTH: 164.25pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" valign="top" width="219"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><font face="Arial">25 threads</font></span></p></td></tr><tr style="mso-yfti-irow: 2; mso-yfti-lastrow: yes"><td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #e0dfe3; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 194.4pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" valign="top" width="259"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><font face="Arial">JDBC Connection Pool: MaxCapacity</font></span></p></td><td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #e0dfe3; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #e0dfe3; WIDTH: 134.05pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" valign="top" width="179"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><font face="Arial">15 connnections</font></span></p></td><td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: #e0dfe3; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: #e0dfe3; WIDTH: 164.25pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; BACKGROUND-COLOR: transparent; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt" valign="top" width="219"><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><font face="Arial">25 connections</font></span></p></td></tr></tbody></table><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><span style="mso-tab-count: 1"><font face="Arial">       </font></span></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">通过启动管理控制台，在域（如：</span><span lang="EN-US"><font face="Arial">mydomain</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">配置</span><font face="Arial"><span lang="EN-US">&gt; </span></font><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">常规选择产品模式。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span lang="EN-US"><font face="Arial">3) </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">尽量开启本地</span><span lang="EN-US"><font face="Arial">I/O</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">；</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">通过启动管理控制台，在域（如：</span><span lang="EN-US"><font face="Arial">mydomain</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">服务器</span><span lang="EN-US"><font face="Arial"> &gt; server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">实例（如：</span><span lang="EN-US"><font face="Arial">myserver</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">配置</span><span lang="EN-US"><font face="Arial"> &gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">调整选择启用本地</span><span lang="EN-US"><font face="Arial">I/O</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span style="COLOR: blue; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">注：此值也可通过手动的修改</span><span lang="EN-US" style="COLOR: blue"><font face="Arial">config.xml</font></span><span style="COLOR: blue; FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">配置文件。</span><span lang="EN-US" style="COLOR: blue"><o:p></o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span lang="EN-US"><font face="Arial">4) </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">调优执行队列线程；</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span lang="EN-US"><font face="Arial">a) </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">修改默认执行线程数</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">在这里，执行队列的线程数表示执行队列能够同时执行的操作的数量。但此值不是设的越大越好，应该恰到好处的去设置它，太小了，执行队列中将会积累很多待处理的任务，太大了，则会消耗大量的系统资源从而影响整体的性能。在产品模式下默认为</span><span lang="EN-US"><font face="Arial">25</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">个执行线程。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">为了设置理想的执行队列的线程数，我们可以启动管理控制台，在域（如：</span><span lang="EN-US"><font face="Arial">mydomain</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">服务器</span><span lang="EN-US"><font face="Arial"> &gt; server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">实例（如：</span><span lang="EN-US"><font face="Arial">myserver</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">监视</span><span lang="EN-US"><font face="Arial"> &gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">性能中监控最大负载时执行队列的吞吐量和队列中的等待请求数，据此确定理想的数值。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><span style="mso-tab-count: 1"><font face="Arial">       </font></span></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">理想的默认执行线程数是由多方面的因素决定的，比如机器</span><span lang="EN-US"><font face="Arial">CPU</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">性能、总体体系架构、</span><span lang="EN-US"><font face="Arial">I/O</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">、操作系统的进程调度机制、</span><span lang="EN-US"><font face="Arial">JVM</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">的线程调度机制。随着</span><span lang="EN-US"><font face="Arial">CPU</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">个数的增加，</span><span lang="EN-US"><font face="Arial">WebLogic</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">可以近乎线性地提高线程数。线程数越多，花费在线程切换的时间也就越多；线程数越小，</span><span lang="EN-US"><font face="Arial">CPU</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">可能无法得到充分的利用。为获取一个理想的线程数，需要经过反复的测试。在测试中，可以以</span><span lang="EN-US"><font face="Arial">25*CPU</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">个数为基准进行调整。当空闲线程较少，</span><span lang="EN-US"><font face="Arial">CPU</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">利用率较低时，可以适当增加线程数的大小（每五个递增）。对于</span><span lang="EN-US"><font face="Arial">PC Server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">和</span><span lang="EN-US"><font face="Arial">Windows 2000</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">，则最好每个</span><span lang="EN-US"><font face="Arial">CPU</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">小于</span><span lang="EN-US"><font face="Arial">50</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">个线程，以</span><span lang="EN-US"><font face="Arial">CPU</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">利用率为</span><span lang="EN-US"><font face="Arial">90%</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">左右为最佳。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><span style="mso-tab-count: 1"><font face="Arial">       </font></span></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">通过启动管理控制台，在域（如：</span><span lang="EN-US"><font face="Arial">mydomain</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">服务器</span><span lang="EN-US"><font face="Arial"> &gt; server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">实例（如：</span><span lang="EN-US"><font face="Arial">myserver</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt; Execute Queue &gt; weblogic.kernel.Defalt &gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">配置中修改线程计数。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><font face="Arial"><span style="mso-tab-count: 1">       </span>b) </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">设定执行队列的溢出条件；</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><font face="Arial"><span style="mso-tab-count: 1">       </span>Weblogic Server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">提供给默认的执行队列或用户自定义的执行队列自定义溢出条件的功能，当满足此溢出条件时，服务器改变其状态为“警告”状态，并且额外的再分配一些线程去处理在队列中的请求，而达到降低队列长度的目的。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"><span lang="EN-US"><span style="mso-tab-count: 1"><font face="Arial">       </font></span></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">通过启动管理控制台，在域（如：</span><span lang="EN-US"><font face="Arial">mydomain</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">服务器</span><span lang="EN-US"><font face="Arial"> &gt; server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">实例（如：</span><span lang="EN-US"><font face="Arial">myserver</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt; Execute Queue &gt; weblogic.kernel.Defalt &gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">配置下面几项：</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l3 level2 lfo3; tab-stops: list 42.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'">         </span></span></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">队列长度：此值表示执行队列中可容纳的最大请求数，默认值是</span><span lang="EN-US"><font face="Arial">65536</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">，最后不要手动改变此值。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l3 level2 lfo3; tab-stops: list 42.0pt"><span class="dialog-label"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'">         </span></span></span></span><span class="dialog-label"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">队列长度阈值百分比：此值表示溢出条件，</span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">在此服务器指出队列溢出之前可以达到的队列长度大小的百分比。</span></span><span class="dialog-label"><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l3 level2 lfo3; tab-stops: list 42.0pt"><span class="dialog-label"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'">         </span></span></span></span><span class="dialog-label"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">线程数增加：当检测到溢出条件时，将增加到执行队列中的线程数量。如果</span><span lang="EN-US"><font face="Arial">CPU</font></span></span><span class="dialog-label"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">和内存不是足够的高，尽量不要改变默认值“</span><span lang="EN-US"><font face="Arial">0</font></span></span><span class="dialog-label"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">”。因为</span><span lang="EN-US"><font face="Arial">Weblogic</font></span></span><span class="dialog-label"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">一旦增加后不会自动缩减，虽然最终可能确实起到了降低请求的作用，但在将来的运行中将影响程序的性能。</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l3 level2 lfo3; tab-stops: list 42.0pt"><span class="dialog-label"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'">         </span></span></span></span><span class="dialog-label"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">最大线程数：为了防止创建过多的线程数量，可以通过设定最大的线程数进行控制。</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">在实际的应用场景中，应根据具体情况适当的调整以上参数。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span lang="EN-US"><font face="Arial">c) </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">设定执行队列监测行为</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span lang="EN-US"><font face="Arial">Weblogic Server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">能够自动监测到当一个执行线程变为“阻塞”。变为“阻塞”状态的执行线程将无法完成当前的工作，也无法再执行新请求。如果执行队列中的所有执行线程都变为“阻塞”状态，</span><span lang="EN-US"><font face="Arial">Weblogic server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">可能改变状态为“警告”或“严重”状态。如果</span><span lang="EN-US"><font face="Arial">Weblogic server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">变为“严重”状态，可以通过</span><span lang="EN-US"><font face="Arial">Node Manager</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">来自动关闭此服务器并重新启动它。具体请参考：</span><span lang="EN" style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: Verdana; mso-ansi-language: EN"><a href="http://e-docs.bea.com/wls/docs81/adminguide/nodemgr.html#NodeManagerCapabilities"><font color="#1d58d1">Node Manager Capabilities</font></a></span><span style="FONT-SIZE: 10pt; COLOR: black; FONT-FAMILY: 黑体; mso-ascii-font-family: Verdana; mso-ansi-language: EN; mso-hansi-font-family: Verdana">文档。</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">通过启动管理控制台，在域（如：</span><span lang="EN-US"><font face="Arial">mydomain</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">服务器</span><span lang="EN-US"><font face="Arial"> &gt; server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">实例（如：</span><span lang="EN-US"><font face="Arial">myserver</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt;</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">配置</span><span lang="EN-US"><font face="Arial"> &gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">调整下可配置下面几项：</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo2; tab-stops: list 42.0pt"><span class="dialog-help"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'">         </span></span></span></span><span class="dialog-label"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">阻塞线程最长时间：</span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">在此服务器将线程诊断为阻塞线程之前，线程必须连续工作的时间长度</span><span lang="EN-US"><font face="Arial">(</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">秒</span><span lang="EN-US"><font face="Arial">)</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">。默认情况下，</span><span lang="EN-US"><font face="Arial">WebLogic Server </font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">认为线程在连续工作</span><span lang="EN-US"><font face="Arial"> 600 </font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">秒后成为阻塞线程。</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l0 level1 lfo2; tab-stops: list 42.0pt"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'">         </span></span></span><span class="dialog-label"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">阻塞线程计时器间隔：</span></span><span class="dialog-help"><span lang="EN-US"><font face="Arial">WebLogic Server </font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">定期扫描线程以查看它们是否已经连续工作了</span><span lang="EN-US"><font face="Arial"> "</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">阻塞线程最长时间</span><span lang="EN-US"><font face="Arial">" </font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">字段中指定的时间长度的间隔时间</span><span lang="EN-US"><font face="Arial">(</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">秒</span><span lang="EN-US"><font face="Arial">)</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">。默认情况下，</span><span lang="EN-US"><font face="Arial">WebLogic Server </font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">将此时间间隔设置为</span><span lang="EN-US"><font face="Arial"> 600 </font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">秒。</span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span lang="EN-US"><font face="Arial">5) </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">调优</span><span lang="EN-US"><font face="Arial">TCP</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">连接缓存数；</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span class="dialog-help"><span lang="EN-US"><font face="Arial">WebLogic Server</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">用</span><span lang="EN-US"><font face="Arial">Accept Backlog</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">参数规定服务器向操作系统请求的队列大小，默认值为</span><span lang="EN-US"><font face="Arial">50</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">。当系统重载负荷时</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">这个值可能过小</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">日志中报</span><span lang="EN-US"><font face="Arial">Connection Refused,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">导致有效连接请求遭到拒绝</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">此时可以提高</span><span lang="EN-US"><font face="Arial">Accept Backlog 25%</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">直到连接拒绝错误消失。对于</span><span lang="EN-US"><font face="Arial">Portal</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">类型的应用</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">默认值往往是不够的。</span><span lang="EN-US"><font face="Arial">Login Timeout</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">和</span><span lang="EN-US"><font face="Arial">SSL Login Timeout</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">参数表示普通连接和</span><span lang="EN-US"><font face="Arial">SSL</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">连接的超时时间</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">如果客户连接被服务器中断或者</span><span lang="EN-US"><font face="Arial">SSL</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">容量大</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">可以尝试增加该值。</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">通过启动管理控制台，在域（如：</span><span lang="EN-US"><font face="Arial">mydomain</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">服务器</span><span lang="EN-US"><font face="Arial"> &gt; server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">实例（如：</span><span lang="EN-US"><font face="Arial">myserver</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt;</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">配置</span><span lang="EN-US"><font face="Arial"> &gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">调整下可配置“接受预备连接”。</span><span class="dialog-help"><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span class="dialog-help"><span lang="EN-US"><font face="Arial">6) </font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">改变</span><span lang="EN-US"><font face="Arial">Java</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">编译器；</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">标准的</span><span lang="EN-US"><font face="Arial">Java</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">编译器是</span><span lang="EN-US"><font face="Arial">javac</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">，但编译</span><span lang="EN-US"><font face="Arial">JSP servlets</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">速度太慢，为了提高编译速度，可以使用</span><span lang="EN-US"><font face="Arial">sj</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">或</span><span lang="EN-US"><font face="Arial">jikes</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">编译器取代</span><span lang="EN-US"><font face="Arial">javac</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">编译器。下面说说更改</span><span lang="EN-US"><font face="Arial">Java</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">编译器：</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">通过启动管理控制台，在域（如：</span><span lang="EN-US"><font face="Arial">mydomain</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">服务器</span><span lang="EN-US"><font face="Arial"> &gt; server</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">实例（如：</span><span lang="EN-US"><font face="Arial">myserver</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">）</span><span lang="EN-US"><font face="Arial">&gt;</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">配置</span><span lang="EN-US"><font face="Arial"> &gt; </font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">常规下改变</span><span class="dialog-label"><span lang="EN-US"><font face="Arial">Java </font></span></span><span class="dialog-label"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">编译器</span><font face="Arial">，默认为</font></span><span lang="EN-US"><font face="Arial">javac</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">。输入完整路径，如：</span><span lang="EN-US"><font face="Arial">c:\visualcafe31\bin\sj.exe</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">。然后打开高级选项，在<span class="dialog-label">预规划到类路径</span>填写</span><font face="Arial"><span class="dialog-help">编译</span><span class="dialog-help"><span lang="EN-US"> Java </span></span></font><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">代码时为</span><span lang="EN-US"><font face="Arial"> Java </font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">编译器类路径预规划的选项，如：</span></span><a name="1104268"></a><span class="dialog-help"><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">BEA_HOME\jdk141_02\jre\lib\rt.jar</span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">。</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span class="dialog-help"><span lang="EN" style="mso-ansi-language: EN"><font face="Arial">7) </font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial; mso-ansi-language: EN">使用</span></span><span class="dialog-help"><span lang="EN" style="mso-ansi-language: EN"><font face="Arial">Webogic Server</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial; mso-ansi-language: EN">集群提高性能；</span></span><span class="dialog-help"><span lang="EN" style="mso-ansi-language: EN"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">具体关于如何配置</span><span lang="EN-US"><font face="Arial">Weblogic</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">集群，我就不细说了。详情可参考：</span></span><span lang="EN" style="mso-ansi-language: EN"><a href="http://e-docs.bea.com/wls/docs81/cluster/overview.html"><font face="Arial" color="#1d58d1">Introduction to WebLogic Server Clustering</font></a></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial; mso-ansi-language: EN">。</span><span lang="EN" style="mso-ansi-language: EN"><o:p></o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span lang="EN" style="mso-ansi-language: EN"><font face="Arial">8) Weblogic EJB</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial; mso-ansi-language: EN">调优</span><span lang="EN" style="mso-ansi-language: EN"><o:p></o:p></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">由于</span><span lang="EN-US"><font face="Arial">EJB2.0</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">已经很少项目在用了，</span><span lang="EN-US"><font face="Arial">EJB3.0</font></span><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">再成熟一点，我再补充这一部分吧！</span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span class="dialog-help"><span lang="EN-US"><font face="Arial">9) JDBC</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">应用调优</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span class="dialog-help"><span lang="EN-US"><font face="Arial">JDBC Connection Pool</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">的调优受制于</span><span lang="EN-US"><font face="Arial">WebLogic Server</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">线程数的设置和数据库进程数</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">游标的大小。通常我们在一个线程中使用一个连接</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">所以连接数并不是越多越好</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">为避免两边的资源消耗，建议设置连接池的最大值等于或者略小于线程数。同时为了减少新建连接的开销</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">将最小值和最大值设为一致。</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">增加</span><span lang="EN-US"><font face="Arial">Statement Cache Size</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">对于大量使用</span><span lang="EN-US"><font face="Arial">PreparedStatement</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">对象的应用程序很有帮助</span><span lang="EN-US"><font face="Arial">,WebLogic</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">能够为每一个连接缓存这些对象</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">此值默认为</span><span lang="EN-US"><font face="Arial">10</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">。在保证数据库游标大小足够的前提下</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">可以根据需要提高</span><span lang="EN-US"><font face="Arial">Statement Cache Size</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">。比如当你设置连接数为</span><span lang="EN-US"><font face="Arial">25,Cache Size</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">为</span><span lang="EN-US"><font face="Arial">10</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">时</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">数据库可能需要打开</span><span lang="EN-US"><font face="Arial">25*10=250</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">个游标。不幸的是</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">当遇到与</span><span lang="EN-US"><font face="Arial">PreparedStatement Cache</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">有关的应用程序错误时</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">你需要将</span><span lang="EN-US"><font face="Arial">Cache Size</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">设置为</span><span lang="EN-US"><font face="Arial">0</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">。</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">尽管</span><span lang="EN-US"><font face="Arial">JDBC Connection Pool</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">提供了很多高级参数</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">在开发模式下比较有用</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">但大部分在生产环境下不需调整。这里建议最好不要设置测试表</span><span lang="EN-US"><font face="Arial">, </font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">同时</span><span lang="EN-US"><font face="Arial">Test Reserved Connections</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">和</span><span lang="EN-US"><font face="Arial">Test Released Connections</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">也无需勾上。</span><font face="Arial"></font></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">当然如果你的数据库不稳定</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">时断时续</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">你就可能需要上述的参数打开。</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 21pt"><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">最后提一下驱动程序类型的选择</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">以</span><span lang="EN-US"><font face="Arial">Oracle</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">为例</span><span lang="EN-US"><font face="Arial">,Oracle</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">提供</span><span lang="EN-US"><font face="Arial">thin</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">驱动和</span><span lang="EN-US"><font face="Arial">oci</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">驱动</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">从性能上来讲</span><span lang="EN-US"><font face="Arial">,oci</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">驱动强于</span><span lang="EN-US"><font face="Arial">thin</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">驱动</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">特别是大数据量的操作。但在简单的数据库操作中</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">性能相差不大</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">随着</span><span lang="EN-US"><font face="Arial">thin</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">驱动的不断改进</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">这一弱势将得到弥补。而</span><span lang="EN-US"><font face="Arial">thin</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">驱动的移植性明显强于</span><span lang="EN-US"><font face="Arial">oci</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">驱动。所以在通常情况下建议使用</span><span lang="EN-US"><font face="Arial">thin</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">驱动。而最新驱动器由于</span><span lang="EN-US"><font face="Arial">WebLogic server/bin</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">目录下的类包可能不是最新的</span><span lang="EN-US"><font face="Arial">,</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">请以</span><span lang="EN-US"><font face="Arial">Oracle</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">网站为准</span><span lang="EN-US"><font face="Arial">: </font><a href="http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/htdocs/jdbc9201.html"><font face="Arial" color="#1d58d1">http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/htdocs/jdbc9201.html</font></a></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">。</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 21pt"><span class="dialog-help"><span lang="EN-US"><font face="Arial">10) JSP</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">调优</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l2 level1 lfo4; tab-stops: list 42.0pt"><span class="dialog-help"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'">         </span></span></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">设置</span><span lang="EN-US"><font face="Arial">jsp-param pageCheckSeconds=-1</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">；</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l2 level1 lfo4; tab-stops: list 42.0pt"><span class="dialog-help"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'">         </span></span></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">设置</span><span lang="EN-US"><font face="Arial">serlet-reload-check=-1</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">或</span><span lang="EN-US"><font face="Arial">ServletReloadCheckSecs=-1</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">；</span><span lang="EN-US"><o:p></o:p></span></span></p><p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 42pt; TEXT-INDENT: -21pt; mso-list: l2 level1 lfo4; tab-stops: list 42.0pt"><span class="dialog-help"><span lang="EN-US" style="FONT-FAMILY: Wingdings; mso-fareast-font-family: Wingdings; mso-bidi-font-family: Wingdings"><span style="mso-list: Ignore">l<span style="FONT: 7pt 'Times New Roman'">         </span></span></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">设置</span><span lang="EN-US"><font face="Arial">jsp-param precompile=true</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">，关闭</span><span lang="EN-US"><font face="Arial">JSP</font></span></span><span class="dialog-help"><span style="FONT-FAMILY: 黑体; mso-ascii-font-family: Arial">预编译选项。</span><span lang="EN-US"><o:p></o:p></span></span></p></div><img src ="http://www.blogjava.net/TrampEagle/aggbug/27901.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/TrampEagle/" target="_blank">TrampEagle</a> 2006-01-13 12:47 <a href="http://www.blogjava.net/TrampEagle/articles/27901.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>