﻿<?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-疯狂 --专注java,开源,架构,项目管理-随笔分类-web</title><link>http://www.blogjava.net/freeman1984/category/44672.html</link><description>         
        STANDING ON THE SHOULDERS OF GIANTS</description><language>zh-cn</language><lastBuildDate>Fri, 16 Nov 2012 18:14:08 GMT</lastBuildDate><pubDate>Fri, 16 Nov 2012 18:14:08 GMT</pubDate><ttl>60</ttl><item><title>Servlet3.0引入的新特性 </title><link>http://www.blogjava.net/freeman1984/archive/2012/11/16/391444.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 16 Nov 2012 05:50:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/11/16/391444.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/391444.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/11/16/391444.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/391444.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/391444.html</trackback:ping><description><![CDATA[<p>转自：<a href="http://www.cnblogs.com/rongxh7/archive/2010/04/28/1723200.html">http://www.cnblogs.com/rongxh7/archive/2010/04/28/1723200.html</a><br />Servlet3.0规范的新特性主要是为了3个目的： <br />1.简化开发 <br />2.便于布署 <br />3.支持Web2.0原则 <br />为了简化开发流程，Servlet3.0引入了注解（annotation），这使得web布署描述符web.xml不在是必须的选择。 <br /><strong>Pluggability</strong><strong>可插入性</strong> <br />当使用任何第三方的框架，如Struts，JSF或Spring，我们都需要在web.xml中添加对应的Servlet的入口。这使得web描述符笨重而难以维护。Servlet3.0的新的可插入特性使得web应用程序模块化而易于维护。通过web fragment实现的可插入性减轻了开发人员的负担，不需要再在web.xml中配置很多的Servlet入口。 <br /><strong>Asynchronous Processing </strong><strong>异步处理</strong> <br />另外一个显著的改变就是Servlet3.0支持异步处理，这对AJAX应用程序非常有用。当一个Servlet创建一个线程来创建某些请求的时候，如查询数据库或消息连接，这个线程要等待直到获得所需要的资源才能够执行其他的操作。异步处理通过运行线程执行其他的操作来避免了这种阻塞。 <br />Apart from the features mentioned here, several other enhancements have been made to the existing API. The sections towards the end of the article will explore these features one by one in detail. <br />除了这些新特性之外， Servlet3.0对已有的API也做了一些改进，在本文的最后我们会做介绍。 <br /><strong>Annotations in Servlet Servlet</strong><strong>中使用注解</strong> <br />Servlet3.0的一个主要的改变就是支持注解。使用注解来定义Servlet和filter使得我们不用在web.xml中定义相应的入口。 <br /><strong>@WebServlet</strong> <br />@WebServlet用来定义web应用程序中的一个Servlet。这个注解可以应用于继承了HttpServlet。这个注解有多个属性，例如name，urlPattern, initParams,我们可以使用者的属性来定义Servlet的行为。urlPattern属性是必须指定的。 <br />例如我们可以象下面的例子这样定义：</p>
<p>1. @WebServlet(name = "GetQuoteServlet",&nbsp; urlPatterns = {"/getquote"} )</p>
<p>2. public class GetQuoteServlet extends HttpServlet {</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp; @Override</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp; protected void doGet(HttpServletRequest request, HttpServletResponse response)</p>
<p>5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws ServletException, IOException {</p>
<p>6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrintWriter out = response.getWriter();</p>
<p>7.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</p>
<p>8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String symbol = request.getParameter("symbol");</p>
<p>9.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.println("&lt;h1&gt;Stock Price is&lt;/h1&gt;" + StockQuoteBean.getPrice(symbol);</p>
<p>10.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {</p>
<p>11.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();</p>
<p>12.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>13.&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>14. }</p>
<p>15.</p>
<p>16. public class StockQuoteBean {</p>
<p>17. private StockQuoteServiceEntity serviceEntity = new StockQuoteServiceEntity();</p>
<p>18.&nbsp;&nbsp;&nbsp;&nbsp; public double getPrice(String symbol) {</p>
<p>19.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(symbol !=null )&nbsp; {</p>
<p>20. return serviceEntity.getPrice(symbol);</p>
<p>21.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {</p>
<p>22.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0.0;</p>
<p>23.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>24.&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>25. }</p>
<p>复制代码</p>
<p>在上面的例子中，一个Servlet只对应了一个urlPattern。实际上一个Servlet可以对应多个urlPattern，我们可以这样定义：</p>
<p>1. @WebServlet(name = "GetQuoteServlet",&nbsp; urlPatterns = {"/getquote",&nbsp; "/stockquote"} )</p>
<p>2. public class GetQuoteServlet extends HttpServlet {</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp; @Override</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp; protected void doGet(HttpServletRequest request, HttpServletResponse response)</p>
<p>5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws ServletException, IOException {</p>
<p>6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrintWriter out = response.getWriter();</p>
<p>7.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</p>
<p>8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String symbol = request.getParameter("symbol");</p>
<p>9.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.println("&lt;h1&gt;Stock Price is&lt;/h1&gt;" + StockQuoteBean.getPrice(symbol);</p>
<p>10.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {</p>
<p>11.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();</p>
<p>12.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>13.&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>14. }</p>
<p>复制代码</p>
<p><strong>@WebFilter</strong> <br />我们可以使用@WebFilter注解来定义filter。这个注解可以被应用在实现了javax.servlet.Filter接口的类上。同样的，urlPattern属性是必须指定的。下面就是一个例子。</p>
<p>1. @WebFilter(filterName = "AuthenticateFilter", urlPatterns = {"/stock.jsp", "/getquote"})</p>
<p>2. public class AuthenticateFilter implements Filter {</p>
<p>3.</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp; public void doFilter(ServletRequest request, ServletResponse response,</p>
<p>5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FilterChain chain)&nbsp;&nbsp;&nbsp;&nbsp; throws IOException, ServletException {</p>
<p>6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String username = ((HttpServletRequest) request).getParameter("uname");</p>
<p>7.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String password = ((HttpServletRequest) request).getParameter("password");</p>
<p>8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (username == null || password == null) {</p>
<p>9.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((HttpServletResponse) response).sendRedirect("index.jsp");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </p>
<p>10. if (username.equals("admin") &amp;&amp; password.equals("admin")) {</p>
<p>11.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chain.doFilter(request, response);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </p>
<p>12. else {</p>
<p>13.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((HttpServletResponse) response).sendRedirect("index.jsp");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>14.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>15.</p>
<p>16.&nbsp;&nbsp;&nbsp;&nbsp; public void destroy() {</p>
<p>17.&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>18.&nbsp;&nbsp;&nbsp;&nbsp; public void init(FilterConfig filterConfig) {</p>
<p>19.&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>20. }</p>
<p>复制代码</p>
<p><strong>@WebInitParam</strong> <br />可以使用@WebInitParam注解来制定Servlet或filter的初始参数。当然我们也可以使用@WebServlet或@WebFileter的initParam属性来指定初始参数。下面是使用@WebInitParam的例子：</p>
<p>1. @WebServlet(name = "GetQuoteServlet", urlPatterns = {"/getquote"})</p>
<p>2. @WebInitParam(name = "default_market", value = "NASDAQ")</p>
<p>3. public class GetQuoteServlet extends HttpServlet {</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp; @Override</p>
<p>5.&nbsp;&nbsp;&nbsp;&nbsp; protected void doGet(HttpServletRequest request, HttpServletResponse response)</p>
<p>6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws ServletException, IOException {</p>
<p>7.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; response.setContentType("text/html;charset=UTF-8");</p>
<p>8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrintWriter out = response.getWriter();</p>
<p>9.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</p>
<p>10.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String market = getInitParameter("default_market");</p>
<p>11.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String symbol = request.getParameter("symbol");</p>
<p>12.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.println("&lt;h1&gt;Stock Price in " + market + " is&lt;/h1&gt;" + StockQuoteBean.getPrice(symbol, market));</p>
<p>13.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {</p>
<p>14.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();</p>
<p>15.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>16.&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>17. }</p>
<p>复制代码</p>
<p>下面是使用initParam属性的例子：</p>
<p>1. @WebServlet(name = "GetQuoteServlet",</p>
<p>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; urlPatterns = {"/getquote"},</p>
<p>3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; initParams={@WebInitParam(name="default_market",&nbsp; value="NASDAQ")}</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )</p>
<p>5. public class GetQuoteServlet extends HttpServlet {</p>
<p>6.&nbsp;&nbsp;&nbsp;&nbsp; @Override</p>
<p>7.&nbsp;&nbsp;&nbsp;&nbsp; protected void doGet(HttpServletRequest request, HttpServletResponse response)</p>
<p>8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throws ServletException, IOException {</p>
<p>9.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; response.setContentType("text/html;charset=UTF-8");</p>
<p>10.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrintWriter out = response.getWriter();</p>
<p>11.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</p>
<p>12.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String market = getInitParameter("default_market");</p>
<p>13.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String symbol = request.getParameter("symbol");</p>
<p>14.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.println("&lt;h1&gt;Stock Price in " + market + " is&lt;/h1&gt;" + StockQuoteBean.getPrice(symbol, market));</p>
<p>15.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } finally {</p>
<p>16.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; out.close();</p>
<p>17.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>18.&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>19. }</p>
<p>复制代码</p>
<p><strong>@WebListener</strong> <br />@WebListener注解被应用在作为listener监听web应用程序事件的类上，所以@WebListener能够被应用在实现了ServletContextListener，ServletContextAttributeListener，ServletRequestListener，ServletRequestAttributeListener，HttpSessionListener和HttpSessionAttributeListener接口的类上。在下面的例子中，该类实现了ServletContextListener接口。</p>
<p>1. @WebListener</p>
<p>2. public class QuoteServletContextListener implements ServletContextListener {</p>
<p>3.&nbsp;&nbsp;&nbsp; public void contextInitialized(ServletContextEvent sce) {</p>
<p>4.&nbsp;&nbsp;&nbsp; ServletContext context = sce.getServletContext();</p>
<p>5. context.setInitParameter(&#8220;default_market&#8221;, &#8220;NASDAQ&#8221;);</p>
<p>6. }</p>
<p>7. public void contextDestroyed(ServletContextEvent sce) {</p>
<p>8. }</p>
<p>9. }</p>
<p>复制代码</p>
<p><strong>@MultipartConfig</strong> <br />使用@MultipartConfig注解来指定Servlet要求的multipart MIME类型。这种类型的MIME附件将从request对象中读取。 <br /><strong>The Metadata and Common Annotations</strong><strong>元数据与通用的注解</strong> <br />除了以上的Servlet特定的注解之外，Servlet3.0还支持JSR175（Java元数据规范）和JSR250（Java平台通用注解）所规定的注解，包括： <br />&nbsp;&nbsp;&nbsp; * 安全相关的注解，如 @DeclareRoles 和 @RolesAllowed <br />&nbsp;&nbsp;&nbsp; * 使用EJB的注解，如 @EJB 和 @EJBs <br />&nbsp;&nbsp;&nbsp; * 资源注入相关的注解，如 @Resource 和 @Resources <br />&nbsp;&nbsp;&nbsp; * 使用JPA的注解，如 @PersistenceContext, @PersistenceContexts, @PersistenceUnit, 和 @PersistenceUnits <br />&nbsp;&nbsp;&nbsp; * 生命周期的注解，如 @PostConstruct和 @PreDestroy <br />&nbsp;&nbsp;&nbsp; * 提供WebService引用的注解，如 @WebServiceRef and @WebServiceRefs <br /><strong>注解和web.xml哪个会生效</strong> <br />注解的引入使得web.xml变成可选的了。但是，我们还是可以使用web.xml。容器会根据web.xml中的metadata-complete元素的值来决定使用web.xml还是使用注解。如果该元素的值是true，那么容器不处理注解，web.xml是所有信息的来源。如果该元素不存在或者其值不为true，容器才会处理注解。 <br /><strong>Web</strong><strong>框架的可插入性</strong> <br />我们前面说过了Servlet3.0的改进之一就是使得我们能够将框架和库插入到web应用程序中。这种可插入性减少了配置，并且提高了web应用程序的模块化。Servlet3.0是通过web模块布署描述片段（简称web片段）来实现插入性的。 <br />一个web片段就是web.xml文件的一部分，被包含在框架特定的Jar包的META-INF目录中。Web片段使得该框架组件逻辑上就是web应用程序的一部分，不需要编辑web布署描述文件。 <br />Web片段中使用的元素和布署文件中使用的元素基本相同，除了根元素不一样。Web片段的根元素是&lt;web-fragment&gt;,而且文件名必须叫做web-fragment.xml。容器只会在放在WEB-INF\lib目录下的Jar包中查找web-fragment.xml文件。如果这些Jar包含有web-fragment.xml文件，容器就会装载需要的类来处理他们。 <br />在web.xml中，我们要求Servlet的name必须唯一。同样的，在web.xml和所有的web片段中，Servlet的name也必须唯一。 <br />下面就是一个web-fragment的例子： <br />web-fragment.xml</p>
<p>1. &lt;web-fragment&gt;</p>
<p>2. &lt;servlet&gt;</p>
<p>3. &lt;servlet-name&gt;ControllerServlet&lt;/servlet-name&gt;</p>
<p>4. &lt;servlet-class&gt;com.app.control.ControllerServlet&lt;/servlet-class&gt;</p>
<p>5. &lt;/servlet&gt;</p>
<p>6. &lt;listener&gt;</p>
<p>7. &lt;listener-class&gt;com.listener.AppServletContextListener&lt;/listener-class&gt;</p>
<p>8. &lt;/listener&gt;</p>
<p>9. &lt;/web-fragment&gt;</p>
<p>复制代码</p>
<p>框架的Jar包是放在WEB-INF\lib目录下的，但是Servlet3.0提供两种方法指定多个web片段之间的顺序： <br />&nbsp;&nbsp; 1. 绝对顺序 <br />&nbsp;&nbsp; 2. 相对顺序 <br />我们通过web.xml文件中的&lt;absolute-ordering&gt;元素来指定绝对顺序。这个元素有之元素name，name的值是各个web片段的name元素的值。这样就指定了web片段的顺序。如果多个web片段有相同的名字，容器会忽略后出现的web片段。下面是一个指定绝对顺序的例子： <br />web.xml</p>
<p>1. &lt;web-app&gt;</p>
<p>2. &lt;name&gt;DemoApp&lt;/name&gt;</p>
<p>3. &lt;absolute-ordering&gt;</p>
<p>4. &lt;name&gt;WebFragment1&lt;/name&gt;</p>
<p>5. &lt;name&gt;WebFragment2&lt;/name&gt;</p>
<p>6. &lt;/absolute-ordering&gt;</p>
<p>7. ...</p>
<p>8. &lt;/web-app&gt;</p>
<p>复制代码</p>
<p>相对顺序通过web-fragment.xml中的&lt;ordering&gt;元素来确定。Web片段的顺序由&lt;ordering&gt;的子元素&lt;before&gt;,&lt;after&gt;和&lt;others&gt;来决定。当前的web片段会放在所有的&lt;before&gt;元素中的片段之前。同样的，会放在所有的&lt;after&gt;元素中的片段之后。&lt;others&gt;用来代替所有的其他片段。注意只有当web.xml中没有&lt;absolute-ordering&gt;时，容器才会使用web片段中定义的相对顺序。 <br />下面是一个帮助理解相对顺序的例子： <br />web-fragment.xml</p>
<p>1. &lt;web-fragment&gt;</p>
<p>2. &lt;name&gt;WebFragment1&lt;/name&gt;</p>
<p>3. &lt;ordering&gt;&lt;after&gt;WebFragment2&lt;/after&gt;&lt;/ordering&gt;</p>
<p>4. ...</p>
<p>5. &lt;/web-fragment&gt;</p>
<p>复制代码</p>
<p>web-fragment.xml</p>
<p>1. &lt;web-fragment&gt;</p>
<p>2. &lt;name&gt;WebFragment2&lt;/name&gt;</p>
<p>3. ..</p>
<p>4. &lt;/web-fragment&gt;</p>
<p>复制代码</p>
<p>web-fragment.xml</p>
<p>1. &lt;web-fragment&gt;</p>
<p>2. &lt;name&gt;WebFragment3&lt;/name&gt;</p>
<p>3. &lt;ordering&gt;&lt;before&gt;&lt;others/&gt;&lt;/before&gt;&lt;/ordering&gt;</p>
<p>复制代码</p>
<p>.. <br />&lt;/web-fragment&gt; <br />这些文件将会按照下面的顺序被处理： <br />&nbsp;&nbsp; 1. WebFragment3 <br />&nbsp;&nbsp; 2. WebFragment2 <br />&nbsp;&nbsp; 3. WebFragment1 <br />包含WebFragment3的Jar文件被最先处理，包含WebFragment2的文件被第二个处理，包含WebFragment1的文件被最后处理。 <br />如果既没有定义绝对顺序，也没有定义相对顺序，那么容器就认为所有的web片段间没有顺序上的依赖关系。 <br /><strong>Servlet</strong><strong>中的异步处理</strong> <br />很多时候Servlet要和其他的资源进行互动，例如访问数据库，调用web service。在和这些资源互动的时候，Servlet不得不等待数据返回，然后才能够继续执行。这使得Servlet调用这些资源的时候阻塞。Servlet3.0通过引入异步处理解决了这个问题。异步处理允许线程调用资源的时候不被阻塞，而是直接返回。AsyncContext负责管理从资源来的回应。AsyncContext决定该回应是应该被原来的线程处理还是应该分发给容器中其他的资源。AsyncContext有一些方法如start，dispatch和complete来执行异步处理。 <br />要想使用Servlet3.0的异步处理，我们需要设置@Webservlet和@WebFilter注解的asyncSupport属性。这个属性是布尔值，缺省值是false。 <br />Servlet3.0的异步处理可以很好的和AJAX配合。在Servlet的init方法中，我们能够访问数据库或从JMS读取消息。在doGet或doPost方法中，我们能够启动异步处理，AsyncContext会通过AsyncEvent和AsyncListener来管理线程和数据库操作/JMS操作自己的关系。 <br /><strong>已有API的改进</strong> <br />除了这些新特性之外，Servlet3.0还对以往已经存在的API做了一些改进。 <br /><strong>HttpServletRequest</strong> <br />To support the multipart/form-data MIME type, the following methods have been added to the HttpServletRequest interface: <br />为了支持multipart/form-data MIME类型，在HttpServletRequest接口中添加了项目的方法： <br />&nbsp;&nbsp;&nbsp; * Iterable&lt;Part&gt; getParts() <br />&nbsp;&nbsp;&nbsp; * Part getPart(String name) <br /><strong>Cookies</strong> <br />为了避免一些跨站点攻击，Servlet3.0支持HttpOnly的cookie。HttpOnly cookie不想客户端暴露script代码。Servlet3.0在Cookie类中添加了如下的方法来支持HttpOnly cookie： <br />&nbsp;&nbsp;&nbsp; * void setHttpOnly(boolean isHttpOnly) <br />&nbsp;&nbsp;&nbsp; * boolean isHttpOnly() <br /><strong>ServletContext</strong> <br />通过在ServletContext中添加下面的方法，Servlet3.0允许Servlet或filter被编程的加入到context中： <br />&nbsp;&nbsp;&nbsp; * addServlet(String servletName, String className) <br />&nbsp;&nbsp;&nbsp; * addServlet(String servletName, Servlet servlet) <br />&nbsp;&nbsp;&nbsp; * addServlet(String servletName, Class&lt;? extends Servlet&gt; servletClass) <br />&nbsp;&nbsp;&nbsp; * addFilter(String filterName, String className) <br />&nbsp;&nbsp;&nbsp; * addFilter(String filterName, Filter filter) <br />&nbsp;&nbsp;&nbsp; * addFilter(String filterName, Class&lt;? extends Filter&gt;filterClass) <br />&nbsp;&nbsp;&nbsp; * setInitParameter (String name, String Value)<br /></p>
<h1 class="postTitle"><a id="cb_post_title_url" class="postTitle2" href="http://www.cnblogs.com/rongxh7/archive/2010/04/27/1721944.html"><font color="#333333" size="2">Servlet3.0新功能: 异步处理</font></a> </h1>
<div class="clear"></div>
<div class="postBody">
<div id="cnblogs_post_body">
<p>J2EE 6和Glassfish 3V正式发布了,J2EE 6正式发布了Servlet3.0, 为了能更好的对WEB2.0提供支持, <span class="hilite2">3</span>.0添加了异步处理的机制.</p>
<p>&nbsp;</p>
<p><strong>HTTP1.1相对于HTTP1.0的影响</strong>.</p>
<p>&nbsp;</p>
<p>HTTP1.1最大的一个改变就是提供了长连接,这样HTTP不再是一次请求,一次连接的协议了,只要HTTP的connection不关闭,一次HTTP连接可以支持任意多次request/reponse处理. 当WEB Client与WEB Server建立连接时,客户端可以采用长连接,也就是说Client会一直保持对WEB Server的连接(例如:Browser对一个网站保持当连接,知道Browser关闭或最终退出该网站). 旧的WEB Server会为每一个Http连接分配一个active的Thread,这样当Client的数量增大时,Server端Thread Pool的最大容量也需要相应增大,但Thread是相当耗内存的,一个不小心就会导致Server端NotEnoughMemory...</p>
<p>&nbsp;</p>
<p>基于HTTP1.1,大部分支持Servlet2.X的WEB容器都采用的NIO去接收和处理请求. 当Client和Server端建立连接时,Server端并不分配一个Thread给HTTP连接.直到Server端收到Client端发送的Request时, Server才开始为该Request分配Thread(<span style="color: #ff0000">注意:这里不是为HTTP连接分配Thread</span>). </p>
<p>&nbsp;</p>
<p>这样当大量的Client建立长连接与Server进行交互时,Server无需维持一个Thread给inactive的HTTP长连接, 每个<span class="hilite1">Servlet</span>在doReceived()时其实对应的是一个active Request,而不是HTTPConnection本身. 这样Server端所需的最大Thread数大大地减少了.</p>
<p>&nbsp;</p>
<p><strong>AJAX的影响</strong></p>
<p>&nbsp;</p>
<p>1. Request的数量爆炸性增加增加</p>
<p>&nbsp;</p>
<p>过去WEB Browser打开一个Web page,只需要和Web Server端建立一个HTTP连接.但AJAX技术出现以后,一个Web page上可能有多个与Web Server的连接,而且Ajax request通常是十分频繁的,Server接收到的Request数量大大增长了, 这样原先NIO的技术已经不能很好的支持基于Ajax的服务了.</p>
<p>&nbsp;</p>
<p><span class="hilite1">Servlet</span> <span class="hilite2">3</span>.0的异步处理就能够解决上面的问题.</p>
<p>&nbsp;</p>
<p>Servlet3.0的solution:</p>
<p>当request发送到Server端时,<span class="hilite1">servlet</span>的doReceived()将request放进一个queue里,然后doReceived结束.这个时候server并没有关闭response,Client端一直在等server端response的内容. Server端维护自己的ThreadPool,当ThreadPool里有idle的Thread,就从queue里取出一个request,分配idle的Thread给request,并进行处理.</p>
<p>&nbsp;</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <embed height="15" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" width="14" src="http://taojingrui.javaeye.com/javascripts/syntaxhighlighter/clipboard_new.swf" allowscriptaccess="always" quality="high" flashvars="clipboard=%20%20%20%40WebServlet(%22%2Ftest%22%20asyncSupported%3Dtrue)%0A%20%20%20public%20class%20MyServlet%20extends%20HttpServlet%20%7B%0A%20%20%20%20%20%20%20ScheduledThreadPoolExecutor%20executor%20%3D%20null%3B%0A%0A%20%20%20%20%20%20%20%20public%20void%20init(ServletConfig%20arg0)%20throws%20ServletException%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20executor%20%3D%20new%20ThreadPoolExecutor(10)%3B%2F%2F%E7%8B%AC%E7%AB%8B%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%A4%84%E7%90%86%E8%AF%B7%E6%B1%82%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20public%20void%20doGet(HttpServletRequest%20req%2C%20HttpServletResponse%20res)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20...%0A%20%20%20%20%20%20%20%20%20%20%20%20AsyncContext%20aCtx%20%3D%20request.startAsync(req%2C%20res)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20executor.execute(new%20AsyncWebService(aCtx))%3B%2F%2F%E5%BC%82%E6%AD%A5%E5%A4%84%E7%90%86%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20public%20class%20AsyncWebService%20implements%20Runnable%20%7B%0A%20%20%20%20%20%20%20%20AsyncContext%20ctx%3B%0A%20%20%20%20%20%20%20%20public%20AsyncWebService(AsyncContext%20ctx)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20this.ctx%20%3D%20ctx%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20public%20void%20run()%20%7B%2F%2F%E5%A4%84%E7%90%86%E8%AF%B7%E6%B1%82%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FDo%20something%20here%20...%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Dispatch%20the%20request%20to%20render%20the%20result%20to%20a%20JSP.%0A%20%20%20%20%20%20%20%20%20%20%20%20ctx.dispatch(%22%2Frender.jsp%22)%3B%0A%20%20%20%7D%0A%7D%0A"></embed></div></div>
<ol class="dp-j"><li><span>&nbsp;&nbsp;&nbsp;</span><span class="annotation">@WebServlet</span><span>(</span><span class="string">"/test"</span><span>&nbsp;asyncSupported=</span><span class="keyword">true</span><span>)&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;MyServlet&nbsp;</span><span class="keyword">extends</span><span>&nbsp;HttpServlet&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ScheduledThreadPoolExecutor&nbsp;executor&nbsp;=&nbsp;<span class="keyword">null</span><span>;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;init(ServletConfig&nbsp;arg0)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;ServletException&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executor&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;ThreadPoolExecutor(</span><span class="number">10</span><span>);</span><span class="comment">//独立的线程池处理请求</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;doGet(HttpServletRequest&nbsp;req,&nbsp;HttpServletResponse&nbsp;res)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AsyncContext&nbsp;aCtx&nbsp;=&nbsp;request.startAsync(req,&nbsp;res);&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executor.execute(<span class="keyword">new</span><span>&nbsp;AsyncWebService(aCtx));</span><span class="comment">//异步处理</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;AsyncWebService&nbsp;</span><span class="keyword">implements</span><span>&nbsp;Runnable&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AsyncContext&nbsp;ctx;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;AsyncWebService(AsyncContext&nbsp;ctx)&nbsp;{&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.ctx&nbsp;=&nbsp;ctx;&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;run()&nbsp;{</span><span class="comment">//处理请求</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//Do&nbsp;something&nbsp;here&nbsp;...</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;Dispatch&nbsp;the&nbsp;request&nbsp;to&nbsp;render&nbsp;the&nbsp;result&nbsp;to&nbsp;a&nbsp;JSP.</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctx.dispatch(<span class="string">"/render.jsp"</span><span>);&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre class="java" name="code">   @WebServlet("/test" asyncSupported=true)   public class MyServlet extends HttpServlet {       ScheduledThreadPoolExecutor executor = null;        public void init(ServletConfig arg0) throws ServletException {                   executor = new ThreadPoolExecutor(10);//独立的线程池处理请求        }        public void doGet(HttpServletRequest req, HttpServletResponse res) {            ...            AsyncContext aCtx = request.startAsync(req, res);            executor.execute(new AsyncWebService(aCtx));//异步处理        }   }   public class AsyncWebService implements Runnable {        AsyncContext ctx;        public AsyncWebService(AsyncContext ctx) {            this.ctx = ctx;        }        public void run() {//处理请求            //Do something here ...            // Dispatch the request to render the result to a JSP.            ctx.dispatch("/render.jsp");   }}</pre>
<p>&nbsp;以上的例子可以用于处理对Ajax的请求,因为通常Ajax的请求多,但对响应速度的要求并不太高. 对于正常的页面请求,要求一定的响应速度,可以沿用以前<span class="hilite1">Servlet</span>同步的实现.</p>
<p>&nbsp;</p>
<p>2. Server端推送信息</p>
<p>在Web2.0的应用中, Ajax可用通过不断的发送Request来获取Server端某种信息的变化,但这种实现会产生大量的Client请求. 当前推荐的方法是,让Server端自己推送信息变化给Client.</p>
<p>&nbsp;</p>
<p>因为Servlet3.0提供了异步处理的方式, Request提交给Server以后, Server可以为Request注册一个Listener,由Listener去monitor信息的变化,当信息发生变化时,由Listener负责把信息变化发送给Cient(Listener关闭HTTP response).</p></div></div>
<p>&nbsp;</p><img src ="http://www.blogjava.net/freeman1984/aggbug/391444.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-11-16 13:50 <a href="http://www.blogjava.net/freeman1984/archive/2012/11/16/391444.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>html字符换行的几个css</title><link>http://www.blogjava.net/freeman1984/archive/2012/02/23/370566.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 23 Feb 2012 02:30:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2012/02/23/370566.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/370566.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2012/02/23/370566.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/370566.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/370566.html</trackback:ping><description><![CDATA[word-break : normal |break-all |keep-all <br />normal : 依照亚洲语言和非亚洲语言的文本规则，允许在字内换行。 
<div class="spctrl"></div>　　break-all : 该行为与亚洲语言的normal相同。也允许非亚洲语言文本行的任意字内断开。该值适合包含一些非亚洲文本的亚洲文本。 
<div class="spctrl"></div>　　keep-all : 与所有非亚洲语言的normal相同。对于中文，韩文，日文，不允许字断开。适合包含少量亚洲文本的非亚洲文本。 
<div class="spctrl"></div>　　说明： 
<div class="spctrl"></div>　　设置或检索对象内文本的字内换行行为。尤其在出现多种语言时。 
<div class="spctrl"></div>　　对于中文，应该使用break-all 。 
<div class="spctrl"></div>　　对应的脚本特性为wordBreak。 
<div class="spctrl"></div>　　示例： 
<div class="spctrl"></div>　　div {word-break : break-all; }<br /><br />规定td中的文本不进行换行： 
<div class="spctrl"></div>　　td { white-space: nowrap }<br /><br /><br />.....待续<br /><img src ="http://www.blogjava.net/freeman1984/aggbug/370566.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2012-02-23 10:30 <a href="http://www.blogjava.net/freeman1984/archive/2012/02/23/370566.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>精通 JS正则表达式(转帖) </title><link>http://www.blogjava.net/freeman1984/archive/2011/11/15/363852.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 15 Nov 2011 07:43:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/11/15/363852.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/363852.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/11/15/363852.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/363852.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/363852.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 正则表达式可以: &#8226;测试字符串的某个模式。例如，可以对一个输入字符串进行测试，看在该字符串是否存在一个电话号码模式或一个信用卡号码模式。这称为数据有效性验证 &#8226;替换文本。可以在文档中使用一个正则表达式来标识特定文字，然后可以全部将其删除，或者替换为别的文字 &#8226;根据模式匹配从字符串中提取一个子字符串。可以用来在文本或输入字段中查找特定文字 正则表达式语法 一个正则...&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/11/15/363852.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/363852.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-11-15 15:43 <a href="http://www.blogjava.net/freeman1984/archive/2011/11/15/363852.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>xmlrpc介绍和使用</title><link>http://www.blogjava.net/freeman1984/archive/2011/11/11/363526.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 11 Nov 2011 06:58:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/11/11/363526.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/363526.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/11/11/363526.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/363526.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/363526.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: xmlrpc介绍，并模拟blogjava的xml-rpc api写个例子。<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/11/11/363526.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/363526.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-11-11 14:58 <a href="http://www.blogjava.net/freeman1984/archive/2011/11/11/363526.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>js,JQuery获得select选中的值</title><link>http://www.blogjava.net/freeman1984/archive/2011/11/02/362510.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 02 Nov 2011 02:24:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/11/02/362510.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/362510.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/11/02/362510.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/362510.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/362510.html</trackback:ping><description><![CDATA[<p>用JQuery写的：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Js代码 <a title="复制代码" href="http://sh2015yao.iteye.com/blog/859678#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-c"><li><span>Jquery获得select下拉选项option的值: &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&lt;script&nbsp;type</span><span class="string">"text/javascript"</span><span>&gt; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>$(document).ready(</span><span class="keyword"><font color="#7f0055">function</font></span><span>()&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>$(</span><span class="string">"#selProv"</span><span>).change(</span><span class="keyword"><font color="#7f0055">function</font></span><span>(){ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>alert(&nbsp;$(</span><span class="string">"#selProv&nbsp;option:selected"</span><span>).text()&nbsp;);}) &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>}); &nbsp;&nbsp;</span></li><li><span></span><span class="comment">//alert($("#selProv&nbsp;option[value='01']").val());//也可以这样获得一个值 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&lt;/script&gt; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&lt;select&nbsp;id=</span><span class="string">"selProv"</span><span>&gt; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&lt;option&nbsp;value=</span><span class="string">"1"</span><span>&gt;text111111&lt;/option&gt; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&lt;option&nbsp;value=</span><span class="string">"2"</span><span>&gt;text222222&lt;/option&gt; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&lt;/select&gt;&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="js" title="js获得select选中的值  JQuery获得select选中的值" pre_index="0" source_url="http://sh2015yao.iteye.com/blog/859678" codeable_type="Blog" codeable_id="859678" name="code">Jquery获得select下拉选项option的值:

&lt;script type"text/javascript"&gt;

$(document).ready(function() {

$("#selProv").change(function(){

alert( $("#selProv option:selected").text() );})

});
//alert($("#selProv option[value='01']").val());//也可以这样获得一个值
&lt;/script&gt;

&lt;select id="selProv"&gt;

&lt;option value="1"&gt;text111111&lt;/option&gt;

&lt;option value="2"&gt;text222222&lt;/option&gt;

&lt;/select&gt;
</pre>
<p>&nbsp;</p>
<p>用javascript的写的：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Js代码 <a title="复制代码" href="http://sh2015yao.iteye.com/blog/859678#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-c"><li><span class="keyword"><font color="#7f0055">var</font></span><span>&nbsp;str&nbsp;=&nbsp;document.getElementById(</span><span class="string">"stBegin"</span><span>); &nbsp;&nbsp;</span></li><li><span>alert(str.options[str.selectedIndex].value);&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="js" title="js获得select选中的值  JQuery获得select选中的值" pre_index="1" source_url="http://sh2015yao.iteye.com/blog/859678" codeable_type="Blog" codeable_id="859678" name="code">        var str = document.getElementById("stBegin");
        alert(str.options[str.selectedIndex].value);</pre>
<p>&nbsp;</p>
<p>如何添加select的option呢？</p>
<p>有如下两种方法，当然还有其它的方法，下面的只是经常用到：</p>
<p>&#9312;JS代码：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Js代码 <a title="复制代码" href="http://sh2015yao.iteye.com/blog/859678#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-c"><li><span class="keyword"><font color="#7f0055">var</font></span><span>&nbsp;op&nbsp;=&nbsp;</span><span class="keyword"><font color="#7f0055">new</font></span><span>&nbsp;Option(</span><span class="string">"text"</span><span>,&nbsp;</span><span class="string">"value"</span><span>);</span><span class="comment">//创建一个option对象 </span><span>&nbsp;&nbsp;</span></li><li><span>op.selected&nbsp;=&nbsp;</span><span class="keyword"><font color="#7f0055">true</font></span><span>;</span><span class="comment">//设置其为默认选中项 </span><span>&nbsp;&nbsp;</span></span></li><li><span>$(</span><span class="string">"#stBegin"</span><span>)[0].options.add(op);</span><span class="comment">//添加到select对像</span><span>&nbsp;&nbsp;</span></span></li></ol></div><pre style="display: none" class="js" title="js获得select选中的值  JQuery获得select选中的值" pre_index="2" source_url="http://sh2015yao.iteye.com/blog/859678" codeable_type="Blog" codeable_id="859678" name="code">var op = new Option("text", "value");//创建一个option对象
op.selected = true;//设置其为默认选中项
$("#stBegin")[0].options.add(op);//添加到select对像</pre>
<p>&nbsp;&#9313;JQuery代码：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Js代码 <a title="复制代码" href="http://sh2015yao.iteye.com/blog/859678#"></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"></a></div></div>
<ol class="dp-c"><li><span>$(</span><span class="string">"#stBegin"</span><span>).append(</span><span class="string">"&lt;option&nbsp;value='00000'&nbsp;selected&gt;oooo&lt;/option&gt;"</span><span>);</span><span class="comment">//使用JQuery的append方法，来天添加</span><span>&nbsp;&nbsp;</span></li></ol></div><br />文章来自：<a href="http://sh2015yao.iteye.com/blog/859678">http://sh2015yao.iteye.com/blog/859678</a><img src ="http://www.blogjava.net/freeman1984/aggbug/362510.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-11-02 10:24 <a href="http://www.blogjava.net/freeman1984/archive/2011/11/02/362510.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>发布一个struts2的插件学习版，用来支持rest风格 url的参数绑定。</title><link>http://www.blogjava.net/freeman1984/archive/2011/10/28/362261.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 28 Oct 2011 15:53:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/10/28/362261.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/362261.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/10/28/362261.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/362261.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/362261.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 可以匹配例如：info/{id}/{group}/{userName}  ->info1/admin/joe.do，同时讲参数id，group，userName 绑定到action的对应的属性上。<br>&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/10/28/362261.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/362261.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-10-28 23:53 <a href="http://www.blogjava.net/freeman1984/archive/2011/10/28/362261.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring3.1 mvc+spring jdbc实例以及源码下载</title><link>http://www.blogjava.net/freeman1984/archive/2011/10/24/361899.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 24 Oct 2011 07:54:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/10/24/361899.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/361899.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/10/24/361899.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/361899.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/361899.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: spring3.1 mvc+spring jdbc实例&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/10/24/361899.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/361899.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-10-24 15:54 <a href="http://www.blogjava.net/freeman1984/archive/2011/10/24/361899.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jstl和struts自定义标签的几篇文章</title><link>http://www.blogjava.net/freeman1984/archive/2011/10/20/361665.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 20 Oct 2011 09:43:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/10/20/361665.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/361665.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/10/20/361665.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/361665.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/361665.html</trackback:ping><description><![CDATA[<font color="#108ac6">这个是比较全的所有标签的查询网址：<a href="http://www.web-tag.net/1d41a9e832f49015.htm">http://www.web-tag.net/1d41a9e832f49015.htm</a>&nbsp;这是chm版本的感谢原作者<br /><br /><a href="/Files/freeman1984/javaWebTag.rar">/Files/freeman1984/javaWebTag.rar</a><br /><br />关于web和jstl <a href="http://www.blogjava.net/freeman1984/archive/2011/04/09/347931.html">http://www.blogjava.net/freeman1984/archive/2011/04/09/347931.html<br /></a>el相关知识 <a href="http://www.blogjava.net/freeman1984/archive/2011/04/09/347964.html">http://www.blogjava.net/freeman1984/archive/2011/04/09/347964.html</a><br />有正文的且带有属性的JSP自定义标签实现</font>&nbsp; <a href="http://qqwyy.iteye.com/blog/609864">http://qqwyy.iteye.com/blog/609864</a><br /><font color="#108ac6">没有正文的但带有属性的JSP自定义标签标签实现</font> <em class="actions"></em><a href="http://qqwyy.iteye.com/blog/609859">http://qqwyy.iteye.com/blog/609859</a><br /><font color="#108ac6">没有正文的JSP自定义标签实现</font> <em class="actions"></em><a href="http://qqwyy.iteye.com/blog/609459">http://qqwyy.iteye.com/blog/609459</a><br />函数定义 <a href="http://www.blogjava.net/freeman1984/archive/2007/10/21/154669.html">http://www.blogjava.net/freeman1984/archive/2007/10/21/154669.html</a> <br />struts标签 <a href="http://www.blogjava.net/natlive/archive/2009/05/21/271890.html">http://www.blogjava.net/natlive/archive/2009/05/21/271890.html</a><br />其他的请兄弟们补充。 <br /><img src ="http://www.blogjava.net/freeman1984/aggbug/361665.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-10-20 17:43 <a href="http://www.blogjava.net/freeman1984/archive/2011/10/20/361665.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>高性能JavaScript(来自高性能JavaScript一书)</title><link>http://www.blogjava.net/freeman1984/archive/2011/10/09/360260.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sun, 09 Oct 2011 03:56:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/10/09/360260.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/360260.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/10/09/360260.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/360260.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/360260.html</trackback:ping><description><![CDATA[<h1 class="postTitle"><a id="ctl02_TitleUrl" class="postTitle2" href="http://www.cnblogs.com/pansly/archive/2011/06/29/2093769.html"><font color="#1a8bc8">高性能JavaScript</font></a></h1>
<div id="cnblogs_post_body">
<p>一下内容是转载的，内容应该出自高性能JavaScript一书中，此书值得一读。<br /><br />学习过程中写的笔记，有误请指正。</p>
<p>性能并不是唯一的考虑因素，在对性能要求并非苛刻的环境中，性能也可让位于：团队编码规范，个人编码习惯，代码可读性，模块可扩展性等因素。</p>
<p>以下提到的对性能的优化，仅仅提供了从性能的角度去阐释一些设计思路，但实际上，浏览器本身会逐步优化自身的性能问题，而我们那些提高性能的hack，可能会因为浏览器的版本更新，导致成为一种无用的hack，甚至让性能更慢，所以不要无谓的使用一些hack，去优化一些执行次数很少的代码，而降低代码的可读性，或增加代码量，，一句话：如非必要，请勿hack。</p>
<p><strong>一 javascript加载和执行</strong></p>
<p>1 无论是外链还是内联，script标签都会阻塞页面的渲染，所以script标签的位置最好是&lt;/body&gt;前<br />2 减少http请求，合并多个script文件为一个，1个90k的文件比3个30k的文件载入速度要快<br />3 如何不阻塞页面，而载入一个脚本呢：<br />1）给script标签加defer属性：&lt;script src=&#8221;xxx&#8221; defer&gt;&lt;/script&gt;，这样不会使页面执行过程阻塞，但并不是所有浏览器都支持这个defer属性<br />2）xmlHttpRequest来请求脚本内容并eval，虽然这样可以灵活的控制脚本下载过程 及 何时执行，但不能跨域是个硬伤<br />3）createElement(&#8216;script&#8217;)然后append是个不错的方案，无阻塞，有onload用onload，IE没有就用onreadystatechange实现加载完成的事件，注意readyState属性的值是complete或者loaded都要执行回调函数并清除onreadystatechange，因为这两个状态值不稳定。</p>
<p>4 所以推荐的方式是第三种：在载入js-loader部分的少量代码后，就用loader去加载其他js吧，注意一些市面上流行的库如labjs实现了这些功能(广告下：<a href="http://www.qwrap.com/" target="_blank"><font color="#1a8bc8">qwrap实现了依赖管理及动态加载</font></a>)</p>
<p><strong>二 数据访问</strong><br />数据存储在：直接量，变量，数组元素，对象成员中。<br />这又让我想起了编译型的语言，直接量存在于pe文件的.rdata段中，变量在调用栈上，数组元素和对象成员的访问需要基址+偏移量来定位，多层对象嵌套需要多次计算基址+偏移量来定位。</p>
<p>这些在javascript中依然没有太大变化：</p>
<p>1 直接量的访问无疑是迅速的</p>
<p>2 变量的访问需要考虑javascript允许函数进行嵌套定义，也就形成了基于函数定义的作用域链，而变量的访问，可能需要跨作用域来访问，所以这里有一点性能损失，但先进的js引擎用空间换时间（猜测在子作用域中缓存了所有父层作用域链上变量的name和地址，所以不会进行上溯作用域链，直接执行hash定位即可，但一个函数中如果包含eval,with,catch块的话，通过静态代码分析就没办法知道该函数中声明了哪些变量，也就无法做到这个优化），，不过，从性能上来看，与我的实际测试，大家编码的时候不需要注意这种性能考虑，按团队编码规范和个人编码习惯来吧。</p>
<p>3 对象成员的访问要考虑上溯原型链，所以理论上来说访问实例本身上的成员比访问原型的成员速度要快。</p>
<p>4 多层对象的嵌套要慢，但是在对性能要求并非很苛刻的环境中不用关心这些。</p>
<p><strong>三 dom编程</strong></p>
<p>1 dom的访问和修改<br />1) 标准dom方式(createElement,createTextNode,appendChild) 和 字符串拼接后设置innerHTML 之间的性能相差无几，各个浏览器不同<br />2) 节点克隆速度快一些，先用createElement创建好需要用到的元素类型后，以后在循环中调用元素的cloneNode来克隆<br />3) getElementsByName,getElementsByClassName,getElementsByTagName以及.images,.links,.forms属性返回的都是html集合，是个类数组，没有数组的方法，但提供了length属性和索引器，，HTML集合处于&#8220;实时状态&#8221;，底层文档对象更新时后自动更新javascript中的集合，访问length时候也会去查询，所以遍历集合时候要缓存length来提高效率<br />4) 遍历集合前记录length，循环体中避免对集合中某相同元素进行多次索引，一次索引到局部变量中，因为对html集合的索引性能很差，特别在某些老浏览器中<br />5) 遍历dom节点的话，综合来说使用nextSibling性能会比childNodes快一点，如果只遍历element的话，children被所有浏览器支持，所以尽量用children而不要用childNodes再自行筛选，其他的如childElementCount,firstElementChild,lastElementChild,nextElementSibling,previousElementSibling不被全面支持，注意做特性检测及兼容处理<br />6) 注意所使用的类库是否支持原生的querySelectorAll优先规则，querySelectorAll返回NodeList而不会返回HTML集合，不存在实时文档结构的性能问题</p>
<p>2 重绘和重排</p>
<p>改变dom节点的几何属性会引起重排(reflow)，而后发生重绘(repaint)。</p>
<p>由于重排需要产生大量的计算，所以浏览器一般会通过队列化修改并批量执行来优化重排，获取最新布局信息的操作会导致强制触发队列的执行，如获取offsetTop,scrollTop,clientTop或调用getComputedStyle方法(currentStyle in IE)的时候，要返回诸如此类的最新的布局信息的时候，浏览器就会立即渲染队列中的变化，触发重排，然后返回正确的值。</p>
<p>由于动作的队列是基于页面的，所以，即使你获取的最新布局信息的节点没有待执行的动作，也会触发重排。</p>
<p>所以，尽量将修改元素样式的操作放在一起，然后再执行获取元素最新布局信息的操作，尽量不要交叉进行，因为每次获取元素的最新布局信息，都将触发重排和重绘操作。</p>
<p>虽然，现代浏览器进行了优化，并不会在每次设置元素的样式或改变dom的结构时都会重绘和重排，，但旧版浏览器仍会有性能问题，所以尽量用以下规则来最小化重绘和重排：<br />1） 设置样式：使用cssText属性来合并更新的样式信息： el.style.cssText=&#8221;padding-left:10px;border:1px&#8221;<br />2） 改变dom结构：将元素脱离文档流，然后进行一系列改变，然后再带回文档流中，方法如下：<br />(1) 隐藏元素，对元素的dom结构进行一系列更改，再显示元素<br />(2) 使用createDocumentFragment创建文档碎片，针对文档碎片进行批量操作，然后一次性添加到文档中<br />(3) 将原始元素clone到一个脱离文档流的节点中，修改这个副本后，替换原始元素<br />3） 缓存布局信息<br />尽量减少布局信息的获取次数，如果有针对布局信息的迭代操作，先将布局信息保存到局部变量中，对该局部变量进行迭代更新，然后将该局部变量更新到dom上<br />4） 动画效果时脱离文档流<br />&nbsp; 一个元素进行动画效果时：<br />(1) 将该元素脱离文档流，比如绝对定位该元素<br />(2) 对该元素进行动画操作，这样不会触发其他区域的重排和重绘<br />(3) 动画结束时，将元素恢复文档流位置，这样只会对其余区域进行一次重排和重绘</p>
<p>3 使用事件委托来减少dom树上的事件响应函数<br />对文档中大量的元素进行事件绑定会导致运行时效率下降，基于事件都会冒泡到父层，可以在父层上绑定一个事件，然后识别target(srcElement)来自行dispatch事件。</p>
<p><strong>四 算法和流程控制</strong><br />1 循环<br />1) while,for,do-while性能上基本没差别，不过while和do-while一般被用于基于某个条件的循环，而for用于数组的迭代或线性的工作，而for-in用于对象的枚举<br />2）减少循环次数或减少循环中的工作量都可以优化性能，如duff循环，但性能提升微乎其微，实际测试，在某些浏览器下duff循环不仅不会提升性能，还会降低性能，另外倒序循环可能会快一些，毕竟正序是与长度进行对比后的boolean值，而倒序循环是将表示当前循环进度的数值转换为boolean<br />3) 迭代器如js1.6的forEach方法等，性能比用for进行循环要慢一些，但更语义化<br />附(我写的一个duff循环的js版本)</p>
<div class="hl-surround">
<ol class="hl-main ln-show" title="Double click to hide line number."><li class="hl-firstline"><span style="color: #ffa500">//注:duff的原理是减少循环次数，从而减少对循环条件的判断，所以duff的性能优化只对超大数组(10万次条件判断会降低为10万/8次条件判断)有意义，与循环体中的语句数量无关，所以，duff只适用于循环体执行速度非常快，而循环规模非常大的状况，在js中只有略微的性能提升</span></li><li><span style="color: green">function</span><span style="color: gray"> </span><span style="color: blue">duff</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: gray">,</span><span style="color: blue">callback</span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">i</span><span style="color: gray"> = </span><span style="color: blue">list</span><span style="color: gray">.</span><span style="color: blue">length</span><span style="color: gray"> % </span><span style="color: maroon">8</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">tails</span><span style="color: gray"> = </span><span style="color: blue">i</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">while</span><span style="color: olive">(</span><span style="color: blue">i</span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">callback</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: olive">[</span><span style="color: gray">--</span><span style="color: blue">i</span><span style="color: olive">])</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span></li><li><span style="color: gray"></span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">greatest_factor</span><span style="color: gray"> = </span><span style="color: blue">list</span><span style="color: gray">.</span><span style="color: blue">length</span><span style="color: gray">-</span><span style="color: maroon">1</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">do</span><span style="color: olive">{</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">process</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: olive">[</span><span style="color: blue">greatest_factor</span><span style="color: olive">])</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">process</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: olive">[</span><span style="color: blue">greatest_factor</span><span style="color: gray">-</span><span style="color: maroon">1</span><span style="color: olive">])</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">process</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: olive">[</span><span style="color: blue">greatest_factor</span><span style="color: gray">-</span><span style="color: maroon">2</span><span style="color: olive">])</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">process</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: olive">[</span><span style="color: blue">greatest_factor</span><span style="color: gray">-</span><span style="color: maroon">3</span><span style="color: olive">])</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">process</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: olive">[</span><span style="color: blue">greatest_factor</span><span style="color: gray">-</span><span style="color: maroon">4</span><span style="color: olive">])</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">process</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: olive">[</span><span style="color: blue">greatest_factor</span><span style="color: gray">-</span><span style="color: maroon">5</span><span style="color: olive">])</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">process</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: olive">[</span><span style="color: blue">greatest_factor</span><span style="color: gray">-</span><span style="color: maroon">6</span><span style="color: olive">])</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">process</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: olive">[</span><span style="color: blue">greatest_factor</span><span style="color: gray">-</span><span style="color: maroon">7</span><span style="color: olive">])</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">greatest_factor</span><span style="color: gray">-=</span><span style="color: maroon">8</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span><span style="color: green">while</span><span style="color: olive">(</span><span style="color: blue">greatest_factor</span><span style="color: gray">&gt;</span><span style="color: blue">tails</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: olive">}</span> </li></ol></div>
<p>2 条件语句<br />1)switch比if-else快一些，但性能微乎其微，建议在数量较多的分支时使用switch，而进行范围判断或多重条件的时候使用if-else<br />2)if-else的排列从大概率向小概率<br />3)如果条件太多，建议使用查找表，而且查找表具有动态扩充的能力<br />3 递归<br />1) 由于调用栈的限制，递归是很危险的<br />2) 非自调用，而是交叉调用形成的&#8220;隐伏递归&#8221;是很危险的，出错之后很难排错<br />3) 尽量将递归转化为迭代，比如树的遍历，用非递归的dfs,bfs来实现就好<br />4) 很常用的函数，进行memoize,用空间换取时间</p>
<p><strong>五 字符串和正则表达式</strong></p>
<p>1 理解各个浏览器的js引擎字符串合并的内部机制：<br />1) 避免产生临时字符串，如用str+=&#8217;abc&#8217;;str+=&#8217;def&#8217;&nbsp; 而不要用 str+=&#8217;abc&#8217;+'def&#8217;<br />2) firefox会在编译期合并字符串常量，如str+= &#8216;abc&#8217;+'def&#8217;会被转化为str+=&#8217;abcdef&#8217;，yur-compressor也有这个功能<br />3) 数组的join方法，性能不会比+连接符更快，因为大多数浏览器的+连接符不会开辟新内存空间，而ie7,ie6却会开辟新空间，所以ie6,7中字符串连接应该用数组的join，而其他浏览器用+连接符，，concat方法是最慢的方式</p>
<p>2 正则表达式优化<br />基于各js引擎中正则表达式引擎的不同，以下某些方法会带来某引擎性能的提升但可能同样导致其他引擎性能的下降，所以原书原文也只是原理性阐述，实际开发时视具体情况而定。<br />1) 循环中使用的正则对象尽量在循环前初始化，并赋予一个变量<br />2) 编写正则表达式时，尽量考虑较少的回溯，比如编写分支时将大概率分支放在前面，在贪婪模式是从尾部向前回溯，懒惰模式从headPart向尾部逐字符回溯<br />3) 关于回溯失控，起因是太宽泛的匹配模式，如最后的part没能成功匹配，则会记住回溯位置，尝试修改前面的part的匹配方式，如尝试让前面的懒惰模式包含一次endPart，然后从新位置再尝试匹配，正则引擎会一直尝试，最终导致回溯失控<br />4) 在只是搜索确定的字面量，及字面量位置也确定如行首，行尾等，正则非最佳工具<br />(详细的正则优化先略过，等以后再回来写吧)</p>
<p><strong>六 快速响应用户界面</strong></p>
<p>1 浏览器UI线程和UI队列<br />UIThread:javascript和ui是共用同一个线程的，这样做的好处是无需考虑运行时的用户态或核心态的线程同步，也无需在语言层面实现临界区(critical section)，在我最初自己摸索javascript的时候，认为javascript也是多线程的，后来写代码测试后发现，javascript并非多线程，且javascript代码的执行会阻塞和ui共用的这唯一的线程，使用户的操作得不到ui的反馈。</p>
<p>UIQueue:上面的UIThread负责执行UIQueue中的task，无论用户对UI采取的动作触发的dom事件响应函数，还是javascript执行过程中用setTimeout或setInterval创建的定时器事件响应函数，都会被插入到UIQueue中，当UIThread处于busy状态时，可能会忽略掉一些task，不置入UIQueue，比如用户动作的产生的ui更新task和触发的dom-event两者，ui更新的task会被忽略不放入UIQueue，而dom-event会放入UIQueue等待UIThread处于idle状态时执行，而setInterval函数的周期性定时器事件，会视UIQueue中是否有相同的事件响应函数，如没有才会将该task置入UIQueue。<br />UIQueue的task来源：<br />1) 用户操作产生的ui更新重绘<br />2) 用户操作触发的绑定在dom上的javascript事件<br />3) dom节点自身状态改变触发的绑定在自身上的javascript事件，如<img  alt="" />的onload<br />4) setTimeout与setInterval设置的定时器事件<br />5) ajax过程中的onreadystatechange事件，这个javascript函数并非绑定在dom上，而是绑定在xmlHttpRequest对象上</p>
<p>浏览器限制：为了避免某个javascript事件函数执行时间过长，一直占据UIThread，从而导致用户操作触发的UIUpdate任务得不到执行，各个浏览器使用不同的方案限制了单个javascript事件函数的执行时间<br />1) ie:500万条，在注册表有设置<br />2) firefox: 10秒，在浏览器配置设置中(about:config-&gt;dom.max_script_run_time)<br />3) safari: 5秒，无法修改<br />4) chrome: 依赖通用崩溃检测系统<br />5) opera: 无</p>
<p>界面多久无反应会让用户无法忍受： <strong>最长100毫秒</strong>，用户的动作之后超过100毫秒界面没有做出响应，用户就会认为自己和界面失去了联系。</p>
<p>2 用定时器让出时间片断(分解任务)<br />任务分解过程：用户无法忍受一个10秒的任务占据UI线程，而自己的任何操作得不到反馈，于是我们可以将这个10秒的任务分为200次50毫秒的任务，每执行50毫秒，让出UI线程去执行UI队列中的界面更新的任务，让用户及时得到反馈，然后再执行50毫秒，直到执行完毕。<br />基于大多数长时间UI任务都是对数组的循环操作，于是我们可以将这个循环过程进行拆解，示例代码：</p>
<div class="hl-surround">
<ol class="hl-main ln-show" title="Double click to hide line number."><li class="hl-firstline"><span style="color: green">function</span><span style="color: gray"> </span><span style="color: blue">timedProcessArray</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: gray">, </span><span style="color: blue">callback</span><span style="color: gray">, </span><span style="color: blue">complete</span><span style="color: gray">, </span><span style="color: blue">progress</span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">total</span><span style="color: gray"> = </span><span style="color: blue">list</span><span style="color: gray">.</span><span style="color: blue">length</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">curProgress</span><span style="color: gray"> = </span><span style="color: maroon">0</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">preProgress</span><span style="color: gray"> = </span><span style="color: maroon">0</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: olive">(</span><span style="color: green">function</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: gray">, </span><span style="color: blue">iteration</span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">fn</span><span style="color: gray"> = </span><span style="color: blue">arguments</span><span style="color: gray">.</span><span style="color: blue">callee</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">st</span><span style="color: gray"> = +</span><span style="color: green">new</span><span style="color: gray"> </span><span style="color: teal">Date</span><span style="color: olive">()</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">while</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: gray">.</span><span style="color: blue">length</span><span style="color: gray"> &amp;&amp; </span><span style="color: olive">(</span><span style="color: gray">+</span><span style="color: green">new</span><span style="color: gray"> </span><span style="color: teal">Date</span><span style="color: olive">()</span><span style="color: gray"> - </span><span style="color: blue">st</span><span style="color: gray"> &lt; </span><span style="color: maroon">50</span><span style="color: olive">)</span><span style="color: gray"> </span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">iteration</span><span style="color: gray"> = </span><span style="color: blue">callback</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: gray">.</span><span style="color: blue">shift</span><span style="color: olive">()</span><span style="color: gray">, </span><span style="color: blue">iteration</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">if</span><span style="color: olive">(</span><span style="color: blue">list</span><span style="color: gray">.</span><span style="color: blue">length</span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">if</span><span style="color: olive">(</span><span style="color: blue">progress</span><span style="color: olive">){</span><span style="color: gray"> </span><span style="color: #ffa500">//如果需要对进度进行通知)</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">curProgress</span><span style="color: gray"> = </span><span style="color: maroon">100</span><span style="color: gray"> - </span><span style="color: olive">(</span><span style="color: maroon">100</span><span style="color: gray"> </span><span style="color: #8b0000">/</span><span style="color: red"> total * list.length ^ 0);</span></li><li><span style="color: red"></span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(curProgress != preProgress){</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; preProgress = curProgress;</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; progress(curProgress);</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setTimeout(function(){</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fn.call(null, list, iteration);</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }, 25);</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }else{</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; progress &amp;&amp; progress(100);</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; complete &amp;&amp; complete(iteration);</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp; })(list.concat(),0);</span></li><li><span style="color: red">&nbsp;&nbsp;&nbsp; </span></li><li><span style="color: red">}</span> </li></ol></div>
<p>阻塞和非阻塞(任务分割)方式的示例，:<a href="http://lichaosoft.net/case/progress.html" target="_blank"><font color="#1a8bc8">http://lichaosoft.net/case/progress.html</font></a></p>
<p>3 web-workers<br />在web-workers之前，javascript是没有多线程的，web-workers标准带来了真正的多线程，web-workers本来是html5的一部分，现在已经分离出去成为独立的规范：http://www.w3.org/TR/workers/</p>
<p>和web-workers之间仅能通过onmessage和postMessage交互。</p>
<p>使用web-workers以辅助线程进行计算并拥有进度通知的示例：<br /><a href="http://lichaosoft.net/case/worker.html" target="_blank"><font color="#1a8bc8">http://lichaosoft.net/case/worker.html</font></a>（请使用支持web-workers的chrome或safari浏览）</p>
<p>web-workers适用于那些无法拆解的任务，对数组的遍历是一个可以被拆解的任务，对树的遍历通过使用dfs或bfs将树平坦化为数组后也可以进行拆解，不能拆解的任务:<br />1) 编码/解码大字符串<br />2) 复杂数学运算<br />3) 大数组排序</p>
<p>超过100毫秒的任务，如浏览器支持web-workers，优先使用web-workers，如不支持则使用timedProcessArray进行分割运行。</p>
<p>没有任何javascript代码的重要度高于用户体验，用户体验是至高重要的，无论如何不能让用户觉得界面反应速度慢。</p>
<p><strong>七 AJAX</strong><br />从广义上来看，AJAX是指不重载整个页面的情况下，与服务端进行数据传输，解析数据，并局部刷新页面区域的改善用户体验的行为，那么我们下面介绍：数据传输，数据格式。</p>
<p>1 数据传输<br />1) XHR: 创建一个XMLHttpRequest对象与服务端通信<br />2) 动态脚本注入: 这是一个hack，创建一个script元素并设置src为任意uri-A(可跨域)，可在页面中先定义一个数据处理函数如function newsListProc(list){}，然后在该uri-A指向的script文件中调用newsListProc并将数据传入，这项技术也称为：JSON-P。<br />3) mXHR: 将多个资源文件使用XHR传输到浏览器端，js负责对数据流分割，然后dispath给不同类型资源文件的处理函数<br />4) 流式XHR: 在支持readyState为3时，可访问已解析好的部分xhr数据，既是支持流式XHR，可进行流式处理来优化执行效率，目前实际测试ff3.6支持，而ie6,7,8及chrome都不支持流式XHR。<br />5) iframes: 待续<br />6) comet: 待续</p>
<p>注1：关于mXHR和流式XHR，我写了一个demo用来演示多资源文件合并，由XHR向客户端传输，并在支持流式XHR的浏览器中使用流式XHR，DEMO地址：</p>
<p>注2：纯粹的发送数据而无需接受数据，可用beacons方式，类似动态脚本注入，不过创建的不是script元素，而是Image对象，并设置src为要请求的URI，所以这种方式只能使用GET方式，代码示例:</p>
<div class="hl-surround">
<ol class="hl-main ln-show" title="Double click to hide line number."><li class="hl-firstline"><span style="color: green">function</span><span style="color: gray"> </span><span style="color: blue">keepalive</span><span style="color: olive">(</span><span style="color: blue">uri</span><span style="color: gray">, </span><span style="color: blue">delay</span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">beacon</span><span style="color: gray">, </span><span style="color: blue">delay</span><span style="color: gray"> = </span><span style="color: blue">delay</span><span style="color: gray"> || </span><span style="color: maroon">1000</span><span style="color: gray">,</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: blue">timer</span><span style="color: gray"> = </span><span style="color: blue">setTimeout</span><span style="color: olive">(</span><span style="color: green">function</span><span style="color: olive">(){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">fn</span><span style="color: gray"> = </span><span style="color: blue">arguments</span><span style="color: gray">.</span><span style="color: blue">callee</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">beacon</span><span style="color: gray"> = </span><span style="color: green">new</span><span style="color: gray"> </span><span style="color: teal">Image</span><span style="color: olive">()</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">beacon</span><span style="color: gray">.</span><span style="color: blue">onload</span><span style="color: gray"> = </span><span style="color: blue">beacon</span><span style="color: gray">.</span><span style="color: blue">onerror</span><span style="color: gray"> = </span><span style="color: green">function</span><span style="color: olive">(){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">timer</span><span style="color: gray"> = </span><span style="color: blue">setTimeout</span><span style="color: olive">(</span><span style="color: blue">fn</span><span style="color: gray">, </span><span style="color: blue">delay</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">beacon</span><span style="color: gray">.</span><span style="color: blue">src</span><span style="color: gray"> = </span><span style="color: blue">uri</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span><span style="color: gray">, </span><span style="color: blue">delay</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">return</span><span style="color: gray"> </span><span style="color: green">function</span><span style="color: olive">(){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">console</span><span style="color: gray">.</span><span style="color: blue">log</span><span style="color: olive">(</span><span style="color: #8b0000">'</span><span style="color: red">stop</span><span style="color: #8b0000">'</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">clearTimeout</span><span style="color: olive">(</span><span style="color: blue">timer</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span><span style="color: gray">;</span></li><li><span style="color: olive">}</span> </li></ol></div>
<p>2 数据格式<br />1) XML: 使用responseXML对象的getElementsByTagName,getElementById,node.getAttribute等api对xml文档进行解析，也可以用XPath进行解析，性能更好些，硬伤是：<br />(1) &#8220;结构/数据&#8221;比 太高<br />(2) XPath在支持并不广泛<br />(3) 最重要的就是需要先知道内容的详细结构，针对每个数据结构编写特定的解析方法<br />2) JSON: 最广泛的数据格式，解析性能较之xml高，&#8221;结构/数据&#8221;比低，如使用缩略属性名或完全使用多层数组格式，结构数据比更低，传输性能更高<br />3) JSON-P: 无需解析，属于javascript的正常函数调用，性能最高<br />4) HTML: 无需解析，服务端已构造好用于局部更新的html数据，直接用innerHTML更新，数据结构比太高，压力被集中在服务端，网络传输数据量高<br />5) 自定义分隔符: 性能最高，结构数据比最低，对于性能要求比较苛刻的环境中使用</p>
<p>附:创建xhr对象的代码：</p>
<div class="hl-surround">
<ol class="hl-main ln-show" title="Double click to hide line number."><li class="hl-firstline"><span style="color: green">function</span><span style="color: gray"> </span><span style="color: blue">createXhrObject</span><span style="color: olive">(){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">if</span><span style="color: olive">(</span><span style="color: teal">window</span><span style="color: gray">.</span><span style="color: blue">XMLHttpRequest</span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">return</span><span style="color: gray"> </span><span style="color: green">new</span><span style="color: gray"> </span><span style="color: blue">XMLHttpRequest</span><span style="color: olive">()</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span><span style="color: green">else</span><span style="color: olive">{</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">msxml_progid</span><span style="color: gray"> = </span><span style="color: olive">[</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #8b0000">'</span><span style="color: red">MSXML2.XMLHTTP.6.0</span><span style="color: #8b0000">'</span><span style="color: gray">, </span><span style="color: #ffa500">//支持readyState的3状态，但此状态时读取responseText为空，觉得似乎没意义。。</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #8b0000">'</span><span style="color: red">MSXML3.XMLHTTP</span><span style="color: #8b0000">'</span><span style="color: gray">,</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #8b0000">'</span><span style="color: red">Microsoft.XMLHTTP</span><span style="color: #8b0000">'</span><span style="color: gray">,</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #8b0000">'</span><span style="color: red">MSXML2.XMLHTTP.3.0</span><span style="color: #8b0000">'</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: olive">]</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">req</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">for</span><span style="color: olive">(</span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">i</span><span style="color: gray">=</span><span style="color: maroon">0</span><span style="color: gray">;</span><span style="color: blue">i</span><span style="color: gray">&lt;</span><span style="color: blue">msxml_progid</span><span style="color: gray">.</span><span style="color: blue">length</span><span style="color: gray">;</span><span style="color: blue">i</span><span style="color: gray">++</span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">try</span><span style="color: olive">{</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">req</span><span style="color: gray"> = </span><span style="color: green">new</span><span style="color: gray"> </span><span style="color: blue">ActiveXObject</span><span style="color: olive">(</span><span style="color: blue">msxml_progid</span><span style="color: olive">[</span><span style="color: blue">i</span><span style="color: olive">])</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">break</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span><span style="color: green">catch</span><span style="color: olive">(</span><span style="color: blue">ex</span><span style="color: olive">){}</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">return</span><span style="color: gray"> </span><span style="color: blue">req</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span></li><li><span style="color: olive">}</span> </li></ol></div>
<p>从字符流中异步解析数据的工具类</p>
<div class="hl-surround">
<ol class="hl-main ln-show" title="Double click to hide line number."><li class="hl-firstline"><span style="color: #ffa500">/* </span></li><li><span style="color: #ffa500">* @method StringStreamParser 流式字符串异步解析类</span></li><li><span style="color: #ffa500">* @param onRow 解析出数据行的回调函数</span></li><li><span style="color: #ffa500">* @param RowSeperator 行分隔符,默认'u0001'</span></li><li><span style="color: #ffa500">* @param ColSeperator 列分隔符,默认'u0002'</span></li><li><span style="color: #ffa500">*/</span></li><li><span style="color: green">function</span><span style="color: gray"> </span><span style="color: blue">StringStreamParser</span><span style="color: olive">(</span><span style="color: blue">onRow</span><span style="color: gray">, </span><span style="color: blue">rowSeperator</span><span style="color: gray">, </span><span style="color: blue">colSeperator</span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">if</span><span style="color: gray"> </span><span style="color: olive">(</span><span style="color: gray">!</span><span style="color: olive">(</span><span style="color: green">this</span><span style="color: gray"> </span><span style="color: green">instanceof</span><span style="color: gray"> </span><span style="color: blue">arguments</span><span style="color: gray">.</span><span style="color: blue">callee</span><span style="color: olive">)){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">return</span><span style="color: gray"> </span><span style="color: green">new</span><span style="color: gray"> </span><span style="color: blue">arguments</span><span style="color: gray">.</span><span style="color: blue">callee</span><span style="color: olive">(</span><span style="color: blue">onRow</span><span style="color: gray">, </span><span style="color: blue">rowSeperator</span><span style="color: gray">, </span><span style="color: blue">colSeperator</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span></li><li><span style="color: gray"></span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">stream</span><span style="color: gray"> = </span><span style="color: #8b0000">''</span><span style="color: gray">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: blue">rowSeperator</span><span style="color: gray"> = </span><span style="color: blue">rowSeperator</span><span style="color: gray"> || </span><span style="color: #8b0000">'</span><span style="color: red">u0001</span><span style="color: #8b0000">'</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: blue">colSeperator</span><span style="color: gray"> = </span><span style="color: blue">colSeperator</span><span style="color: gray"> || </span><span style="color: #8b0000">'</span><span style="color: red">u0002</span><span style="color: #8b0000">'</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: #ffa500">/* @method write 向字符流写入包</span></li><li><span style="color: #ffa500">&nbsp;&nbsp;&nbsp;&nbsp; * @param packet 写入的包</span></li><li><span style="color: #ffa500">&nbsp;&nbsp;&nbsp;&nbsp; * @param lastPacket 是否为最后一个包，默认false</span></li><li><span style="color: #ffa500">&nbsp;&nbsp;&nbsp;&nbsp; */</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: green">this</span><span style="color: gray">.</span><span style="color: blue">write</span><span style="color: gray"> = </span><span style="color: green">function</span><span style="color: olive">(</span><span style="color: blue">packet</span><span style="color: gray">, </span><span style="color: blue">lastPacket</span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">stream</span><span style="color: gray"> += </span><span style="color: blue">packet</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">rowIdx</span><span style="color: gray"> = </span><span style="color: blue">stream</span><span style="color: gray">.</span><span style="color: blue">indexOf</span><span style="color: olive">(</span><span style="color: blue">rowSeperator</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">var</span><span style="color: gray"> </span><span style="color: blue">colIdx</span><span style="color: gray">,</span><span style="color: blue">strRow</span><span style="color: gray">, </span><span style="color: blue">dataRow</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">while</span><span style="color: olive">(</span><span style="color: blue">rowIdx</span><span style="color: gray">!==-</span><span style="color: maroon">1</span><span style="color: gray"> || </span><span style="color: blue">lastPacket</span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">if</span><span style="color: olive">(</span><span style="color: blue">rowIdx</span><span style="color: gray">===-</span><span style="color: maroon">1</span><span style="color: olive">){</span><span style="color: gray">&nbsp;&nbsp;&nbsp; </span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">strRow</span><span style="color: gray"> = </span><span style="color: blue">stream</span><span style="color: gray">.</span><span style="color: blue">substr</span><span style="color: olive">(</span><span style="color: maroon">0</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">lastPacket</span><span style="color: gray"> = </span><span style="color: green">false</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span><span style="color: green">else</span><span style="color: olive">{</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">strRow</span><span style="color: gray"> = </span><span style="color: blue">stream</span><span style="color: gray">.</span><span style="color: blue">substr</span><span style="color: olive">(</span><span style="color: maroon">0</span><span style="color: gray">,</span><span style="color: blue">rowIdx</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">stream</span><span style="color: gray"> = </span><span style="color: blue">stream</span><span style="color: gray">.</span><span style="color: blue">substr</span><span style="color: olive">(</span><span style="color: blue">rowIdx</span><span style="color: gray">+</span><span style="color: maroon">1</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">rowIdx</span><span style="color: gray"> = </span><span style="color: blue">stream</span><span style="color: gray">.</span><span style="color: blue">indexOf</span><span style="color: olive">(</span><span style="color: blue">rowSeperator</span><span style="color: olive">)</span><span style="color: gray">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">dataRow</span><span style="color: gray"> = </span><span style="color: olive">[]</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">while</span><span style="color: olive">(</span><span style="color: blue">colIdx</span><span style="color: gray"> = </span><span style="color: blue">strRow</span><span style="color: gray">.</span><span style="color: blue">indexOf</span><span style="color: olive">(</span><span style="color: blue">colSeperator</span><span style="color: olive">)){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">if</span><span style="color: olive">(</span><span style="color: blue">colIdx</span><span style="color: gray"> !== -</span><span style="color: maroon">1</span><span style="color: olive">){</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">dataRow</span><span style="color: gray">.</span><span style="color: blue">push</span><span style="color: olive">(</span><span style="color: blue">strRow</span><span style="color: gray">.</span><span style="color: blue">substr</span><span style="color: olive">(</span><span style="color: maroon">0</span><span style="color: gray">, </span><span style="color: blue">colIdx</span><span style="color: olive">))</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">strRow</span><span style="color: gray"> = </span><span style="color: blue">strRow</span><span style="color: gray">.</span><span style="color: blue">substr</span><span style="color: olive">(</span><span style="color: blue">colIdx</span><span style="color: gray">+</span><span style="color: maroon">1</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span><span style="color: green">else</span><span style="color: olive">{</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">dataRow</span><span style="color: gray">.</span><span style="color: blue">push</span><span style="color: olive">(</span><span style="color: blue">strRow</span><span style="color: gray">.</span><span style="color: blue">substr</span><span style="color: olive">(</span><span style="color: maroon">0</span><span style="color: olive">))</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: green">break</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: blue">onRow</span><span style="color: gray">.</span><span style="color: blue">call</span><span style="color: olive">(</span><span style="color: green">null</span><span style="color: gray">, </span><span style="color: blue">dataRow</span><span style="color: olive">)</span><span style="color: gray">;</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span></li><li><span style="color: gray">&nbsp;&nbsp;&nbsp; </span><span style="color: olive">}</span></li><li><span style="color: olive">}</span> </li></ol></div>
<p>3 其他<br />在确定了合适的数据传输技术，和数据传输格式之后，还可以采取以下方式酌情优化ajax:<br />1) 缓存数据: 最快的请求，是不请求，有以下两种方式缓存:<br />&nbsp; (1) 对于GET请求，在response中，设置expires头信息，浏览器即会将此请求缓存，这种缓存是跨会话也是跨页面的<br />(2) 在javascript中，以url作为唯一标识符缓存请求到的数据，无法跨页面也无法跨会话，但可编程控制缓存过程（不能跨会话也不能跨页面，这种缓存基本上是无意义的）<br />2) 在必要的时候，直接使用XHR对象而非ajax库，如需要流式的数据处理</p>
<p>八 常见编码中的性能提高点<br />1 避免双重求值: eval,Function,setTimeout和setInterval都允许传入字符串，而此时会创建一个新的编译器的实例，将会导致很大的性能损失。(另外这些方式执行代码时，代码的作用域在各个浏览器也不尽相同，容易掉坑)<br />2 使用Object/Array的直接量进行定义(且直接量比new Object()然后设置属性更节省代码)<br />3 不要让代码重复运行<br />1) 延迟定义</p>
<div class="hl-surround">
<ol class="hl-main ln-show" title="Double click to hide line number."><li class="hl-firstline"></li></ol></div>
<p>2) 条件预定义<br />4 尽量使用原生javascript<br />转载自：<a href="http://www.cnblogs.com/pansly/archive/2011/06/29/2093769.html">http://www.cnblogs.com/pansly/archive/2011/06/29/2093769.html</a></p></div><script type="text/javascript">
if ($ != jQuery) {
	$ = jQuery.noConflict();
}
var isLogined = false;
var cb_blogId = 78100;
var cb_entryId = 2093769;
var cb_blogApp = "pansly";
var cb_blogUserGuid = "3bd23d3f-827b-df11-ba8f-001cf0cd104b";
var cb_entryCreatedDate = '2011/6/29 21:16:00';
</script><img src ="http://www.blogjava.net/freeman1984/aggbug/360260.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-10-09 11:56 <a href="http://www.blogjava.net/freeman1984/archive/2011/10/09/360260.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jsessionid 问题分析</title><link>http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 02 Sep 2011 08:33:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/357833.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/357833.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/357833.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: JSESSIONID 问题分析&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/357833.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-09-02 16:33 <a href="http://www.blogjava.net/freeman1984/archive/2011/09/02/357833.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>websphere相关命令</title><link>http://www.blogjava.net/freeman1984/archive/2011/08/29/357505.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 29 Aug 2011 07:58:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/08/29/357505.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/357505.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/08/29/357505.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/357505.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/357505.html</trackback:ping><description><![CDATA[<font face="Times New Roman">serverStatus.sh -all 查看已有的服务<br /></font>&nbsp;./startServer.sh server1 启动server1 <br /><img src ="http://www.blogjava.net/freeman1984/aggbug/357505.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-08-29 15:58 <a href="http://www.blogjava.net/freeman1984/archive/2011/08/29/357505.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EL表达式回忆</title><link>http://www.blogjava.net/freeman1984/archive/2011/07/22/354854.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 22 Jul 2011 06:50:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/07/22/354854.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/354854.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/07/22/354854.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/354854.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/354854.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: EL表达式 EL 全名为Expression LanguageEL 语法很简单，它最大的特点就是使用上很方便。接下来介绍EL主要的语法结构：${sessionScope.user.sex}所有EL都是以${为起始、以}为结尾的。上述EL范例的意思是：从Session的范围中，取得用户的性别。假若依照之前JSP Scriptlet的写法如下：User user = (...&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/07/22/354854.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/354854.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-07-22 14:50 <a href="http://www.blogjava.net/freeman1984/archive/2011/07/22/354854.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让tomcat运行php的几种方式(linux,aix和windows环境)</title><link>http://www.blogjava.net/freeman1984/archive/2011/06/16/352427.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 16 Jun 2011 07:04:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/06/16/352427.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/352427.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/06/16/352427.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/352427.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/352427.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: tomcat运行php的几种方式&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/06/16/352427.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/352427.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-06-16 15:04 <a href="http://www.blogjava.net/freeman1984/archive/2011/06/16/352427.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使得网页网页可编辑的js</title><link>http://www.blogjava.net/freeman1984/archive/2011/05/24/350934.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Tue, 24 May 2011 08:41:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/05/24/350934.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/350934.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/05/24/350934.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/350934.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/350934.html</trackback:ping><description><![CDATA[<br />使得网页网页可编辑的js：<br />在地址栏输入：回车即可<br />javascript:document.body.contentEditable= true ; document.designMode= on ; void 0<img src ="http://www.blogjava.net/freeman1984/aggbug/350934.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-05-24 16:41 <a href="http://www.blogjava.net/freeman1984/archive/2011/05/24/350934.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HTML  DOCTYPE</title><link>http://www.blogjava.net/freeman1984/archive/2011/04/20/348665.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 20 Apr 2011 15:29:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/04/20/348665.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/348665.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/04/20/348665.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/348665.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/348665.html</trackback:ping><description><![CDATA[<p>DOCTYPE不可怕，但把它拿走，会让你怕了又怕。</p>
<p>最近在蓝色理想转悠，发现很多朋友提出有关DIV+CSS排版问题，以及IE与FF的兼容问题。怎么问的都有，结果就是一个——显示很奇怪，很难调整。我们浏览的大多数网站，或者用Dreamweaver创建一个新的网页文档时，源码的顶部都会有DocType声明，但是很多人没有注意它，甚至在创作时候直接将它删掉，其实这往往就是噩梦的开始。在遵循标准的任何Web文档中，DOCTYPE都是一项必需的元素。它会影响代码验证，并决定了浏览器最终如何显示你的web文档。为了避免DOCTYPE的问题重复出现，我根据手头的资料整理了这篇文档，以备自己及有兴趣的朋友参考。</p>
<p>在默认情况下，FF和IE的解释标准是不一样的，也就是说，如果一个网页没有声明DOCTYPE，它就会以默认的DOCTYPE解释下面的HTML。在同一种标准下，不同浏览器的解释模型都有所差异，如果声明标准不同，不用我说，您自己想就可以了。学习网页标准，浏览器兼容，从哪里开始您自己决定，但是，请认识DOCTYPE：</p>
<p><strong>一、什么是DOCTYPE</strong></p>
<p>DOCTYPE是Document Type（文档类型）的简写，在页面中，用来指定页面所使用的XHTML（或者HTML）的版本。要想制作符合标准的页面，一个必不可少的关键组成部分就是DOCTYPE声明。只有确定了一个正确的DOCTYPE，XHTML里的标识和CSS才能正常生效。</p>
<p><strong>二、DOCTYPE的规则</strong></p>
<p>DOCTYPE声明的写法遵循一定的规则，它指出阅读程序应该用什么规则集来解释文档中的标记。在Web文档的情况下，&#8220;阅读程序&#8221;通常是浏览器或者校验器这样的一个程序，&#8220;规则&#8221;则是w3c所发布的一个文档类型定义（dtd）中包含的规则。<br />
每个dtd都包括标记、attributes、properties等内容，它们用于标记web文档的内容；此外还包括一些规则，它们规定了哪些标记能出现在其他哪些标记中。每个web建议标准（比如html 4 frameset和xhtml 1.0 transitional）都有自己的dtd。</p>
<p>以下是从手册上摘抄的规则：</p>
<p>语法：</p>
<p><span class="code">HTML&nbsp; 顶级元素&nbsp; 可用性 "注册//组织//类型 标签//定义&nbsp; 语言""URL" </span></p>
<p>可能值：</p>
<p><span class="code">- 顶级元素：指定 DTD 中声明的顶级元素类型。这与声明的 SGML 文档类型相对应。 HTML 默认。HTML。 <br />
- 可用性：指定正式公开标识符(FPI)是可公开访问的对象还是系统资源。 PUBLIC 默认。可公开访问的对象。SYSTEM 系统资源，如本地文件或 URL。 <br />
- 注册：指定组织是否由国际标准化组织(ISO)注册。 + 默认。组织名称已注册。 <br />
- 组织名称未注册。Internet 工程任务组(IETF)和万维网协会(W3C)并非注册的 ISO 组织。 <br />
组织：指定表明负责由 !DOCTYPE 声明引用的 DTD 的创建和维护的团体或组织的名称，即 OwnderID。 IETF IETF。 W3C W3C。 <br />
- 类型：指定公开文本类，即所引用的对象类型。 DTD 默认。DTD。 <br />
- 标签：指定公开文本描述，即对所引用的公开文本的唯一描述性名称。后面可附带版本号。 HTML 默认。HTML。 <br />
- 定义：指定文档类型定义。 <br />
　　Frameset 框架集文档。 <br />
　　Strict 排除所有 W3C 专家希望逐步淘汰的代表性属性和元素，因为样式表已经很完善了。 <br />
　　Transitional 包含除 frameSet 元素的全部内容。 <br />
- 语言：指定公开文本语言，即用于创建所引用对象的自然语言编码系统。该语言定义已编写为 ISO 639&nbsp; 语言代码(大写两个字母)。 EN 默认。英语。 <br />
- URL：指定所引用对象的位置</span> </p>
<p>为了获得正确的DOCTYPE声明，关键就是让dtd与文档所遵循的标准对应。例如，假定文档遵循的是xhtml 1.0 strict标准，文档的doctype声明就应该引用相应的dtd。另一方面，如果doctype声明指定的是xhtml dtd，但文档包含的是旧式风格的html标记，就是不恰当的；类似地，如果doctype声明指定的是html dtd，但文档包含的是xhtml 1.0 strict标记，同样是不恰当的。</p>
<p><strong>三、选择什么样的DOCTYPE</strong></p>
<p>如上例所示，XHTML 1.0中有3种DTD（文档类型定义）声明可以选择：过渡的（Transitional）、严格的（Strict）和框架的（Frameset）。这里分别介绍如下。</p>
<p>1．过渡的</p>
<p>一种要求不很严格的DTD，允许在页面中使用HTML4.01的标识（符合xhtml语法标准）。过渡的DTD的写法如下：</p>
<p><span class="code">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"<br />
"<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</a>"&gt;</span></p>
<p>2．严格的</p>
<p>一种要求严格的DTD，不允许使用任何表现层的标识和属性，例如&lt;br/&gt;等。严格的DTD的写法如下：</p>
<p><span class="code">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"<br />
"<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd</a>"&gt;</span></p>
<p>3．框架的</p>
<p>一种专门针对框架页面所使用的DTD，当页面中含有框架元素时，就要采用这种DTD。框架的DTD的写法如下：</p>
<p><span class="code">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"<br />
"<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd</a>"&gt;</span></p>
<p>使用严格的DTD来制作页面，当然是最理想的方式。但是，对于没有深入了解Web标准的网页设计者，比较合适的是使用过渡的DTD。因为这种DTD还允许使用表现层的标识、元素和属性，比较适合大多数网页制作人员。</p>
<p><strong>四、需要注意的问题</strong></p>
<p>没什么特别的，就是一定要将DOCTYPE声明放在XHTML文档的顶部，上面哪怕多个HTML注释标记都不行。</p>
<p>最好示例代码也加上DOCTYPE，否则效果会有差异。<br />
<br />
本文转载自：<a href="http://www.blueidea.com/tech/web/2007/5172.asp">http://www.blueidea.com/tech/web/2007/5172.asp</a><br />
</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/348665.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-04-20 23:29 <a href="http://www.blogjava.net/freeman1984/archive/2011/04/20/348665.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>el2</title><link>http://www.blogjava.net/freeman1984/archive/2011/04/09/347964.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sat, 09 Apr 2011 11:06:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/04/09/347964.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/347964.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/04/09/347964.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/347964.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/347964.html</trackback:ping><description><![CDATA[<p>期待已久的日子即将到来: 最新版<a href="http://fatkun.com/goto/http://java.sun.com/products/jsp/" rel="nofollow" target="_blank">JavaServer Pages (JSP)</a>2.0 规范即将和其他的J2EE 1.4一同发布。新的JSP版本有一个新的飞跃，采用了新的方式：由于新的语言表达式（Expression Language，以下简称为EL）和JSP标准标签库（JSP Standard Tag Library ,以下简称为JSTL）这两种新的方式，在页面中不需要用java,对于开发一般的应用来说，重用代码变得更加容易。更具体来说，JSP 2.0带来了以下的优点：</p>
<ul>
    <li>首次被JSTL 1.0引入的EL现在被合并到JSP规范中，就像应用template text一样地使用所有的标准的和定制的组件。
    <li>新的EL已经被扩展，具备一个函数调用机制，JSTL1.1整合了一系列经常需要使用的函数。
    <li>新增加的变量和servlet 规范定义的错误处理机制被更好地组织起来。通过新增加的变量，JSP error pages 现在可以提供更多的错误信息。
    <li>容器因为更加严格的语法检查可以更容易地找出发生的错误。
    <li>所有的J2EE 1.4规范（包括JSP 2.0 和 Servlet 2.4），为了声明部署的规则描述而应用了XML schema。这样的好处之一是你现在可以通过任何顺序列出web.xml文件中的描述。JSP 2.0也增加了一些新的配置选项用于部署描述，允许通过全局的配置来代替基于每页的配置。
    <li>由于更具伸缩性的规则和新的自定义action element，现在就像编写XML文件一样，编写JSP页面变得更加容易。
    <li>定制的标签库现在可以开发成一系列的标签文件（具有JSP元素的文本文件），标签处理器可以使用新的、简化的标签处理器的API。与此同时，新规范加入了一些新的特性，比如：支持在jsp页面上显示动态属性列表和可执行片断属性。 </li>
</ul>
<p>在众多的书籍中，这是头一个讲解JSP 2.0新特性的文章。在这一部分，我们将看到和EL相关的信息，其他的新特性留到后面。在这里我假定读者已经熟悉JSP 1.2，而且至少听说过JSTL。</p>
<p>你可能对这本第三版的《JavaServer Pages》感兴趣。这本书中，我尽可能在细节上讲述所有的内容，而且并不认为你对JSP或者JSTL了解一切。这本书预计在2003年12月 出版，但是你现在可以在<a href="http://fatkun.com/goto/http://www.amazon.com/" rel="nofollow" target="_blank">http://www.amazon.com</a>、Barnes&amp;Noble，或者其他在线书店预订。</p>
<p>EL(The Expression Language)</p>
<p>如果过去使用过JSTL，那么你可能已经熟悉 了EL。EL在JSTL 1.0规范中被引入，用来在运行期间对Java表达式中action element属性赋值提供另一种选择。当JSTL EL已经非常迅速的流行起来情况下，还是存在一个问题： JSTL EL 表达式仅仅可以与JSTL和custom action一起使用，怎样才能使用非标准API对EL表达式求值？</p>
<p>JSP 2.0中,JSP容器自己可以理解EL表达式。这使你在所有过去只能应用Java表达式的地方应用EL表达式成为可能，比如：标准和定制action的属性值，模板文本。</p>
<p>在我们看具体的例子前，让我们更进一步的看看 什么是EL。EL是从JavaScript中获得启发的一种语言，XPath(一种用来访问XML文档的语言)，但是EL在对变量的null值和执行更多 数据类型的自动类型转换的处理上更加宽松。这些新特性对于web应用非常重要，在这些应用中输入通常通过html表单的request parameter来得到。这些参数可能仅仅在某些请求下才能体现出来，而且浏览器经常将request parameter作为文本发送，然而应用程序经常需要把他们作为数字类型、布尔类型（true 或者 false）来使用。通过EL，你根本就很少需要关心缺少某些参数的值或者类型转换。</p>
<p>一个EL表达式包含变量和操作符。任何存储在某个JSP作用范围(如：page、 request、session、application)的bean能被作为一个EL变量来使用。另外，EL支持以下预定义的变量：</p>
<table border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td>变量名称</td>
            <td>说明</td>
        </tr>
        <tr>
            <td valign="top">pageScope</td>
            <td>一个包含所有page scope范围的变量集合 (a java.util.Map)</td>
        </tr>
        <tr>
            <td valign="top">requestScope</td>
            <td>一个包含所有request scope范围的变量集合 (a java.util.Map)</td>
        </tr>
        <tr>
            <td valign="top">sessionScope</td>
            <td>一个包含所有session scope范围的变量集合 (a java.util.Map)</td>
        </tr>
        <tr>
            <td valign="top">applicationScope</td>
            <td>一个包含所有application scope范围的变量集合 (a java.util.Map)</td>
        </tr>
        <tr>
            <td valign="top">param</td>
            <td>一个包含所有请求参数的集合 (a java.util.Map)，通过每个参数对应一个String值的方式赋值</td>
        </tr>
        <tr>
            <td valign="top">paramValues</td>
            <td>一个包含所有请求参数的集合 (a java.util.Map)，通过每个参数对应一个String数组的方式赋值</td>
        </tr>
        <tr>
            <td valign="top">header</td>
            <td>一个包含所有请求的头信息的集合， (a java.util.Map) ,通过每个头信息对应一个String值的方式赋值</td>
        </tr>
        <tr>
            <td valign="top">headerValues</td>
            <td>一个包含所有请求的头信息的集合 (a java.util.Map) ，通过每个头信息的值都保存在一个String数组的方式赋值</td>
        </tr>
        <tr>
            <td valign="top">cookie</td>
            <td>一个包含所有请求的 cookie集合 (a java.util.Map)， &nbsp;&nbsp; 通过每一个cookie（javax.servlet.http.Cookie）对应一个cookie值的方式赋值</td>
        </tr>
        <tr>
            <td valign="top">initParam</td>
            <td>一个包含所有应用程序初始化参数的集合(a java.util.Map) ，通过每个参数分别对应一个String值的方式赋值</td>
        </tr>
        <tr>
            <td valign="top">pageContext</td>
            <td>一个javax.servlet.jsp.PageContext类的实例, 用来提供访问不同的请求数据</td>
        </tr>
    </tbody>
</table>
<p>操作符描述了你对变量所期望的操作。如果你之前曾经使用过任何编程语言的话，在EL表达式中所使用的操作符对你来说可能看起来很熟悉。因为它们和那些在大多数语言中所支持的操作符一样。</p>
<table border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td>Operator</td>
            <td>Description</td>
        </tr>
        <tr>
            <td valign="top">.</td>
            <td>访问一个bean属性或者 Map entry</td>
        </tr>
        <tr>
            <td valign="top">[]</td>
            <td>访问一个数组或者链表元素</td>
        </tr>
        <tr>
            <td valign="top">()</td>
            <td>对子表达式分组，用来改变赋值顺序</td>
        </tr>
        <tr>
            <td valign="top">? :</td>
            <td>条件语句，比如: 条件 ? ifTrue : ifFalse.如果条件为真，表达式值为前者，反之为后者</td>
        </tr>
        <tr>
            <td valign="top">+</td>
            <td>数学运算符，加操作</td>
        </tr>
        <tr>
            <td valign="top">-</td>
            <td>数学运算符，减操作或者对一个值取反</td>
        </tr>
        <tr>
            <td valign="top">*</td>
            <td>数学运算符，乘操作</td>
        </tr>
        <tr>
            <td valign="top">/ or div</td>
            <td>数学运算符，除操作</td>
        </tr>
        <tr>
            <td valign="top">% or mod</td>
            <td>数学运算符，模操作(取余)</td>
        </tr>
        <tr>
            <td valign="top">== or eq</td>
            <td>逻辑运算符，判断符号左右两端是否相等，如果相等返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">!= or ne</td>
            <td>逻辑运算符，判断符号左右两端是否不相等，如果不相等返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">&lt; or lt</td>
            <td>逻辑运算符，判断符号左边是否小于右边，如果小于返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">&gt; or gt</td>
            <td>逻辑运算符，判断符号左边是否大于右边，如果大于返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">&lt;= or le</td>
            <td>逻辑运算符，判断符号左边是否小于或者等于右边，如果小于或者等于返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">&gt;= or ge</td>
            <td>逻辑运算符，判断符号左边是否大于或者等于右边，如果大于或者等于返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">&amp;&amp; or and</td>
            <td>逻辑运算符，与操作赋。如果左右两边同为true返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">|| or or</td>
            <td>逻辑运算符，或操作赋。如果左右两边有任何一边为true返回true，否则返回false</td>
        </tr>
        <tr>
            <td valign="top">! or not</td>
            <td>逻辑运算符，非操作赋。如果对true取运算返回false，否则返回true</td>
        </tr>
        <tr>
            <td valign="top">empty</td>
            <td>用来对一个空变量值进行判断: null、一个空String、空数组、 空Map、没有条目的Collection集合</td>
        </tr>
        <tr>
            <td valign="top">func(args)</td>
            <td>调用方法, func是方法名，args是参数，可以没有，或者有一个、多个参数.参数间用逗号隔开</td>
        </tr>
    </tbody>
</table>
<p>一个EL表达式可以包含：数字、文本（在单引号或者双引号之间）、布尔值、null值。</p>
<p>因为一个EL表达式可以出现在静态文本出现的 地方，因此你必须告诉JSP容器它应该被当作一个EL表达式来处理。你可以通过使用定界符来做到这一点。一个EL表达式总是以&#8221;${ }&#8221;来标记（一个&#8220;$&#8221;符号和一个左花括号,右花括号）。这里有一个EL表达式，它将一个命名为amount的变量加5：</p>
<p>${amount + 5}</p>
<p>如果你想要将5加到一个bean的property上，可以使用property访问操作符：</p>
<p>${order.amount + 5}</p>
<p>在当前这个指定的bean或者collection集合中，Property访问操作符（一个&#8220;.&#8220;符号）告诉EL去寻找名字为amount的property。</p>
<p>${order['amount'] + 5}</p>
<p>在[]之间的值必须是一个property的名字（就像上面的例子中那样）或者是一个保存property名字的变量（或者是一个完整的EL子表达式）。</p>
<p>EL表达式可以被用来赋值给任何标准的或者定制的JSP行为属性（action attribute），这些行为属性被标记为可以接受动态值（或者请求期间的属性值，就象它被正式调用一样）：</p>
<p>&lt;c:out value=&#8221;${order.amount + 5}&#8221;/&gt;</p>
<p>在JSP 2.0之前，你不得不使用Java表达式去给一个属性动态赋值。在过去的很多年中，这已经成为语法混乱的一个普遍根源。</p>
<p>最后，EL表达式可以在页面中和模板直接混合使用。当你生成HTML并且需要设置一个动态值给一个属性的时候，这非常方便：</p>
<p>&lt;input name=&#8221;firstName&#8221; value=&#8221;${customer.firstName}&#8221;&gt;</p>
<p>JSP 1.2中，你不得不使用JSTL的&lt;c:out&gt;来实现同样的事情，最后把各种不同类型的元素混合起来，这导致程序理解起来非常的困难：</p>
<p>&lt;input name=&#8221;firstName&#8221;</p>
<p>value=&#8221;&lt;c:out value=&#8221;${customer.firstName}&#8221;/&gt;&#8221; &gt;</p>
<p>新JSTL 1.1 Tag Library 标识符</p>
<p>JSTL1.1发布的是一个初级的版本，主要 目的是用来整合JSTL和JSP2.0 。最明显的变化是JSTL1.0 &#8220;孪生函数库&#8221;（一组库用来接受EL表达式，另外一组用来接受JAVA表达式），而它们已经被一组既可以用于EL表达式也可以用于JAVA表达式的函数库 所代替。</p>
<p>在JSTL 1.1中使用以下标识符:</p>
<table border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td>库</td>
            <td>URI</td>
            <td>前缀</td>
        </tr>
        <tr>
            <td>Core</td>
            <td>http://java.sun.com/jsp/jstl/core</td>
            <td>c</td>
        </tr>
        <tr>
            <td>XML processing</td>
            <td>http://java.sun.com/jsp/jstl/xml</td>
            <td>x</td>
        </tr>
        <tr>
            <td>I18N formatting</td>
            <td>http://java.sun.com/jsp/jstl/fmt</td>
            <td>fmt</td>
        </tr>
        <tr>
            <td>Database access</td>
            <td>http://java.sun.com/jsp/jstl/sql</td>
            <td>sql</td>
        </tr>
        <tr>
            <td>Functions</td>
            <td>http://java.sun.com/jsp/jstl/functions</td>
            <td>fn</td>
        </tr>
    </tbody>
</table>
<p>如果你曾经使用过JSTL1.0，你可能会注意到新的标识符和旧的EL库标试符一模一样，除了加入了&#8220;/jsp path&#8221; element。你也可能注意到在JSTL1.1中有一个库，包含了EL的函数。我们稍后就会看到。</p>
<p>一个新的EL操作符</p>
<p>在JSP页面中一个非常普遍的需求就是：当某 个条件为真时，要在网页中包含一些文字。在JSP1.2和JSTL1.1中，用具有代表性的&lt;c:if&gt;来实现，但是这样做非常繁琐。 JSP2.0增加了一个新的条件操作符用于EL，以更加优雅的方式来处理这样的情况。这个条件操作符存在于很多编程语言中（比 如：Java,C,JavaScript）,因此你可能以前就见过它。它判断一个布尔的条件，当条件为真或者假时，分别取不同的结果。</p>
<p>一个能清楚说明它如何工作的例子：</p>
<p>&lt;select name=&#8221;artist&#8221;&gt;</p>
<p>&lt;option value=&#8221;1&#8243; ${param.artist == 1 ? &#8216;selected&#8217; : &#8221;}&gt;</p>
<p>Vesica Pisces</p>
<p>&lt;option value=&#8221;2&#8243; ${param.artist == 2 ? &#8216;selected&#8217; : &#8221;}&gt;</p>
<p>Cortical Control</p>
<p>&lt;option value=&#8221;3&#8243; ${param.artist == 3 ? &#8216;selected&#8217; : &#8221;}&gt;</p>
<p>Vida Vierra</p>
<p>&lt;/select&gt;</p>
<p>在这里，我使用了EL表达式和条件操作符来选 择是否包含 html 中的 &#8220;selected&#8221;属性，只有符合条件的 &#8220;option&#8221; 才被添加 &#8220;selected&#8221; 属性。如果条件（param.artist==1）为真时，前面的&#8220;selected&#8221; 才被添加到网页中；否则就添加后面的（在这里是空字符串 &#8216;&#8217;）到页面中。</p>
<p>EL函数</p>
<p>当EL从JSTL规范中移到JSP规范中，它使用了一个如何进行函数调用的技巧。这个EL函数语法非常简单：方法名，紧接着在圆括号中有一组参数：&lt;%@ taglib prefix=&#8221;fn&#8221;</p>
<p>uri=&#8221;http://java.sun.com/jsp/jstl/functions&#8221; %&gt;</p>
<p>${fn:length(myCollection)}</p>
<p>这是一个属于标签库中的函数,并且函数名字在页面中所包含的前缀要指定taglib库。在这个例子中，我使用了前缀fn,这是JSTL function库默认的前缀。</p>
<p>标签库描述符（Tag Library Descriptor,TLD）将函数名称映射到一个由JAVA实现的静态方法中：&lt;function&gt;</p>
<p>&lt;description&gt;</p>
<p>Returns the number of items in a collection or the number of characters in a string.</p>
<p>&lt;/description&gt;</p>
<p>&lt;name&gt;length&lt;/name&gt;</p>
<p>&lt;function-class&gt;</p>
<p>org.apache.taglibs.standard.functions.Functions</p>
<p>&lt;/function-class&gt;</p>
<p>&lt;function-signature&gt;</p>
<p>int length(java.lang.Object)</p>
<p>&lt;/function-signature&gt;</p>
<p>&lt;/function&gt;</p>
<p>在这里最有趣的element 是&lt;function-signature&gt;。它包含一个函数返回类型的声明，静态的方法的名字，在圆括号中声明该方法所有参数的类型（可以 没有参数或者有多个，参数间用逗号间隔开）。返回值类型和参数类型必须是java的原始类型（Object）或者是其他合法类型。</p>
<p>这个静态方法 length()在Jakarta Taglibs标准库中用类似于下面的代码实现的：</p>
<div class="wp_syntax">
<table>
    <tbody>
        <tr>
            <td class="line_numbers">
            <pre>1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            27
            28
            29
            30
            31
            32
            33
            34
            35
            36
            37
            38
            39
            40
            41
            42
            43
            44
            45
            46
            47
            48
            49
            50
            51
            52
            53
            54
            55
            56
            57
            58
            59
            60
            61
            62
            63
            64
            65
            66
            67
            68
            69
            </pre>
            </td>
            <td class="code">
            <pre style="font-family: monospace" class="java"><span style="color: #000000; font-weight: bold">public</span> <span style="color: #000000; font-weight: bold">static</span> <span style="color: #000066; font-weight: bold">int</span> length<span style="color: #009900">(</span><span style="color: #003399">Object</span> obj<span style="color: #009900">)</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">throws</span> JspTagException <span style="color: #009900">{</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">if</span> <span style="color: #009900">(</span>obj <span style="color: #339933">==</span> <span style="color: #000066; font-weight: bold">null</span><span style="color: #009900">)</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> <span style="color: #cc66cc">0</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">if</span> <span style="color: #009900">(</span>obj <span style="color: #000000; font-weight: bold">instanceof</span> <span style="color: #003399">String</span><span style="color: #009900">)</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> <span style="color: #009900">(</span><span style="color: #009900">(</span><span style="color: #003399">String</span><span style="color: #009900">)</span>obj<span style="color: #009900">)</span>.<span style="color: #006633">length</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">if</span> <span style="color: #009900">(</span>obj <span style="color: #000000; font-weight: bold">instanceof</span> <span style="color: #003399">Collection</span><span style="color: #009900">)</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> <span style="color: #009900">(</span><span style="color: #009900">(</span><span style="color: #003399">Collection</span><span style="color: #009900">)</span>obj<span style="color: #009900">)</span>.<span style="color: #006633">size</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">if</span> <span style="color: #009900">(</span>obj <span style="color: #000000; font-weight: bold">instanceof</span> <span style="color: #003399">Map</span><span style="color: #009900">)</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> <span style="color: #009900">(</span><span style="color: #009900">(</span><span style="color: #003399">Map</span><span style="color: #009900">)</span>obj<span style="color: #009900">)</span>.<span style="color: #006633">size</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000066; font-weight: bold">int</span> count <span style="color: #339933">=</span> <span style="color: #cc66cc">0</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">if</span> <span style="color: #009900">(</span>obj <span style="color: #000000; font-weight: bold">instanceof</span> <span style="color: #003399">Iterator</span><span style="color: #009900">)</span> <span style="color: #009900">{</span>
            &nbsp;
            <span style="color: #003399">Iterator</span> iter <span style="color: #339933">=</span> <span style="color: #009900">(</span><span style="color: #003399">Iterator</span><span style="color: #009900">)</span> obj<span style="color: #339933">;</span>
            &nbsp;
            count <span style="color: #339933">=</span> <span style="color: #cc66cc">0</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">while</span> <span style="color: #009900">(</span>iter.<span style="color: #006633">hasNext</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #009900">)</span> <span style="color: #009900">{</span>
            &nbsp;
            count<span style="color: #339933">++;</span>
            &nbsp;
            iter.<span style="color: #006633">next</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #009900">}</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> count<span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #009900">}</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">if</span> <span style="color: #009900">(</span>obj <span style="color: #000000; font-weight: bold">instanceof</span> <span style="color: #003399">Enumeration</span><span style="color: #009900">)</span> <span style="color: #009900">{</span>
            &nbsp;
            <span style="color: #003399">Enumeration</span> <span style="color: #000000; font-weight: bold">enum</span> <span style="color: #339933">=</span> <span style="color: #009900">(</span><span style="color: #003399">Enumeration</span><span style="color: #009900">)</span> obj<span style="color: #339933">;</span>
            &nbsp;
            count <span style="color: #339933">=</span> <span style="color: #cc66cc">0</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">while</span> <span style="color: #009900">(</span><span style="color: #000000; font-weight: bold">enum</span>.<span style="color: #006633">hasMoreElements</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #009900">)</span> <span style="color: #009900">{</span>
            &nbsp;
            count<span style="color: #339933">++;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">enum</span>.<span style="color: #006633">nextElement</span><span style="color: #009900">(</span><span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #009900">}</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> count<span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #009900">}</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">try</span> <span style="color: #009900">{</span>
            &nbsp;
            count <span style="color: #339933">=</span> <span style="color: #003399">Array</span>.<span style="color: #006633">getLength</span><span style="color: #009900">(</span>obj<span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">return</span> count<span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #009900">}</span> <span style="color: #000000; font-weight: bold">catch</span> <span style="color: #009900">(</span><span style="color: #003399">IllegalArgumentException</span> ex<span style="color: #009900">)</span> <span style="color: #009900">{</span><span style="color: #009900">}</span>
            &nbsp;
            <span style="color: #000000; font-weight: bold">throw</span> <span style="color: #000000; font-weight: bold">new</span> JspTagException<span style="color: #009900">(</span><span style="color: #0000ff">"Unsupported type"</span><span style="color: #009900">)</span><span style="color: #009900">)</span><span style="color: #339933">;</span>
            &nbsp;
            <span style="color: #009900">}</span></pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<p>就像你所看到的，在那里没有什么出奇的地方。它是一个常规的静态方法，这个函数中通过对运行期中的参数类别的判断，找出参数的长度。</p>
<p>除了在这个方法中使用的length()方法，JSTL1.1标签库还包含了许多其它经常使用的函数：</p>
<table border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td>函数</td>
            <td>描述</td>
        </tr>
        <tr>
            <td valign="top">fn:contains(string, substring)</td>
            <td>如果参数string中包含参数substring，返回true</td>
        </tr>
        <tr>
            <td valign="top">fn:containsIgnoreCase(string, substring)</td>
            <td>如果参数string中包含参数substring（忽略大小写），返回true</td>
        </tr>
        <tr>
            <td valign="top">fn:endsWith(string, suffix)</td>
            <td>如果参数 string 以参数suffix结尾，返回true</td>
        </tr>
        <tr>
            <td valign="top">fn:escapeXml(string)</td>
            <td>将有特殊意义的XML (和HTML)转换为对应的XML character entity code，并返回</td>
        </tr>
        <tr>
            <td valign="top">fn:indexOf(string, substring)</td>
            <td>返回参数substring在参数string中第一次出现的位置</td>
        </tr>
        <tr>
            <td valign="top">fn:join(array, separator)</td>
            <td>将一个给定的数组array用给定的间隔符separator串在一起，组成一个新的字符串并返回。</td>
        </tr>
        <tr>
            <td valign="top">fn:length(item)</td>
            <td>返回参数item中包含元素的数量。参数Item类型是数组、collection或者String。如果是String类型,返回值是String中的字符数。</td>
        </tr>
        <tr>
            <td valign="top">fn:replace(string, before, after)</td>
            <td valign="top">返回一个String对象。用参数after字符串替换参数string中所有出现参数before字符串的地方，并返回替换后的结果</td>
        </tr>
        <tr>
            <td valign="top">fn:split(string, separator)</td>
            <td>返回一个数组，以参数separator 为分割符分割参数string，分割后的每一部分就是数组的一个元素</td>
        </tr>
        <tr>
            <td valign="top">fn:startsWith(string, prefix)</td>
            <td>如果参数string以参数prefix开头，返回true</td>
        </tr>
        <tr>
            <td valign="top">fn:substring(string, begin, end)</td>
            <td>返回参数string部分字符串, 从参数begin开始到参数end位置，包括end位置的字符</td>
        </tr>
        <tr>
            <td valign="top">fn:substringAfter(string, substring)</td>
            <td>返回参数substring在参数string中后面的那一部分字符串</td>
        </tr>
        <tr>
            <td valign="top">fn:substringBefore(string, substring)</td>
            <td>返回参数substring在参数string中前面的那一部分字符串</td>
        </tr>
        <tr>
            <td valign="top">fn:toLowerCase(string)</td>
            <td>将参数string所有的字符变为小写，并将其返回</td>
        </tr>
        <tr>
            <td valign="top">fn:toUpperCase(string)</td>
            <td>将参数string所有的字符变为大写，并将其返回</td>
        </tr>
        <tr>
            <td valign="top">fn:trim(string)</td>
            <td>去除参数string 首尾的空格，并将其返回</td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/347964.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-04-09 19:06 <a href="http://www.blogjava.net/freeman1984/archive/2011/04/09/347964.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>web和jstl</title><link>http://www.blogjava.net/freeman1984/archive/2011/04/09/347931.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sat, 09 Apr 2011 02:26:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/04/09/347931.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/347931.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/04/09/347931.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/347931.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/347931.html</trackback:ping><description><![CDATA[<p>关于taglib中tld定义的说明</p>
<p>在JSP中使用标签是很平常的事情，在制作自定义变迁时，通常都需要写tld文件来定义变迁的各种属性，对应的java类，前缀等等。标签与tld文件紧紧相连，那么，到底应该怎么放置tld文件？在web.xml中怎么定义tld文件的位置？</p>
<p>以下是具体的分析</p>
<p>&#216;&nbsp; Taglib的使用：</p>
<p>首先是在头部申明taglib, uri必须是web.xml定义的，或者是原始tld文件定义的。</p>
<p>&lt;%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %&gt;</p>
<p>&lt;%@ taglib prefix="ex" uri="/jstl-examples-taglib" %&gt;</p>
<p>&nbsp;</p>
<p>然后便可以在jsp页面中通过prefix使用相应的标签</p>
<p>&lt;c:import varReader="reader" url="${filepath}"&gt;</p>
<p>&nbsp; &lt;ex:escapeHtml reader="${reader}"/&gt;</p>
<p>&lt;/c:import&gt;</p>
<p>&nbsp;</p>
<p>&#216;&nbsp; Uri与tld文件的映射关系</p>
<p>JSP文件中使用的标签通常都有一个tld定义文件(标签库定义文件，主要定义标签对应的java类，标签的属性等等信息)与之对应的,web容器需要找到相应的tld文件，以tld文件中定义的内容判断标签的使用是否正确。</p>
<p>Web做【使用正确性】判断处理，当遇到类似【&lt;c:import】这样的标签时，会通过prefix定位到uri，再根据uri定位到相应的tld文件，对tld文件进行解析。其中uri&#223;&#224;tld文件的映射关系如下：</p>
<p>Key</p>
<p>（Uri）<br />
&nbsp;Value</p>
<p>（String[] taglib_tld_location）<br />
&nbsp;<br />
Taglib-URI：</p>
<p>(如/jstl-examples-taglib、http://java.sun.com/jstl/core等)<br />
&nbsp;taglib_tld_location[0]<br />
&nbsp;<br />
taglib_tld_location[1]<br />
&nbsp;</p>
<p>本文主要介绍的便是uri到tld的映射</p>
<p>&nbsp;</p>
<p>&#216;&nbsp; Tld文件路径定义方式</p>
<p>如下方式1和方式2只能在2.3版本使用，Servlet2.4开始便不能在web.xml中定义taglib了。</p>
<p>&lt;!DOCTYPE web-app</p>
<p>&nbsp;&nbsp;&nbsp; PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"</p>
<p>&nbsp;&nbsp;&nbsp; "http://java.sun.com/dtd/web-app_2_3.dtd"&gt;</p>
<p>l&nbsp; 方式1：</p>
<p>如下所示，在web.xml中定义</p>
<p>&nbsp;&nbsp;&nbsp; &lt;taglib&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;taglib-uri&gt;/jstl-examples-taglib&lt;/taglib-uri&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;taglib-location&gt;/WEB-INF/lib/jstl-examples.tld&lt;/taglib-location&gt;</p>
<p>&lt;/taglib&gt;</p>
<p>如果这样定义的话，映射关系便如下：</p>
<p>/jstl-examples-taglib&#223;&#224;{&#8220;/WEB-INF/lib/jstl-examples.tld&#8221;,&#8221;&#8221;} // taglib_tld_location[0]就足以表示tld路径，因此taglib_tld_location[1]为空。</p>
<p>&nbsp;</p>
<p>l&nbsp; 方式2：</p>
<p>如下所示，在web.xml中定义</p>
<p>&nbsp;&nbsp;&nbsp; &lt;taglib&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;taglib-uri&gt;/jstl-examples-taglib&lt;/taglib-uri&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;taglib-location&gt;/WEB-INF/lib/ jstl-examples.jar&lt;/taglib-location&gt;</p>
<p>&lt;/taglib&gt;</p>
<p>如果这样定义的话，映射关系便如下：</p>
<p>/jstl-examples-taglib&#223;&#224;{&#8220;/WEB-INF/lib/ jstl-examples.jar&#8221;,&#8221; META-INF/taglib.tld&#8221;}</p>
<p>&nbsp;// taglib_tld_location[0]表示jar路径，taglib_tld_location[1]固定为META-INF/taglib.tld(也就是说，tld在jar文件中的保存路径必须是META-INF/taglib.tld，名称必须是taglib.tld)。这就是说一个jar里只能有一个tld。如果代码中不固定为taglib.tld的话，也很难处理，因为如果tld的名称可以随便定义的话，出现多个tld在jar文件中时将会导致混乱。</p>
<p>&nbsp;</p>
<p>l&nbsp; 方式3：</p>
<p>不需要在web.xml中定义，只需要把tld保存在web应用能够使用的jar文件中的META-INF路径下便可。这种情况的机制是这样的：web容器会遍历当前web应用能够访问的jar文件，从jar文件中查找META-INF/xxx.tld文件，当找到一个tld文件之后，便会解析tld文件，取出&lt;taglib&gt;节点的&lt;uri&gt;值，把uri作为key值生成映射关系。</p>
<p>如下所示的jstl的core标签库的tld文件，便会有如下的映射关系</p>
<p>http://java.sun.com/jstl/core&#223;&#224;{&#8220;tld文件所在的jar文件的路径&#8221;,&#8221; META-INF/xxx.tld&#8221;}//taglib_tld_location[0]表示jar路径，taglib_tld_location[1]为所搜到的tld在jar文件中的相对路径</p>
<p>&#8230;&#8230;</p>
<p>&lt;taglib&gt;</p>
<p>&nbsp; &lt;tlib-version&gt;1.0&lt;/tlib-version&gt;</p>
<p>&nbsp; &lt;jsp-version&gt;1.2&lt;/jsp-version&gt;</p>
<p>&nbsp; &lt;short-name&gt;c&lt;/short-name&gt;</p>
<p>&nbsp; &lt;uri&gt;http://java.sun.com/jstl/core&lt;/uri&gt;</p>
<p>&nbsp; &lt;display-name&gt;JSTL core&lt;/display-name&gt;</p>
<p>&nbsp; &lt;description&gt;JSTL 1.0 core library&lt;/description&gt;</p>
<p>&#8230;&#8230;</p>
<p>&nbsp; &lt;tag&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;name&gt;catch&lt;/name&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;tag-class&gt;org.apache.taglibs.standard.tag.common.core.CatchTag&lt;/tag-class&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;body-content&gt;JSP&lt;/body-content&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;description&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Catches any Throwable that occurs in its body and optionally</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exposes it.</p>
<p>&nbsp;&nbsp;&nbsp; &lt;/description&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;attribute&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;name&gt;var&lt;/name&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;required&gt;false&lt;/required&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;rtexprvalue&gt;false&lt;/rtexprvalue&gt;</p>
<p>&nbsp;&nbsp;&nbsp; &lt;/attribute&gt;</p>
<p>&nbsp; &lt;/tag&gt;</p>
<p>&#8230;&#8230;</p>
<p>&nbsp;</p>
<p>&#216;&nbsp; Tld文件的解析逻辑</p>
<p>以jstl为例：</p>
<p>Web容器遇到类似【&lt;c:import】标签时，就会通过在头部中定义的&lt;%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %&gt;找到uri，再根据此uri便可以定位到taglib_tld_location。当taglib_tld_location[0]不是jar文件时，便直接使用java的FileInputStream读取tld文件；当taglib_tld_location[0]是jar文件时，则会</p>
<p>通过如下代码读取tld文件。</p>
<p>URL jarFileUrl = new URL("jar:" + location[0] + "!/");</p>
<p>ZipEntry jarEntry = jarFile.getEntry(location[1]);</p>
<p>&nbsp;</p>
<p>&#216;&nbsp; 总结：</p>
<p>Tld的定义可以不在web.xml中定义，这时需要保证tld在web应用能够访问的jar中，并且保存在jar的META-INF目录下。此时JSP直接使用tld中定义的&lt;uri&gt;便可；</p>
<p>如果在web.xml中定义tld的路径的话，可以直接指定tld文件路径，此时要保证tld不在jar包中(比如在WEB-INF目录下)；也可以指定为jar文件路径，此时要保证tld在jar中且路径为META-INF/taglib.tld。</p>
<p>&nbsp;</p>
<p>以前用WSAD wizard做的，都可以在JSP页面中解析到EL表达式，当然前提是JSP2.0的情况下。 <br />
今天遇到了一个莫名其妙的问题。刚下载Eclipse3.3+MyEclipse6.0体验的过程中，遇上了解析不到EL表达式的问题。经过好几个小时的琢磨终于发现了，给大家share一下： <br />
问题就出在建Web Project的时候web.xml声明上。 <br />
web.xml声明部分一般分为如下版本的xsd, <br />
web-app_2_2.xsd <br />
web-app_2_3.xsd <br />
web-app_2_4.xsd <br />
web-app_2_5.xsd <br />
<br />
更详细的列出各版本web.xml声明部分吧，如下： <br />
web-app_2_2.xsd <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/dtd/web-app_2_2.dtd"&gt;<br />
<br />
web-app_2_3.xsd <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"&gt;<br />
<br />
web-app_2_4.xsd <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee&nbsp; http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"&gt;<br />
<br />
web-app_2_5.xsd <br />
<br />
&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee&nbsp; http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"&gt;<br />
<br />
<br />
确定web.xml里的xsd版本之后一定要在JSP的声明(&lt;%@page %&gt;)部分加一行，如下： <br />
&lt;%@ page isELIgnored="false" %&gt; <br />
这样设为false才能解析EL表达式。 <br />
经过各版本的test之后.... <br />
注意!! 其中servlets 2.4(我没记错的话JSP 2.0出来之后的第一个版本)，这个版本的isELIgnored默认设置为false。所以使用web.xml里用web-app_2_4.xsd声明的时候在JSP页面不用特意声明。 <br />
<br />
下面是官方Documention中isELIgnored Attribute的详解： <br />
The isELIgnored Attribute <br />
&#8226; Format <br />
&#8211; &lt;%@ page isELIgnored="false" %&gt; <br />
&#8211; &lt;%@ page isELIgnored="true" %&gt; <br />
Purpose <br />
&#8211; To control whether the JSP 2.0 Expression Language <br />
(EL) is ignored (true) or evaluated normally (false). <br />
&#8226; Notes <br />
&#8211; If your web.xml specifies servlets 2.3 (corresponding to <br />
JSP 1.2) or earlier, the default is true <br />
&#8226; But it is still legal to change the default—you are permitted <br />
to use this attribute in a JSP-2.0-compliant server <br />
regardless of the web.xml version. <br />
&#8211; If your web.xml specifies servlets 2.4 (corresponding to <br />
JSP 2.0) or earlier, the default is false <br />
</p>
<p><br />
本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/qingkangxu/archive/2010/12/05/6057034.aspx</p>
 <img src ="http://www.blogjava.net/freeman1984/aggbug/347931.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-04-09 10:26 <a href="http://www.blogjava.net/freeman1984/archive/2011/04/09/347931.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>提高AJAX客户端响应速度(转载)</title><link>http://www.blogjava.net/freeman1984/archive/2011/02/11/344056.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 11 Feb 2011 07:23:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/02/11/344056.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/344056.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/02/11/344056.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/344056.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/344056.html</trackback:ping><description><![CDATA[&nbsp;
<h1 style="text-align: left" align="left"><span style="font-family: 宋体">提高</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">客户端响应速度</span></h1>
<p>(<span style="font-family: 宋体">文：包一磊</span>)</p>
<p style="text-align: left; margin: 15.6pt 0cm" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">的出现极大的改变了</span><span style="font-family: 'Verdana', 'sans-serif'">Web</span><span style="font-family: 宋体">应用客户端的操作模式，它使的用户可以在全心工作时不必频繁的忍受那令人厌恶的页面刷新。理论上</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">技术在很大的程度上可以减少用户操作的等待时间，同时节约网络上的数据流量。而然，实际情况却并不总是这样。用户时常会抱怨用了</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">的系统响应速度反而降低了。</span></p>
<p style="text-align: left; margin: 15.6pt 0cm" class="MsoNormal" align="left"><span style="font-family: 宋体">笔者从事</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">方面的研发多年，参与开发了目前国内较为成熟的</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">平台</span><span style="font-family: 'Verdana', 'sans-serif'">-dorado</span><span style="font-family: 宋体">。根据笔者的经验，导致这种结果的根本原因并不在</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">。很多时候系统响应速度的降低都是由不够合理的界面设计和不够高效的编程习惯造成的。下面我们就来分析几个</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">开发过程中需要时刻注意的环节。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">合理的使用客户端编程和远程过程调用。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">客户端的编程主要都是基于</span><span style="font-family: 'Verdana', 'sans-serif'">JavaScript</span><span style="font-family: 宋体">的。而</span><span style="font-family: 'Verdana', 'sans-serif'">JavaScript</span><span style="font-family: 宋体">是一种解释型的编程语言，它的运行效率相对于</span><span style="font-family: 'Verdana', 'sans-serif'">Java</span><span style="font-family: 宋体">等都要稍逊一筹。同时</span><span style="font-family: 'Verdana', 'sans-serif'">JavaScript</span><span style="font-family: 宋体">又是运行在浏览器这样一个严格受限的环境当中。因此开发人员对于哪些逻辑可以在客户端执行应该有一个清醒的认识。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">在实际的应用中究竟应该怎样使用</span><span style="font-family: 宋体">客户端编程，这依赖于开发人员的经验判断。这里很多问题是只可意会的。由于篇幅有限，在这里我们大致归纳出下面这几个注意事项：</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 63pt; tab-stops: list 63.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">u&nbsp;</span><span style="font-family: 宋体">尽可能避免频繁的使用远程过程调用，例如避免在循环体中使用远程过程调用。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 63pt; tab-stops: list 63.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">u&nbsp;</span><span style="font-family: 宋体">如果可能的话尽可能使用</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">方式的远程过程调用（异步方式的远程过程调用）。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 63pt; tab-stops: list 63.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">u&nbsp;</span><span style="font-family: 宋体">避免将重量级的数据操作放置在</span><span style="font-family: 宋体">客户端。例如：大批量的数据复制操作、需要通过大量的数据遍历完成的计算等。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">改进对</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的操作方式。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">客户端的编程中，对</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的操作往往是最容易占用</span><span style="font-family: 'Verdana', 'sans-serif'">CPU</span><span style="font-family: 宋体">时间的。而对于</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的操作，不同的编程方法之间的性能差异又往往是非常大的。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">以下是三段运行结果完全相同的代码，它们的作用是在网页中创建一个</span><span style="font-family: 'Verdana', 'sans-serif'">10x1000</span><span style="font-family: 宋体">的表格。然而它们的运行速度却有着天壤之别。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">1 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 41</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">*/</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var table = document.createElement("TABLE");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">document.body.appendChild(table);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for(var i = 0; i &lt; 1000; i++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;var row = table.insertRow(-1);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;for(var j = 0; j &lt; 10; j++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp; var cell = objRow.insertCell(-1);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; cell.innerText = "( " + i + " , " + j + " )";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">2 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 7.6</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var table = document.getElementById("TABLE");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">document.body.appendChild(table);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var tbody = document.createElement("TBODY");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">table.appendChild(tbody);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for(var i = 0; i &lt; 1000; i++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;var row = document.createElement("TR");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;tbody.appendChild(row);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;for(var j = 0; j &lt; 10; j++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp; var cell = document.createElement("TD");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; row.appendChild(cell);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; cell.innerText = "( " + i + " , " + j + " )";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">3 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 1.26</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var tbody = document.createElement("TBODY");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for(var i = 0; i &lt; 1000; i++){&nbsp;&nbsp; </span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;var row = document.createElement("TR");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(var j = 0; j &lt; 10; j++){</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp; var cell = document.createElement("TD");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; cell.innerText = "( " + i + " , " + j + " )";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; row.appendChild(cell);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;tbody.appendChild(row);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var table = document.getElementById("TABLE");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">table.appendChild(tbody); </span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">document.body.appendChild(table);</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">这里的&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">1</span><span style="font-family: 宋体">&#8221;和&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;之间的差别在于在创建表格单元时使用了不同的</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">方法。而&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;和&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">3</span><span style="font-family: 宋体">&#8221;</span><span style="font-family: 宋体">之间的差别在于处理顺序的略微不同。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">1</span><span style="font-family: 宋体">&#8221;和&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;之间如此大的性能差别我们无从分析，目前所知的是</span><span style="font-family: 'Verdana', 'sans-serif'">insertRow</span><span style="font-family: 宋体">和</span><span style="font-family: 'Verdana', 'sans-serif'">insertCell</span><span style="font-family: 宋体">是</span><span style="font-family: 'Verdana', 'sans-serif'">DHTML</span><span style="font-family: 宋体">中表格特有的</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">，</span><span style="font-family: 'Verdana', 'sans-serif'">createElement</span><span style="font-family: 宋体">和</span><span style="font-family: 'Verdana', 'sans-serif'">appendChild</span><span style="font-family: 宋体">是</span><span style="font-family: 'Verdana', 'sans-serif'">W3C DOM</span><span style="font-family: 宋体">的原生</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">。而前者应该是对后者的封装。不过，我们并不能因此而得出结论认为</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">的原生</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">总是优于对象特有的</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">。建议大家在需要频繁调用某一</span><span style="font-family: 'Verdana', 'sans-serif'">API</span><span style="font-family: 宋体">时，对其性能表现做一些基本的测试。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;和&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">3</span><span style="font-family: 宋体">&#8221;之间的性能差异主要来自于他们的构建顺序不同。&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">2</span><span style="font-family: 宋体">&#8221;的做法是首先创建最外层的</span><span style="font-family: 'Verdana', 'sans-serif'">&lt;TABLE&gt;</span><span style="font-family: 宋体">对象，然后再在循环中依次创建</span><span style="font-family: 'Verdana', 'sans-serif'">&lt;TR&gt;</span><span style="font-family: 宋体">和</span><span style="font-family: 'Verdana', 'sans-serif'">&lt;TD&gt;</span><span style="font-family: 宋体">。而&#8220;测试代码</span><span style="font-family: 'Verdana', 'sans-serif'">3</span><span style="font-family: 宋体">&#8221;的做法是首先在内存中由内到外的构建好整个表格，最后再将它添加到网页中。这样做的目的是尽可能的减少浏览器重新计算页面布局的次数。每当我们将一个对象添加到网页中时，浏览器都会尝试对页面中的控件的布局进行重新计算。所以，<span style="color: blue">如果我们能够首先在内存中将整个要构造的对象全部创建好，然后再一次性的添加到网页中。那么，浏览器将只会做一次布局的重计算</span>。总结为一句话那就是越晚执行</span><span style="font-family: 'Verdana', 'sans-serif'">appendChild</span><span style="font-family: 宋体">越好。有时为了提高运行效率，我们甚至可以考虑先使用</span><span style="font-family: 'Verdana', 'sans-serif'">removeChild</span><span style="font-family: 宋体">将已存在的控件从页面中移除，然后构造完成后再重新将其放置回页面当中。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">提高字符串累加的速度</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">在使用</span><span style="font-family: 'Verdana', 'sans-serif'">AJAX</span><span style="font-family: 宋体">提交信息时，我可能常常需要拼装一些比较大的字符串通过</span><span style="font-family: 'Verdana', 'sans-serif'">XmlHttp</span><span style="font-family: 宋体">来完成</span><span style="font-family: 'Verdana', 'sans-serif'">POST</span><span style="font-family: 宋体">提交。尽管提交这样大的信息的做法看起来并不优雅，但有时我们可能不得不面对这样的需求。那么</span><span style="font-family: 'Verdana', 'sans-serif'">JavaScript</span><span style="font-family: 宋体">中对字符串的累加速度如何呢？我们先来做下面的这个实验。累加一个长度为</span><span style="font-family: 'Verdana', 'sans-serif'">30000</span><span style="font-family: 宋体">的字符串。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">1 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 14.325</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var str = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for (var i = 0; i &lt; 50000; i++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str += "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">这段代码耗时</span><span style="font-family: 'Verdana', 'sans-serif'">14.325</span><span style="font-family: 宋体">秒，结果并不理想。现在我们将代码改为如下的形式：</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">2 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 0.359</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var str = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for (var i = 0; i &lt; 100; i++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var sub = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var j = 0; j &lt; 500; j++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sub += "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str += sub;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">这段代码耗时</span><span style="font-family: 'Verdana', 'sans-serif'">0.359</span><span style="font-family: 宋体">秒！同样的结果，我们做的只是首先拼装一些较小的字符串然后再组装成更大的字符串。这种做法可以有效的在字符串拼装的后期减小内存复制的数据量。知道了这一原理之后我们还可以把上面的代码进一步拆散以后进行测试。下面的代码仅耗时</span><span style="font-family: 'Verdana', 'sans-serif'">0.140</span><span style="font-family: 宋体">秒。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">测试代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">3 - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 0.140</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var str = "";&nbsp;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for (var i1 = 0; i1 &lt; 5; i1++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var str1 = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var i2 = 0; i2 &lt; 10; i2++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var str2 = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var i3 = 0; i3 &lt; 10; i3++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var str3 = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var i4 = 0; i4 &lt; 10; i4++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var str4 = "";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (var i5 = 0; i5 &lt; 10; i5++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str4 += "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str3 += str4;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str2 += str3;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str1 += str2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str += str1;&nbsp;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">不过，上面这种做法也许并不是最好的！如果我们需要提交的信息是</span><span style="font-family: 'Verdana', 'sans-serif'">XML</span><span style="font-family: 宋体">格式的（其实绝大多数情况下，我们都可以设法将要提交的信息组装成</span><span style="font-family: 'Verdana', 'sans-serif'">XML</span><span style="font-family: 宋体">格式），我们还能找到更高效更优雅的方法</span>—<span style="font-family: 宋体">利用</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象为我们组装字符串。下面这段代买组装一个长度为</span><span style="font-family: 'Verdana', 'sans-serif'">950015</span><span style="font-family: 宋体">的字符串仅须耗时</span><span style="font-family: 'Verdana', 'sans-serif'">0.890</span><span style="font-family: 宋体">秒。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">利用</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">DOM</span><span style="font-family: 宋体; font-size: 9pt">对象组装信息</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> - </span><span style="font-family: 宋体; font-size: 9pt">耗时</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">: 0.890</span><span style="font-family: 宋体; font-size: 9pt">秒</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var xmlDoc;&nbsp;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">if (browserType == BROWSER_IE) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlDoc = new ActiveXObject("Msxml.DOMDocument");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">else {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlDoc = document.createElement("DOM");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var root = xmlDoc.createElement("root");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">for (var i = 0; i &lt; 50000; i++) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var node = xmlDoc.createElement("data");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (browserType == BROWSER_IE) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.text = "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.innerText = "xxxxxx";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; root.appendChild(node);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">xmlDoc.appendChild(root);</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">var str;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">if (browserType == BROWSER_IE) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str = xmlDoc.xml;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">else {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str = xmlDoc.innerHTML;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">避免</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的内存泄漏。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">关于</span><span style="font-family: 'Verdana', 'sans-serif'">IE</span><span style="font-family: 宋体">中</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">对象的内存泄露是一个常常被开发人员忽略的问题。然而它带来的后果却是非常严重的！它会导致</span><span style="font-family: 'Verdana', 'sans-serif'">IE</span><span style="font-family: 宋体">的内存占用量持续上升，并且浏览器的整体运行速度明显下降。对于一些泄露比较严重的网页，甚至只要刷新几次，运行速度就会降低一倍。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">比较常见的内存泄漏的模型有&#8220;</span><span style="font-family: 'Verdana', 'sans-serif'"><a href="http://birdshome.cnblogs.com/archive/2006/05/28/IE_MemoryLeak.html"><span style="font-family: 宋体; color: windowtext; text-decoration: none; text-underline: none">循环引用</span></a></span><span style="font-family: 宋体">模型&#8221;、&#8220;</span><span style="font-family: 'Verdana', 'sans-serif'"><a href="http://birdshome.cnblogs.com/archive/2006/06/01/ClosureReferences.html"><span style="font-family: 宋体; color: windowtext; text-decoration: none; text-underline: none">闭包函数</span></a></span><span style="font-family: 宋体">模型&#8221;和&#8220;</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">插入顺序模型&#8221;</span><span style="font-family: 'Verdana', 'sans-serif'">,</span><span style="font-family: 宋体">对于前两种泄漏模型，我们都可以通过在网页析构时解除引用的方式来避免。而对于&#8220;</span><span style="font-family: 'Verdana', 'sans-serif'">DOM</span><span style="font-family: 宋体">插入顺序模型&#8221;则需要通过改变一些惯有的编程习惯的方式来避免。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">有关内存泄漏的模型的更多介绍可以通过</span><span style="font-family: 'Verdana', 'sans-serif'">Google</span><span style="font-family: 宋体">很快的查到，本文不做过多的阐述。不过，这里我向您推荐一个可用于查找和分析网页内存泄露的小工具</span>—<span style="font-family: 'Verdana', 'sans-serif'">Drip</span><span style="font-family: 宋体">，目前的较新版本是</span><span style="font-family: 'Verdana', 'sans-serif'">0.5</span><span style="font-family: 宋体">，下载地址是</span><span style="font-family: 'Verdana', 'sans-serif'">http://outofhanwell.com/ieleak/index.php</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">复杂页面的分段装载和初始化</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">对系统当中某些确实比较复杂而又不便使用</span><span style="font-family: 'Verdana', 'sans-serif'">IFrame</span><span style="font-family: 宋体">的界面，我们可以对其实施分段装载。例如对于多页标签的界面，我们可以首先下载和初始化多页标签的默认页，然后利用</span><span style="font-family: 'Verdana', 'sans-serif'">AJAH</span><span style="font-family: 宋体">（</span><span style="font-family: 'Verdana', 'sans-serif'">asynchronous JavaScript and HTML</span><span style="font-family: 宋体">）技术来异步的装载其他标签页中的内容。这样就能保证界面可以在第一时间首先展现给用户。把整个复杂界面的装载过程分散到用户的操作过程当中。</span></p>
<p style="text-align: left; text-indent: -21pt; margin: 7.8pt 0cm 7.8pt 42pt; tab-stops: list 42.0pt" class="MsoNormal" align="left"><span style="font-family: Wingdings">n&nbsp;</span><span style="font-family: 宋体">利用</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">压缩网络流量。</span></p>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">除了上面提到的这些代码级的改良之外，我们还可以利用</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">来有效的降低网络流量。目前常见的主流浏览器已经全部支持</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">算法，我们往往只需要编写少量的代码就可以支持</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">了。例如在</span><span style="font-family: 'Verdana', 'sans-serif'">J2EE</span><span style="font-family: 宋体">中我们可以在</span><span style="font-family: 'Verdana', 'sans-serif'">Filter</span><span style="font-family: 宋体">中通过下面的代码来判断客户端浏览器是否支持</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">算法，然后根据需要利用</span><span style="font-family: 'Verdana', 'sans-serif'">java.util.zip.GZIPOutputStream</span><span style="font-family: 宋体">来实现</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">的输出。</span></p>
<table style="border-bottom: medium none; border-left: medium none; border-collapse: collapse; background: #f3f3f3; border-top: medium none; border-right: medium none" class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0">
    <tbody>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">/* </span><span style="font-family: 宋体; font-size: 9pt">判断浏览器对</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">GZIP</span><span style="font-family: 宋体; font-size: 9pt">支持方式的代码</span><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt"> */</span></p>
            </td>
        </tr>
        <tr>
            <td style="border-bottom: medium none; border-left: medium none; padding-bottom: 0cm; padding-left: 5.4pt; width: 426.1pt; padding-right: 5.4pt; border-top: medium none; border-right: medium none; padding-top: 0cm" valign="top" width="568">
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">private static String getGZIPEncoding(HttpServletRequest request) {</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;String acceptEncoding = request.getHeader("Accept-Encoding");</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;if (acceptEncoding == null) return null;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;acceptEncoding = acceptEncoding.toLowerCase();</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;if (acceptEncoding.indexOf("x-gzip") &gt;= 0) return "x-gzip";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;if (acceptEncoding.indexOf("gzip") &gt;= 0) return "gzip";</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">&nbsp;return null;</span></p>
            <p style="text-align: left" class="MsoNormal" align="left"><span style="font-family: 'Verdana', 'sans-serif'; font-size: 9pt">}</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align: left; margin: 7.8pt 0cm 7.8pt 42pt" class="MsoNormal" align="left"><span style="font-family: 宋体">一般而言，</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">对于</span><span style="font-family: 'Verdana', 'sans-serif'">HTML</span><span style="font-family: 宋体">、</span><span style="font-family: 'Verdana', 'sans-serif'">JSP</span><span style="font-family: 宋体">的压缩比可以达到</span><span style="font-family: 'Verdana', 'sans-serif'">80%</span><span style="font-family: 宋体">左右，而它造成的服务端和客户端的性能损耗几乎是可以忽略的。结合其他因素，支持</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">的网站有可能为我们节约</span><span style="font-family: 'Verdana', 'sans-serif'">50%</span><span style="font-family: 宋体">的网络流量。因此</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">的使用可以为那些网络环境不是特别好的应用带来显著的性能提升。使用</span><span style="font-family: 'Verdana', 'sans-serif'">Http</span><span style="font-family: 宋体">的监视工具</span><span style="font-family: 'Verdana', 'sans-serif'">Fiddler</span><span style="font-family: 宋体">可以方便的检测出网页在使用</span><span style="font-family: 'Verdana', 'sans-serif'">GZIP</span><span style="font-family: 宋体">前后的通讯数据量。</span><span style="font-family: 'Verdana', 'sans-serif'">Fiddler</span><span style="font-family: 宋体">的下载地址是</span><span style="font-family: 'Verdana', 'sans-serif'">http://www.fiddlertool.com/fiddler/</span></p>
<p style="text-align: left; margin: 15.6pt 0cm" class="MsoNormal" align="left"><span style="font-family: 宋体">关于</span><span style="font-family: 'Verdana', 'sans-serif'">Web</span><span style="font-family: 宋体">应用的性能优化其实是一个非常大的话题。本文由于篇幅有限，只能涉及其中的几个细节，并且也无法将这些细节的优化方式全面的展现给大家。期望本文能够引起大家对</span><span style="font-family: 'Verdana', 'sans-serif'">Web</span><span style="font-family: 宋体">应用尤其是客户端性能优化的充分重视。毕竟服务端编程技巧已为大家熟知多年，在服务端挖掘性能的潜力已经不大了。而在客户端的方法改进往往能够得到令人惊奇的性能提升。</span></p>
 <img src ="http://www.blogjava.net/freeman1984/aggbug/344056.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-02-11 15:23 <a href="http://www.blogjava.net/freeman1984/archive/2011/02/11/344056.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>输入内容的百分比限制</title><link>http://www.blogjava.net/freeman1984/archive/2010/12/13/340503.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 13 Dec 2010 06:11:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/12/13/340503.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/340503.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/12/13/340503.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/340503.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/340503.html</trackback:ping><description><![CDATA[&lt;style type="text/css"&gt;<br />
.progress{<br />
&nbsp;width: 1px;<br />
&nbsp;height: 14px;<br />
&nbsp;color: white;<br />
&nbsp;font-size: 12px;<br />
&nbsp;&nbsp;&nbsp; overflow: hidden;<br />
&nbsp;background-color: navy;<br />
&nbsp;padding-left: 5px;<br />
}<br />
&lt;/style&gt;<br />
&lt;script type="text/JavaScript"&gt;<br />
function textCounter(field,counter,maxlimit,linecounter) {<br />
&nbsp;// text width//<br />
&nbsp;var fieldWidth =&nbsp; parseInt(field.offsetWidth);<br />
&nbsp;var charcnt = field.value.length;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;// trim the extra text<br />
&nbsp;if (charcnt &gt; maxlimit) { <br />
&nbsp; field.value = field.value.substring(0, maxlimit);<br />
&nbsp;}<br />
&nbsp;else { <br />
&nbsp;// progress bar percentage<br />
&nbsp;var percentage = parseInt(100 - (( maxlimit - charcnt) * 100)/maxlimit) ;<br />
&nbsp;document.getElementById(counter).style.width =&nbsp; parseInt((fieldWidth*percentage)/100)+"px";<br />
&nbsp;document.getElementById(counter).innerHTML="已输: "+percentage+"%"<br />
&nbsp;// color correction on style from CCFFF -&gt; CC0000<br />
&nbsp;setcolor(document.getElementById(counter),percentage,"background-color");<br />
&nbsp;}<br />
}<br />
function setcolor(obj,percentage,prop){<br />
&nbsp;obj.style[prop] = "rgb(80%,"+(100-percentage)+"%,"+(100-percentage)+"%)";<br />
}<br />
&lt;/script&gt;<br />
&lt;p&gt;限制：120字节&lt;/P&gt;<br />
&lt;form&gt;<br />
&lt;textarea rows="5" cols="40" name="maxcharfield" id="maxcharfield" <br />
onKeyDown="textCounter(this,'progressbar1',120)" <br />
onKeyUp="textCounter(this,'progressbar1',120)"<br />
onPaste="textCounter(this,'progressbar1',120)" <br />
onFocus="textCounter(this,'progressbar1',120)" &gt;&lt;/textarea&gt;&lt;br /&gt;<br />
&lt;div id="progressbar1" class="progress"&gt;&lt;/div&gt;<br />
&lt;script&gt;textCounter(document.getElementById("maxcharfield"),"progressbar1",120)&lt;/script&gt;<br />
&lt;/form&gt;<br />
<img src ="http://www.blogjava.net/freeman1984/aggbug/340503.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-12-13 14:11 <a href="http://www.blogjava.net/freeman1984/archive/2010/12/13/340503.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jquery 相关操作记录 随时更新</title><link>http://www.blogjava.net/freeman1984/archive/2010/11/25/339000.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 25 Nov 2010 02:51:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/11/25/339000.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/339000.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/11/25/339000.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/339000.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/339000.html</trackback:ping><description><![CDATA[&nbsp; 获取父窗口里面某个id：<br />
$("#pausebutton",parent.document).find
<img src ="http://www.blogjava.net/freeman1984/aggbug/339000.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-11-25 10:51 <a href="http://www.blogjava.net/freeman1984/archive/2010/11/25/339000.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>html标题滚动例子</title><link>http://www.blogjava.net/freeman1984/archive/2010/11/22/338659.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 22 Nov 2010 01:37:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/11/22/338659.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/338659.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/11/22/338659.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/338659.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/338659.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: html标题滚动例子及代码&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2010/11/22/338659.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/338659.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-11-22 09:37 <a href="http://www.blogjava.net/freeman1984/archive/2010/11/22/338659.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FreeMarker教程</title><link>http://www.blogjava.net/freeman1984/archive/2010/11/04/337239.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 04 Nov 2010 07:35:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/11/04/337239.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/337239.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/11/04/337239.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/337239.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/337239.html</trackback:ping><description><![CDATA[<font size="3">FreeMarker是一个模板引擎，一个基于模板生成文本输出的通用工具，使用纯Java编写 <br />
<br />
FreeMarker被设计用来生成HTML Web页面，特别是基于MVC模式的应用程序 <br />
<br />
虽然FreeMarker具有一些编程的能力，但通常由Java程序准备要显示的数据，由FreeMarker生成页面，通过模板显示准备的数据（如下图）<br />
&nbsp;<br />
<br />
FreeMarker不是一个Web应用框架，而适合作为Web应用框架一个组件 <br />
<br />
FreeMarker与容器无关，因为它并不知道HTTP或Servlet；FreeMarker同样可以应用于非Web应用程序环境 <br />
<br />
FreeMarker更适合作为Model2框架（如Struts）的视图组件，你也可以在模板中使用JSP标记库 <br />
<br />
FreeMarker是免费的 <br />
<br />
&nbsp; <br />
<br />
&nbsp; <br />
<br />
1、通用目标 <br />
<br />
能够生成各种文本：HTML、XML、RTF、Java源代码等等 <br />
<br />
易于嵌入到你的产品中：轻量级；不需要Servlet环境 <br />
<br />
插件式模板载入器：可以从任何源载入模板，如本地文件、数据库等等 <br />
<br />
你可以按你所需生成文本：保存到本地文件；作为Email发送；从Web应用程序发送它返回给Web浏览器 <br />
<br />
&nbsp; <br />
<br />
2、强大的模板语言 <br />
<br />
所有常用的指令：include、if/elseif/else、循环结构 <br />
<br />
在模板中创建和改变变量 <br />
<br />
几乎在任何地方都可以使用复杂表达式来指定值 <br />
<br />
命名的宏，可以具有位置参数和嵌套内容 <br />
<br />
名字空间有助于建立和维护可重用的宏库，或者将一个大工程分成模块，而不必担心名字冲突 <br />
<br />
输出转换块：在嵌套模板片段生成输出时，转换HTML转义、压缩、语法高亮等等；你可以定义自己的转换 <br />
<br />
&nbsp; <br />
<br />
3、通用数据模型 <br />
<br />
freeMarker不是直接反射到Java对象，Java对象通过插件式对象封装，以变量方式在模板中显示 <br />
<br />
你可以使用抽象（接口）方式表示对象（JavaBean、XML文档、SQL查询结果集等等），告诉模板开发者使用方法，使其不受技术细节的打扰 <br />
<br />
&nbsp; <br />
<br />
4、为Web准备 <br />
<br />
在模板语言中内建处理典型Web相关任务（如HTML转义）的结构 <br />
<br />
能够集成到Model2 Web应用框架中作为JSP的替代 <br />
<br />
支持JSP标记库 <br />
<br />
为MVC模式设计：分离可视化设计和应用程序逻辑；分离页面设计员和程序员 <br />
<br />
&nbsp; <br />
<br />
5、智能的国际化和本地化 <br />
<br />
字符集智能化（内部使用UNICODE） <br />
<br />
数字格式本地化敏感 <br />
<br />
日期和时间格式本地化敏感 <br />
非US字符集可以用作标识（如变量名） <br />
多种不同语言的相同模板 <br />
<br />
&nbsp; <br />
<br />
6、强大的XML处理能力 <br />
<br />
&lt;#recurse&gt; 和&lt;#visit&gt;指令（2.3版本）用于递归遍历XML树 <br />
<br />
在模板中清楚和直觉的访问XML对象模型 <br />
<br />
&nbsp; <br />
&nbsp;<br />
FreeMarker设计指南(1) <br />
<br />
--------------------------------------------------------------------------------<br />
<br />
&nbsp;<br />
&nbsp;<br />
&nbsp; <br />
&nbsp;<br />
<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
1、快速入门<br />
<br />
（1）模板 + 数据模型 = 输出<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FreeMarker基于设计者和程序员是具有不同专业技能的不同个体的观念<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 他们是分工劳动的：设计者专注于表示——创建HTML文件、图片、Web页面的其它可视化方面；程序员创建系统，生成设计页面要显示的数据<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 经常会遇到的问题是：在Web页面（或其它类型的文档）中显示的信息在设计页面时是无效的，是基于动态数据的<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这里，你可以在HTML（或其它要输出的文本）中加入一些特定指令，FreeMarker会在输出页面给最终用户时，用适当的数据替代这些代码<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面是一个例子：<br />
<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&nbsp; &lt;title&gt;Welcome!&lt;/title&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&nbsp; &lt;h1&gt;Welcome ${user}!&lt;/h1&gt;<br />
&nbsp; &lt;p&gt;Our latest product:<br />
&nbsp; &lt;a href="${latestProduct.url}"&gt;${latestProduct.name}&lt;/a&gt;!<br />
&lt;/body&gt;<br />
&lt;/html&gt;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个例子是在简单的HTML中加入了一些由${&#8230;}包围的特定代码，这些特定代码是FreeMarker的指令，而包含FreeMarker的指令的文件就称为模板（Template）<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 至于user、latestProduct.url和latestProduct.name来自于数据模型（data model）<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数据模型由程序员编程来创建，向模板提供变化的信息，这些信息来自于数据库、文件，甚至于在程序中直接生成<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 模板设计者不关心数据从那儿来，只知道使用已经建立的数据模型<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面是一个可能的数据模型：<br />
<br />
(root)<br />
&nbsp; |<br />
&nbsp; +- user = "Big Joe"<br />
&nbsp; |<br />
&nbsp; +- latestProduct<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- url = "products/greenmouse.html"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- name = "green mouse"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数据模型类似于计算机的文件系统，latestProduct可以看作是目录，而user、url和name看作是文件，url和name文件位于latestProduct目录中（这只是一个比喻，实际并不存在）<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当FreeMarker将上面的数据模型合并到模板中，就创建了下面的输出：<br />
<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&nbsp; &lt;title&gt;Welcome!&lt;/title&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&nbsp; &lt;h1&gt;Welcome Big Joe!&lt;/h1&gt;<br />
&nbsp; &lt;p&gt;Our latest product:<br />
&nbsp; &lt;a href="products/greenmouse.html"&gt;green mouse&lt;/a&gt;!<br />
&lt;/body&gt;<br />
&lt;/html&gt;&nbsp; <br />
（2）数据模型<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 典型的数据模型是树型结构，可以任意复杂和深层次，如下面的例子：<br />
<br />
(root)<br />
&nbsp; |<br />
&nbsp; +- animals<br />
&nbsp; |&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp; +- mouse<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; <br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; +- size = "small"<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; <br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; +- price = 50<br />
&nbsp; |&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp; +- elephant<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; <br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; +- size = "large"<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; <br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; +- price = 5000<br />
&nbsp; |&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp; +- python<br />
&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; <br />
&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- size = "medium"<br />
&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; <br />
&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- price = 4999<br />
&nbsp; |<br />
&nbsp; +- test = "It is a test"<br />
&nbsp; |<br />
&nbsp; +- whatnot<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- because = "don't know"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类似于目录的变量称为hashes，包含保存下级变量的唯一的查询名字<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类似于文件的变量称为scalars，保存单值<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; scalars保存的值有两种类型：字符串（用引号括起，可以是单引号或双引号）和数字（不要用引号将数字括起，这会作为字符串处理）<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对scalars的访问从root开始，各部分用&#8220;.&#8221;分隔，如animals.mouse.price<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另外一种变量是sequences，和hashes类似，只是不使用变量名字，而使用数字索引，如下面的例子：<br />
<br />
（root)<br />
&nbsp; |<br />
&nbsp; +- animals<br />
&nbsp; |&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp; +- (1st)<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; +- name = "mouse"<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; +- size = "small"<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; +- price = 50<br />
&nbsp; |&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp; +- (2nd)<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; +- name = "elephant"<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; +- size = "large"<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp; |&nbsp;&nbsp; +- price = 5000<br />
&nbsp; |&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp; +- (3rd)<br />
&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- name = "python"<br />
&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- size = "medium"<br />
&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- price = 4999<br />
&nbsp; |<br />
&nbsp; +- whatnot<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- fruits<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- (1st) = "orange"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- (2nd) = "banana"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这种对scalars的访问使用索引，如animals[0].name<br />
<br />
（3）模板<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在FreeMarker模板中可以包括下面三种特定部分：<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${&#8230;}：称为interpolations，FreeMarker会在输出时用实际值进行替代<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTL标记（FreeMarker模板语言标记）：类似于HTML标记，为了与HTML标记区分，用#开始（有些以@开始，在后面叙述）<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注释：包含在&lt;#--和--&gt;（而不是&lt;!--和--&gt;）之间<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面是一些使用指令的例子：<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if指令<br />
<br />
&lt;#if animals.python.price &lt; animals.elephant.price&gt;<br />
&nbsp; Pythons are cheaper than elephants today.<br />
&lt;#else&gt;<br />
&nbsp; Pythons are not cheaper than elephants today.<br />
&lt;/#if&gt;&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list指令<br />
<br />
&lt;p&gt;We have these animals:<br />
&lt;table border=1&gt;<br />
&nbsp; &lt;tr&gt;&lt;th&gt;Name&lt;th&gt;Price<br />
&nbsp; &lt;#list animals as being&gt;<br />
&nbsp; &lt;tr&gt;&lt;td&gt;${being.name}&lt;td&gt;${being.price} Euros<br />
&nbsp; &lt;/#list&gt;<br />
&lt;/table&gt;&nbsp; <br />
输出为：<br />
<br />
&lt;p&gt;We have these animals:<br />
&lt;table border=1&gt;<br />
&nbsp; &lt;tr&gt;&lt;th&gt;Name&lt;th&gt;Price<br />
&nbsp; &lt;tr&gt;&lt;td&gt;mouse&lt;td&gt;50 Euros<br />
&nbsp; &lt;tr&gt;&lt;td&gt;elephant&lt;td&gt;5000 Euros<br />
&nbsp; &lt;tr&gt;&lt;td&gt;python&lt;td&gt;4999 Euros<br />
&lt;/table&gt;&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; include指令<br />
<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&nbsp; &lt;title&gt;Test page&lt;/title&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&nbsp; &lt;h1&gt;Test page&lt;/h1&gt;<br />
&nbsp; &lt;p&gt;Blah blah...<br />
&lt;#include "/copyright_footer.html"&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一起使用指令<br />
<br />
&lt;p&gt;We have these animals:<br />
&lt;table border=1&gt;<br />
&nbsp; &lt;tr&gt;&lt;th&gt;Name&lt;th&gt;Price<br />
&nbsp; &lt;#list animals as being&gt;<br />
&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;#if being.size = "large"&gt;&lt;b&gt;&lt;/#if&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${being.name}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;#if being.size = "large"&gt;&lt;/b&gt;&lt;/#if&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;td&gt;${being.price} Euros<br />
&nbsp; &lt;/#list&gt;<br />
&lt;/table&gt;&nbsp; <br />
&nbsp;<br />
<br />
&nbsp;<br />
FreeMarker设计指南(3) <br />
<br />
--------------------------------------------------------------------------------<br />
<br />
&nbsp;<br />
&nbsp;<br />
&nbsp; <br />
&nbsp;<br />
<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
3、模板<br />
<br />
（1）整体结构<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 模板使用FTL（FreeMarker模板语言）编写，是下面各部分的一个组合：<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 文本：直接输出<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Interpolation：由${和}，或#{和}来限定，计算值替代输出<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTL标记：FreeMarker指令，和HTML标记类似，名字前加#予以区分，不会输出<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注释：由&lt;#--和--&gt;限定，不会输出<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面是以一个具体模板例子：<br />
<br />
&lt;html&gt;[BR]<br />
&lt;head&gt;[BR]<br />
&nbsp; &lt;title&gt;Welcome!&lt;/title&gt;[BR]<br />
&lt;/head&gt;[BR]<br />
&lt;body&gt;[BR]<br />
&nbsp; &lt;#-- Greet the user with his/her name --&gt;[BR]<br />
&nbsp; &lt;h1&gt;Welcome ${user}!&lt;/h1&gt;[BR]<br />
&nbsp; &lt;p&gt;We have these animals:[BR]<br />
&nbsp; &lt;ul&gt;[BR]<br />
&nbsp; &lt;#list animals as being&gt;[BR]<br />
&nbsp;&nbsp;&nbsp; &lt;li&gt;${being.name} for ${being.price} Euros[BR]<br />
&nbsp; &lt;/#list&gt;[BR]<br />
&nbsp; &lt;/ul&gt;[BR]<br />
&lt;/body&gt;[BR]<br />
&lt;/html&gt;&nbsp; <br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [BR]是用于换行的特殊字符序列<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意事项：<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTL区分大小写，所以list是正确的FTL指令，而List不是；${name}和${NAME}是不同的<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Interpolation只能在文本中使用<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTL标记不能位于另一个FTL标记内部，例如：<br />
<br />
&lt;#if &lt;#include 'foo'&gt;='bar'&gt;...&lt;/if&gt;<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注释可以位于FTL标记和Interpolation内部，如下面的例子：<br />
<br />
&lt;h1&gt;Welcome ${user &lt;#-- The name of user --&gt;}!&lt;/h1&gt;[BR]<br />
&lt;p&gt;We have these animals:[BR]<br />
&lt;ul&gt;[BR]<br />
&lt;#list &lt;#-- some comment... --&gt; animals as &lt;#-- again... --&gt; being&gt;[BR]<br />
...&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 多余的空白字符会在模板输出时移除<br />
<br />
（2）指令<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在FreeMarker中，使用FTL标记引用指令<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有三种FTL标记，这和HTML标记是类似的：<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 开始标记：&lt;#directivename parameters&gt;<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 结束标记：&lt;/#directivename&gt;<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 空内容指令标记：&lt;#directivename parameters/&gt;<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有两种类型的指令：预定义指令和用户定义指令<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户定义指令要使用@替换#，如&lt;@mydirective&gt;...&lt;/@mydirective&gt;（会在后面讲述）<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FTL标记不能够交叉，而应该正确的嵌套，如下面的代码是错误的：<br />
<br />
&lt;ul&gt;<br />
&lt;#list animals as being&gt;<br />
&nbsp; &lt;li&gt;${being.name} for ${being.price} Euros<br />
&nbsp; &lt;#if use = "Big Joe"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; (except for you)<br />
&lt;/#list&gt;<br />
&lt;/#if&gt; &lt;#-- WRONG! --&gt;<br />
&lt;/ul&gt;&nbsp; <br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果使用不存在的指令，FreeMarker不会使用模板输出，而是产生一个错误消息<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FreeMarker会忽略FTL标记中的空白字符，如下面的例子：<br />
<br />
&lt;#list[BR]<br />
&nbsp; animals&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; as[BR]<br />
&nbsp;&nbsp;&nbsp;&nbsp; being[BR]<br />
&gt;[BR]<br />
${being.name} for ${being.price} Euros[BR]<br />
&lt;/#list&nbsp;&nbsp;&nbsp; &gt;&nbsp; <br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 但是，&lt;、&lt;/和指令之间不允许有空白字符<br />
<br />
（3）表达式<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 直接指定值<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 字符串<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用单引号或双引号限定<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果包含特殊字符需要转义，如下面的例子：<br />
<br />
${"It's \"quoted\" and<br />
this is a backslash: \\"}<br />
&nbsp;<br />
${'It\'s "quoted" and<br />
this is a backslash: \\'} <br />
输出结果是：<br />
<br />
It's "quoted" and<br />
this is a backslash: \<br />
&nbsp;<br />
It's "quoted" and<br />
this is a backslash: \ <br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面是支持的转义序列：<br />
<br />
转义序列<br />
&nbsp;含义<br />
&nbsp;<br />
\"<br />
&nbsp;双引号(u0022)<br />
&nbsp;<br />
\'<br />
&nbsp;单引号(u0027)<br />
&nbsp;<br />
\\<br />
&nbsp;反斜杠(u005C)<br />
&nbsp;<br />
\n<br />
&nbsp;换行(u000A)<br />
&nbsp;<br />
\r<br />
&nbsp;Return (u000D)<br />
&nbsp;<br />
\t<br />
&nbsp;Tab (u0009)<br />
&nbsp;<br />
\b<br />
&nbsp;Backspace (u0008)<br />
&nbsp;<br />
\f<br />
&nbsp;Form feed (u000C)<br />
&nbsp;<br />
\l<br />
&nbsp;&lt;<br />
&nbsp;<br />
\g<br />
&nbsp;&gt;<br />
&nbsp;<br />
\a<br />
&nbsp;&amp;<br />
&nbsp;<br />
\{<br />
&nbsp;{<br />
&nbsp;<br />
\xCode<br />
&nbsp;4位16进制Unicode代码<br />
&nbsp;<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有一类特殊的字符串称为raw字符串，被认为是纯文本，其中的\和{等不具有特殊含义，该类字符串在引号前面加r，下面是一个例子：<br />
<br />
${r"${foo}"}<br />
${r"C:\foo\bar"}&nbsp; <br />
输出的结果是：<br />
<br />
${foo}<br />
C:\foo\bar&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数字<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 直接输入，不需要引号<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 精度数字使用&#8220;.&#8221;分隔，不能使用分组符号<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 目前版本不支持科学计数法，所以&#8220;1E3&#8221;是错误的<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不能省略小数点前面的0，所以&#8220;.5&#8221;是错误的<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数字8、+8、08和8.00都是相同的<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 布尔值<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true和false，不使用引号<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 序列<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由逗号分隔的子变量列表，由方括号限定，下面是一个例子：<br />
<br />
&lt;#list ["winter", "spring", "summer", "autumn"] as x&gt;<br />
${x}<br />
&lt;/#list&gt; <br />
输出的结果是：<br />
<br />
winter<br />
spring<br />
summer<br />
autumn<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 列表的项目是表达式，所以可以有下面的例子：<br />
<br />
[2 + 2, [1, 2, 3, 4], "whatnot"]<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以使用数字范围定义数字序列，例如2..5等同于[2, 3, 4, 5]，但是更有效率，注意数字范围没有方括号<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以定义反递增的数字范围，如5..2<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 散列（hash）<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由逗号分隔的键/值列表，由大括号限定，键和值之间用冒号分隔，下面是一个例子：<br />
<br />
{"name":"green mouse", "price":150}<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 键和值都是表达式，但是键必须是字符串<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 获取变量<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 顶层变量： ${variable}，变量名只能是字母、数字、下划线、$、@和#的组合，且不能以数字开头<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从散列中获取数据<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以使用点语法或方括号语法，假设有下面的数据模型：<br />
<br />
(root)<br />
&nbsp;|<br />
&nbsp;+- book<br />
&nbsp;|&nbsp;&nbsp; |<br />
&nbsp;|&nbsp;&nbsp; +- title = "Breeding green mouses"<br />
&nbsp;|&nbsp;&nbsp; |<br />
&nbsp;|&nbsp;&nbsp; +- author<br />
&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- name = "Julia Smith"<br />
&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |<br />
&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +- info = "Biologist, 1923-1985, Canada"<br />
&nbsp;|<br />
&nbsp;+- test = "title" <br />
下面都是等价的：<br />
<br />
book.author.name<br />
book["author"].name<br />
book.author.["name"]<br />
book["author"]["name"]<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用点语法，变量名字有顶层变量一样的限制，但方括号语法没有该限制，因为名字是任意表达式的结果<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从序列获得数据：和散列的方括号语法语法一样，只是方括号中的表达式值必须是数字；注意：第一个项目的索引是0<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 序列片断：使用[startIndex..endIndex]语法，从序列中获得序列片断（也是序列）；startIndex和endIndex是结果为数字的表达式<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 特殊变量：FreeMarker内定义变量，使用.variablename语法访问<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 字符串操作<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Interpolation（或连接操作）<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以使用${..}（或#{..}）在文本部分插入表达式的值，例如：<br />
<br />
${"Hello ${user}!"}<br />
${"${user}${user}${user}${user}"}&nbsp; <br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以使用+操作符获得同样的结果<br />
<br />
${"Hello " + user + "!"}<br />
${user + user + user + user}<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${..}只能用于文本部分，下面的代码是错误的：<br />
<br />
&lt;#if ${isBig}&gt;Wow!&lt;/#if&gt;<br />
&lt;#if "${isBig}"&gt;Wow!&lt;/#if&gt;<br />
应该写成：<br />
<br />
&lt;#if isBig&gt;Wow!&lt;/#if&gt;<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 子串<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例子（假设user的值为&#8220;Big Joe&#8221;）：<br />
<br />
${user[0]}${user[4]}<br />
${user[1..4]}<br />
结果是（注意第一个字符的索引是0）：<br />
<br />
BJ<br />
ig J <br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 序列操作<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 连接操作：和字符串一样，使用+，下面是一个例子：<br />
<br />
&lt;#list ["Joe", "Fred"] + ["Julia", "Kate"] as user&gt;<br />
- ${user}<br />
&lt;/#list&gt;<br />
输出结果是：<br />
<br />
- Joe<br />
- Fred<br />
- Julia<br />
- Kate<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 散列操作<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 连接操作：和字符串一样，使用+，如果具有相同的key，右边的值替代左边的值，例如：<br />
<br />
&lt;#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}&gt;<br />
- Joe is ${ages.Joe}<br />
- Fred is ${ages.Fred}<br />
- Julia is ${ages.Julia}&nbsp; <br />
输出结果是：<br />
<br />
- Joe is 30<br />
- Fred is 25<br />
- Julia is 18&nbsp; <br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 算术运算<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ＋、－、&#215;、／、％，下面是一个例子：<br />
<br />
${x * x - 100}<br />
${x / 2}<br />
${12 % 10}<br />
输出结果是（假设x为5）：<br />
<br />
-75<br />
2.5<br />
2&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 操作符两边必须是数字，因此下面的代码是错误的：<br />
<br />
${3 * "5"} &lt;#-- WRONG! --&gt;&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用+操作符时，如果一边是数字，一边是字符串，就会自动将数字转换为字符串，例如：<br />
<br />
${3 + "5"}&nbsp; <br />
输出结果是：<br />
<br />
35<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用内建的int（后面讲述）获得整数部分，例如：<br />
<br />
${(x/2)?int}<br />
${1.1?int}<br />
${1.999?int}<br />
${-1.1?int}<br />
${-1.999?int}<br />
输出结果是（假设x为5）：<br />
<br />
2<br />
1<br />
1<br />
-1<br />
-1<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 比较操作符<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用=（或==，完全相等）测试两个值是否相等，使用!= 测试两个值是否不相等<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =和!=两边必须是相同类型的值，否则会产生错误，例如&lt;#if 1 = "1"&gt;会引起错误<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Freemarker是精确比较，所以对"x"、"x&nbsp; "和"X"是不相等的<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对数字和日期可以使用&lt;、&lt;=、&gt;和&gt;=，但不能用于字符串<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于Freemarker会将&gt;解释成FTL标记的结束字符，所以对于&gt;和&gt;=可以使用括号来避免这种情况，例如&lt;#if (x &gt; y)&gt;<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另一种替代的方法是，使用lt、lte、gt和gte来替代&lt;、&lt;=、&gt;和&gt;=<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 逻辑操作符<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp;（and）、||（or）、!（not），只能用于布尔值，否则会产生错误<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例子：<br />
<br />
&lt;#if x &lt; 12 &amp;&amp; color = "green"&gt;<br />
&nbsp; We have less than 12 things, and they are green.<br />
&lt;/#if&gt;<br />
&lt;#if !hot&gt; &lt;#-- here hot must be a boolean --&gt;<br />
&nbsp; It's not hot.<br />
&lt;/#if&gt;&nbsp; <br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内建函数<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内建函数的用法类似访问散列的子变量，只是使用&#8220;?&#8221;替代&#8220;.&#8221;，下面列出常用的一些函数<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 字符串使用的：<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; html：对字符串进行HTML编码<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cap_first：使字符串第一个字母大写<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lower_case：将字符串转换成小写<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; upper_case：将字符串转换成大写<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; trim：去掉字符串前后的空白字符<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 序列使用的：<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; size：获得序列中元素的数目<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数字使用的：<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int：取得数字的整数部分（如-1.9?int的结果是-1）<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例子（假设test保存字符串"Tom &amp; Jerry"）：<br />
<br />
${test?html}<br />
${test?upper_case?html}<br />
输出结果是：<br />
<br />
Tom &amp;amp; Jerry<br />
TOM &amp;amp; JERRY&nbsp; <br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 操作符优先顺序<br />
<br />
操作符组<br />
&nbsp;操作符<br />
&nbsp;<br />
后缀<br />
&nbsp;[subvarName] [subStringRange] . (methodParams)<br />
&nbsp;<br />
一元<br />
&nbsp;+expr、-expr、!<br />
&nbsp;<br />
内建<br />
&nbsp;?<br />
&nbsp;<br />
乘法<br />
&nbsp;*、 / 、%<br />
&nbsp;<br />
加法<br />
&nbsp;+、-<br />
&nbsp;<br />
关系<br />
&nbsp;&lt;、&gt;、&lt;=、&gt;=（lt、lte、gt、gte）<br />
&nbsp;<br />
相等<br />
&nbsp;==（=）、!=<br />
&nbsp;<br />
逻辑and<br />
&nbsp;&amp;&amp;<br />
&nbsp;<br />
逻辑or<br />
&nbsp;||<br />
&nbsp;<br />
数字范围<br />
&nbsp;..<br />
&nbsp;<br />
<br />
（4）Interpolation<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Interpolation有两种类型：<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通用Interpolation：${expr}<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数字Interpolation：#{expr}或#{expr; format}<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意：Interpolation只能用于文本部分<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通用Interpolation<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 插入字符串值：直接输出表达式结果<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 插入数字值：根据缺省格式（由#setting指令设置）将表达式结果转换成文本输出；可以使用内建函数string格式化单个Interpolation，下面是一个例子：<br />
<br />
&lt;#setting number_format="currency"/&gt;<br />
&lt;#assign answer=42/&gt;<br />
${answer}<br />
${answer?string}&nbsp; &lt;#-- the same as ${answer} --&gt;<br />
${answer?string.number}<br />
${answer?string.currency}<br />
${answer?string.percent} <br />
输出结果是：<br />
<br />
$42.00<br />
$42.00<br />
42<br />
$42.00<br />
4,200%<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 插入日期值：根据缺省格式（由#setting指令设置）将表达式结果转换成文本输出；可以使用内建函数string格式化单个Interpolation，下面是一个使用格式模式的例子：<br />
<br />
${lastUpdated?string("yyyy-MM-dd HH:mm:ss zzzz")}<br />
${lastUpdated?string("EEE, MMM d, ''yy")}<br />
${lastUpdated?string("EEEE, MMMM dd, yyyy, hh:mm:ss a '('zzz')'")}&nbsp; <br />
输出的结果类似下面的格式：<br />
<br />
2003-04-08 21:24:44 Pacific Daylight Time<br />
Tue, Apr 8, '03<br />
Tuesday, April 08, 2003, 09:24:44 PM (PDT)<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 插入布尔值：根据缺省格式（由#setting指令设置）将表达式结果转换成文本输出；可以使用内建函数string格式化单个Interpolation，下面是一个例子：<br />
<br />
&lt;#assign foo=true/&gt;<br />
${foo?string("yes", "no")}<br />
输出结果是：<br />
<br />
yes<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数字Interpolation的#{expr; format}形式可以用来格式化数字，format可以是：<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mX：小数部分最小X位<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MX：小数部分最大X位<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例子：<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;#-- If the language is US English the output is: --&gt;<br />
&lt;#assign x=2.582/&gt;<br />
&lt;#assign y=4/&gt;<br />
#{x; M2}&nbsp;&nbsp; &lt;#-- 2.58 --&gt;<br />
#{y; M2}&nbsp;&nbsp; &lt;#-- 4&nbsp;&nbsp;&nbsp; --&gt;<br />
#{x; m1}&nbsp;&nbsp; &lt;#-- 2.6 --&gt;<br />
#{y; m1}&nbsp;&nbsp; &lt;#-- 4.0 --&gt;<br />
#{x; m1M2} &lt;#-- 2.58 --&gt;<br />
#{y; m1M2} &lt;#-- 4.0&nbsp; --&gt; <br />
&nbsp;<br />
<br />
&nbsp;<br />
FreeMarker设计指南(4) <br />
<br />
--------------------------------------------------------------------------------<br />
<br />
&nbsp;<br />
&nbsp;<br />
&nbsp; <br />
&nbsp;<br />
<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
4、杂项<br />
<br />
（1）用户定义指令<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 宏和变换器变量是两种不同类型的用户定义指令，它们之间的区别是宏是在模板中使用macro指令定义，而变换器是在模板外由程序定义，这里只介绍宏<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基本用法<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 宏是和某个变量关联的模板片断，以便在模板中通过用户定义指令使用该变量，下面是一个例子：<br />
<br />
&lt;#macro greet&gt;<br />
&nbsp; &lt;font size="+2"&gt;Hello Joe!&lt;/font&gt;<br />
&lt;/#macro&gt;&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作为用户定义指令使用宏变量时，使用@替代FTL标记中的#<br />
<br />
&lt;@greet&gt;&lt;/@greet&gt;<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果没有体内容，也可以使用：<br />
<br />
&lt;@greet/&gt;<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 参数<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在macro指令中可以在宏变量之后定义参数，如：<br />
<br />
&lt;#macro greet person&gt;<br />
&nbsp; &lt;font size="+2"&gt;Hello ${person}!&lt;/font&gt;<br />
&lt;/#macro&gt; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以这样使用这个宏变量：<br />
<br />
&lt;@greet person="Fred"/&gt; and &lt;@greet person="Batman"/&gt; <br />
输出结果是：<br />
<br />
&nbsp; &lt;font size="+2"&gt;Hello Fred!&lt;/font&gt;<br />
&nbsp;and&nbsp;&nbsp; &lt;font size="+2"&gt;Hello Batman!&lt;/font&gt;<br />
&nbsp;&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 宏的参数是FTL表达式，所以下面的代码具有不同的意思：<br />
<br />
&lt;@greet person=Fred/&gt;<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这意味着将Fred变量的值传给person参数，该值不仅是字符串，还可以是其它类型，甚至是复杂的表达式<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 宏可以有多参数，下面是一个例子：<br />
<br />
&lt;#macro greet person color&gt;<br />
&nbsp; &lt;font size="+2" color="${color}"&gt;Hello ${person}!&lt;/font&gt;<br />
&lt;/#macro&gt; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以这样使用该宏变量：<br />
<br />
&lt;@greet person="Fred" color="black"/&gt; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中参数的次序是无关的，因此下面是等价的：<br />
<br />
&lt;@greet color="black" person="Fred"/&gt;<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 只能使用在macro指令中定义的参数，并且对所有参数赋值，所以下面的代码是错误的：<br />
<br />
&lt;@greet person="Fred" color="black" background="green"/&gt;<br />
&lt;@greet person="Fred"/&gt;<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以在定义参数时指定缺省值，如：<br />
<br />
&lt;#macro greet person color="black"&gt;<br />
&nbsp; &lt;font size="+2" color="${color}"&gt;Hello ${person}!&lt;/font&gt;<br />
&lt;/#macro&gt;&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这样&lt;@greet person="Fred"/&gt;就正确了<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 宏的参数是局部变量，只能在宏定义中有效<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 嵌套内容<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户定义指令可以有嵌套内容，使用&lt;#nested&gt;指令执行指令开始和结束标记之间的模板片断<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例子：<br />
<br />
&lt;#macro border&gt;<br />
&nbsp; &lt;table border=4 cellspacing=0 cellpadding=4&gt;&lt;tr&gt;&lt;td&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;#nested&gt;<br />
&nbsp; &lt;/tr&gt;&lt;/td&gt;&lt;/table&gt;<br />
&lt;/#macro&gt;&nbsp; <br />
这样使用该宏变量：<br />
<br />
&lt;@border&gt;The bordered text&lt;/@border&gt;<br />
输出结果：<br />
<br />
&nbsp; &lt;table border=4 cellspacing=0 cellpadding=4&gt;&lt;tr&gt;&lt;td&gt;<br />
&nbsp;&nbsp;&nbsp; The bordered text<br />
&nbsp; &lt;/tr&gt;&lt;/td&gt;&lt;/table&gt;<br />
&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;#nested&gt;指令可以被多次调用，例如：<br />
<br />
&lt;#macro do_thrice&gt;<br />
&nbsp; &lt;#nested&gt;<br />
&nbsp; &lt;#nested&gt;<br />
&nbsp; &lt;#nested&gt;<br />
&lt;/#macro&gt;<br />
&lt;@do_thrice&gt;<br />
&nbsp; Anything.<br />
&lt;/@do_thrice&gt;&nbsp; <br />
输出结果：<br />
<br />
&nbsp; Anything.<br />
&nbsp; Anything.<br />
&nbsp; Anything. <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 嵌套内容可以是有效的FTL，下面是一个有些复杂的例子：<br />
<br />
&lt;@border&gt;<br />
&nbsp; &lt;ul&gt;<br />
&nbsp; &lt;@do_thrice&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;li&gt;&lt;@greet person="Joe"/&gt;<br />
&nbsp; &lt;/@do_thrice&gt;<br />
&nbsp; &lt;/ul&gt;<br />
&lt;/@border&gt; <br />
输出结果：<br />
<br />
&nbsp; &lt;table border=4 cellspacing=0 cellpadding=4&gt;&lt;tr&gt;&lt;td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ul&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;li&gt;&lt;font size="+2"&gt;Hello Joe!&lt;/font&gt;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp; &lt;li&gt;&lt;font size="+2"&gt;Hello Joe!&lt;/font&gt;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp; &lt;li&gt;&lt;font size="+2"&gt;Hello Joe!&lt;/font&gt;<br />
&nbsp;<br />
&nbsp; &lt;/ul&gt;<br />
&nbsp;<br />
&nbsp; &lt;/tr&gt;&lt;/td&gt;&lt;/table&gt;&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 宏定义中的局部变量对嵌套内容是不可见的，例如：<br />
<br />
&lt;#macro repeat count&gt;<br />
&nbsp; &lt;#local y = "test"&gt;<br />
&nbsp; &lt;#list 1..count as x&gt;<br />
&nbsp;&nbsp;&nbsp; ${y} ${count}/${x}: &lt;#nested&gt;<br />
&nbsp; &lt;/#list&gt;<br />
&lt;/#macro&gt;<br />
&lt;@repeat count=3&gt;${y?default("?")} ${x?default("?")} ${count?default("?")}&lt;/@repeat&gt;<br />
输出结果：<br />
<br />
&nbsp;&nbsp;&nbsp; test 3/1: ? ? ?<br />
&nbsp;&nbsp;&nbsp; test 3/2: ? ? ?<br />
&nbsp;&nbsp;&nbsp; test 3/3: ? ? ?<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在宏定义中使用循环变量<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户定义指令可以有循环变量，通常用于重复嵌套内容，基本用法是：作为nested指令的参数传递循环变量的实际值，而在调用用户定义指令时，在&lt;@&#8230;&gt;开始标记的参数后面指定循环变量的名字<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 例子：<br />
<br />
&lt;#macro repeat count&gt;<br />
&nbsp; &lt;#list 1..count as x&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;#nested x, x/2, x==count&gt;<br />
&nbsp; &lt;/#list&gt;<br />
&lt;/#macro&gt;<br />
&lt;@repeat count=4 ; c, halfc, last&gt;<br />
&nbsp; ${c}. ${halfc}&lt;#if last&gt; Last!&lt;/#if&gt;<br />
&lt;/@repeat&gt;&nbsp; <br />
输出结果：<br />
<br />
&nbsp; 1. 0.5<br />
&nbsp; 2. 1<br />
&nbsp; 3. 1.5<br />
&nbsp; 4. 2 Last!<br />
&nbsp; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 指定的循环变量的数目和用户定义指令开始标记指定的不同不会有问题<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 调用时少指定循环变量，则多指定的值不可见<br />
<br />
n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 调用时多指定循环变量，多余的循环变量不会被创建<br />
<br />
（2）在模板中定义变量<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在模板中定义的变量有三种类型：<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; plain变量：可以在模板的任何地方访问，包括使用include指令插入的模板，使用assign指令创建和替换<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 局部变量：在宏定义体中有效，使用local指令创建和替换<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 循环变量：只能存在于指令的嵌套内容，由指令（如list）自动创建；宏的参数是局部变量，而不是循环变量<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 局部变量隐藏（而不是覆盖）同名的plain变量；循环变量隐藏同名的局部变量和plain变量，下面是一个例子：<br />
<br />
&lt;#assign x = "plain"&gt;<br />
1. ${x}&nbsp; &lt;#-- we see the plain var. here --&gt;<br />
&lt;@test/&gt;<br />
6. ${x}&nbsp; &lt;#-- the value of plain var. was not changed --&gt;<br />
&lt;#list ["loop"] as x&gt;<br />
&nbsp;&nbsp;&nbsp; 7. ${x}&nbsp; &lt;#-- now the loop var. hides the plain var. --&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;#assign x = "plain2"&gt; &lt;#-- replace the plain var, hiding does not mater here --&gt;<br />
&nbsp;&nbsp;&nbsp; 8. ${x}&nbsp; &lt;#-- it still hides the plain var. --&gt;<br />
&lt;/#list&gt;<br />
9. ${x}&nbsp; &lt;#-- the new value of plain var. --&gt;<br />
&nbsp;<br />
&lt;#macro test&gt;<br />
&nbsp; 2. ${x}&nbsp; &lt;#-- we still see the plain var. here --&gt;<br />
&nbsp; &lt;#local x = "local"&gt;<br />
&nbsp; 3. ${x}&nbsp; &lt;#-- now the local var. hides it --&gt;<br />
&nbsp; &lt;#list ["loop"] as x&gt;<br />
&nbsp;&nbsp;&nbsp; 4. ${x}&nbsp; &lt;#-- now the loop var. hides the local var. --&gt;<br />
&nbsp; &lt;/#list&gt;<br />
&nbsp; 5. ${x}&nbsp; &lt;#-- now we see the local var. again --&gt;<br />
&lt;/#macro&gt;&nbsp; <br />
输出结果：<br />
<br />
1. plain<br />
&nbsp; 2. plain<br />
&nbsp; 3. local<br />
&nbsp;&nbsp;&nbsp; 4. loop<br />
&nbsp; 5. local<br />
6. plain<br />
&nbsp;&nbsp;&nbsp; 7. loop<br />
&nbsp;&nbsp;&nbsp; 8. loop<br />
9. plain2<br />
&nbsp;<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内部循环变量隐藏同名的外部循环变量，如：<br />
<br />
&lt;#list ["loop 1"] as x&gt;<br />
&nbsp; ${x}<br />
&nbsp; &lt;#list ["loop 2"] as x&gt;<br />
&nbsp;&nbsp;&nbsp; ${x}<br />
&nbsp;&nbsp;&nbsp; &lt;#list ["loop 3"] as x&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ${x}<br />
&nbsp;&nbsp;&nbsp; &lt;/#list&gt;<br />
&nbsp;&nbsp;&nbsp; ${x}<br />
&nbsp; &lt;/#list&gt;<br />
&nbsp; ${x}<br />
&lt;/#list&gt;<br />
输出结果：<br />
<br />
&nbsp; loop 1<br />
&nbsp;&nbsp;&nbsp; loop 2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; loop 3<br />
&nbsp;&nbsp;&nbsp; loop 2<br />
&nbsp; loop 1 <br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 模板中的变量会隐藏（而不是覆盖）数据模型中同名变量，如果需要访问数据模型中的同名变量，使用特殊变量global，下面的例子假设数据模型中的user的值是Big Joe：<br />
<br />
&lt;#assign user = "Joe Hider"&gt;<br />
${user}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;#-- prints: Joe Hider --&gt;<br />
${.globals.user} &lt;#-- prints: Big Joe --&gt;&nbsp; <br />
（3）名字空间<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通常情况，只使用一个名字空间，称为主名字空间<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为了创建可重用的宏、变换器或其它变量的集合（通常称库），必须使用多名字空间，其目的是防止同名冲突<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 创建库<br />
<br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面是一个创建库的例子（假设保存在lib/my_test.ftl中）：<br />
<br />
&lt;#macro copyright date&gt;<br />
&nbsp; &lt;p&gt;Copyright (C) ${date} Julia Smith. All rights reserved.<br />
&nbsp; &lt;br&gt;Email: ${mail}&lt;/p&gt;<br />
&lt;/#macro&gt;&nbsp; <br />
&lt;#assign mail = "jsmith@acme.com"&gt; <br />
&#216;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用import指令导入库到模板中，Freemarker会为导入的库创建新的名字空间，并可以通过import指令中指定的散列变量访问库中的变量：<br />
<br />
&lt;#import "/lib/my_test.ftl" as my&gt;<br />
&lt;#assign mail="fred@acme.com"&gt;<br />
&lt;@my.copyright date="1999-2002"/&gt;<br />
${my.mail}<br />
${mail}&nbsp; <br />
输出结果：<br />
<br />
&nbsp; &lt;p&gt;Copyright (C) 1999-2002 Julia Smith. All rights reserved.<br />
&nbsp; &lt;br&gt;Email: jsmith@acme.com&lt;/p&gt;<br />
jsmith@acme.com<br />
fred@acme.com&nbsp; <br />
可以看到例子中使用的两个同名变量并没有冲突，因为它们位于不同的名字空间<br />
<br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以使用assign指令在导入的名字空间中创建或替代变量，下面是一个例子：<br />
<br />
&lt;#import "/lib/my_test.ftl" as my&gt;<br />
${my.mail}<br />
&lt;#assign mail="jsmith@other.com" in my&gt;<br />
${my.mail}&nbsp; <br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 输出结果：<br />
<br />
jsmith@acme.com<br />
jsmith@other.com&nbsp; <br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数据模型中的变量任何地方都可见，也包括不同的名字空间，下面是修改的库：<br />
<br />
&lt;#macro copyright date&gt;<br />
&nbsp; &lt;p&gt;Copyright (C) ${date} ${user}. All rights reserved.&lt;/p&gt;<br />
&lt;/#macro&gt;<br />
&lt;#assign mail = "${user}@acme.com"&gt;&nbsp;&nbsp; <br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 假设数据模型中的user变量的值是Fred，则下面的代码：<br />
<br />
&lt;#import "/lib/my_test.ftl" as my&gt;<br />
&lt;@my.copyright date="1999-2002"/&gt;<br />
${my.mail}&nbsp;&nbsp; <br />
l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 输出结果：<br />
<br />
&nbsp; &lt;p&gt;Copyright (C) 1999-2002 Fred. All rights reserved.&lt;/p&gt;<br />
Fred@acme.com&nbsp;&nbsp; <br />
&nbsp;<br />
<br />
&nbsp;<br />
<br />
&nbsp;<br />
Freemarker - 几个比较实用的例子 - -<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用Freemarker做模本语言有一段时间了，列出几个和JSP或者Velocity相比起来比较方便的用途，目的是引诱更多的人跳上Freemarker这个贼船， <br />
<br />
1. String内置的JavaScript转换： js_string <br />
用途：用于JavaScript转义，转换',",换行等特殊字符 <br />
模板: <br />
<br />
&lt;script&gt; <br />
alert("${errorMessage?js_string}"); <br />
&lt;/script&gt; <br />
<br />
<br />
输出: <br />
<br />
&lt;script&gt; <br />
alert("Readonly\'s pet name is \"Cross Bone\""); <br />
&lt;/script&gt; <br />
<br />
<br />
2.内置的默认值处理：default <br />
用途: 用于处理默认值 <br />
模本: <br />
<br />
User: ${userLogin.name?default("Anonymous")} <br />
<br />
&lt;td&gt;${(employee.department.manager.name)?default(" ")}&lt;/td&gt; <br />
<br />
<br />
输出: <br />
<br />
User: Anonymous <br />
&lt;td&gt; &lt;/td&gt; <br />
<br />
<br />
注，可以对整个对象树加上()，再用内置处理器这种方便的做法，偶也是最近刚学会的，以前一直用很傻的方法做..... <br />
<br />
3. Sequence内置的计数器: xxx_index <br />
用途：显示序号 <br />
模板: <br />
<br />
&lt;#list employees as e&gt; <br />
${e_index}. ${e.name} <br />
&lt;/#list&gt; <br />
<br />
<br />
输出: <br />
<br />
1. Readonly <br />
2. Robbin <br />
<br />
<br />
4. Sequence内置的分段器: chunk <br />
用途：某些比较BT的排版需求 <br />
模板: <br />
<br />
&lt;#assign seq = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']&gt; <br />
&lt;#list seq?chunk(4) as row&gt; <br />
&lt;ul&gt; <br />
&lt;li&gt;&lt;#list row as cell&gt;${cell} &lt;/#list&gt;&lt;/li&gt; <br />
&lt;/ul&gt; <br />
&lt;/#list&gt; <br />
<br />
&lt;#list seq?chunk(4, '-') as row&gt; <br />
&lt;tr&gt; <br />
&lt;td&gt;&lt;#list row as cell&gt;${cell} &lt;/#list&gt;&lt;/td&gt; <br />
&lt;/tr&gt; <br />
&lt;/#list&gt; <br />
<br />
<br />
输出: <br />
<br />
&lt;ul&gt; <br />
&lt;li&gt;a&lt;/li&gt; <br />
&lt;li&gt;b&lt;/li&gt; <br />
&lt;li&gt;c&lt;/li&gt; <br />
&lt;li&gt;d&lt;/li&gt; <br />
&lt;/ul&gt; <br />
&lt;ul&gt; <br />
&lt;li&gt;e&lt;/li&gt; <br />
&lt;li&gt;f&lt;/li&gt; <br />
&lt;li&gt;g&lt;/li&gt; <br />
&lt;li&gt;h&lt;/li&gt; <br />
&lt;/ul&gt; <br />
&lt;ul&gt; <br />
&lt;li&gt;i&lt;/li&gt; <br />
&lt;li&gt;j&lt;/li&gt; <br />
&lt;/ul&gt; <br />
<br />
&lt;tr&gt; <br />
&lt;td&gt;a&lt;/td&gt; <br />
&lt;td&gt;b&lt;/td&gt; <br />
&lt;td&gt;c&lt;/td&gt; <br />
&lt;td&gt;d&lt;/td&gt; <br />
&lt;/tr&gt; <br />
&lt;tr&gt; <br />
&lt;td&gt;e&lt;/td&gt; <br />
&lt;td&gt;f&lt;/td&gt; <br />
&lt;td&gt;g&lt;/td&gt; <br />
&lt;td&gt;h&lt;/td&gt; <br />
&lt;/tr&gt; <br />
&lt;tr&gt; <br />
&lt;td&gt;i&lt;/td&gt; <br />
&lt;td&gt;j&lt;/td&gt; <br />
&lt;td&gt;-&lt;/td&gt; <br />
&lt;td&gt;-&lt;/td&gt; <br />
&lt;/tr&gt;&nbsp;</font><br />
转载自：http://student.csdn.net/space.php?uid=40568&amp;do=blog&amp;id=19054
<img src ="http://www.blogjava.net/freeman1984/aggbug/337239.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-11-04 15:35 <a href="http://www.blogjava.net/freeman1984/archive/2010/11/04/337239.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>加速Javascript：DOM操作优化</title><link>http://www.blogjava.net/freeman1984/archive/2010/10/17/335395.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sun, 17 Oct 2010 15:53:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/17/335395.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/335395.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/17/335395.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/335395.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/335395.html</trackback:ping><description><![CDATA[<p>原文：《Speeding up JavaScript: Working with the DOM》</p>
<p>作者： KeeKim Heng, Google Web Developer</p>
<p>在我们开发互联网富应用（RIA）时，我们经常写一些javascript脚本来修改或者增加页面元素，这些工作最终是DOM——或者说文档对象模型——来完成的，而我们的实现方式会影响到应用的响应速度。</p>
<p>DOM操作会导致浏览器重解析(reflow)，这是浏览器的一个决定页面元素如何展现的计算过程。直接修改DOM，修改元素的CSS样式，修改浏览器的窗口大小，都会触发重解析。读取元素的布局属性比如offsetHeithe或者offsetWidth也会触发重解析。重解析需要花费计算时间，因此重解析触发的越少，应用就会越快。</p>
<p>DOM操作通常要不就是修改已经存在的页面上的元素，要不就是创建新的页面元素。下面的4种优化方案覆盖了修改和创建DOM节点两种方式，帮助你减少触发浏览器重解析的次数。</p>
<p>方案一：通过CSS类名切换来修改DOM</p>
<p>&nbsp;</p>
<p>这个方案让我们可以一次性修改一个元素和它的子元素的多个样式属性而只触发一次重解析。</p>
<p>需求：</p>
<p>（emu注：原文作者写到这里的时候脑子显然短路了一下，把后面的Out-of-the-flow DOM Manipulation模式要解决的问题给摆到这里来了，不过从示范代码中很容易明白作者真正想描述的问题，因此emu就不照翻原文了）</p>
<p>我们现在需要写一个函数来修改一个超链接的几个样式规则。要实现很简单，把这几个规则对应的属性逐一改了就好了。但是带来的问题是，每修改一个样式属性，都会导致一次页面的重解析。</p>
<p>view plaincopy to clipboardprint?<br />
function selectAnchor(element) {&nbsp;&nbsp; <br />
&nbsp; element.style.fontWeight = 'bold';&nbsp;&nbsp; <br />
&nbsp; element.style.textDecoration = 'none';&nbsp;&nbsp; <br />
&nbsp; element.style.color = '#000';&nbsp;&nbsp; <br />
}&nbsp; <br />
function selectAnchor(element) {<br />
&nbsp; element.style.fontWeight = 'bold';<br />
&nbsp; element.style.textDecoration = 'none';<br />
&nbsp; element.style.color = '#000';<br />
} </p>
<p>解决方案</p>
<p>要解决这个问题，我们可以先创建一个样式名，并且把要修改的样式规则都放到这个类名上，然后我们给超链接添加上这个新类名，就可以实现添加几个样式规则而只触发一次重解析了。这个模式还有个好处是也实现了表现和逻辑相分离。</p>
<p>view plaincopy to clipboardprint?<br />
.selectedAnchor {&nbsp;&nbsp; <br />
&nbsp; font-weight: bold;&nbsp;&nbsp; <br />
&nbsp; text-decoration: none;&nbsp;&nbsp; <br />
&nbsp; color: #000;&nbsp;&nbsp; <br />
}&nbsp;&nbsp; <br />
&nbsp; <br />
function selectAnchor(element) {&nbsp;&nbsp; <br />
&nbsp; element.className = 'selectedAnchor';&nbsp;&nbsp; <br />
}&nbsp; <br />
.selectedAnchor {<br />
&nbsp; font-weight: bold;<br />
&nbsp; text-decoration: none;<br />
&nbsp; color: #000;<br />
}</p>
<p>function selectAnchor(element) {<br />
&nbsp; element.className = 'selectedAnchor';<br />
}</p>
<p>&nbsp;方案二：在非渲染区修改DOM</p>
<p>（emu注：作者在这里再次脑子短路，把DocumentFragment DOM Generation模式的介绍提前到这里来了，emu只好再次发挥一下）<br />
上一个方案解决的是修改一个超链接的问题，当一次需要对很多个超链接进行相同修改的时候，这个方案就可以大显身手了。</p>
<p>需求</p>
<p>需求是这样的，我们要写一个函数来修改一个指定元素的子元素中所有的超链接的样式名（className）属性。要实现很简单，我们可以通过遍历每个超链接并且修改它们的样式名来完成任务。但是带来的问题就是，每修改一个超链接都会导致一次重解析。</p>
<p>view plaincopy to clipboardprint?<br />
function updateAllAnchors(element, anchorClass) {&nbsp;&nbsp; <br />
&nbsp; var anchors = element.getElementsByTagName('a');&nbsp;&nbsp; <br />
&nbsp; for (var i = 0, length = anchors.length; i &lt; length; i ++) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; anchors[i].className = anchorClass;&nbsp;&nbsp; <br />
&nbsp; }&nbsp;&nbsp; <br />
}&nbsp; <br />
function updateAllAnchors(element, anchorClass) {<br />
&nbsp; var anchors = element.getElementsByTagName('a');<br />
&nbsp; for (var i = 0, length = anchors.length; i &lt; length; i ++) {<br />
&nbsp;&nbsp;&nbsp; anchors[i].className = anchorClass;<br />
&nbsp; }<br />
}<br />
&nbsp;</p>
<p>解决方案</p>
<p>要解决这个问题，我们可以把被修改的指定元素从DOM里面移除，再修改所有的超链接，然后在把这个元素插入回到它原来的位置上。为了完成这个复杂的操作，我们可以先写一个可重用的函数，它不但移除了这个DOM节点，还返回了一个把元素插回到原来的位置的函数。</p>
<p>view plaincopy to clipboardprint?<br />
/**&nbsp; <br />
&nbsp;* Remove an element and provide a function that inserts it into its original position&nbsp; <br />
&nbsp;* @param element {Element} The element to be temporarily removed&nbsp; <br />
&nbsp;* @return {Function} A function that inserts the element into its original position&nbsp; <br />
&nbsp;**/&nbsp; <br />
function removeToInsertLater(element) {&nbsp;&nbsp; <br />
&nbsp; var parentNode = element.parentNode;&nbsp;&nbsp; <br />
&nbsp; var nextSibling = element.nextSibling;&nbsp;&nbsp; <br />
&nbsp; parentNode.removeChild(element);&nbsp;&nbsp; <br />
&nbsp; return function() {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; if (nextSibling) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parentNode.insertBefore(element, nextSibling);&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; } else {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parentNode.appendChild(element);&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp; <br />
&nbsp; };&nbsp;&nbsp; <br />
}&nbsp; <br />
/**<br />
&nbsp;* Remove an element and provide a function that inserts it into its original position<br />
&nbsp;* @param element {Element} The element to be temporarily removed<br />
&nbsp;* @return {Function} A function that inserts the element into its original position<br />
&nbsp;**/<br />
function removeToInsertLater(element) {<br />
&nbsp; var parentNode = element.parentNode;<br />
&nbsp; var nextSibling = element.nextSibling;<br />
&nbsp; parentNode.removeChild(element);<br />
&nbsp; return function() {<br />
&nbsp;&nbsp;&nbsp; if (nextSibling) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parentNode.insertBefore(element, nextSibling);<br />
&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parentNode.appendChild(element);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; };<br />
} </p>
<p>有了上面这个函数，现在我们就可以在一个不需要解析渲染的元素上面修改那些超链接了。这样只在移除和插入元素的时候各触发一次重解析。</p>
<p>view plaincopy to clipboardprint?<br />
function updateAllAnchors(element, anchorClass) {&nbsp;&nbsp; <br />
&nbsp; var insertFunction = removeToInsertLater(element);&nbsp;&nbsp; <br />
&nbsp; var anchors = element.getElementsByTagName('a');&nbsp;&nbsp; <br />
&nbsp; for (var i = 0, length = anchors.length; i &lt; length; i ++) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; anchors[i].className = anchorClass;&nbsp;&nbsp; <br />
&nbsp; }&nbsp;&nbsp; <br />
&nbsp; insertFunction();&nbsp;&nbsp; <br />
}&nbsp; <br />
function updateAllAnchors(element, anchorClass) {<br />
&nbsp; var insertFunction = removeToInsertLater(element);<br />
&nbsp; var anchors = element.getElementsByTagName('a');<br />
&nbsp; for (var i = 0, length = anchors.length; i &lt; length; i ++) {<br />
&nbsp;&nbsp;&nbsp; anchors[i].className = anchorClass;<br />
&nbsp; }<br />
&nbsp; insertFunction();<br />
}<br />
&nbsp;</p>
<p>方案三：一次性的DOM元素生成</p>
<p>这个方案让我们创建一个元素的过程只触发一次重解析。在创建完元素以后，先进行所有需要的修改，最后才把它插入到DOM里面去就可以了</p>
<p>需求</p>
<p>需求是这样的，实现一个函数，往一个指定的父元素上插入一个超链接元素。这个函数要同时可以设置这个超链接的显示文字和样式类。我们可以这样做：创建元素，插入到DOM里面，然后设置相应的属性。这就要触发3次重解析。</p>
<p>view plaincopy to clipboardprint?<br />
function addAnchor(parentElement, anchorText, anchorClass) {&nbsp;&nbsp; <br />
&nbsp; var element = document.createElement('a');&nbsp;&nbsp; <br />
&nbsp; parentElement.appendChild(element);&nbsp;&nbsp; <br />
&nbsp; element.innerHTML = anchorText;&nbsp;&nbsp; <br />
&nbsp; element.className = anchorClass;&nbsp;&nbsp; <br />
}&nbsp; <br />
function addAnchor(parentElement, anchorText, anchorClass) {<br />
&nbsp; var element = document.createElement('a');<br />
&nbsp; parentElement.appendChild(element);<br />
&nbsp; element.innerHTML = anchorText;<br />
&nbsp; element.className = anchorClass;<br />
}<br />
&nbsp;</p>
<p>解决方案</p>
<p>很简单，我们只要把插入元素这个操作放到最后做，就可以只进行一次重解析了。</p>
<p>view plaincopy to clipboardprint?<br />
function addAnchor(parentElement, anchorText, anchorClass) {&nbsp;&nbsp; <br />
&nbsp; var element = document.createElement('a');&nbsp;&nbsp; <br />
&nbsp; element.innerHTML = anchorText;&nbsp;&nbsp; <br />
&nbsp; element.className = anchorClass;&nbsp;&nbsp; <br />
&nbsp; parentElement.appendChild(element);&nbsp;&nbsp; <br />
}&nbsp; <br />
function addAnchor(parentElement, anchorText, anchorClass) {<br />
&nbsp; var element = document.createElement('a');<br />
&nbsp; element.innerHTML = anchorText;<br />
&nbsp; element.className = anchorClass;<br />
&nbsp; parentElement.appendChild(element);<br />
} </p>
<p>不过，要是我们想要插入很多个超链接到一个元素里面的话，那么这个做法还是有问题：每插入一个超链接还是要触发一次重解析。下一个方案可以解决这个问题。</p>
<p>方案四：通过文档片段对象（DocumentFragment）创建一组元素</p>
<p>这个方案允许我们创建并插入很多个元素而只触发一次重解析。要实现这点需要用到所谓的文档片段对象（DocumentFragment）。我们先在DOM之外创建一个文档片段对象（这样它也就不需要解析和渲染），然后我们在文档片段对象中创建很多个元素，最后我们把这个文档片段对象中所有的元素一次性放到DOM里面去，只触发一次重解析。</p>
<p>需求</p>
<p><br />
我们要写一个函数，往一个指定的元素上面增加10个超链接。如果我们简单的直接插入10个超链接到元素上面，就会触发10次重解析。</p>
<p>view plaincopy to clipboardprint?<br />
function addAnchors(element) {&nbsp;&nbsp; <br />
&nbsp; var anchor;&nbsp;&nbsp; <br />
&nbsp; for (var i = 0; i &lt; 10; i ++) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; anchor = document.createElement('a');&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; anchor.innerHTML = 'test';&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; element.appendChild(anchor);&nbsp;&nbsp; <br />
&nbsp; }&nbsp;&nbsp; <br />
}&nbsp; <br />
function addAnchors(element) {<br />
&nbsp; var anchor;<br />
&nbsp; for (var i = 0; i &lt; 10; i ++) {<br />
&nbsp;&nbsp;&nbsp; anchor = document.createElement('a');<br />
&nbsp;&nbsp;&nbsp; anchor.innerHTML = 'test';<br />
&nbsp;&nbsp;&nbsp; element.appendChild(anchor);<br />
&nbsp; }<br />
} </p>
<p>解决方案</p>
<p>要解决这个问题，我们要先创建一个文档片段对象，然后把每个新创建的超链接都插入到它里面去。当我们把文档片段对象用appendChild命令插入到指定的节点时，这个文档片段对象的所有子节点就一起被插入到指定的元素里面，而且只需要触发一次重解析。</p>
<p>view plaincopy to clipboardprint?<br />
function addAnchors(element) {&nbsp;&nbsp; <br />
&nbsp; var anchor, fragment = document.createDocumentFragment();&nbsp;&nbsp; <br />
&nbsp; for (var i = 0; i &lt; 10; i ++) {&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; anchor = document.createElement('a');&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; anchor.innerHTML = 'test';&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; fragment.appendChild(anchor);&nbsp;&nbsp; <br />
&nbsp; }&nbsp;&nbsp; <br />
&nbsp; element.appendChild(fragment);&nbsp;&nbsp; <br />
}&nbsp; </p>
<p>&nbsp;</p>
<p>本文来自CSDN博客，转载请标明出处：http://blog.csdn.net/emu/archive/2010/03/01/5334583.aspx</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/335395.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-17 23:53 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/17/335395.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Comet：基于 HTTP 长连接的“服务器推”技术</title><link>http://www.blogjava.net/freeman1984/archive/2010/10/17/335394.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Sun, 17 Oct 2010 15:45:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/17/335394.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/335394.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/17/335394.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/335394.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/335394.html</trackback:ping><description><![CDATA[<p>Comet：基于 HTTP 长连接的&#8220;服务器推&#8221;技术<br />
2008-06-30 21:31<br />
别： 中级 <br />
周 婷 (zhouting@cn.ibm.com), 软件工程师, IBM 中国软件开发技术实验室</p>
<p>2007 年 8 月 31 日</p>
<p>很多应用譬如监控、即时通信、即时报价系统都需要将后台发生的变化实时传送到客户端而无须客户端不停地刷新、发送请求。本文首先介绍、比较了常用的&#8220;服务器推&#8221;方案，着重介绍了 Comet － 使用 HTTP 长连接、无须浏览器安装插件的两种&#8220;服务器推&#8221;方案：基于 AJAX 的长轮询方式；基于 iframe 及 htmlfile 的流方式。最后分析了开发 Comet 应用需要注意的一些问题，以及如何借助开源的 Comet 框架－pushlet 构建自己的&#8220;服务器推&#8221;应用。<br />
&#8220;服务器推&#8221;技术的应用</p>
<p>&nbsp;请访问 Ajax 技术资源中心，这是有关 Ajax 编程模型信息的一站式中心，包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。&nbsp; <br />
&nbsp;&nbsp; 订阅 Ajax 相关文章和教程的 RSS 提要 <br />
&nbsp;</p>
<p>&nbsp;<br />
&nbsp;<br />
传统模式的 Web 系统以客户端发出请求、服务器端响应的方式工作。这种方式并不能满足很多现实应用的需求，譬如：</p>
<p>监控系统：后台硬件热插拔、LED、温度、电压发生变化； <br />
即时通信系统：其它用户登录、发送信息； <br />
即时报价系统：后台数据库内容发生变化； <br />
这些应用都需要服务器能实时地将更新的信息传送到客户端，而无须客户端发出请求。&#8220;服务器推&#8221;技术在现实应用中有一些解决方案，本文将这些解决方案分为两类：一类需要在浏览器端安装插件，基于套接口传送信息，或是使用 RMI、CORBA 进行远程调用；而另一类则无须浏览器安装任何插件、基于 HTTP 长连接。</p>
<p>将&#8220;服务器推&#8221;应用在 Web 程序中，首先考虑的是如何在功能有限的浏览器端接收、处理信息：</p>
<p>客户端如何接收、处理信息，是否需要使用套接口或是使用远程调用。客户端呈现给用户的是 HTML 页面还是 Java applet 或 Flash 窗口。如果使用套接口和远程调用，怎么和 JavaScript 结合修改 HTML 的显示。 <br />
客户与服务器端通信的信息格式，采取怎样的出错处理机制。 <br />
客户端是否需要支持不同类型的浏览器如 IE、Firefox，是否需要同时支持 Windows 和 Linux 平台。 <br />
&nbsp; <br />
&nbsp; 回页首 <br />
&nbsp;<br />
基于客户端套接口的&#8220;服务器推&#8221;技术</p>
<p>Flash XMLSocket</p>
<p>如果 Web 应用的用户接受应用只有在安装了 Flash 播放器才能正常运行， 那么使用 Flash 的 XMLSocket 也是一个可行的方案。</p>
<p>这种方案实现的基础是：</p>
<p>Flash 提供了 XMLSocket 类。 <br />
JavaScript 和 Flash 的紧密结合：在 JavaScript 可以直接调用 Flash 程序提供的接口。 <br />
具体实现方法：在 HTML 页面中内嵌入一个使用了 XMLSocket 类的 Flash 程序。JavaScript 通过调用此 Flash 程序提供的套接口接口与服务器端的套接口进行通信。JavaScript 在收到服务器端以 XML 格式传送的信息后可以很容易地控制 HTML 页面的内容显示。</p>
<p>关于如何去构建充当了 JavaScript 与 Flash XMLSocket 桥梁的 Flash 程序，以及如何在 JavaScript 里调用 Flash 提供的接口，我们可以参考 AFLAX（Asynchronous Flash and XML）项目提供的 Socket Demo 以及 SocketJS（请参见 参考资源）。</p>
<p>Javascript 与 Flash 的紧密结合，极大增强了客户端的处理能力。从 Flash 播放器 V7.0.19 开始，已经取消了 XMLSocket 的端口必须大于 1023 的限制。Linux 平台也支持 Flash XMLSocket 方案。但此方案的缺点在于：</p>
<p>客户端必须安装 Flash 播放器； <br />
因为 XMLSocket 没有 HTTP 隧道功能，XMLSocket 类不能自动穿过防火墙； <br />
因为是使用套接口，需要设置一个通信端口，防火墙、代理服务器也可能对非 HTTP 通道端口进行限制； <br />
不过这种方案在一些网络聊天室，网络互动游戏中已得到广泛使用。</p>
<p>Java Applet 套接口 </p>
<p>在客户端使用 Java Applet，通过 java.net.Socket 或 java.net.DatagramSocket 或 java.net.MulticastSocket 建立与服务器端的套接口连接，从而实现&#8220;服务器推&#8221;。</p>
<p>这种方案最大的不足在于 Java applet 在收到服务器端返回的信息后，无法通过 JavaScript 去更新 HTML 页面的内容。</p>
<p>&nbsp; <br />
&nbsp; 回页首 <br />
&nbsp;<br />
基于 HTTP 长连接的&#8220;服务器推&#8221;技术</p>
<p>Comet 简介</p>
<p>浏览器作为 Web 应用的前台，自身的处理功能比较有限。浏览器的发展需要客户端升级软件，同时由于客户端浏览器软件的多样性，在某种意义上，也影响了浏览器新技术的推广。在 Web 应用中，浏览器的主要工作是发送请求、解析服务器返回的信息以不同的风格显示。AJAX 是浏览器技术发展的成果，通过在浏览器端发送异步请求，提高了单用户操作的响应性。但 Web 本质上是一个多用户的系统，对任何用户来说，可以认为服务器是另外一个用户。现有 AJAX 技术的发展并不能解决在一个多用户的 Web 应用中，将更新的信息实时传送给客户端，从而用户可能在&#8220;过时&#8221;的信息下进行操作。而 AJAX 的应用又使后台数据更新更加频繁成为可能。</p>
<p>图 1. 传统的 Web 应用模型与基于 AJAX 的模型之比较&nbsp; <br />
&#8220;服务器推&#8221;是一种很早就存在的技术，以前在实现上主要是通过客户端的套接口，或是服务器端的远程调用。因为浏览器技术的发展比较缓慢，没有为&#8220;服务器推&#8221;的实现提供很好的支持，在纯浏览器的应用中很难有一个完善的方案去实现&#8220;服务器推&#8221;并用于商业程序。最近几年，因为 AJAX 技术的普及，以及把 IFrame 嵌在&#8220;htmlfile&#8220;的 ActiveX 组件中可以解决 IE 的加载显示问题，一些受欢迎的应用如 meebo，gmail+gtalk 在实现中使用了这些新技术；同时&#8220;服务器推&#8221;在现实应用中确实存在很多需求。因为这些原因，基于纯浏览器的&#8220;服务器推&#8221;技术开始受到较多关注，Alex Russell（Dojo Toolkit 的项目 Lead）称这种基于 HTTP 长连接、无须在浏览器端安装插件的&#8220;服务器推&#8221;技术为&#8220;Comet&#8221;。目前已经出现了一些成熟的 Comet 应用以及各种开源框架；一些 Web 服务器如 Jetty 也在为支持大量并发的长连接进行了很多改进。关于 Comet 技术最新的发展状况请参考关于 Comet 的 wiki。</p>
<p>下面将介绍两种 Comet 应用的实现模型。</p>
<p>基于 AJAX 的长轮询（long-polling）方式</p>
<p>如 图 1 所示，AJAX 的出现使得 JavaScript 可以调用 XMLHttpRequest 对象发出 HTTP 请求，JavaScript 响应处理函数根据服务器返回的信息对 HTML 页面的显示进行更新。使用 AJAX 实现&#8220;服务器推&#8221;与传统的 AJAX 应用不同之处在于：</p>
<p>服务器端会阻塞请求直到有数据传递或超时才返回。 <br />
客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后，再次发出请求，重新建立连接。 <br />
当客户端处理接收的数据、重新建立连接时，服务器端可能有新的数据到达；这些信息会被服务器端保存直到客户端重新建立连接，客户端会一次把当前服务器端所有的信息取回。 <br />
图 2. 基于长轮询的服务器推模型&nbsp; <br />
一些应用及示例如 &#8220;Meebo&#8221;, &#8220;Pushlet Chat&#8221; 都采用了这种长轮询的方式。相对于&#8220;轮询&#8221;（poll），这种长轮询方式也可以称为&#8220;拉&#8221;（pull）。因为这种方案基于 AJAX，具有以下一些优点：请求异步发出；无须安装插件；IE、Mozilla FireFox 都支持 AJAX。</p>
<p>在这种长轮询方式下，客户端是在 XMLHttpRequest 的 readystate 为 4（即数据传输结束）时调用回调函数，进行信息处理。当 readystate 为 4 时，数据传输结束，连接已经关闭。Mozilla Firefox 提供了对 Streaming AJAX 的支持， 即 readystate 为 3 时（数据仍在传输中），客户端可以读取数据，从而无须关闭连接，就能读取处理服务器端返回的信息。IE 在 readystate 为 3 时，不能读取服务器返回的数据，目前 IE 不支持基于 Streaming AJAX。</p>
<p>基于 Iframe 及 htmlfile 的流（streaming）方式</p>
<p>iframe 是很早就存在的一种 HTML 标记， 通过在 HTML 页面里嵌入一个隐蔵帧，然后将这个隐蔵帧的 SRC 属性设为对一个长连接的请求，服务器端就能源源不断地往客户端输入数据。</p>
<p>图 3. 基于流方式的服务器推模型&nbsp; <br />
上节提到的 AJAX 方案是在 JavaScript 里处理 XMLHttpRequest 从服务器取回的数据，然后 Javascript 可以很方便的去控制 HTML 页面的显示。同样的思路用在 iframe 方案的客户端，iframe 服务器端并不返回直接显示在页面的数据，而是返回对客户端 Javascript 函数的调用，如&#8220;&lt;script type="text/javascript"&gt;js_func(&#8220;data from server &#8221;)&lt;/script&gt;&#8221;。服务器端将返回的数据作为客户端 JavaScript 函数的参数传递；客户端浏览器的 Javascript 引擎在收到服务器返回的 JavaScript 调用时就会去执行代码。</p>
<p>从 图 3 可以看到，每次数据传送不会关闭连接，连接只会在通信出现错误时，或是连接重建时关闭（一些防火墙常被设置为丢弃过长的连接， 服务器端可以设置一个超时时间， 超时后通知客户端重新建立连接，并关闭原来的连接）。</p>
<p>使用 iframe 请求一个长连接有一个很明显的不足之处：IE、Morzilla Firefox 下端的进度栏都会显示加载没有完成，而且 IE 上方的图标会不停的转动，表示加载正在进行。Google 的天才们使用一个称为&#8220;htmlfile&#8221;的 ActiveX 解决了在 IE 中的加载显示问题，并将这种方法用到了 gmail+gtalk 产品中。Alex Russell 在 &#8220;What else is burried down in the depth's of Google's amazing JavaScript?&#8221;文章中介绍了这种方法。Zeitoun 网站提供的 comet-iframe.tar.gz，封装了一个基于 iframe 和 htmlfile 的 JavaScript comet 对象，支持 IE、Mozilla Firefox 浏览器，可以作为参考。（请参见 参考资源）</p>
<p>&nbsp; <br />
&nbsp; 回页首 <br />
&nbsp;<br />
使用 Comet 模型开发自己的应用</p>
<p>上面介绍了两种基于 HTTP 长连接的&#8220;服务器推&#8221;架构，更多描述了客户端处理长连接的技术。对于一个实际的应用而言，系统的稳定性和性能是非常重要的。将 HTTP 长连接用于实际应用，很多细节需要考虑。</p>
<p>不要在同一客户端同时使用超过两个的 HTTP 长连接</p>
<p>我们使用 IE 下载文件时会有这样的体验，从同一个 Web 服务器下载文件，最多只能有两个文件同时被下载。第三个文件的下载会被阻塞，直到前面下载的文件下载完毕。这是因为 HTTP 1.1 规范中规定，客户端不应该与服务器端建立超过两个的 HTTP 连接， 新的连接会被阻塞。而 IE 在实现中严格遵守了这种规定。</p>
<p>HTTP 1.1 对两个长连接的限制，会对使用了长连接的 Web 应用带来如下现象：在客户端如果打开超过两个的 IE 窗口去访问同一个使用了长连接的 Web 服务器，第三个 IE 窗口的 HTTP 请求被前两个窗口的长连接阻塞。</p>
<p>所以在开发长连接的应用时， 必须注意在使用了多个 frame 的页面中，不要为每个 frame 的页面都建立一个 HTTP 长连接，这样会阻塞其它的 HTTP 请求，在设计上考虑让多个 frame 的更新共用一个长连接。</p>
<p>服务器端的性能和可扩展性</p>
<p>一般 Web 服务器会为每个连接创建一个线程，如果在大型的商业应用中使用 Comet，服务器端需要维护大量并发的长连接。在这种应用背景下，服务器端需要考虑负载均衡和集群技术；或是在服务器端为长连接作一些改进。</p>
<p>应用和技术的发展总是带来新的需求，从而推动新技术的发展。HTTP 1.1 与 1.0 规范有一个很大的不同：1.0 规范下服务器在处理完每个 Get/Post 请求后会关闭套接口连接； 而 1.1 规范下服务器会保持这个连接，在处理两个请求的间隔时间里，这个连接处于空闲状态。 Java 1.4 引入了支持异步 IO 的 java.nio 包。当连接处于空闲时，为这个连接分配的线程资源会返还到线程池，可以供新的连接使用；当原来处于空闲的连接的客户发出新的请求，会从线程池里分配一个线程资源处理这个请求。 这种技术在连接处于空闲的机率较高、并发连接数目很多的场景下对于降低服务器的资源负载非常有效。</p>
<p>但是 AJAX 的应用使请求的出现变得频繁，而 Comet 则会长时间占用一个连接，上述的服务器模型在新的应用背景下会变得非常低效，线程池里有限的线程数甚至可能会阻塞新的连接。Jetty 6 Web 服务器针对 AJAX、Comet 应用的特点进行了很多创新的改进，请参考文章&#8220;AJAX，Comet and Jetty&#8221;（请参见 参考资源）。</p>
<p>控制信息与数据信息使用不同的 HTTP 连接</p>
<p>使用长连接时，存在一个很常见的场景：客户端网页需要关闭，而服务器端还处在读取数据的堵塞状态，客户端需要及时通知服务器端关闭数据连接。服务器在收到关闭请求后首先要从读取数据的阻塞状态唤醒，然后释放为这个客户端分配的资源，再关闭连接。</p>
<p>所以在设计上，我们需要使客户端的控制请求和数据请求使用不同的 HTTP 连接，才能使控制请求不会被阻塞。</p>
<p>在实现上，如果是基于 iframe 流方式的长连接，客户端页面需要使用两个 iframe，一个是控制帧，用于往服务器端发送控制请求，控制请求能很快收到响应，不会被堵塞；一个是显示帧，用于往服务器端发送长连接请求。如果是基于 AJAX 的长轮询方式，客户端可以异步地发出一个 XMLHttpRequest 请求，通知服务器端关闭数据连接。</p>
<p>在客户和服务器之间保持&#8220;心跳&#8221;信息</p>
<p>在浏览器与服务器之间维持一个长连接会为通信带来一些不确定性：因为数据传输是随机的，客户端不知道何时服务器才有数据传送。服务器端需要确保当客户端不再工作时，释放为这个客户端分配的资源，防止内存泄漏。因此需要一种机制使双方知道大家都在正常运行。在实现上：</p>
<p>服务器端在阻塞读时会设置一个时限，超时后阻塞读调用会返回，同时发给客户端没有新数据到达的心跳信息。此时如果客户端已经关闭，服务器往通道写数据会出现异常，服务器端就会及时释放为这个客户端分配的资源。 <br />
如果客户端使用的是基于 AJAX 的长轮询方式；服务器端返回数据、关闭连接后，经过某个时限没有收到客户端的再次请求，会认为客户端不能正常工作，会释放为这个客户端分配、维护的资源。 <br />
当服务器处理信息出现异常情况，需要发送错误信息通知客户端，同时释放资源、关闭连接。 <br />
Pushlet - 开源 Comet 框架</p>
<p>Pushlet 是一个开源的 Comet 框架，在设计上有很多值得借鉴的地方，对于开发轻量级的 Comet 应用很有参考价值。</p>
<p>观察者模型</p>
<p>Pushlet 使用了观察者模型：客户端发送请求，订阅感兴趣的事件；服务器端为每个客户端分配一个会话 ID 作为标记，事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。</p>
<p>客户端 JavaScript 库</p>
<p>pushlet 提供了基于 AJAX 的 JavaScript 库文件用于实现长轮询方式的&#8220;服务器推&#8221;；还提供了基于 iframe 的 JavaScript 库文件用于实现流方式的&#8220;服务器推&#8221;。</p>
<p>JavaScript 库做了很多封装工作：</p>
<p>定义客户端的通信状态：STATE_ERROR、STATE_ABORT、STATE_NULL、STATE_READY、STATE_JOINED、STATE_LISTENING； <br />
保存服务器分配的会话 ID，在建立连接之后的每次请求中会附上会话 ID 表明身份； <br />
提供了 join()、leave()、subscribe()、 unsubsribe()、listen() 等 API 供页面调用； <br />
提供了处理响应的 JavaScript 函数接口 onData()、onEvent()&#8230; <br />
网页可以很方便地使用这两个 JavaScript 库文件封装的 API 与服务器进行通信。</p>
<p>客户端与服务器端通信信息格式</p>
<p>pushlet 定义了一套客户与服务器通信的信息格式，使用 XML 格式。定义了客户端发送请求的类型：join、leave、subscribe、unsubscribe、listen、refresh；以及响应的事件类型：data、join_ack、listen_ack、refresh、heartbeat、error、abort、subscribe_ack、unsubscribe_ack。</p>
<p>服务器端事件队列管理</p>
<p>pushlet 在服务器端使用 Java Servlet 实现，其数据结构的设计框架仍可适用于 PHP、C 编写的后台客户端。</p>
<p>Pushlet 支持客户端自己选择使用流、拉（长轮询）、轮询方式。服务器端根据客户选择的方式在读取事件队列（fetchEvents）时进行不同的处理。&#8220;轮询&#8221;模式下 fetchEvents() 会马上返回。&#8221;流&#8220;和&#8221;拉&#8220;模式使用阻塞的方式读事件，如果超时，会发给客户端发送一个没有新信息收到的&#8220;heartbeat&#8220;事件，如果是&#8220;拉&#8221;模式，会把&#8220;heartbeat&#8221;与&#8220;refresh&#8221;事件一起传给客户端，通知客户端重新发出请求、建立连接。</p>
<p>客户服务器之间的会话管理</p>
<p>服务端在客户端发送 join 请求时，会为客户端分配一个会话 ID， 并传给客户端，然后客户端就通过此会话 ID 标明身份发出 subscribe 和 listen 请求。服务器端会为每个会话维护一个订阅的主题集合、事件队列。</p>
<p>服务器端的事件源会把新产生的事件以多播的方式发送到每个会话（即订阅者）的事件队列里。</p>
<p>&nbsp; <br />
&nbsp; 回页首 <br />
&nbsp;<br />
小结</p>
<p>本文介绍了如何在现有的技术基础上选择合适的方案开发一个&#8220;服务器推&#8221;的应用，最优的方案还是取决于应用需求的本身。相对于传统的 Web 应用， 目前开发 Comet 应用还是具有一定的挑战性。</p>
<p>&#8220;服务器推&#8221;存在广泛的应用需求，为了使 Comet 模型适用于大规模的商业应用，以及方便用户构建 Comet 应用，最近几年，无论是服务器还是浏览器都出现了很多新技术，同时也出现了很多开源的 Comet 框架、协议。需求推动技术的发展，相信 Comet 的应用会变得和 AJAX 一样普及。</p>
<p>参考资料 </p>
<p>学习 <br />
developerWorks 文章&#8220; 面向 Java 开发人员的 Ajax: 使用 Jetty 和 Direct Web Remoting 编写可扩展的 Comet 应用程序&#8221;：受异步服务器端事件驱动的 Ajax 应用程序实现较为困难，本文介绍了一种结合使用 Comet 模式和 Jetty 6 Continuations API 的解决方法。 <br />
&#8220;Comet: Low Latency Data for the Browser&#8221;：Alex Russell 是 Dojo Toolkit 的项目主管和 Dojo Foundation 的主席，他在这篇博客文章中提出了 Comet 这个术语。 <br />
&#8220;What else is burried down in the depth&#8217;s of Google&#8217;s amazing JavaScript?&#8221;（Alex Russel，2006 年 2 月）：Alex 在这篇文章里介绍了如何使用&#8220;htmlfile&#8221;ActiveX 控件解决 iframe 请求长连接时 IE 的加载显示问题。 <br />
Comet wiki：提供了很多开源 Comet 框架的链接。 <br />
Jetty：Jetty 是一种开源的基于标准的 Web 服务器，完全使用 Java 语言实现。 <br />
&#8220;Ajax, Comet and Jetty&#8221;（Greg Wilkins，Webtide，2006 年 1 月）：Wilkins 的这份白皮书讨论了扩展 Ajax 连接的 Jetty 架构方法。 <br />
Continuations：了解更多关于 Jetty 的 Continuations 特性的信息。 <br />
&#8220;pushlet&#8221;：开源 comet 框架，使用了观察者模型。浏览器端提供了基于 AJAX 和 iframe 的 JavaScript 库，服务器端使用 Java Servlet。 <br />
&#8220;How to implement COMET with PHP&#8221;：提供的 comet-iframe.tar.gz 使用 iframe/htmlfile 封装了一个 JavaScript comet 对象，支持 IE、Mozilla Firefox 浏览器。 <br />
&#8220;AFLAX&#8221;：Asynchronous Flash and XML，提供了强大的 Flash、Javascript 库和很多范例。 <br />
developerWorks Ajax 技术资源中心：能找到更多关于 Ajax 技术的文章和教程。 <br />
developerWorks Web 开发技术专区：提供了关于 Web 开发和架构方面的大量文章。 <br />
developerWorks Java 技术专区：提供了关于 Java 编程各个方面的数百篇文章。 <br />
浏览 技术书店，查阅有关本文所述主题以及其他技术主题的书籍。&nbsp; </p>
<p><br />
&nbsp;</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/335394.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-17 23:45 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/17/335394.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tomcat启动分析server.xml </title><link>http://www.blogjava.net/freeman1984/archive/2010/10/11/334485.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 11 Oct 2010 15:13:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/10/11/334485.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/334485.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/10/11/334485.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/334485.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/334485.html</trackback:ping><description><![CDATA[<div>
<p><font color="#000080">1 - Tomcat Server的组成部分 <br />
1.1 - Server </font></p>
<p><font color="#000080">A Server element represents the entire Catalina servlet container. (Singleton) </font></p>
<p><font color="#000080">1.2 - Service </font></p>
<p><font color="#000080">A Service element represents the combination of one or more Connector components that share a single Engine<br />
Service是这样一个集合：它由一个或者多个Connector组成，以及一个Engine，负责处理所有Connector所获得的客户请求</font></p>
<p><font color="#000080">1.3 - Connector </font></p>
<p><font color="#000080">一个Connector将在某个指定端口上侦听客户请求，并将获得的请求交给Engine来处理，从Engine处获得回应并返回客户<br />
TOMCAT有两个典型的Connector，一个直接侦听来自browser的http请求，一个侦听来自其它WebServer的请求<br />
Coyote Http/1.1 Connector 在端口8080处侦听来自客户browser的http请求<br />
Coyote JK2 Connector 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求</font></p>
<p><font color="#000080">1.4 - Engine </font></p>
<p><font color="#000080">The Engine element represents the entire request processing machinery associated with a particular Service<br />
It receives and processes all requests from one or more Connectors<br />
and returns the completed response to the Connector for ultimate transmission back to the client<br />
Engine下可以配置多个虚拟主机Virtual Host，每个虚拟主机都有一个域名<br />
当Engine获得一个请求时，它把该请求匹配到某个Host上，然后把该请求交给该Host来处理<br />
Engine有一个默认虚拟主机，当请求无法匹配到任何一个Host上的时候，将交给该默认Host来处理</font></p>
<p><font color="#000080">1.5 - Host </font></p>
<p><font color="#000080">代表一个Virtual Host，虚拟主机，每个虚拟主机和某个网络域名Domain Name相匹配<br />
每个虚拟主机下都可以部署(deploy)一个或者多个Web App，每个Web App对应于一个Context，有一个Context path<br />
当Host获得一个请求时，将把该请求匹配到某个Context上，然后把该请求交给该Context来处理<br />
匹配的方法是&#8220;最长匹配&#8221;，所以一个path==""的Context将成为该Host的默认Context<br />
所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配</font></p>
<p><br />
<font color="#000080">1.6 - Context </font></p>
<p><font color="#000080">一个Context对应于一个Web Application，一个Web Application由一个或者多个Servlet组成<br />
Context在创建的时候将根据配置文件＄CATALINA_HOME/conf/web.xml和＄WEBAPP_HOME/WEB-INF/web.xml载入Servlet类<br />
当Context获得请求时，将在自己的映射表(mapping table)中寻找相匹配的Servlet类<br />
如果找到，则执行该类，获得请求的回应，并返回</font></p>
<p><font color="#000080">2 - Tomcat Server的结构图 <br />
&nbsp;<br />
3 - 配置文件＄CATALINA_HOME/conf/server.xml的说明 <br />
该文件描述了如何启动Tomcat Server </font></p>
<p><br />
<font color="#000080">&lt;!-----------------------------------------------------------------------------------------------&gt;</font></p>
<p><br />
<font color="#000080">&lt;!-- 启动Server<br />
&nbsp;&nbsp;&nbsp;&nbsp; 在端口8005处等待关闭命令<br />
&nbsp;&nbsp;&nbsp;&nbsp; 如果接受到"SHUTDOWN"字符串则关闭服务器<br />
&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</font></p>
<p><font color="#000080">&lt;Server port="8005" shutdown="SHUTDOWN" debug="0"&gt;</font></p>
<p><br />
<font color="#000080">&nbsp; &lt;!-- Listener ???<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 目前没有看到这里<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</font></p>
<p><font color="#000080">&nbsp; &lt;Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" debug="0"/&gt;<br />
&nbsp; &lt;Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" debug="0"/&gt;</font></p>
<p><br />
<font color="#000080">&nbsp; &lt;!-- Global JNDI resources ???<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 目前没有看到这里，先略去<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</font></p>
<p><font color="#000080">&nbsp; &lt;GlobalNamingResources&gt;<br />
&nbsp;&nbsp;&nbsp; ... ... ... ...<br />
&nbsp; &lt;/GlobalNamingResources&gt;</font></p>
<p><font color="#000080">&nbsp; &lt;!-- Tomcat的Standalone Service<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Service是一组Connector的集合<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 它们共用一个Engine来处理所有Connector收到的请求<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</font></p>
<p><font color="#000080">&nbsp; &lt;Service name="Tomcat-Standalone"&gt;</font></p>
<p><br />
<font color="#000080">&nbsp;&nbsp;&nbsp; &lt;!-- Coyote HTTP/1.1 Connector<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; className : 该Connector的实现类是org.apache.coyote.tomcat4.CoyoteConnector<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; port : 在端口号8080处侦听来自客户browser的HTTP1.1请求<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; minProcessors : 该Connector先创建5个线程等待客户请求，每个请求由一个线程负责<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maxProcessors : 当现有的线程不够服务客户请求时，若线程总数不足75个，则创建新线程来处理请求<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; acceptCount : 当现有线程已经达到最大数75时，为客户请求排队<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当队列中请求数超过100时，后来的请求返回Connection refused错误<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redirectport : 当客户请求是https时，把该请求转发到端口8443去<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其它属性略<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp; &lt;Connector className="org.apache.coyote.tomcat4.CoyoteConnector" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; port="8080" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; minProcessors="5" maxProcessors="75" acceptCount="100" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enableLookups="true" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; redirectPort="8443" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; debug="0" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connectionTimeout="20000" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; useURIValidationHack="false" <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; disableUploadTimeout="true" /&gt;</font></p>
<p><br />
<font color="#000080">&nbsp;&nbsp;&nbsp; &lt;!-- Engine用来处理Connector收到的Http请求<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 它将匹配请求和自己的虚拟主机，并把请求转交给对应的Host来处理<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 默认虚拟主机是localhost<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp; &lt;Engine name="Standalone" defaultHost="localhost" debug="0"&gt;<br />
&nbsp;&nbsp;&nbsp; </font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 日志类，目前没有看到，略去先 --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Logger className="org.apache.catalina.logger.FileLogger" .../&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- Realm，目前没有看到，略去先 --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Realm className="org.apache.catalina.realm.UserDatabaseRealm" .../&gt;</font></p>
<p><br />
<font color="#000080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 虚拟主机localhost<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; appBase : 该虚拟主机的根目录是webapps/<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 它将匹配请求和自己的Context的路径，并把请求转交给对应的Context来处理<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Host name="localhost" debug="0" appBase="webapps" unpackWARs="true" autoDeploy="true"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 日志类，目前没有看到，略去先 --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Logger className="org.apache.catalina.logger.FileLogger" .../&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- Context，对应于一个Web App<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; path : 该Context的路径名是""，故该Context是该Host的默认Context<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; docBase : 该Context的根目录是webapps/mycontext/<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Context path="" docBase="mycontext" debug="0"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!-- 另外一个Context，路径名是/wsota --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Context path="/wsota" docBase="wsotaProject" debug="0"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Host&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &lt;/Engine&gt;</font></p>
<p><font color="#000080">&nbsp; &lt;/Service&gt;</font></p>
<p><font color="#000080">&lt;/Server&gt;</font></p>
<p><br />
<font color="#000080">&lt;!-----------------------------------------------------------------------------------------------&gt;</font></p>
<p><font color="#000080"></font>&nbsp;</p>
<p><font color="#000080">4 - Context的部署配置文件web.xml的说明 <br />
一个Context对应于一个Web App，每个Web App是由一个或者多个servlet组成的<br />
当一个Web App被初始化的时候，它将用自己的ClassLoader对象载入&#8220;部署配置文件web.xml&#8221;中定义的每个servlet类<br />
它首先载入在＄CATALINA_HOME/conf/web.xml中部署的servlet类<br />
然后载入在自己的Web App根目录下的WEB-INF/web.xml中部署的servlet类<br />
web.xml文件有两部分：servlet类定义和servlet映射定义<br />
每个被载入的servlet类都有一个名字，且被填入该Context的映射表(mapping table)中，和某种URL PATTERN对应<br />
当该Context获得请求时，将查询mapping table，找到被请求的servlet，并执行以获得请求回应</font></p>
<p><br />
<font color="#000080">　　分析一下所有的Context共享的web.xml文件，在其中定义的servlet被所有的Web App载入</font></p>
<p><font color="#000080"></font>&nbsp;</p>
<p><br />
<font color="#000080">&lt;!-----------------------------------------------------------------------------------------------&gt;</font></p>
<p><br />
<font color="#000080">&lt;web-app&gt;</font></p>
<p><br />
<font color="#000080">&nbsp; &lt;!-- 概述：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 该文件是所有的WEB APP共用的部署配置文件，<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 每当一个WEB APP被DEPLOY，该文件都将先被处理，然后才是WEB APP自己的/WEB-INF/web.xml<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</font></p>
<p><font color="#000080"></font>&nbsp;</p>
<p><font color="#000080">&nbsp; &lt;!--&nbsp; +-------------------------+&nbsp; --&gt;<br />
&nbsp; &lt;!--&nbsp; |&nbsp;&nbsp;&nbsp; servlet类定义部分&nbsp;&nbsp;&nbsp; |&nbsp; --&gt;<br />
&nbsp; &lt;!--&nbsp; +-------------------------+&nbsp; --&gt;</font></p>
<p><font color="#000080"></font></p>
<p><font color="#000080">&nbsp; &lt;!-- DefaultServlet<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当用户的HTTP请求无法匹配任何一个servlet的时候，该servlet被执行<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; URL PATTERN MAPPING : /<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp; &lt;servlet&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-name&gt;default&lt;/servlet-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; org.apache.catalina.servlets.DefaultServlet<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/servlet-class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;debug&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;0&lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;listings&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;true&lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/servlet&gt;</font></p>
<p><br />
<font color="#000080">&nbsp; &lt;!-- InvokerServlet<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 处理一个WEB APP中的匿名servlet<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当一个servlet被编写并编译放入/WEB-INF/classes/中，却没有在/WEB-INF/web.xml中定义的时候<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 该servlet被调用，把匿名servlet映射成/servlet/ClassName的形式<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; URL PATTERN MAPPING : /servlet/*<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp; &lt;servlet&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-name&gt;invoker&lt;/servlet-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; org.apache.catalina.servlets.InvokerServlet<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/servlet-class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;debug&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;0&lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/servlet&gt;</font></p>
<p><br />
<font color="#000080">&nbsp; &lt;!-- JspServlet<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当请求的是一个JSP页面的时候（*.jsp）该servlet被调用<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 它是一个JSP编译器，将请求的JSP页面编译成为servlet再执行<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; URL PATTERN MAPPING : *.jsp<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp; &lt;servlet&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-name&gt;jsp&lt;/servlet-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-class&gt;org.apache.jasper.servlet.JspServlet&lt;/servlet-class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;logVerbosityLevel&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;WARNING&lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;load-on-startup&gt;3&lt;/load-on-startup&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/servlet&gt;</font></p>
<p><font color="#000080"></font>&nbsp;</p>
<p><font color="#000080">&nbsp; &lt;!--&nbsp; +---------------------------+&nbsp; --&gt;<br />
&nbsp; &lt;!--&nbsp; |&nbsp;&nbsp;&nbsp; servlet映射定义部分&nbsp;&nbsp;&nbsp; |&nbsp; --&gt;<br />
&nbsp; &lt;!--&nbsp; +---------------------------+&nbsp; --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; &lt;servlet-mapping&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-name&gt;default&lt;/servlet-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;/&lt;/url-pattern&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/servlet-mapping&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp; &lt;servlet-mapping&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-name&gt;invoker&lt;/servlet-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;/servlet/*&lt;/url-pattern&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/servlet-mapping&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp; &lt;servlet-mapping&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;servlet-name&gt;jsp&lt;/servlet-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/servlet-mapping&gt;</font></p>
<p><br />
<font color="#000080">&nbsp; &lt;!--&nbsp; +------------------------+&nbsp; --&gt;<br />
&nbsp; &lt;!--&nbsp; |&nbsp;&nbsp;&nbsp; 其它部分，略去先&nbsp;&nbsp;&nbsp; |&nbsp; --&gt;<br />
&nbsp; &lt;!--&nbsp; +------------------------+&nbsp; --&gt;</font></p>
<p><font color="#000080">&nbsp;&nbsp;&nbsp; ... ... ... ...</font></p>
<p><font color="#000080">&lt;/web-app&gt;</font></p>
<p><br />
<font color="#000080">&lt;!-----------------------------------------------------------------------------------------------&gt;</font></p>
<p><font color="#000080"></font>&nbsp;</p>
<p><font color="#000080">5 - Tomcat Server处理一个http请求的过程 <br />
假设来自客户的请求为：<br />
</font><a href="http://localhost:8080/wsota/wsota_index.jsp"><font color="#000080">http://localhost:8080/wsota/wsota_index.jsp</font></a></p>
<p><font color="#000080">1) 请求被发送到本机端口8080，被在那里侦听的Coyote HTTP/1.1 Connector获得</font></p>
<p><font color="#000080">2) Connector把该请求交给它所在的Service的Engine来处理，并等待来自Engine的回应</font></p>
<p><font color="#000080">3) Engine获得请求localhost/wsota/wsota_index.jsp，匹配它所拥有的所有虚拟主机Host</font></p>
<p><font color="#000080">4) Engine匹配到名为localhost的Host（即使匹配不到也把请求交给该Host处理，因为该Host被定义为该Engine的默认主机）</font></p>
<p><font color="#000080">5) localhost Host获得请求/wsota/wsota_index.jsp，匹配它所拥有的所有Context</font></p>
<p><font color="#000080">6) Host匹配到路径为/wsota的Context（如果匹配不到就把该请求交给路径名为""的Context去处理）</font></p>
<p><font color="#000080">7) path="/wsota"的Context获得请求/wsota_index.jsp，在它的mapping table中寻找对应的servlet</font></p>
<p><font color="#000080">8) Context匹配到URL PATTERN为*.jsp的servlet，对应于JspServlet类</font></p>
<p><font color="#000080">9) 构造HttpServletRequest对象和HttpServletResponse对象，作为参数调用JspServlet的doGet或doPost方法</font></p>
<p><font color="#000080">10)Context把执行完了之后的HttpServletResponse对象返回给Host</font></p>
<p><font color="#000080">11)Host把HttpServletResponse对象返回给Engine</font></p>
<p><font color="#000080">12)Engine把HttpServletResponse对象返回给Connector</font></p>
<p><font color="#000080">13)Connector把HttpServletResponse对象返回给客户browser</font></p>
</div>
转载自：http://www.360doc.com/content/05/1116/10/2689_31126.shtml
<img src ="http://www.blogjava.net/freeman1984/aggbug/334485.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-10-11 23:13 <a href="http://www.blogjava.net/freeman1984/archive/2010/10/11/334485.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅析struts中的ExecuteAndWaitInterceptor，以及简单例子</title><link>http://www.blogjava.net/freeman1984/archive/2010/09/25/332787.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 24 Sep 2010 16:59:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/09/25/332787.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/332787.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/09/25/332787.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/332787.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/332787.html</trackback:ping><description><![CDATA[<p>&nbsp; 大致把源码中类前面的一段注释给翻译一下：<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp; 1 ExecuteAndWaitInterceptor很适合在后台长时间运行的action时，他可以可为用户一个友好的等待界面，例如进度条。<br />
&nbsp;&nbsp;&nbsp; 2&nbsp; 不在默认的拦截<em>stack</em>&nbsp;里面，使用的时候需要配置，但必须是在拦截堆栈的最后一个。<br />
&nbsp;&nbsp;&nbsp;大致配置如下：<br />
&nbsp;&nbsp;&lt;action name="test" method="test" class="com.joe.web.action.ActionTest"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;interceptor-ref name="completeStack"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;interceptor-ref name="execAndWait"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;param name="delay"&gt;1000&lt;/param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;param name="delaySleepInterval"&gt;50&lt;/param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/interceptor-ref&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;result name="wait"&gt;wait.jsp&lt;/result&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;result name="success"&gt;success.jsp&lt;/result&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;/action&gt;&nbsp;&nbsp;&nbsp; 3 使用的时候需要配置一个名为wait的result，并指向自己的等待页面，如果没有struts</p>
将使用FreeMarker代替，通过使用FreemarkerResult动态注入一个等待页面：struts提供的面板页面可见于：<br />
org/apache/struts2/interceptor/wait.ftl<br />
内容大致如下：<br />
<p>&lt;html&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;head&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;meta http-equiv="refresh" content="5;url=&lt;@s.url includeParams="none"/&gt;"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/head&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;body&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Please wait while we process your request...<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p/&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This page will reload automatically and display your request when it is completed.<br />
&nbsp;&nbsp;&nbsp; &lt;/body&gt;<br />
&lt;/html&gt;</p>
<p style="margin: 0cm 0cm 0pt; layout-grid-mode: char; text-indent: 21pt; line-height: 200%"><span style="font-family: 宋体">其中的</span>includeParams<span style="font-family: 宋体">参数取值为</span></p>
<p style="margin: 0cm 0cm 0pt; layout-grid-mode: char; text-indent: 21pt; line-height: 200%">none,<span style="font-family: 宋体">不把参数参加到</span>url<span style="font-family: 宋体">参数中</span></p>
<p style="margin: 0cm 0cm 0pt; layout-grid-mode: char; text-indent: 21pt; line-height: 200%">all,<span style="font-family: 宋体">是把</span>get<span style="font-family: 宋体">和</span>post<span style="font-family: 宋体">中的参数参加到</span>url<span style="font-family: 宋体">参数中</span></p>
<p style="margin: 0cm 0cm 0pt; layout-grid-mode: char; text-indent: 21pt; line-height: 200%">get,<span style="font-family: 宋体">是只把</span>get<span style="font-family: 宋体">中的参数参加到</span>url<span style="font-family: 宋体">参数中<br />
</span></p>
&nbsp;&nbsp;&nbsp;&nbsp; execAndWait拦截器有2个参数：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delay ：意思是初始等待多少秒才出现等待页面。当在这个等待时间内action执行完毕，就不用出现wai界面，如果不配，一开始就会出现。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;delaySleepInterval：每个对少时间检查action是否执行完毕。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp; -------------<br />
大致的原理是：strus遇到这种配置了execAndWait的action会另外起一个线程来执行，这个线程名叫BackgroundProcess，并通过一个done属性的变化来标准执行情况，struts将此线程放到session中，页面每隔一段时间去检查是done==true?&nbsp;&nbsp;如果不是，就据需返回wai页面，否则返回主action的返回界面。<br />
&nbsp;BackgroundProcess大致源码：<br />
&nbsp;
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img id="Codehighlighter1_99_816_Open_Image" onclick="this.style.display='none'; Codehighlighter1_99_816_Open_Text.style.display='none'; Codehighlighter1_99_816_Closed_Image.style.display='inline'; Codehighlighter1_99_816_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_99_816_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_99_816_Closed_Text.style.display='none'; Codehighlighter1_99_816_Open_Image.style.display='inline'; Codehighlighter1_99_816_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;BackgroundProcess(String&nbsp;threadName,&nbsp;</span><span style="color: #0000ff">final</span><span style="color: #000000">&nbsp;ActionInvocation&nbsp;invocation,&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;threadPriority)&nbsp;</span><span id="Codehighlighter1_99_816_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_99_816_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">this</span><span style="color: #000000">.invocation&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;invocation;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">this</span><span style="color: #000000">.action&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;invocation.getAction();<br />
<img id="Codehighlighter1_197_751_Open_Image" onclick="this.style.display='none'; Codehighlighter1_197_751_Open_Text.style.display='none'; Codehighlighter1_197_751_Closed_Image.style.display='inline'; Codehighlighter1_197_751_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_197_751_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_197_751_Closed_Text.style.display='none'; Codehighlighter1_197_751_Open_Image.style.display='inline'; Codehighlighter1_197_751_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">try</span><span style="color: #000000">&nbsp;</span><span id="Codehighlighter1_197_751_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_197_751_Open_Text"><span style="color: #000000">{<br />
<img id="Codehighlighter1_254_638_Open_Image" onclick="this.style.display='none'; Codehighlighter1_254_638_Open_Text.style.display='none'; Codehighlighter1_254_638_Closed_Image.style.display='inline'; Codehighlighter1_254_638_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_254_638_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_254_638_Closed_Text.style.display='none'; Codehighlighter1_254_638_Open_Image.style.display='inline'; Codehighlighter1_254_638_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">final</span><span style="color: #000000">&nbsp;Thread&nbsp;t&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Thread(</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Runnable()&nbsp;</span><span id="Codehighlighter1_254_638_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_254_638_Open_Text"><span style="color: #000000">{<br />
<img id="Codehighlighter1_290_624_Open_Image" onclick="this.style.display='none'; Codehighlighter1_290_624_Open_Text.style.display='none'; Codehighlighter1_290_624_Closed_Image.style.display='inline'; Codehighlighter1_290_624_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_290_624_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_290_624_Closed_Text.style.display='none'; Codehighlighter1_290_624_Open_Image.style.display='inline'; Codehighlighter1_290_624_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;run()&nbsp;</span><span id="Codehighlighter1_290_624_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_290_624_Open_Text"><span style="color: #000000">{<br />
<img id="Codehighlighter1_316_489_Open_Image" onclick="this.style.display='none'; Codehighlighter1_316_489_Open_Text.style.display='none'; Codehighlighter1_316_489_Closed_Image.style.display='inline'; Codehighlighter1_316_489_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_316_489_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_316_489_Closed_Text.style.display='none'; Codehighlighter1_316_489_Open_Image.style.display='inline'; Codehighlighter1_316_489_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">try</span><span style="color: #000000">&nbsp;</span><span id="Codehighlighter1_316_489_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_316_489_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;beforeInvocation();<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;invocation.invokeActionOnly();<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;afterInvocation();<br />
<img id="Codehighlighter1_511_572_Open_Image" onclick="this.style.display='none'; Codehighlighter1_511_572_Open_Text.style.display='none'; Codehighlighter1_511_572_Closed_Image.style.display='inline'; Codehighlighter1_511_572_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_511_572_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_511_572_Closed_Text.style.display='none'; Codehighlighter1_511_572_Open_Image.style.display='inline'; Codehighlighter1_511_572_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">catch</span><span style="color: #000000">&nbsp;(Exception&nbsp;e)&nbsp;</span><span id="Codehighlighter1_511_572_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_511_572_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exception&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;e;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;done&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">true</span><span style="color: #000000">;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000">);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.setName(threadName);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.setPriority(threadPriority);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.start();<br />
<img id="Codehighlighter1_773_810_Open_Image" onclick="this.style.display='none'; Codehighlighter1_773_810_Open_Text.style.display='none'; Codehighlighter1_773_810_Closed_Image.style.display='inline'; Codehighlighter1_773_810_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_773_810_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_773_810_Closed_Text.style.display='none'; Codehighlighter1_773_810_Open_Image.style.display='inline'; Codehighlighter1_773_810_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">catch</span><span style="color: #000000">&nbsp;(Exception&nbsp;e)&nbsp;</span><span id="Codehighlighter1_773_810_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_773_810_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exception&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;e;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>
<br />
当这个action结束后会将done属性设置为true表示执行结束，正是每次去检查这个属性来判别。<br />
<br />
&nbsp;&nbsp; 拦截器主要源码：<br />
<br />
&nbsp;
<p>&nbsp;if ((!executeAfterValidationPass || secondTime) &amp;&amp; bp == null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bp = getNewBackgroundProcess(name, actionInvocation, threadPriority);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.put(KEY + name, bp);//放入session<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; performInitialDelay(bp); // first time let some time pass before showing wait page<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; secondTime = false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((!executeAfterValidationPass || !secondTime) &amp;&amp; bp != null &amp;&amp; !bp.isDone()) {//是否完毕<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; actionInvocation.getStack().push(bp.getAction<strong><span style="color: red"><strong>());//将后台action的相关信息push到statck，时候的页面可是使用</strong></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (TokenHelper.getToken() != null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.put(TokenHelper.getTokenName(), TokenHelper.getToken());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map results = proxy.getConfig().getResults();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!results.containsKey(WAIT)) <span style="color: red"><strong>{//如果没有配置wait，struts将为你inject一个<br />
</strong></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LOG.warn("ExecuteAndWait interceptor has detected that no result named 'wait' is available. " +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Defaulting to a plain built-in wait page. It is highly recommend you " +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "provide an action-specific or global result named '" + WAIT +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "'.");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // no wait result? hmm -- let's try to do dynamically put it in for you!</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //we used to add a fake "wait" result here, since the configuration is unmodifiable, that is no longer<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //an option, see WW-3068<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FreemarkerResult waitResult = new FreemarkerResult();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; container.inject(waitResult);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; waitResult.setLocation("/org/apache/struts2/interceptor/wait.ftl");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; waitResult.execute(actionInvocation);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Action.NONE;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return WAIT;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if ((!executeAfterValidationPass || !secondTime) &amp;&amp; bp != null &amp;&amp; bp.isDone()) <span style="color: red"><strong>{//如果执行完毕return&nbsp; bp.getResult();<br />
</strong></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; session.remove(KEY + name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; actionInvocation.getStack().push(bp.getAction());</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // if an exception occured during action execution, throw it here<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (bp.getException() != null) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw bp.getException();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return bp.getResult();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // this is the first instance of the interceptor and there is no existing action<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // already run in the background, so let's just let this pass through. We assume<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // the action invocation will be run in the background on the subsequent pass through<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // this interceptor<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return actionInvocation.invoke();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
。<br />
<br />
一个简单的例子（不包含lib）：<br />
&nbsp;&nbsp;<a href="/Files/freeman1984/execAndWait.rar">/Files/freeman1984/execAndWait.rar</a><br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;
 <img src ="http://www.blogjava.net/freeman1984/aggbug/332787.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-09-25 00:59 <a href="http://www.blogjava.net/freeman1984/archive/2010/09/25/332787.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>tomcat user</title><link>http://www.blogjava.net/freeman1984/archive/2010/09/17/332276.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 17 Sep 2010 03:11:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/09/17/332276.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/332276.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/09/17/332276.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/332276.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/332276.html</trackback:ping><description><![CDATA[<strong>Tomcat的配置</strong> <br />
<br />
　　Tomcat的主要配置文件有3个，分别是Tomcat-users.xml、web.xml和server.xml。它先前的版本采用了和Apache一样的conf文本文件。这样的文本文件对于初学者是一种很大的挑战。但现在它采用了比较通用的XML文件格式，这是一种向着开放性、标准性的转变。下面分别对3个文件进行说明。 <br />
<br />
<strong>配置Tomcat-users.xml</strong> <br />
<br />
　　该文件包含了所有Tomcat服务器的注册用户，其中有role（角色）、user（用户）两种信息。下面列举出这个XML文件的部分内容。 <br />
<br />
<table border="1" cellspacing="0" bordercolorlight="#000000" bordercolordark="#ffffff" cellpadding="2" width="540" align="center">
    <tbody>
        <tr>
            <td bgcolor="#e6e6e6">
            <pre>&lt;?xml version='1.0' encoding='utf-8'?&gt;
            &lt;Tomcat-users&gt;
            &lt;role rolename="Tomcat"/&gt;
            &lt;user username="Tomcat" password="Tomcat" roles="Tomcat,admin"/&gt;
            &lt;/Tomcat-users&gt;</pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
　　1.role参数 <br />
<br />
　　Tomcat中保存了一些用户权限，也就是角色，比如admin、Tomcat等。用户还可以自定义，通过""来注册一个角色。它只有rolename一个属性,通过这个属性可以把用户的权限进行分配。 <br />
<br />
　　2.User参数 <br />
<br />
这个数据项中包含了诸如用户名、用户密码、用户权限、用户说明等数据属性。通过下面的这个例子讲解。 <br />
<br />
<table border="1" cellspacing="0" bordercolorlight="#000000" bordercolordark="#ffffff" cellpadding="2" width="540" align="center">
    <tbody>
        <tr>
            <td bgcolor="#e6e6e6">
            <pre>&lt;user username="wudi" password="wudi" fullName="test"
            roles="admin,manager,role1,Tomcat"/&gt;</pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
　　这个语句建立了一个用户，用户名是"wudi"，密码也是"wudi"。这个用户的全称是"test"。"wudi"这个用户拥有的权限是admin、manager、role1、Tomcat。这些用户权限是Tomcat系统默认的。在这里有一些需要声明，Tomcat的系统管理员必须有admin的用户权限,否则无法登陆Tomcat的管理界面。 <br />
<img src ="http://www.blogjava.net/freeman1984/aggbug/332276.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-09-17 11:11 <a href="http://www.blogjava.net/freeman1984/archive/2010/09/17/332276.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>google Analytics 初探</title><link>http://www.blogjava.net/freeman1984/archive/2010/09/16/332234.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 16 Sep 2010 13:37:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/09/16/332234.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/332234.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/09/16/332234.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/332234.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/332234.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;最近公司的在线运营网站要加大市场分析力度，因此公司想要网站的力量统计，包括用户来源分布统计，功能使用率统计等，为了这就来研究下google Analytics 了，一开始没做过，上网搜了搜，看见一篇不错的文章就照着整了，等过段时间看看统计效果咋样，这里转载文章大家看看，写的不错，自己也就先不写啥了，最近在啃他的api ，api地址：<br />
http://code.google.com/intl/zh-CN/apis/analytics/docs/gaJS/gaJSApiBasicConfiguration.html<br />
当然要想用的更好就需要去研究下他的api，包扩一些新特新，和一些统计的api。这篇文章是关于豆瓣网的使用经验，后面还附加了点评网的代码。<br />
&nbsp;&nbsp;&nbsp;内容如下：
<p>豆瓣从今年开始也加入 Google Analytics 的统计阵营。让我们通过它加载的 Google Analytics 源码，简单分析一下它都是怎么应用的。</p>
<p>我们先从豆瓣的源码来看看它的Google Analytics统计代码</p>
<p class="entry_img"><img style="display: inline; filter: ; zoom: 1" alt="豆瓣 Google Analytics 代码" src="http://pic.fairyfish.com/2009/07/douban-ga.jpg" loaded="true" original="http://pic.fairyfish.com/2009/07/douban-ga.jpg" jquery1284642036359="40" /><br />
豆瓣 Google Analytics 代码 </p>
<p>我们知道一般默认的 Google Analytics代码如下：</p>
<p class="entry_img"><img style="display: inline; filter: ; zoom: 1" alt="默认  Google Analytics 统计代码" src="http://pic.fairyfish.com/2009/07/ga-default.jpg" loaded="true" original="http://pic.fairyfish.com/2009/07/ga-default.jpg" jquery1284642036359="41" /><br />
默认 Google Analytics 统计代码 </p>
<p>两相对比，我们就会发现豆瓣加载 <code>ga.js </code>的方式与默认的方式有些不太一样，由于豆瓣并没有采用 https 加密访问，所以撇弃了默认的ga.js加载方式。</p>
<p>默认的统计函数，<code>pageTracker </code>也被豆瓣改成了 <code>_ga</code> ，这个只是名称定义上的区别，并没有什么实质的改变。豆瓣的主要应用是下面两个函数：</p>
<h3>使用 _ga._addOrganic 识别非主流搜索引擎</h3>
<p>再来看豆瓣比默认 Google Analytics 代码增加的部分，那就是多了数个 <code>_ga._addOrganic </code>，这是 Google Analytics 添加自定义搜索引擎的代码。尽管 Google Analytics 对于主流的搜索引擎都能自动识别，但毕竟能识别的是国外的主流搜索引擎，在国内，像搜狐的 Sogou，QQ 的 soso，网易的有道等搜索引擎，<strong>都不能被 Google Analytics 正确识别，而被当作推荐来源</strong>。这时候我们就可以利用<code>_addOrganic</code> 参数来识别这些非主流搜索引擎，如豆瓣的做法。</p>
<h3>使用 _addIgnoredOrganic 忽略关键字</h3>
<p>除了添加自定义搜索引擎，豆瓣在最后还添加了如下这些代码:</p>
<pre>_ga._addIgnoredOrganic("豆瓣");
_ga._addIgnoredOrganic("douban");
_ga._addIgnoredOrganic("豆瓣网");
_ga._addIgnoredOrganic("www.douban.com");
</pre>
<p>这些代码用来把引号中的关键词从搜索引擎的关键词报告中排除，而当成直接点击量来源。</p>
<p>为什么要这么做？因为一个知名的大网站，来自这些品牌词的搜索流量都非常大，常常是排在前几位的搜索关键词来源，而这通常是因为搜索引擎养成现在的人都懒得记网址，直接搜索品牌名来记住域名。这些品牌词对于网站的关键词来源分析并没有很直接的帮助，所以在来自品牌词的流量很大的情况下，可以直接把这些关键词识别成直接点击量来源。</p>
<p>关于<strong>自定义 Google Analytics 搜索引擎</strong>和<strong>排除特定关键词为直接点击量来源</strong>的语法，可以参考<a class="external" title="_addOrganic() 与 _addIgnoredOrganic() 用法介绍" href="http://code.google.com/apis/analytics/docs/gaJS/gaJSApiSearchEngines.html" target="_blank"> Google Code 上关于这方面的详细介绍。</a></p>
<h2>通过 _setVar 识别用户</h2>
<p>当我们登录豆瓣后，再来分析豆瓣的源码，会发现多了一个<code>ga._setVar(&#8221;xxxx&#8221;)</code>的 Google Analytics 参数。</p>
<p class="entry_img"><img style="display: inline; filter: ; zoom: 1" alt="豆瓣使用 Google Analytics 的._setVar参数来跟踪登录用户行为" src="http://pic.fairyfish.com/2009/07/douban-set_var.jpg" loaded="true" original="http://pic.fairyfish.com/2009/07/douban-set_var.jpg" jquery1284642036359="44" /><br />
豆瓣使用 Google Analytics 的._setVar参数来跟踪登录用户行为 </p>
<p><code>_setVar()</code> 函数是 Google Analytics 的用户定义函数，主要用于对特定来源的用户行为进行分类，例如可以对登录浏览的用户设置一个数值，然后在 Google Analytics 后台的<strong>访问者/用户定义</strong> 中查看其浏览属性。</p>
<p class="entry_img"><img style="display: inline; filter: ; zoom: 1" alt="Google Analytics 访问者/用户定义报告" src="http://pic.fairyfish.com/2009/07/user-define.jpg" width="600" loaded="true" original="http://pic.fairyfish.com/2009/07/user-define.jpg" jquery1284642036359="45" /><br />
Google Analytics 访问者/用户定义报告 </p>
<p>分析豆瓣的源码可以知道，豆瓣对每一个登录后的用户，都赋以一个专门的 id 值，这样可以在用户定义报告里，看到整体的登录用户访问行为，乃至每个登录用户的浏览行为。通过这样设定后，豆瓣便可以轻易获取高忠诚度访问用户的访问行为。<a class="external" title="_setVar 设置说明" href="http://code.google.com/apis/analytics/docs/gaJS/gaJSApiBasicConfiguration.html#_gat.GA_Tracker_._setVar" target="_blank">关于_setVar()的更多说明，请参阅 Google Analytics的技术文档</a></p>
<p>如何根据访问者在我的网站上访问的页面或在表单上做出的响应对其进行分类？<a class="external" title=" 如何根据访问者在我的网站上访问的页面或在表单上做出的响应对其进行分类？" href="http://www.google.com/support/googleanalytics/bin/answer.py?hlrm=en&amp;answer=57045" target="_blank">在 Google Analytics 官方的帮助文件，也给出了另外一个应用案例</a></p>
<p>值得注意的是，原来在设置 <code>_setVar()</code> 函数的时候，整个网站的跳出率会出现重大的偏差，不过在<a class="external" title="Google Analytics修正_setVar函数对网站跳出率的影响" href="http://analytics.blogspot.com/2009/01/using-setvar-heres-update-on-bounce.html" target="_blank">最近的google analytics官方博客，指出该bug已经修正</a>，客户在进行这方面设置的时候，还是要注意对比前后数据是否有重大偏差。</p>
<h2>通过 _trackPageview 区分不同类型的评论</h2>
<p>豆瓣上的书评，影评和乐评可以说是豆瓣网站的核心价值所在。一般评论的URL格式如下：</p>
<p class="entry_img"><img style="display: inline; filter: ; zoom: 1" alt="豆瓣上单条评论的URL" src="http://pic.fairyfish.com/2009/07/douban-url.jpg" loaded="true" original="http://pic.fairyfish.com/2009/07/douban-url.jpg" jquery1284642036359="48" /><br />
豆瓣上单条评论的URL </p>
<p>当我们查看该页面的网页源代码时，会发现有趣的现象:</p>
<p class="entry_img"><img style="display: inline; filter: ; zoom: 1" alt="豆瓣单条评论页的 Google Analytics 代码" src="http://pic.fairyfish.com/2009/07/douban_trackpageview.jpg" loaded="true" original="http://pic.fairyfish.com/2009/07/douban_trackpageview.jpg" jquery1284642036359="49" /><br />
豆瓣单条评论页的 Google Analytics 代码 </p>
<p>我们知道，一般 Google Analytics 的<code>_trackPageview()</code> 括弧中的参数是留空的， Google Analytics 会自动捕获网址的 URL 参数，如果在 <code>_trackPageview()</code>括弧中输入特定的数值，那么在 Google Analytics 的报表中，URL 将是我们指定的参数，而不再是我们在地址栏看到的 URL。</p>
<p>如上面的例子，我们在 Google Analytics 中看到的URL将是<span style="color: #ff0000">/book/review/1946018/</span>，而不再是我们在浏览器地址栏看到的<span style="color: #ff0000">/review/1946018/</span></p>
<p>当所在频道是电影或者音乐时，<code>_trackPageview()</code> 中的参数将根据所在频道的属性，变为/movie/xxxxx 或者 /music/xxxxx的数值。</p>
<p>豆瓣通过对的参数进行重新指定，主要有以下的好处：</p>
<p>保证了用户和搜索引擎看到的 URL 比较简短，达到 URL 对用户友好和对搜索引擎友好的目的；而在 Google Analytics 报告中，通过 <span style="color: #ff0000">内容/内容细目/ </span>报告，又能了解到各个频道总的浏览情况。</p>
<p>在GA的<span style="color: #ff0000">内容细目</span>报告中，将会多出 <span style="color: #ff0000">/book/ /music/ /movie/</span> 这样的文件夹来，总而获得各个频道的合计浏览数据。</p>
<p>而如果只是使用默认 <code>_trackPageview()</code>，你将只能得到所有评论页面的浏览数据，而无法得到细分的各个频道的浏览数据。</p>
<p>关于<code>_trackPageview()</code>的具体的使用方法<a class="external" title="_trackPageview中参数的使用" href="http://code.google.com/apis/analytics/docs/gaJS/gaJSApi.html#_gat.GA_Tracker_._trackPageview" target="_blank">可参照 Google Code 的说明</a></p>
<p>注意事项:使用 <code>_trackPageview()</code> 参数重新指定 URL 之后，网站覆盖图的数据将受到影响。<a class="external" href="http://www.google.com/support/analytics/bin/answer.py?hl=cn&amp;answer=66982" target="_blank">可参阅 Google Analytics 的官方帮助文件</a></p>
<p>除了豆瓣使用 <code>_trackPageview()</code> 来对URL进行重写，<a class="external" href="http://www.dianping.com/" target="_blank">大众点评网</a>也采用了类似的做法（应该是比豆瓣更早采用。。。因为是我在点评网任职时候实验的做法;那时候豆瓣还没有使用 Google Analytis 统计代码，呵呵），有兴趣的同学可以自己去研究点评的 Google Analytis 代码。<br />
</p>
<p>文章来自：http://fairyfish.net/2009/06/30/google-analytics-in-douban/<br />
<br />
----------------------------------------大众点评网的的代码，主页的<br />
&lt;script type="text/javascript"&gt;<br />
var pageTracker = _gat._getTracker("UA-464026-1");<br />
pageTracker._addOrganic("soso", "w");<br />
pageTracker._addOrganic("sogou", "query");<br />
pageTracker._addOrganic("yodao", "q");<br />
pageTracker._addOrganic("bing", "q");<br />
pageTracker._addOrganic("gougou", "search");<br />
pageTracker._initData();<br />
pageTracker._trackPageview("home/beijing_all");<br />
&lt;/script&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;这个是子页面search/category/2/10/g328<br />
&lt;script type="text/javascript"&gt;<br />
var pageTracker = _gat._getTracker("UA-464026-1");<br />
pageTracker._addOrganic("soso", "w");<br />
pageTracker._addOrganic("sogou", "query");<br />
pageTracker._addOrganic("yodao", "q");<br />
pageTracker._addOrganic("bing", "q");<br />
pageTracker._addOrganic("gougou", "search");<br />
pageTracker._initData();<br />
pageTracker._trackPageview("dp_searchpv_card");<br />
pageTracker._trackPageview("dp_searchpv_promo");<br />
pageTracker._trackPageview("search/beijing_food_category/g328");<br />
&lt;/script&gt;<br />
可以看出其中的pageTracker._trackPageview("。。。");是动态的也就是页面的，我们可以动态的赋值，这样就可以显示正确的地址了。</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;大家如果有什么这方面的经验可以一同分享下。<br />
<br />
&nbsp;&nbsp;&nbsp; </p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/332234.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-09-16 21:37 <a href="http://www.blogjava.net/freeman1984/archive/2010/09/16/332234.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用tomcat的compression来提高网页加载速度</title><link>http://www.blogjava.net/freeman1984/archive/2010/09/15/332121.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 15 Sep 2010 15:39:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/09/15/332121.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/332121.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/09/15/332121.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/332121.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/332121.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当网站从服器端请求的数据较大时，在有限的带宽下就会造成浏览器加载缓慢，有时候会造成页面没有响应，使用户体验变得很差，tomcat为我们提供了有效的解决了办法，就是使用压缩来解决传输问题。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tomcat使用HTTP/1.1 GZIP&nbsp;来压缩，以减少带宽压力，<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先介绍下gzip：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度。这一般是指WWW服务器中安装的一个功能,当有人来访问这个服务器中的网站时,服务器中的这个功能就将网页内容压缩后传输到来访的电脑浏览器中显示出来.一般对纯文本内容可压缩到原大小的40％.这样传输就快了,效果就是你点击网址后会很快的显示出来.当然这也会增加服务器的负载.&nbsp;一般服务器中都安装有这个功能模块的.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们使用简单的例子来介绍tomcat的压缩使用：（使用firebug查看请求情况）<br />
<br />
&nbsp;首先是一个简单的servlet：<br />
内容：<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;doPost(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)<br />
<img id="Codehighlighter1_117_696_Open_Image" onclick="this.style.display='none'; Codehighlighter1_117_696_Open_Text.style.display='none'; Codehighlighter1_117_696_Closed_Image.style.display='inline'; Codehighlighter1_117_696_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_117_696_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_117_696_Closed_Text.style.display='none'; Codehighlighter1_117_696_Open_Image.style.display='inline'; Codehighlighter1_117_696_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;ServletException,&nbsp;IOException&nbsp;</span><span id="Codehighlighter1_117_696_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_117_696_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.setContentType(</span><span style="color: #000000">"</span><span style="color: #000000">text/html</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PrintWriter&nbsp;out&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;response.getWriter();<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.println(</span><span style="color: #000000">"</span><span style="color: #000000">&lt;!DOCTYPE&nbsp;HTML&nbsp;PUBLIC&nbsp;\</span><span style="color: #000000">"</span><span style="color: #000000">-</span><span style="color: #008000">//</span><span style="color: #008000">W3C</span><span style="color: #008000">//</span><span style="color: #008000">DTD&nbsp;HTML&nbsp;4.01&nbsp;Transitional</span><span style="color: #008000">//</span><span style="color: #008000">EN\"&gt;");</span><span style="color: #008000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.println(</span><span style="color: #000000">"</span><span style="color: #000000">&lt;HTML&gt;</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.println(</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;&nbsp;&lt;HEAD&gt;&lt;TITLE&gt;A&nbsp;Servlet&lt;/TITLE&gt;&lt;/HEAD&gt;</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.println(</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;&nbsp;&lt;BODY&gt;</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.print(</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;&lt;select&gt;&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img id="Codehighlighter1_465_581_Open_Image" onclick="this.style.display='none'; Codehighlighter1_465_581_Open_Text.style.display='none'; Codehighlighter1_465_581_Closed_Image.style.display='inline'; Codehighlighter1_465_581_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_465_581_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_465_581_Closed_Text.style.display='none'; Codehighlighter1_465_581_Open_Image.style.display='inline'; Codehighlighter1_465_581_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">for</span><span style="color: #000000">&nbsp;(</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;i&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">;&nbsp;i&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">100000</span><span style="color: #000000">;&nbsp;i</span><span style="color: #000000">++</span><span style="color: #000000">)&nbsp;</span><span id="Codehighlighter1_465_581_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_465_581_Open_Text"><span style="color: #000000">{<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.print(</span><span style="color: #000000">"</span><span style="color: #000000">&lt;option&gt;testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest</span><span style="color: #000000">"</span><span style="color: #000000">+</span><span style="color: #000000">i</span><span style="color: #000000">+</span><span style="color: #000000">"</span><span style="color: #000000">&lt;/option&gt;</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.println(</span><span style="color: #000000">"</span><span style="color: #000000">&lt;/select&gt;</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.println(</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;&nbsp;&lt;/BODY&gt;</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.println(</span><span style="color: #000000">"</span><span style="color: #000000">&lt;/HTML&gt;</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.flush();<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.close();<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>
<br />
我们将输出一个十万个选项的下拉框，在不使用的压缩的时候：<br />
<img height="476" alt="" src="http://www.blogjava.net/images/blogjava_net/freeman1984/g1.JPG" width="821" border="0" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;请求数据达到9m ,大概的计算下我的下载用时（4m长城宽带）：9*1024/(4*1024/8)=18m&nbsp; ，加上多人共享带宽，也就是差不多20m。firebug显示20.96。<br />
<br />
&nbsp;&nbsp;&nbsp; 这个速度网站体验肯定是很差的，接下来使用tomcat的压缩以后看看：<br />
<br />
&nbsp;&nbsp; 当然是要对其进行配置：<br />
&nbsp;&nbsp; 有以下几个参数可以使用：<br />
<br />
&nbsp;&nbsp;&nbsp; compression="on"&nbsp;<br />
是否启用压缩 on为启用（文本数据压缩） off为不启用， force 压缩所有数据<br />
compressionMinSize1="2048"&nbsp;<br />
当超过最小数据大小才进行压缩<br />
&nbsp;noCompressionUserAgents="gozilla, traviata"&nbsp;<br />
哪些客户端发出的请求不压缩，默认是不限制<br />
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain"<br />
配置想压缩的数据类型，默认是&nbsp;<code>text/html,text/xml,text/plain<br />
</code><br />
配置以后是这样的：<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">&lt;</span><span style="color: #000000">Connector&nbsp;port</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">8088</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;protocol</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">HTTP/1.1</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connectionTimeout</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">20000</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redirectPort</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">8443</span><span style="color: #000000">"</span><span style="color: #000000"><br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;compression</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">on</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;compressionMinSize1</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">2048</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;noCompressionUserAgents</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">gozilla,&nbsp;traviata</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;<br />
<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;compressableMimeType</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">text/html,text/xml,text/javascript,text/css,text/plain</span><span style="color: #000000">"</span><span style="color: #000000">/&gt;</span></div>
<br />
启动后再看：<br />
<img height="523" alt="" src="http://www.blogjava.net/images/blogjava_net/freeman1984/g2.JPG" width="803" border="0" /><br />
&nbsp;<br />
这次数据被压缩到274.7k，响应速度也减少了一半，当然，服务器的数据压缩和浏览器的数据解压都需要使用时间。<br />
<br />
&nbsp; <br />
例子完毕，<br />
&nbsp;&nbsp; 当然tomcat的压缩技术还有很多其他的特性，然而对于大数据量的请求不光是要使用这种技术，还需要在其他地方下功夫，比如ajax技术，缓存等等，<br />
也希望大家补充学习，谢谢。<br />
&nbsp; <br />
<img src ="http://www.blogjava.net/freeman1984/aggbug/332121.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-09-15 23:39 <a href="http://www.blogjava.net/freeman1984/archive/2010/09/15/332121.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>各种浏览器的userAgent</title><link>http://www.blogjava.net/freeman1984/archive/2010/09/10/331704.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 10 Sep 2010 12:32:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/09/10/331704.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/331704.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/09/10/331704.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/331704.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/331704.html</trackback:ping><description><![CDATA[<strong>IE</strong> <br />
&nbsp; 而IE各个版本典型的userAgent如下： <br />
&nbsp; <span style="color: blue">Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) <br />
&nbsp; Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2) <br />
&nbsp; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) <br />
&nbsp; Mozilla/4.0 (compatible; MSIE 5.0; Windows NT)</span> <br />
&nbsp; 其中，版本号是MSIE之后的数字。 <br />
<br />
<strong>Firefox</strong> <br />
&nbsp; Firefox几个版本的userAgent大致如下： <br />
&nbsp; <span style="color: blue">Mozilla/5.0 (Windows; U; Windows NT 5.2) Gecko/2008070208 Firefox/3.0.1 <br />
&nbsp; Mozilla/5.0 (Windows; U; Windows NT 5.1) Gecko/20070309 Firefox/2.0.0.3 <br />
&nbsp; Mozilla/5.0 (Windows; U; Windows NT 5.1) Gecko/20070803 Firefox/1.5.0.12</span>&nbsp; 其中，版本号是Firefox之后的数字。 <br />
<br />
<strong>Opera</strong> <br />
&nbsp; Opera典型的userAgent如下： <br />
&nbsp; <span style="color: blue">Opera/9.27 (Windows NT 5.2; U; zh-cn) <br />
&nbsp; Opera/8.0 (Macintosh; PPC Mac OS X; U; en) <br />
&nbsp; Mozilla/5.0 (Macintosh; PPC Mac OS X; U; en) Opera 8.0</span>&nbsp; <br />
&nbsp; 其中，版本号是靠近Opera的数字。 <br />
<br />
<strong>Safari</strong> <br />
&nbsp; Safari典型的userAgent如下： <br />
&nbsp; <span style="color: blue">Mozilla/5.0 (Windows; U; Windows NT 5.2) AppleWebKit/525.13 (KHTML, like Gecko) Version/3.1 Safari/525.13 <br />
&nbsp; Mozilla/5.0 (iPhone; U; CPU like Mac OS X) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/4A93 Safari/419.3 </span><br />
&nbsp; 其版本号是Version之后的数字。 <br />
<br />
<strong>Chrome</strong> <br />
&nbsp; 目前，Chrome的userAgent是： <br />
<span style="color: blue">Mozilla/5.0 (Windows; U; Windows NT 5.2) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13</span>&nbsp; <br />
&nbsp; 其中，版本号在Chrome之后的数字。 <br />
<br />
<strong>Navigator</strong> <br />
目前，Navigator的userAgent是： <br />
<span style="color: blue">Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080219 Firefox/2.0.0.12 Navigator/9.0.0.6</span> <br />
其中，版本号在Navigator之后的数字。<br />
文章转自：http://www.javaeye.com/topic/243064
<img src ="http://www.blogjava.net/freeman1984/aggbug/331704.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-09-10 20:32 <a href="http://www.blogjava.net/freeman1984/archive/2010/09/10/331704.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>