`

DWR整体流程分析(一)(转)

    博客分类:
  • dwr
 
阅读更多

DWR整体流程分析 
(一)三个基本的准则 对于理解ajax理解dwr有一定的帮助 
1、浏览器:应用而非内容(非显示) 
我们在以往的web编程中,浏览器仅仅是为了显示页面而存在,但是现在有了ajax,浏览器不单单就是为了显示,为什么这么说呢?因为以往的web编程中,浏览器是把服务器发送给浏览器的这个页面给显示出来,仅仅完成这样的一些工作,它其中也嵌入一些javascript的脚本,但是这时候的脚本仅仅就是为了让页面显示得更加美观而设计的没有其他的用处,但是有了ajax之后呢,浏览器当中ajax的javascript脚本不单单就是为了美化这些页面而存在,它还有一部分作用就是对服务器端传过来的数据我需要进行分析,需要要进行处理,然后才能显示在浏览器端。大家都知道,ajax从服务器端传过来的数据有可能是response.text或者是response.xml,如果是text的话,也许就可能在浏览器中直接显示,但是如果是xml的文件的话,浏览器会先把这个xml文件解析之后才显示出来。这个解析的过程也就是相当于是一种应用,而非内容的显示了,所以说浏览器方不仅仅是内容了,应该是一种应用。所以是应用而非内容。 
2、服务器:数据而非内容 
以往服务器端仅仅是发送给浏览器端它需要的页面,这个页面也就是内容,但是现在服务器端不需要发送一些重复性的数据了,这个重复性的数据也就是相当于是我们编写的页面中的页头页角框架等等一些重复性的。它们在服务器端和客户端之间传输,占用一定的网络带宽,传输的数据量变大,速度也会下降的。所以在ajax当中,我们传输到服务器端进行处理的东西仅仅是页面当中的一小块,而服务器端返回的仅仅是我们需要的那一部分数据,然后在浏览器端通过它的应用,通过它的设置来显示我们所要的东西,所以说服务器端是发送给浏览器的数据,而不是内容了。 
3、编程变得严谨 
因为我们在以往的浏览器当中呢,我们仅仅是通过js的脚本来进行一些页面的美观,使页面便得跟花哨一些,但是现在浏览器端它处理的内容将是对数据的处理,它仅仅是一种应用,所以说对javascript的脚本来说,这种弱类型的语言,它的编程就需要更加的严谨。不单单是为了显示在页面上而已。对于我们学java这种强类型的语言来说呢,对这种弱类型的语言的学习有一定的困难。也就是很不适应。要对javascript脚本的学习要有一种耐心细心的精神。 
(二)DWR的请求处理 
当页面发出请求,Servlet被调用是在什么时机? 
我们先来建一个名叫TestSerlet的web工程 
看看我们的Servlet这么写的:

 

package com.lukuijun.demo;   
import java.io.IOException;   
import javax.servlet.ServletException;   
import javax.servlet.http.HttpServlet;   
import javax.servlet.http.HttpServletRequest;   
import javax.servlet.http.HttpServletResponse;   
public class TestServlet extends HttpServlet {   
    @Override  
    public void doGet(HttpServletRequest request, HttpServletResponse response)   
            throws ServletException, IOException {   
        doPost(request,response);   
    }   
    @Override  
    public void doPost(HttpServletRequest request, HttpServletResponse response)   
            throws ServletException, IOException {   
        System.out.println("请求被调用");   
    }   
}  

 

接着我们配置一下web.xml的部署文件: 

 

<servlet>   
  <servlet-name>TestServlet</servlet-name>   
  <servlet-class>com.lukuijun.demo.TestServlet</servlet-class>   
</servlet>   
<servlet-mapping>   
  <servlet-name>TestServlet</servlet-name>   
  <url-pattern>/lukuijun/*</url-pattern>   
</servlet-mapping>  

 

注意:这个url-pattern的格式你是可以随便写的,格式由你自己定,但是在访问的时候也要按照你写的这个格式来的。 
接着我们在index.jsp里面引入script资源:

<script type="text/javascript" src="/TestServlet/lukuijun/lukuijun.js"></script>

也就是我在加载index.jsp这个页面,将这个script资源引入,而引入的这个资源lukuijun.js并不存在。但是它引用的路径src是我们这个应用TestServlet中的lukuijun/lukuijun.js,也是是我们在web.xml里面配置的<url-pattern>/lukuijun/*</url-pattern>的请求路径。 
说明一点:如果采用在Tomcat里配置context的虚拟路进的话,如果把context的path配置为"",即是path="",那么在配置script的src的时候就不需要应用名TestServlet,总之一句话,/lukuijun/lukuijun.js前面的应用名和context的path属性一样,而且必须以"/"打头。 
接着我们在Tomcat里面发布运行一下看看结果: 
在控制台里面打出一句话:请求被调用 
这里我们看看当我请求index.jsp这个Servlet会执行那些操作,当我们请求index.jsp时,接着就调用servlet打印出"请求被调用"。 
一般来说发给servlet的请求呢一般都是在一个页面,假如说在index.jsp这个页面,在这个页面里呢,我们是调用一些链接,这个链接里面包括一些请求的路径,可能是/lukuijun/这个路径,有可能是form的action来发送的请求到它处理。但是我们容易忽略一点:就是在这个页面请求加载的时候,它需要引入一些资源,引入的资源包括文本文件、脚本文件等等。把它们引入的时候呢,如果路径也是servlet可以处理的,那么它会先处理引用资源的这个路径的文件。这里呢就是我在加载这个index.jsp文件的时候,我引入src对应的资源。但是这个资源呢实际上是不存在的,也就是没有这个资源,但是我注意到机器是靠我的指令来执行的,我说这个servlet要对这个请求格式的资源进行处理,所以我把这个src资源路径写成了我刚才创建的TestServlet可以处理的路径。所以我引入这个资源的时候会去调用这个servlet,然后这个servelt会打印输出这样一句话:请求被调用。 
讲此目的:不要忽略一点,因为往往都会在主页面当中发送请求对其处理,但是对于我所说的在页面加载index.jsp的时候,srcipt引入的src这些资源也会被servlet进行处理,这一点一定要注意,而且这一点在dwr里面也有所体现。正式有了它们的引用,有了它们的前处理,才使得我们有些内容,脚本文件,得以顺利的执行。 
好,现在来看看工程Demo1: 

<script type="text/javascript" src="/Demo1/dwr/engine.js"></script>   
<script type="text/javascript" src="/Demo1/dwr/util.js"></script>   
<script type="text/javascript" src="/Demo1/dwr/Demo.js"></script> 

 engine.js是引擎 

util.js是工具类 
Demo.js是我们配置的,我们需要在远程调用的java方法,这个java类会通过服务器端的dwr框架的一些内容,返回给客户端的一个脚本文件。这些东西,前两个可以说是有型的,在dwr.jar下我们会看见有这么两个文件engine.js和util.js。所以引入它们很正常。但是路径src却是servlet请求路径。所以在引入这些资源的时候,都需要在servlet中进行处理。引入engine.js需要到servlet进行处理,处理的时候都做些什么?它主要是对这个文件当中的一些页面的id进行处理,它里面有一些变量呢需要在服务器端发送给客户端,在客户端注册进来。引入engine.js,servlet基本上不做任何处理,因为其中的内容仅仅是一些工具的方法,来让我们在客户端调用使用的,比较方便。引入Demo.js,需要在客户端根据dwr的配置文件dwr.xml所指定的信息来生成我们所需要的一个脚本文件。这个脚本文件就是我们客户端要调用它来完成对服务器端方法的调用。 
明白一点:对客户端发送的请求,也许这个请求是页面发过去,也许是通过javascript的src引入的资源,不管哪种形式,最终都要通过servlet来进行处理。前提是它们请求的资源 
的路径要满足设置的servlet所请求的路径(url-pattern)。DWR对请求的处理一定不能忽略,否则不可能对dwr有深入理解。 
(三)服务器的脚本生成 
在Demo1工程中,服务器脚本的生成是通过engine,js,并不是生成engine.js,而是为engine.js里面的内容进行赋值。看一下engine.js这个文件: 

** The original page id sent from the server */   
dwr.engine._origScriptSessionId = "${scriptSessionId}";   
/** The session cookie name */  
dwr.engine._sessionCookieName = "${sessionCookieName}"; // JSESSIONID   
/** Is GET enabled for the benefit of Safari? */  
dwr.engine._allowGetForSafariButMakeForgeryEasier = "${allowGetForSafariButMakeForgeryEasier}";   
/** The script prefix to strip in the case of scriptTagProtection. */  
dwr.engine._scriptTagProtection = "${scriptTagProtection}";   
/** The default path to the DWR servlet */  
dwr.engine._defaultPath = "${defaultPath}";   
/** Do we use XHR for reverse ajax because we are not streaming? */  
dwr.engine._pollWithXhr = "${pollWithXhr}";   
/** The read page id that we calculate */  
dwr.engine._scriptSessionId = null;  

 原始的page id是从服务器端发送过来的,什么意思呢?这些内容是从服务器端发送过来的,这个文件是放在客户端的,但是它从服务端发送过来,它是以什么形式发送过来?发送过来以后是怎么给它们赋值的?这个就设计到dwr源码的问题。以后会讲解,今天明白一点:我在这个引擎脚本用的时候,在之前,我必须要对这些变量进行赋值,否则,dwr框架就无法应用。但是赋值的时机在哪儿?在什么情况下为它赋值,这就是dwr请求处理当中的引入的资源文件。engine.js这个资源文件是已经存在的,但是为什么还要引入它?而且路径还必须写成servlet的请求处理路径。目的就是为了给文件里面的这些变量进行初始化。为了验证下,我们可以把这些变量中有用的值打印出来。 

打印原始的ScriptSessionId:dwr.engine._origScriptSessionId,这个在index.jsp的什么地方写呀?因为这个页面加载的时候,会先去处理engine.js这个脚本引擎文件,通过它的处理,会把值赋值给engne.js里面的变量。所以目前状况只要这个页面加载,这些变量就已经赋值了。所以在engine.js脚本引擎加载后就可以对其中的变量获得的值进行打印。 
在加载engine.js后,执行下面一个函数

function show(){   
alert("origScriptSessionId:" + dwr.engine._origScriptSessionId);   
}  

 打印出origScriptSessionId:DFCB69D86F4E1AC9CF3900A68164E40A,这个就是服务器端发送给浏览器端的出示的ScriptSessionId,我记住它的后四位E40A,然后在刷新一下页面,重新提交一下打印出origScriptSessionId:DFCB69D86F4E1AC9CF200A68164E3CA,现在后四位E3CA这个和原来的不一样了。造成不一样的原因是什么呢?还是在engine.js,在页面请求加载的时候,它会先去处理engine.js文件,当刷新的时候实际上是又对服务器发送了一次请求,服务器又会给我们返回engine.js里面变量的值赋给它们,每一次请求这些变量的值都是不一样的。如果不刷新重复提交,origScriptSessionId给我们赋值后,它的值不刷新是不会变的。出发再请求了servlet路径下的engine.js文件,它才会给我们重新赋值。 

服务器端脚本生成,第一个就是引擎脚本文件engine.js在加载后,服务器会为我们生成一些变量的值。看一下变量dwr.engine._origScriptSessionId,它是原始的scriptSessionId,它和httpSessionId有所区别:因为httpSessionId它存储在客户端,存在客户端的作用就是当客户端发出请求的时候,它会把这个httpSessionId发送出去,发送出去过后,服务器端端有一个session,它会通过这个session id来判断这个用户是属于哪个session里的,然后到session里去取它的用户信息。如果这个session id不存在,服务器就会为这个客户端创建一个,然后发送给给客户端保存。然后客户端下次再访问的时候,就会把这个id发送给服务器端了,这个session是保存在服务器端的。但是现在这里的原始的scriptSessionId是保存在客户端的。就是客户端每发送一个请求,服务器端都会产生一个scriptSessionId,这个scriptSessionId是针对页面来讲的。在源码中,会详细介绍这一部分。这一部分也是很重要的,因为它提出了新的session,而不是我们原来的http session。它是脚本方面的一个session并且存储在客户端.注意区别我们平时的http 
session。 
引擎当中还有一个session:dwr.engine._getJSessionId,它这个dwr.engine._getJSessionId是一个方法:

dwr.engine._getJSessionId =  function() {   
    var cookies = document.cookie.split(';');   
        for (var i = 0; i < cookies.length; i++) {   
        var cookie = cookies[i];   
        while (cookie.charAt(0) == ' ') cookie = cookie.substring(1, cookie.length);   
        if (cookie.indexOf(dwr.engine._sessionCookieName + "=") == 0) {   
            return cookie.substring(dwr.engine._sessionCookieName.length + 1, cookie.length);   
        }   
    }   
    return "";   
};  

 这个dwr.engine._getJSessionId是一个方法,就相当于httpSessionId。dwr.engine._getJSessionId的作用也是存储在客户端,但是他会产生一个id,这个id的产生方式就是通过这个引擎脚本当中的方法来产生的。看看它的实现:首先它会从浏览器方获得所有的cookie,这些cookie是以分号分割的。然后取出每一个cookie。cookie是以键值对的形式存在的。前面是键然后=后面是值。我们要getJSessionId,前面就应该是一个键,以key=id形式存在的。这里先取出所以cookie,然后循环每一个cookie,判断这个cookie的第0个字符是不是空的,如果是空的话就从第一个位置开始取。因为前面有很多空格,cookie要忽略它的空格。所以有cookie.charAt(0) == ' '判断。这么循环下来之后呢,把前面所有的空格都会消除掉了,最后的形式就是key=value这么一种,而不是前面是一大堆的空格,去掉所有空格后,在判断cookie.indexOf(dwr.engine._sessionCookieName + "=") == 0如果cookie是以dwr.engine._sessionCookieName=开头的话,他就会返回=后面的值,也就是那个SessionId。 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics