2009年11月21日星期六

[note]Servlet中监听器(listener)与过滤器(filter)的区别

监听器(listener):
         用于监听事件的发生,与swing中的监听器类似。可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,如监听在线用户数量,当增加一个HttpSession时,给在线人数加1。编写监听器需要实现相应的接口,编写完成后在web.xml文件中配置一下,就可以起作用了,可以在不修改现有系统基础上,增加web应用程序生命周期事件的跟踪。
         常用的监听器如下:

Listener接口                                       Event类
ServletContextListener                       ServletContextEvent
ServletContextAttributeListener         ServletContextAttributeEvent
HttpSessionListener                           HttpSessionEvent
HttpSessionActivationListener            HttpSessionEvent
HttpSessionAttributeListener             HttpSessionBindingEvent
HttpSessionBindingListener                HttpSessionBindingEvent
ServletRequestListener                       ServletRequestEvent
ServletRequestAttributeListener         ServletRequestAttributeEvent

过滤器(filter):

          用于对服务器请求的过滤,它与监听器最大的不同是:监听器只能够监听请求而无法改变原来的请求、而过滤器可以改变任何请求。所有的过滤器都实现了filter接口中的doFilter方法来实现对请求的过滤,doFilter方法又使用了FilterChain这个传入的值实现过滤链,来进行层层的过滤。过滤器也同样需要对web.xml进行设置。

Servlet过滤器的适用场合:
A.认证过滤
B.登录和审核过滤
C.图像转换过滤
D.数据压缩过滤
E.加密过滤
F.令牌过滤
G.资源访问触发事件过滤
H. 其他

2009年11月20日星期五

[转]Ajax 应用程序中实现实时数据推送

<<<在IBM devleopwork上发现的一篇好文章,主要是先介绍了AJAX实现实事推送的三种方法:短论询、长轮询和流通道。又主讲了AJAX操作TCP套接字连接的两种方法:基于Adobe Flex 或 OpenLaszlo。这里只截取了三种轮询方法的定义,个人认为是我看到的文章里最清晰简洁的定义,原文地址为:http://www.ibm.com/developerworks/cn/web/wa-aj-socket/?ca=drs-tp4608>>>

短轮询

短轮询也称为高频轮询,就是我在本文开头处介绍的技术。这种方法在以下情况中表现最好:

  1. 有足够的带宽可用。
  2. 根据统计数据,大多数时候,请求都能获得更新。例如,股市数据就总是有可用更新。
  3. 使用 HTTP 1.1 协议。设置 keepAlive=true,因而,同一个套接字连接始终保持活动状态,并可重用。

长轮询

长 轮询是用于更新服务器数据的另外一种方法。这种方法的理念就是客户端建立连接,服务器阻塞连接(通过使请求线程在某些条件下处于等待状态),有数据可用 时,服务器将通过阻塞的连接发送数据,随后关闭连接。客户端在接收到更新后,立即重新建立连接,服务器重复上述过程,以此实现近于实时的通信。然而,长轮 询具有以下缺陷:

  1. 一般的浏览器默认允许每台服务器具有两个连接。在这种情况下,一个连接始终是繁忙状态。因而,UI 只有一个连接(也就是说,能力减半)可用于为用户请求提供服务。这可能会导致某些操作的性能降低。
  2. 仍然需要打开和关闭 HTTP 连接,如果采用的是非持久连接模式(keepAlive=false),那么这种方法的代价可能极高。
  3. 这种方法近于实时,但并非真正的实时。(当然,某些外部因素总是不可控的,比如网络延时,在任何方法中都会存在这些因素。)

流通道

流通道(streaming channel)与长轮询大致相同,差别在于服务器不会关闭响应流。而是特意保持其处于打开状态,使浏览器认为还有更多数据即将到来。但是,流通道也有着自己的缺陷:

  1. 最 大的问题就是数据刷新(flushing)。过去,Web 服务器会缓存响应数据,仅在接受到足够的字节数或块数后才会发送出去。在这种情况下,即便应用程序刷新数据,也仍然会由服务器缓存,以实现优化。更糟的 是,如果在客户端和服务器之间存在代理服务器,那么代理也可能会为自身之便缓存数据。
  2. 如果发现套接字将打开较长的时间,某些浏览器实现可能会自行决定关闭套接字。在这种情况下,通道需要重新建立。

通常,第一个问题可通过为每个流响应附加垃圾有效载荷来解决,使响应数据足以填满缓冲区。第二个问题可通过 “保持活动” 或按固定间隔 “同步” 消息来欺瞒浏览器,使浏览器认为数据是以较慢的速率传入的。

这 些解决方案适用的用例范围狭窄。所有这些方法都已经在 Internet 上的某些解决方案中得到了应用。然而,这些解决方案都遭遇了相同的问题:缺乏可伸缩性。典型情况下,要阻塞一个请求,您需要阻塞处理请求的线程,因为如今 几乎所有应用服务器都会执行阻塞 I/O。即便不是这样,Java™ 2 Platform, Enterprise Edition (J2EE) 也未提供为 HTTP 请求和响应执行非阻塞 I/O 的标准。(Servlets 3.0 API 可解决这一问题,因为这些 API 中包含 Comet Servlet。)

至此,您需要具备非阻塞 I/O(NIO)服务器,客户端应用程序通过它进行连接。由于此类套接字是纯 TCP 二进制套接字,因而将实现以下目标:

  1. 由于服务器端具有 NIO,因而可实现更高的可伸缩性。
  2. 响应缓存的问题不复存在,因为这个套接字直接受应用程序的控制。

基于上述说明,有必要指出这种方法的四个缺点:

  1. 由于使用的是二进制 TCP 套接字,因而应用程序无法真正地利用 HTTPS 层提供的 SSL 安全性。所以,要求数据安全性的应用程序可能需要提供自己的加密工具。
  2. 通常情况下,服务器套接字将在 80 以外的端口上运行,如果防火墙仅允许来自端口 80 的流量,将出现问题。因而,可能需要进行一些端口配置。
  3. Ajax 客户端无法通过后端打开 TCP 套接字连接。
  4. 即便 Ajax 客户端能够执行 open 函数,也无法理解二进制内容,这是因为 Ajax 使用的是 XML 或 JSON(基于文本)格式。

在这篇文章中,我要强调的是如何真正地绕开第三个和第四个问题。如果您能够处理安全性和防火墙问题,那么其他问题也能得到处理。这种做法的获益极为显著。

您可为应用程序实现最大程度的实时服务器推送行为(不考虑网络延时等外部因素),您将获得高度可伸缩的解决方案(以同时连接的客户端数量为准)。




[转]Java Web开发字符编码详解

来源:[url]http://www.wangchao.net.cn/bbsdetail_1757458.html[/url]

一、概要
  在Java应用程序非凡是基于WEB的程序中,经常碰到字符的编码问题。为了防止出现乱码,首先需要了解JAVA是如何处理字符的,这样就可以有目的地在输入/输出环节中增加必要的转码。其次,由于各种服务器有不同的处理方式,还需要多做试验,确保使用中不出现乱码。
二、基本概念
2.1 JAVA中字符的表达
  JAVA中有char、byte、String这几个概念。char 指的是一个UNICODE字符,为16位的整数。byte 是字节,字符串在网络传输或存储前需要转换为byte数组。在从网络接收或从存储设备读取后需要将byte数组转换成String。String是字符串,可以看成是由char组成的数组。String 和 char 为内存形式,byte是网络传输或存储的序列化形式。
举例:

String ying = “英”;
char ying = ying.charAt(0);
String yingHex = Integer.toHexString(ying);
82 F1
byte yingGBBytes = ying.getBytes(“GBK”);
GB编码的字节数值
D3 A2
 

2.2 编码方式的简介
  String序列化成byte数组或反序列化时需要选择正确的编码方式。假如编码方式不正确,就会得到一些0x3F的值。常用的字符编码方式有ISO8859_1、GB2312、GBK、UTF-8/UTF-16/UTF-32。
       ISO8859_1用来编码拉丁文,它由单字节(0-255)组成。
  GB2312、GBK用来编码简体中文,它有单字节和双字节混合组成。最高位为1的字节和下一个字节构成一个汉字,最高位为0的字节是ASCII码。
  UTF-8/UTF-16/UTF-32是国际标准UNICODE的编码方式。 用得最多的是UTF-8,主要是因为它在对拉丁文编码时节约空间。

UNICODE值 UTF-8编码
U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

三、J2SE中相关的函数
String str =”英”;
//取得GB2312编码的字节
byte[] bytesGB2312 = str.getBytes(“GB2312”);

//取得平台缺省编码的字节(solaris为ISO8859_1,windows为GB2312)
byte[] bytesDefault = str.getBytes();

//用指定的编码将字节转换成字符串
String newStrGB = new String(bytesGB2312, “GB2312”);
//用平台缺省的编码将字节转换成字符串(solaris为ISO8859_1,windows为GB2312)
String newStrDefault = new String(bytesDefault);

//用指定的编码从字节流里面读取字符
InputStream in = xxx;
InputStreamReader reader = InputStreamReader( in, “GB2312”);
char aChar = reader.read();

四、jsp、数据库的编码
4.1 JSP中的编码
(1) 静态声明:
CHARSET有两个作用:
JSP文件的编码方式:在读取JSP文件、生成JAVA类时,源JSP文件中汉字的编码
JSP输出流的编码方式:在执行JSP时,往response流里面写入数据的编码方式
(2) 动态改变:在往response流里面写数据前可以调用response.setContentType(),设定正确的编码类型。
(3) 在TOMCAT中,由Request.getParameter() 得到的参数,编码方式都是ISO8859_1。所以假如在浏览器输入框内输入一个汉字“英”,在服务器端就得到一个ISO8859_1编码的(0x00,0xD3,0x00,0xA2)。所以通常在接收参数时转码:
String wrongStr = response.getParameter(“name”);
String correctStr = new String(wrongStr.getBytes(“ISO8859_1”),”GB2312”);
在最新的SERVLET规范里面,也可以在获取参数之前执行如下代码:
request.setCharacterEncoding(“GB2312”);

2009年11月18日星期三

picture


2009年11月16日星期一

[note]常在河边走、哪有不湿鞋。被闭包灭了

如题,今天被一个闭包导致的bug困扰了大概15分钟。代码如下(基于jQuery):

    for (var i=1; i<3; i++) {
        $('label.labelTag:first').clone().text("第"+ (i+1) +"条跑道").click(function() {
                console.log(i);
                Runway.moveToRunway(i);
        }).appendTo(wrapper);
    }

看似天衣无缝,但执行的时候 打印出来的i都是“3”!!!

原因就是闭包作怪,jQuery的click函数是设置DOM元素被点击时的动作,它的参数只有一个函数引用。这里就是

function() {
       console.log(i);
       Runway.moveToRunway(i);
}

这个函数在非闭包语言中肯定不能执行,因为变量i未定义!!!在JS中却可以,因为闭包所以只要i被引用了,它就一直会存在。
说到这里,原因也明白了。i一直在由于i++的原因,一直增长到了3。把代码修改成以下形式就又可以使用了!

    for (var i=1; i<3; i++) {
        $('label.labelTag:first').clone().text("第"+ (i+1) +"条跑道").attr("onClick",
                "Runway.moveToRunway("+ i +");").appendTo(wrapper);
    }

这样就不引用函数了,产生不了闭包!

2009年11月13日星期五

[note][精品]Javascript的prototype属性与new机制

<<<<<<<<<<今天看了一篇博客,把我搞得一头雾水,最后终于理解了,在这里写下自己的一些心得>>>>>>>>>>

Object的prototype属性

w3school是这么解释的:
Prototype
对该对象的对象原型的引用。对于所有的对象,它默认返回 Object 对象的一个实例。
prototype的行为类似于C++中的静态域,
将一个属性添加为prototype的属性,这个属性将被该类型创建的所有实例所共享,但是这 种共享是“只读”(无法修改属性)的。在任何一个实例中只能够用自己的同名属性覆盖这个属性,而不能够改变它。换句话说,对象在读取某个属性时,总是先检查自身域的属性表,如果有这个属性,则会返回这个属性,否则就去读取prototype域,返回protoype域上的属性。另外,JavaScript允许protoype 域引用任何类型的对象,因此,如果对protoype域的读取依然没有找到这个属性,则JavaScript将递归地查找prototype域所指向对象 的prototype域,直到这个对象的prototype域为它本身或者出现循环为止。下面的代码可以证明以上解释。

function Dog(name) {
    this.set=function(name1) {
         this.name = name1;
    }
}
Dog.prototype = {
    name:'zhou',
    shout: function() { console.log("I am " + this.name); }
};
var dog1 = new Dog();
dog1.set('xu');
dog1.shout();
Dog.prototype.shout();

运行结果为:
I am xu
I am zhou

new机制

new是Javascript的一个关键字,用于新建一个对象。如下所示:

function class() {}
var obj = new class();

那么new的内部机制是什么样的呢?new其实可以看成一个函数,代码如下:

function newObj(class, arguments) {
     var o ={};
     if (class && typeof class == 'function') {
              o.prototype = class.prototype;
              o.constructor = class;
              class.apply(o, arguments);
     }
     return o;
}

 可见new所做的事是:
  • 新建一个空对象;
  • 设置空对象的prototype与constructor;
  • 执行构造函数;
  • 返回构造完毕的对象;
例子分析:

代码如下:
function Dog(name) {
this.name = name;
Dog.prototype = {
shout: function() { alert("I am " + this.name); }
};
}
var dog1 = new Dog("Dog 1");
dog1.shout();

看上去OK,但其实有错:“Object doesn’t support this property or method”。原因可以通过new函数的内部机制知道:

     var o ={};
     if (class && typeof Dog== 'function') {
              o.prototype = Dog.prototype;
              o.constructor = Dog;
              o.name = name;
              Dog.prototype = {
                       shout: function() { alert("I am " + this.name); }
              };     
     }
     return o;
 
可以知道新建的对象根本没有shout属性。那么建立一个标准类的方法又是如何呢?

function Dog(name) {
        this.name = name;
}
Dog.prototype = {
       constructor: Dog,
       shout: function() { /* ... */ },
       run: function() { /* ... */ }
};

以上才是一个比较好的建立类的方法。把这个拆成new的机制看看如何呢?代码如下

     Dog.prototype = {
             constructor: Dog,
             shout: function() { /* ... */ },
             run: function() { /* ... */ }
     };
     var o ={};
     if (class && typeof Dog== 'function') {
              o.prototype = Dog.prototype;
              o.constructor = Dog;
              o.name = name;
     }
     return o;

因为Dog.prototype得赋值先执行了,所以这回o虽然没有新的方法,但是o.prototype有,所以同样能执行!

[转]Javascript对象的constructor属性

<<<<<<<<<<<<<<<<<<<注意:constructor属性是对象才有的,不是类所有的属性>>>>>>>>>>>>>>>>>>


constructor属性始终指向创建当前对象的构造函数。比如下面例子:

  1. // 等价于 var foo = new Array(1, 56, 34, 12);  
  2. var arr = [1563412];  
  3. console.log(arr.constructor === Array); // true  
  4. // 等价于 var foo = new Function();  
  5. var Foo = function() { };  
  6. console.log(Foo.constructor === Function); // true  
  7. // 由构造函数实例化一个obj对象  
  8. var obj = new Foo();  
  9. console.log(obj.constructor === Foo); // true  
  10.  
  11. // 将上面两段代码合起来,就得到下面的结论  
  12. console.log(obj.constructor.constructor === Function); // true 

但是当constructor遇到prototype时,有趣的事情就发生了。

我们知道每个函数都有一个默认的属性prototype,而这个prototype的constructor默认指向这个函数。如下例所示:

  1. function Person(name) {  
  2.     this.name = name;  
  3. };  
  4. Person.prototype.getName = function() {  
  5.     return this.name;  
  6. };  
  7. var p = new Person("ZhangSan");  
  8.  
  9. console.log(p.constructor === Person);  // true  
  10. console.log(Person.prototype.constructor === Person); // true  
  11. // 将上两行代码合并就得到如下结果  
  12. console.log(p.constructor.prototype.constructor === Person); // true 

当时当我们重新定义函数的prototype时(注意:和上例的区别,这里不是修改而是覆盖),constructor属性的行为就有点奇怪了,如下示例:

  1. function Person(name) {  
  2.     this.name = name;  
  3. };  
  4. Person.prototype = {  
  5.     getName: function() {  
  6.         return this.name;  
  7.     }  
  8. };  
  9. var p = new Person("ZhangSan");  
  10. console.log(p.constructor === Person);  // false  
  11. console.log(Person.prototype.constructor === Person); // false  
  12. console.log(p.constructor.prototype.constructor === Person); // false 

为什么呢?

原来是因为覆盖Person.prototype时,等价于进行如下代码操作:

  1. Person.prototype = new Object({  
  2.     getName: function() {  
  3.         return this.name;  
  4.     }  
  5. }); 

而constructor属性始终指向创建自身的构造函数,所以此时Person.prototype.constructor === Object,即是:

  1. function Person(name) {  
  2.     this.name = name;  
  3. };  
  4. Person.prototype = {  
  5.     getName: function() {  
  6.         return this.name;  
  7.     }  
  8. };  
  9. var p = new Person("ZhangSan");  
  10. console.log(p.constructor === Object);  // true  
  11. console.log(Person.prototype.constructor === Object); // true  
  12. console.log(p.constructor.prototype.constructor === Object); // true 

怎么修正这种问题呢?方法也很简单,重新覆盖Person.prototype.constructor即可:

function Person(name) {  
    this.name = name;  
};  
Person.prototype = new Object({  
    getName: function() {  
        return this.name;  
    }  
});  
Person.prototype.constructor = Person;  
var p = new Person("ZhangSan");  
console.log(p.constructor === Person);  // true  
console.log(Person.prototype.constructor === Person); // true  
console.log(p.constructor.prototype.constructor === Person); // true