2011年12月27日星期二

迷失--剧评

世界只存在吾心,不在别处;所以无需怯弱,也不必沾沾自喜。
"再也不会有这样的一部剧,如此清晰地碰触到我的灵魂,让我泣不成声,让我豁然开朗,让我感动心碎,让我终于明了。 明了的,不仅仅是剧中的所谓谜题和答案;而是明了了这是一场怎样的人生。" 
注:先要告诉读者,我很感动,而且看懂了。此处用词一定要声情并茂、梨花带雨、欲罢不能。先把自己摆在一定的高度。 "——有些人会懂;有些人不会懂。 
不懂的人们,请不必着急。是因为你还没有遇到一件触碰你灵魂的事情。关于"灵性"的东西,一旦你懂了,你就全懂了。" 注:再告诉读者,你不懂是因为你条件不够,而且你一旦懂了与XX相关的东西,那么你就全懂了,所以,那些看不懂的,你们要加油了,而不是在那里废话。另注:XX可用很多词代替,比如"人性"啊,"缘分"啊,"宿命"啊,"灵魂"啊,反正越扯不清的越好。 
"LOST风靡美剧市场六年之久,其中扑朔迷离、细枝末节的无数"奇案",无数"问题",大家都期盼获得一个终极答案,于是对大结局抱有极高的期望。尽管我对结局有过种种猜测和幻想,甚至认为无论怎样结局也很难令人满意了。" 注:要勇于承认大家公认的问题。没有共同点,大家就没得谈了。 "但我万万没想到,大结局的震撼和感人远远出乎了我的意料,它不但解决了几乎全部遗留问题,给出了终极答案,而且还令我们对人生有了重新的思考:我们为什么会遇到一些人,为什么与他们发生了一些事情,为什么厮守,为什么错过,为什么有些事情有结果,而有些没有,我们的命运是注定的吗,这一切都是真实的吗?什么又是"真实"?我们来到这个世界上是有意义的吗,我们为何而来,又去往何方?…… " 注:注意段落结构,先强调剧本的确出人意料的给出了终极答案,但在要说明答案是什么的时候,笔锋急转,开始思考更多的问题。这些问题可以包括很多,比如为什么我们会出生,为什么我们会遇到我们的父母,为什么这是真的,为什么这是真的又变成了假的,为什么假的又不是真的,为什么…… "第六季开播以来,大家都以为Juliet的行动成功了,未来改变了,大家过上了和谐安宁的幸福生活。看到结局这集,再想起那句时刻回想耳边的"what happened,happended"不禁怅然。其实所谓"平行世界",更确切地说是已逝的亡者的灵魂空间。在这里每一个人都不自觉地牵挂着自己最在乎的东西,最爱的人,曾经在前世人生里最想得到的,都在这里实现。——那不是因为未来改变了,飞机从未坠毁;而是因为在这个人人创造的空间里,有最诚挚的梦想在闪耀。 " 注:"想到……(的时候),不禁怅然"此句万能,切记切记。
原来大家都以为未来改变了,其实,错,未来从未改变,这只是大家的集体幻觉。 "这就是为什么Jack有个"幻想出来"的儿子,还和他修好了"父子情";John有了爱他的父亲,而不是无情夺取他一颗肾的骗子;Daniel继续他最喜欢的音乐,成了钢琴家,而不是物理学家;James化身警察而不是罪犯;Ben兼具了善良宽容的美好秉性,服侍着生病的父亲,而不是亲手毒死他;这也就是为什么Boone对Hugo说,我都在这等了你们好久了……等等等等。
 每一个人在通往天堂的路途之前,都在自我反省和救赎。在无意地"修补"他们的前世人生,弥补着他们的终身遗憾。而且,他们会被无形中安排,与生命中曾经最重要的人再次相遇,再次发生联系。就如Jack的父亲Christian对他解释的那样"这是一个大家一起创造的世界,为的是找回所有人。没有谁是独自死去的。在你生命里那些重要的人,要和你,一起走完这段旅程。" Desmond最先醒悟,所以才会在真实世界里笑意盈盈地"乖乖"让Charles带路,去做"该做"的事情。也所以才会在灵魂世界里积极地召集众人,创造他们"回忆"的机会。所以,当Jack在前些集几次发现脖子上的血迹时,我们都和他一样不明白究竟怎么回事,直到最后他抚摸父亲的棺木,他的整个人生,他那些最珍贵的片段是那样地强烈地被激发出来。 " 注:然后开始解释各种各样的事情,因为这是幻觉,所以你怎么解释都可以。 "他终于懂了。 " 注:你们懂了没,没懂?他都懂了,你还不懂?! 
"作为观众,我曾经幻想过最终答案到底是什么呢?没想到,最终答案其实就是在天堂之前的一段温馨的对话。我想,我们每一个都在冥冥中追逐着,询问着,不解着……但许许多多的问题,等你走到终点才发现,它们并没有什么意义。真正有意义的是我们脚下走过的这段过程,我们遇到的人,我们的情感,我们的感知,我们潜在的人性的光辉。 " 注:给出总结性的答案,就是这一切都没有意义,所以,你还要什么答案?!
我们也可以这样理解,这个电视剧本身没有意义,看了也白看,真正有意义的是我们看美剧的过程。 "在教堂里的对话是这样的: Jack问,爸爸,我不明白,既然你死了,你怎么能在这? 父亲说,那你是怎么在这的? Jack顿悟,痛苦地说,我也死了。。 父亲抱住痛苦的儿子说,没事的孩子,没事的,没事的。我爱你,孩子。 Jack:我也爱你。爸爸,你……你是真实的吗? 父亲笑了:是啊,我是真实的,你也是真实的。所有在你生命发生的事情,每一件事情,都是真实的。所有你生命中遇到的人,都是真实的。 Jack:那我们为什么都聚到这里? 父亲:孩子,其实没有一个人是独自死去的。这是一个我们一起创造的世界,为的是寻找到彼此。 Jack:那又是为的什么? 父亲:为了铭记你的这一生,为了放下它,然后前行。 Jack:前行,去哪里呢? 父亲微笑着:来,我们一起去看看吧。 " 注:此处附上原文。 
"影片把两个世界的场景不断切换,回到真实世界里,看到Jack临死前,回到了故事发生的起点,看着最终得救的寥寥几人乘着飞机离开,他终于释然地闭上眼睛。回想第一季第一集,Jack在这里躺下,惊恐地睁开眼睛。这一段路途,可谓圆满。 如果Jack还是穿着第一集的西服死去,那一切就成了幻想,编剧就小儿科了;妙就秒在这不同,Jack已经不是原来那个Jack了,这里发生的一切全是真实的。他真的经历过的,如今,他也真的拯救了小岛,牺牲了自己。" 注:此处再告诉大家,这其实不是梦境,一切都是真实的。
读者: 呔!怎么前后矛盾? 靠,不矛盾你不就看懂了么,你看懂了,我还怎么装? "再追究那山洞里的"小岛心脏"究竟是什么科学原理,我认为已经意义不大。因为到了最终结局,你会发现,那其实已经不是你所关心的问题了。这听上去似乎有些讽刺,但是仔细想想,这不也就类似人生吗?那些我们奋力追逐,拼命要弄个所以然的"问题",等到结束的那天才发现:都是一场空。 " 注:这里告诉读者,你经过以上忽悠,你的问题已经意义不大了,既然意义不大,你还找什么答案呢? "剧中的主角和我们每一个凡人一样,有过梦想,有过挫败,有种种的遗憾和不完整,也都有死亡。我们以为许多事情都是随机发生的,但其实上帝既有他详细的预先安排,也允许每一个人的自由选择意识。LOST是带有宗教色彩的故事,更确切的理解,我认为是更为接近灵魂的东西。 " 注:继续上岗上线,凡事没有逻辑的,都扯上宗教,凡事搞不清楚的,都扯上灵魂。你能解释上帝是什么吗,你知道灵魂是什么吗? 
"这些人们,一上岛就追寻答案:这是哪啊?谁是Jacob啊,从来没见过。数字按钮就是吓唬人的吧,为什么非要按它?我们是被陷害到岛上的吧?…… 我们也曾经和主角们一样,恨不得一把抓住Jacob问无数问题,问个究竟,砸破砂锅问到底。但是有时候,那答案在你还不能理解的时候,你懂得了吗? Jacob就好似上帝的一个喻体,默默地从小关注每一个人,关注他们的成长,关注他们的喜怒哀愁。他不是不能给你答案,而是那些并不是重要的东西,也不是你能力所及可以改变的。 " 注:Jacob说:你们不要问我这么多问题,其实我也是打酱油的。 "现在看是悲剧,或许是好事;现在觉得完全不可能发生的,或许都会在将来发生。但是这是一个集体行动,每个人都不是孤独前行,或许冥冥中一切天定,或许冥冥中改变历史。我们影响自己的同时,也在影响着周围,影响着每一个和我们和联系的人。就好比Jacob选候选人一样,圣经里也谈到,上帝之所以给人赋予生命都是有目的,上帝有一个很宏大的计划,这涉及到每一个人。 那么,这一切的一切的终点在哪里呢? 我想,只有此生结束时,才会知晓了。 " 注:最后一句话亮点,也就是说,等到死,你才知道答案。那你还想知道答案吗? 
"我非常喜欢,尊敬,和赞叹这个LOST大结局,因为这是一个看似开放的不开放结局。它只给了一个答案。但是无数的人可以给出无数的理解,每一个人的角度不同,看到的世界就完全不同。 亦如,这场人生。" 注:说明其实是有答案的,而且理解不同答案不一样,那么你知道答案了吗?
--
言念君子 温其如玉

2011年12月22日星期四

Java初始化顺序

初始化(initialization)其实包含两部分:
1.类的初始化(initialization class & interface)
2.对象的创建(creation of new class instances)。
因为类的初始化其实是类加载(loading of classes)的最后一步,所以很多书中把它归结为"对象的创建"的第一步。其实只是看问题的角度不同而已。为了更清楚的理解,这里还是分开来。

顺序:
应为类的加载肯定是第一步的,所以类的初始化在前。大体的初始化顺序是:
类初始化 -> 子类构造函数 -> 父类构造函数 -> 实例化成员变量 -> 继续执行子类构造函数的语句

下面结合例子,具体解释一下。
1。类的初始化(Initialization classes and interfaces),其实很简单,具体来说有:
(a)初始化类(initialization of class),是指初始化static field 和执行static初始化块。
例如:
class Super {
        static String s = "initialization static field"; //初始化static field,其中"= "initialization static field" "又叫做static field initializer

        // static初始化块,又叫做static initializer,或 static initialization block
        static {
        System.out.println("This is static initializer");
}
}
btw,有些书上提到static initializer 和 static field initializer 的概念,与之对应的还有 instance initializer 和 instance variable initializer。例子中的注释已经解释了其含义。

(b)初始化接口(initialization of interface),是指初始化定义在该interface中的field。

*注意*
--initialization classes 时,该class的superclass 将首先被初始化,但其实现的interface则不会。
--initialization classes 时,该class的superclass,以及superlcass的superclass 会首先被递归地初始化,一直到java.lang.Object为止。但initialiazation interface的时候,却不需如此,只会初始化该interface本身。
--对于由引用类变量(class field)所引发的初始化,只会初始化真正定义该field的class。
--如果一个static field是编译时常量(compile-time constant),则对它的引用不会引起定义它的类的初始化。

为了帮助理解最后两点,请试试看下面的例子:
public class Initialization {
        
        public static void main(String[] args) {
                
                System.out.println(Sub.x); // Won't cause initialization of Sub, because x is declared by S, not Sub.
                                         // 不会引起Sub类的初始化,因为x是定义在Super类中的
                System.out.println("-------------------------");
                System.out.println(Sub.y); // Won't cause initialization of Sub, because y is constant.
                                         // 不会引起Sub类的初始化,因为y是常量
                System.out.println("-------------------------");
                System.out.println(Sub.z = 2004); // Will cause initialization of Sub class
// 将会引起Sub的初始化
        }
}

class Super{
        static int x = 2006;
}

class Sub extends Super {
        
        static final int y = 2005;
        
static int z;
        
static {
                System.out.println("Initialization Sub");
        }
}

2。对象的创建(creation of new class instances),稍微有点烦琐,具体的步骤如下
(a) 所有的成员变量—包括该类,及它的父类中的成员变量--被分配内存空间,并赋予默认值。(Btw,这里是第一次初始化成员变量)
(b) 为所调用的构造函数初始化其参数变量。(如果有参数)
(c) 如果在构造函数中用this 调用了同类中的其他构造函数,则按照步骤(b)~(f)去处理被调用到的构造函数。
(d) 如果在构造函数中用super调用了其父类的构造函数,则按照步骤(b)~(f)去处理被调用到的父类构造函数。
(e) 按照书写顺序,执行instance initializer 和 instance variable initializer来初始化成员变量。(Btw,这里是第二次初始化成员变量)
(f) 按照书写顺序,执行constructor的其余部分。

*注意*
成员变量其实都被初始化2次,第一次是赋予默认值,第二次才是你想要设定的值。

最后看一个例子:
public class InitializationOrder {

        public static void main(String[] args) {
                Subclass sb = new Subclass();
        }
}

class Super{
        
        static {
                System.out.println(1);
        }
        
        Super(int i){
                System.out.println(i);
        }
}

class Subclass extends Super implements Interface{
        
        static {
                System.out.println(2);
        }        
        
        Super su = new Super(4);
        
        Subclass() {
                super(3);
                new Super(5);
        }
}

interface Interface{
        static Super su = new Super(0);
}

稍微解释一下:
首先,Java虚拟机要执行InitializationOrder类中的static 方法main(),这引起了类的初始化。开始初始化InitializationOrder类。具体的步骤略去不说。
接着,InitializationOrder类初始化完毕后,开始执行main()方法。语句Subclass sb = new Subclass()将创建一个Subclass对象。加载类Subclass后对其进行类初始化,但因为Subclass有一个父类Super,所以先初始化Super类,初始化块static {System.out.println(1);}被执行,打印输出1;
第三,Super初始化完毕后,开始初始化Subclass类。static {System.out.println(2);}被执行,打印输出2;
第四,至此,类的加载工作全部完成。开始进入创建Subclass的对象过程。先为Subclass类和其父类Super类分配内存空间,这时Super su 被附值为null;
第五,执行构造函数Subclass()时,super(3)被执行。如前面(d)所说,Super类的构造函数Super(int i){….}被调用,并按照步骤(b)~(f)来处理。因此,递归调用Super类的父类Object类的构造函数,并按照步骤(b)~(f)来初始化Object类,不过没有任何输入结果。最后打印输出3;
第六,如前面(e)所说,初始化成员变量su,其结果是打印输出4;
第七,如前面(f)所说,执行new Super(5),并打印输出5;
最后,Subclass虽然实现了接口Interface,但是初始化它的时候并不会引起接口的初始化,所以接口Interface中的static Super su = new Super(0)自始至终都没有被执行到。

① 类属性 (静态变量) 定义时的初始化,如上例的 static String a = "string-a";
    ② static 块中的初始化代码,如上例 static {} 中的 b = "string-b";
    ③ 对象属性 (非静态变量) 定义时的初始化,如上例的 String c = "stirng-c";
    ④ 构造方法 (函数) 中的初始化代码,如上例构造方法中的 d = "string-d";


--
言念君子 温其如玉

2011年12月20日星期二

GPL VS LGPL

GPL 是 GNU General Public License (GNU 通用公共许可证)的缩写形式;LGPL 是 GNU Lesser General Public License (GNU 宽通用公共许可证)的缩写形式,旧称 GNU Library General Public License (GNU 库通用公共许可证);GFDL 是 GNU Free Documentation License (GNU 自由文档许可证)的缩写形式。它们是自由软件(Free Software)的通用版权认证协议,由自由软件基金会(FSF)制定和发布。

  • 基于 GPL 的软件允许商业化销售,但不允许封闭源代码。
  • 如果您对遵循 GPL 的软件进行任何改动和/或再次开发并予以发布,则您的产品必须继承 GPL 协议,不允许封闭源代码。
  • 基于 LGPL 的软件也允许商业化销售,但不允许封闭源代码。
  • 如果您对遵循 LGPL 的软件进行任何改动和/或再次开发并予以发布,则您的产品必须继承 LGPL 协议,不允许封闭源代码。但是如果您的程序对遵循 LGPL 的软件进行任何连接、调用而不是包含,则允许封闭源代码。

GPL(General Public License)和LGPL( Lesser General Public License)是GNU的两种License。越来越多的自由软件(Free Software)使用GPL作为其授权声明,如果对GPL一点都不了解,有可能在使用自由软件时违反了GPL的授权。如果是个人或不正规的公司倒也无所 谓,但如果是有规模的公司,恐怕会有被起诉的风险。

在使用Log4cpp时我想到了授权的事情,于是有了兴趣对GPL做一下了解。这是必要的,因为公司也维护了一个验证过的自由软件库,里面包含的自由软件除了功能上是可靠的,另外就是一定可以被私有使用的,否则后果很严重(黎叔很生气!)。

Log4cpp最初的版本使用GPL作为授权声明的,在0.2.1版本以后改用更为宽松的 LGPL。LGPL最初是Library GPL的缩写,后来改称作Lesser GPL,即为更宽松的GPL。当一个自由软件使用GPL声明时,该软件的使用者有权重新发布、修改该软件,并得到该软件的源代码;但只要使用者在其程序中 使用了该自由软件,或者是使用修改后的软件,那么使用者的程序也必须公布其源代码,同时允许别人发布、修改。也就是说,使用GPL声明下的的自由软件开发 出来的新软件也一定是自由软件。

LGPL是GPL的变种,也是GNU为了得到更多的甚至是商用软件开发商的支持而提出的。与 GPL的最大不同是,可以私有使用LGPL授权的自由软件,开发出来的新软件可以是私有的而不需要是自由软件。所以任何公司在使用自由软件之前应该保证在 LGPL或其它GPL变种的授权下。

以下是Richard Stallman关于GPL和LGPL的论述

为什么你不应该使用LGPL发布你的下一个库

GNU计划在使用库时有两个首要的许可证.一个是GNU LGPL(库GPL);另一个是普通的GNU GPL.选择不同的许可有很大的不同:选择LGPL允许在私有程序中使用该库;选择普通的GPL则只允许在自由软件中使用它.

关于哪一种许可证对指定的库是最好的这一问题实际上是一个策略问题,它取决于实际情况.当前,大多数的GNU库被采用LGPL,这意味着我们只使用着其中的一个策略,而忽略了另一个. 所以现在我们在寻求更多以普通的GPL许可证形式发布的库.

私有软件开发者有金钱上的优势;自由软件开发者需要相互之间利用各自的优势.对一个库采用普通的GPL对自由软件开发者的优势要大于对私有软件开发者: 他们可以使用的库对于私有软件开发者是不可利用的.

使用普通的GPL并不是对于所有的库都有好处.在某些情况下更有理由来使用LGPL.最常见的情况就是当一个自由库的特性可以很容易地被私有软件以其他可替代库来实现.在这种情况下,库不能给与自由软件任何特别的优势,因而最好还是为LGPL发布该库.

这也就是为什么我们为GNU C 库选择LGPL.总之,有很多的其他C库;我们使用GPL发布该库,将迫使私有软件开发者不得不使用其它的库--对他们来说这不成问题,而我们则有了麻烦.

然而,当一个库所提供的功能是非常独特的时候,如GNU Readline, 情况就大不一样了. Readline库可实现输入编辑和记录交互式程序操作,这在别处通常是不可多得. 在GPL下发布它并限制它只能在自由程序中使用, 这我们的社团是一个重要的促进.至少今天某个应用程序之所以是自由软件,只是因为它必需要用到Readline.

如果我们收集一些强大的、私有软件中没有相类似东西的、采用GPL的库,它们将提供一系列有用 的模块用于新的自由软件的构造. 这对于将来的自由软件开发将是一个显著的优势, 一些项目将为了使用这些库而考虑使软件自由化. 大学的项目是易于被影响的;而且今天,随着某些公司开始考虑使软件自由化, 甚至一些商业项目也会由此受到影响.

私有软件开发者试图否认自由竞争的重要性, 他们会拼命说服作者不要将库使用GPL来发布. 例如,他们会呼吁利己主义,信誓旦旦地说如果我们让他们在私有软件产品中使用代码,将有"更多的用户"用到该库. 流行是一种诱惑,它使一个库开发者倾向于相信这种观点:社会首先需要的是促进一种库的流行;.

但是我们不应该听从这种诱惑,因为如果我们联合起来,我们可以做得更好.我们这些自由软件开发 者应该相互支持. 通过发布只能为自由软件使用的库,我们可以互相帮助,使彼此的自由软件包优于其它的私有替代品. 整个自由软件运动将会有更多的机会,因为自由软件作为一个整体将会在竞争中表现更佳.

因为"LGPL(Library GPL)"的称呼传达了关于这一问题的错误观点,我们计划将称呼改为"次级GPL(Lesser GPL)".事实上要更换名称要花一定的时间,但你不必再等--你可以现在就发布应用GPL许可证的库.


-- 
言念君子 温其如玉

--
言念君子 温其如玉

2011年12月16日星期五

面包配方

面包机食谱
—、带盖白土司带盖白土司(750g)
配料:高筋面粉1/2杯(385g)温开水1杯(235g)盐3/4小勺(3g)糖1/2大勺(20g)脱脂奶粉2大勺(14.5g)白油1/2大勺(17.5g)酵母3/4小勺(2.1g)做法: 1.按菜单键选择全麦档,选择重量750g,选择烧色(可根据您的不同喜好选择) 2.按下开始键,开始自动搅拌、发酵、烘烤 3.约3个半小时左右,面包机发出"嘀嘀嘀"的提示音,说明烘烤结束 4.最后切片完工
面包机的方子:一、普通咸味面包配料 750克 1000克面包 水 1杯+1大勺 1+2/5杯 植物油 3大勺 4大勺盐1+1/2小勺 2小勺 糖 2大勺 2大勺 面包粉 3+1/4杯 4+1/3杯 干酵母 1+5/6小勺 2小勺添加顺序应与配料表中一致,建议使用精致菜油或调和油适用程序:普通面包
二、全麦面包
配料 750克 水 1杯+3大勺全麦粉 1/4杯植物油 2大勺 盐 1小勺 红糖 4大勺奶粉 3大勺 面包粉 3杯干酵母 1+1/2小勺适用程序:全麦面包
三、快速全麦面包
配料 750克 水 1杯+3大勺全麦粉 1/4杯植物油 2大勺 盐 1小勺 红糖 4大勺奶粉 3大勺 面包粉 3杯干酵母 1+1/2小勺适用程序:快速面包
四、健康面包
配料 750克 水 1杯+3大勺全麦粉 2/3杯植物油 2大勺 盐 1小勺 红糖 1大勺面包粉 2+1/2杯 干酵母 1+1/2小勺适用程序:全麦面包
五、玉米面包
配料 750克 玉米面包预拌浓缩粉 1+2/5杯 面包粉 7/8杯 干酵母 2小勺玉米面包预拌浓缩粉为丹麦KMC公司生产的预拌面粉,适用程序:法式面包
六、菠菜包
配料 750克 鸡蛋 1个 盐 1小勺糖 1/4杯奶粉 2大勺 面包粉 1+1/4杯 干酵母 1+1/2小勺 黄油 3大勺面粉改良剂 2小勺菠菜糊 2/3杯菠菜湖制作方法:取250克洗净、空干水份的嫩菠菜,切成厚约2厘米的段,用搅拌机打成细腻糊状,用量杯称取2/3杯。与其他配料一起放入面包桶,其他操作方法一样。适用程序:普通面包
七、咖啡包
配料 750克 水加鸡蛋(一个) 2/3杯 蜂蜜 1大勺 奶粉 1/2杯盐 3/4小勺 糖 1/3杯 面包粉 2+2/3杯 干酵母 2小勺 黄油 2+1/2大勺速溶咖啡粉 1/5杯适用程序:甜面包
八、提子面包
配料 750克 水加鸡蛋(一个) 2/3杯 蜂蜜 1大勺 奶粉 1/2杯盐 3/4小勺 糖 1/3杯 面包粉 2+2/3杯 干酵母 2小勺 香蕉 1/3根 黄油 2+1/2大勺 葡萄干 1/3杯再面粉搅拌过程中蜂鸣器响时将葡萄干加入到料桶中适用程序:甜面包
九、香蕉面包
配料 750克 水加鸡蛋(一个) 2/3杯 蜂蜜 1大勺 奶粉 1/2杯盐 3/4小勺 糖 1/3杯 面包粉 2+2/3杯 干酵母 2小勺 香蕉 1/3根 黄油 2+1/2大勺香蕉切片后,将所有原料加完以后加到料桶中,然后选择"甜面包"程序,开始操作。最好在开始和面10分钟后加入黄油,味道更佳。
十、波萝吐司
配料 750克 水加鸡蛋(一个) 2/3杯 蜂蜜 1大勺 奶粉 1/2杯盐 3/4小勺 糖 1/3杯 面包粉 2+2/3杯 干酵母 2小勺 黄油 2+1/2大勺波萝糊 1/5杯波萝切片后,放入搅拌机中打成糊状。适合程序:甜面包。
十一、椰丝吐司
配料 750克 水加鸡蛋(一个) 2/3杯 蜂蜜 1大勺 奶粉 1/2杯盐 3/4小勺 糖 1/3杯 面包粉 2+2/3杯 干酵母 2小勺 黄油 2+1/2大勺椰丝 1/5杯适合程序:甜面包。
十二、杂粮健康面包
配料 750克 水 1杯全麦面包预拌粉(KMC) 7/8杯 面包粉 1+2/5杯 蜂蜜 2大勺 盐 1+1/2小勺 干酵母 2小勺 适合程序:全麦面包。十三、燕麦苹果面包 配料 750克 水加鸡蛋(一个) 2/3杯蜂蜜 1大勺 奶粉 1/2杯 盐 3/4小勺糖 1/3杯 面包粉 2+2/3杯 干酵母 2小勺 苹果(糊状) 1个黄油 2+1/2大勺 麦片 1/4杯 适合程序:甜面包。
十四、香橙面包
配料 750克 橙汁加鸡蛋(一个) 2/3杯 蜂蜜 1大勺 奶粉 1/2杯盐 3/4小勺 糖 1/3杯 面包粉 2+2/3杯 干酵母 2小勺 香蕉 1/3根 黄油 2+1/2大勺适合程序:甜面包。
十五、高蛋白面包
配料 750克水加鸡蛋清(约1/4杯) 2/3杯 蜂蜜 1大勺奶粉 1/2杯 盐 3/4小勺糖 1/3杯 面包粉 2+2/3杯 干酵母 2小勺黄油 2+1/2大勺 适合程序:甜面包。

--
言念君子 温其如玉

2011年12月2日星期五

[转贴]左小雨:2012,真正的崩溃在滞胀中开场

    一直有朋友来问我,将来会怎么样?我这几年来一直是这么安慰他们说:没事的,没事的。2010年,我告诉大家没事的。2011年,我还是告诉大家没事的。很多人在论坛上说,中国要崩溃了,人民币要变成冥币,一文不值。对这些话,我都是当作笑话,笑笑而过。

  中国这个社会哦,现在很浮躁,不但希望发财的人很浮躁,希望崩溃的人也很浮躁。希望崩溃的那些人他们现在就希望中国一下子完蛋了,然后房价一下子掉下来了,他们可以结婚了。那么今天我就要对这些朋友说,你们想得实在是太好了。如果事情真的是这样发展,出现了美国1929年那样的大萧条的话,那就不叫崩溃了。你们想一想吧,1929年底美国股市崩盘,1945年美国打败法西斯联盟,成为世界上最强大的国家。这当中只有16年的时间。16年就发展成为世界第一强权,如果这样的"崩溃"落到中国的头上,那大概大家晚上做梦都要笑醒了。
  
  所以在这里我很郑重地告诉各位朋友,中国绝对不可能出现苏联式的崩溃,也绝对不可能出现美国式的崩溃,中国的崩溃将是有中国特色的真正的崩溃。
  
  首先,为什么中国不可能出现苏联式的崩溃?大家都知道,苏联崩溃源于轻工业的产能不足,物资紧张,人民生活极其困顿。我还记得苏联崩溃的时候我父亲去莫斯科,带去的牛仔裤子,小电池什么的都成为当地人抢购的紧俏物资。马路上老太太摆个小摊卖东西,卖什么呢?四根胡萝卜。各处的商店空空如也,除了一些刚刚从中国倒卖来的日用品,其他几乎什么都没有。当时苏联就是这么一副惨象。那今天中国会出现这种情况么?不可能,今天你要牛仔裤?你说好了,十万条还是二十万条?随便要。中国现在是什么情况?是严重的产能过剩。根本不是没有东西,而是东西生产出来卖不出去。所以苏联式的崩溃,也就是人民币变冥币,是不可能在中国出现的。
  
  那么美国式的呢?29年大萧条源于贫富差距过大和产能过剩,这和今天中国的情况极其相似,那为什么中国不会出现美国式的崩溃呢?大家要知道,不管是29年的崩溃,80年代的崩盘,还是最近的次贷,都伴随着一个现象出现,那就是大量银行的破产。银行的破产阻碍了金融系统的运作,让整个社会陷入突然性的失血,大量企业纷纷破产。然后人们才看到大崩溃。那么现在大家看看,这在中国可能吗?中国的大银行都是国有的,是国家信用支持的产物。中国的银行破产,几乎等同于国家信用的破产,而国家信用的破产,直接威胁到执政党的地位,这在中国是绝对不会被允许的。因此,中国也不可能出现美国式的大崩溃。
  
  那么中国会是什么样的情况呢?我大概概括一下,那就是小规模危机持续不断,整个社会不断失血,以相当慢的速度,逐渐进入僵尸社会,最后进入真正的崩溃。
  
  以温州为例,温州大家都知道,最近很多老板跳楼跑路。这是什么?这是美国式的崩溃,地下银行崩盘,流动性消失,企业倒闭,老板跳楼,这是经典的1929式的崩溃。但是这个时候哦,你忽然发现,有中国特色的救星到了。跑路的老板,被请回来处理问题。怎么处理啊?他是因为做不下去没有办法了才跑路了,到国外呆了一周就能脱胎换骨解决问题呢?不可能。无非就是国家支持,给你一笔钱,让你把问题解决掉,把厂子维持下去。那么大家想,这些企业,它们是因为经营不下去了倒闭的,你给了它们钱,维持自然可以了,可是利润呢?没有利润,或者利润不足以支付正常的利息的话,那么这些企业就开始变成吸血的僵尸。它们需要你源源不断,小规模地给于支持,同时却不能提供任何值得一提的回报。而更可怕的是,随着国际和国内环境的变化,这些企业只能越来越糟糕。那么民营企业变成僵尸,国企呢?最近的报道说,铁道部获得了2000亿。铁道部自从上次出轨事件后,所有的工程陷入停顿。欠了多少钱呢?据说有两万亿之多。利润呢?1-2亿。大家可以想像,1-2亿的利润如何去支撑2万亿的利息?那给它2000亿能不能解决其债务问题?显然杯水车薪,根本不可能起作用。那这2000亿是干啥的呢?维持。还是维持。
  
  那么这家给2亿,那家给2000亿,这七七八八的维持金到底是从什么地方来的呢?很显然,要么从税收来,要么印。那么税收的情况怎么样呢?从四月份开始,中国各地方政府的城投债,纷纷违约,地方债务的二级市场,几乎死掉。地方政府根本拿不出钱来支付其债务的利息。更不要说,拿出钱来支持那些僵尸企业了。上海等地,已经开始借新债,还旧债。中央政府还算好点,但是要救助这些僵尸企业,那也是心有余而力不足。那么接下来就只有一条路,那就是印。印的结果是什么?大家都知道,那就是通胀。中国的通胀高不高?你们每一个人身受之,比我清楚。所以为什么前面说了半天,都是说维持两个字?那就是因为当局也知道,不能多印啊,多印了这个物价涨起来要死人的。所以今天印一个亿,明天再印一个亿,就只能这么慢慢熬。中国经济就陷入了一放松就通胀,一收缩就破产的死循环,这就是滞胀。
  
  最后会出现什么呢?两个现象,第一个是加税。前几天看谢国忠的谈话。谢先生是我一直很钦佩的一个学者,分析问题非常切中要点,但是这老兄大概是因为美国绿卡没拿到,对中国总是抱着一些不切实际的幻想。他说中国要减税。这话一说出来,恐怕礼堂里要哄堂大笑了。地方政府已经穷到连利息都支付不了了,你还要减税?请问你减税的基础何在?你减税了你的军队还要不要养?稳定还要不要维持?公务员还要不要加薪?地方公债还要不要还?中国绝对不可能减税,即便有,也是名义上的,这里刚减了营业税,那里马上房产税又搞起来了。不管是什么税种,其意义只有一个,那就是从家庭消费部门,和企业生产部门抽钱。钱都叫你们抽去了,那消费还能起来么?内需还能发展么?你们能够干的,不过就是拆东墙补西墙,寅吃卯粮而已。
  
  因为是不断地维持,所以中国不会立马崩溃,但是会缓慢地慢慢地下滑。这个过程会很长,估计超过十年。然后十年以后你们会看到什么?那就是民营经济基本全部死亡。都是一个个靠国家支持的僵尸企业,而生产能力也会逐渐下滑。大量产能闲置,十年后,生锈的生锈,发霉的发霉。这个时候可能会出现一定程度的消费物资短缺。然后还会出现什么?那就是严重的人口老龄化。也就是说,中国改革的时间窗口只有十年,十年之后,天皇老子也救不了,但是这最宝贵的十年,注定会在全社会的稳定中逐渐地失去。所以这才是最严重的危机,这才是真正的崩溃。

--
言念君子 温其如玉

2011年11月23日星期三

亲门耳番

1.今天是____年__月__日,农历_______,距离______还有_____天。今天节目的主要内容有:_____、_____、______。下面请听详细内容。

2.____在钓鱼台国宾馆亲切会见了____,双方进行了亲切友好的会谈。____高度赞赏了____,并对____一贯坚持"一个中国"的原则表示感谢。

3.____出访____,会见了____,_______高度赞扬中__两国关系,对____表示欢迎,并强烈谴责了___国家____的做法。

4.______会议在北京隆重召开。_____致开幕词。____以____票支持、0票反对、1票弃权通过一项____决议。

5.外交部发言人____就____发表声明,对____表示遗憾,提出**,并将继续关注。

6.______就____向______致慰问电,对_____表达诚挚哀悼

7."__五"期间,我国____重点工程,突破____课题,创造效益____,实现利税____。

8.______在____的陪同下,不远万里,来到_____家中,为_____带来了节日的祝福和良好的祝愿,并饶有兴致的观看了_____。____握着___的手激动的说_______。

9.____省____市____县____村加强学习"____"的重要精神,切实为农民办好事,办实事。情为民所系,利为民所谋。一年内共解决_____农民的实际问题,受到农民的好评。

10.____海关加大打击contraband力度,破获一起特大contraband案件,查获____共____件,价值人民币____万元。

11.今天是____日,各地群众、学生纷纷走上街头,宣传普及____知识,加强____教育。

12.____事丶件的原因已经查明,有关责任人已被刑事拘留。

13.今天是____诞辰____周年,____举行座谈会,深入探讨____,缅怀这位____家。

14.本台短评:中国________受到各国称赞,________行为不得民心

15.____国群众不满____,举行**示丶威活动。骚丶乱已持续_____天。

16._____国发生_______级地震,目前已造成______人伤亡。我国已派出______人救援队前往救援

17._____国发生_______特大飓风,_____人受灾,直接经济损失达_________美元。

18.____,____,请看今晚19点38分播出的《焦点访谈》节目。

19.中国__的优秀_员,久经考验的忠诚的__战士,无产阶级__家、__家、__家,我国杰出的___,原___,___,___,______**,于___年__月__日__时__分在北京逝世,享年__岁。

20.联播节目播送完了,谢谢您的收看


--
言念君子 温其如玉

2011年11月15日星期二

GWT中的list

From Evernote:

GWT中的list

对于GWT中的LIST,翻译js的时候估计有缺陷
当做for遍历时候,中间有remove操作
如:
for(PokerPanel panel : selectPanelList) {
   if(xxxxx) { 
        selectPanelList.remove(panel);
    }
}
当该list全部remove,再次遍历selectPanelList 会有空指针异常

解决办法
for (int i = selectPanelList.size(); i > 0; i--) {
     PokerPanel panel = selectPanelList.get(i - 1);
     panel.onRevert();
     selectPanelList.remove(panel);
}

test

From Evernote:

test

测试

2011年8月25日星期四

低俗小说:人人都是老鼠会 ----李承鹏

低俗小说:人人都是老鼠会


拜登走了,可城里的交通还是堵,这让老子有些失望。前两天堵在熊猫基地时,我还发过一条微博:龟儿的欠我们那么多外债,还来扰民。后来知道,当时拜登还没落地,也没有到熊猫基地的日程安排。是咯,熊猫基地在北门,机场在南门,老子属菜鸽子的,把方向搞反了……

 

这些不管了,反正烦这个总统,总统,饭桶,就知道来吃债主。在姚记只吃了79元炸酱面,都明白是想用亲民秀颠覆我国。至于当真颠覆得了不,这个我倒也不太相信,一碗炸酱面就颠覆了国家,这国家就也太面了。红会万元工作餐都颠覆不了,炸酱面怎可能,炸弹面也不可能。何况我们还有航母。咦,这航母烧啥子油,0号还是99号?抬头一看才意识到,我正进加油站。

 

加油站小妹的脸色还是那么难看。小妹,我是来加油的,不是来揩油的。揩油的是你们中石化。小妹听出我的内心独白,粗暴地嚓地把油枪插进车体。油泵表往上直飙,20、130、240、360……内心凄怆得很,感觉不是在加油,这是在抽血。

 

抽完血连个酒精棉也不给,过去都免费送包餐巾纸,现在这个都免了。我正争辩,后面的车喇叭大作,玛莎拉蒂对我直吼:餐巾纸都要贪,卫生巾要不要。贪?有你干爹贪?老子走下去教育这90后妹妹,车上有个小伙对我冷笑,挥手就把我打出鼻血。我很痛,假装打了个喷嚏,走了。我只是不想跟暴发户一般见识,真的,每当看到玛莎拉蒂,不知为何就想起玛勒戈壁。等老子有钱了,一定买辆玛勒戈壁,不对,有钱了还呆在这里干毛线,直接移民米国,把女人、娃儿全带上。

 

至于为什么我这么恨米国,还想移民米国,这个问题一直没想明白。

 

这个夏天特别闷热,湿度大,连蝉都飞不起来了。老家的气候真是变了。当然不是建大坝造成的,这显然是米国人消耗太多能源造成的温室效应。他们把自己国内的油价定得那么低,迫使我们把油价弄得那么高,他们到处指手划脚,却欠了我们上万亿的债。这着实可恨,一时间恨不得组织菜刀队砍翻了这帮鸟人,可联想到菜刀实名制后一时准备不得这么多,最好就由外星UFO直接收了他们。昨天新闻才说上海万米上空有巨大的光柱疑似外星飞船。别留在这里,飞吧,飞到对岸去,平了他们。忽想起那个紧要问题,要是平了那里,我又怎么移民?可这辈子移民遥遥无期,还不如平了那里,感官上爽些。可平了就完全没希望……平,还是不平,一时间我脸色阴晴不定,内心纠结。

 

吱……猛踩刹车,差点撞上一横穿的老太婆。确定没撞上,我驾屁遁飞奔了。这时千万不能下车去搀扶,一扶,就得扶一辈子。

 

真是世风日下,这些老赖……让人真没安全感。其实悄悄也觉得自己很可耻。可没办法,世风不管我事,我要是管了世风,只能喝西北风。公司倒闭后,我每天跑来跑去,有天跑到一个公园累了,刚躺在长椅上准备思考一下再创业,见草坪上人越聚越多。有个大姐就附耳跟我说:放心,我们上面有人,只要发展几个下线,就可以赚钱。

 

别用老鼠会这么难听的名字好吧。老鼠会怎么了,其实我压根看不起李大眼说的"我是这个国家十三亿分之一股东",你有股权吗。你能做空还是做满。你其实连散户都算不上,最多是级别不算太低的一个下线。这个国家几千年从来就不是股份制,从来就是一老鼠会,皇上带着四辅臣的下线,四辅臣带着十六总督的下线,带着108个巡府道台的下线,带着三千二百个知县亭长的下线……总之是少数人控制着多数人的传销制,不是多数人选出少数人的民主制。只要不在大雨天碰到陈胜吴广,就其乐融融,娱乐无极到下线。到今朝的跨越式发展,就是老鼠会发展。世上最勤奋的一个老鼠会,人人都在发展下线,人人都争取成为上线。你看,从幼稚园开始的教育就是传销口号,学雷锋其实是为了忽悠更多的下线,是思想上的老鼠会。考学也是进老鼠会,你学不到什么,从中学到大学到硕博士,不过是下线到上线的一通修炼。每年招公务员,简直就是由国家统一发展下线,科长有七八个下线,局长有百十来号下线,厅长有千八百人下线……一级一级往上爬,等爬到铁道部部长那一层,全国坐火车的全是你的下线。

 

想到这一点,微风中的我忽然张嘴笑了,我不是最恐惧的,这里官员更恐惧。不说在动车追尾之前就有个部长先追了尾,就说前些时候有个教育局官员在微博上跟大波妹聊到,白,嫩,柔滑,喜欢……就下课了。我倒觉得这句从文本意义上也很有文学性,色香味俱全。可惜还是官太小,足够大就不用微博聊奶,就直接养奶。所以官员们拼命往上爬,就是想把这份恐惧感转加给下线。可是又能爬到哪一层,铁道部长还不如王勇平,王勇平还不如凤姐,这下解脱了,在世上最大的一个老鼠会,凤姐能早早清仓,这是一个奇迹。

 

思量间,车已到学校,我抹干鼻血摸出红包,悄悄塞进校长手里,我儿子要读重点中学……校长收下,面无表情远行。我看见她走进一家医院,她儿子喝牛奶后,肾里长了一些舍利子……医生面无表情收下红包。远行。然后走进一处楼盘,把首付交给开发商。开发商收下这些钱,走进一处豪包,把更多的钱交给一个领导。领导满意地点点头,转身把一把车钥匙交给身后一美妞。美妞亲一口领导后走出豪包,开着玛莎拉蒂,转角处悄悄接上一小伙。俩人开进加油站,前面是一个猥琐男,就是我,挥手打我出鼻血。我屁遁经过一老太婆,并不停下。老太婆缠上了后面的玛莎拉蒂……

 

我终于搞懂,这里是世上最勤奋一个老鼠会,人人那么拼命,是想做到最上线,清仓,移民米国。可我搞不懂的是,大家都这么努力,一定都可到了米国,抬头一看全是鼠兄鼠弟,那里又成了世上最大一个老鼠会。等公元20某0年,有个外国元首访


--
言念君子 温其如玉

2011年8月17日星期三

四川人民的呼声

一、后羿,你妈喊你出来射日!!!
二、躺在凉席上,感觉自己就像是铁板牛柳。
三、当电风扇变成了电吹风,我觉得人生都失去了意义。
四、女孩,遇到给宿舍安空调的校长,就嫁了吧!
五、每个在四川上学的孩子,上辈子都是折翼的天使:夏天桑拿,冬天冰箱,晴天火焰山,雨天水帘洞……四年以后都炼成孙悟空,到哪都死不了!
六、有两个陌生人来到四川,然后,然后他俩熟了……
七、桌子太烫……以至于一只蚊子被烫死了……
八、这凉席感觉怎么跟电热毯似的!
九、蚊子不叮人,只叮冷水管了……
十、热干面不用煮了,买不到生鸡蛋了,衣服洗完了可以穿了,汽车发动不用点火了……
十一、我一直在想,哪天绑架了校长,给他绑到学校宿舍的床上,就给他一个小风扇,看他能活多久……
十二、从前有个小孩在四川上学,上着上着他就热死了 ……
十三、这么热的时候停水了,我想去校长家洗澡……'
十四、我的肉身即将热死在四川……我的灵魂将与你们同在……
十五、我若热死在四川,兄弟们记得来收尸,辛苦你们了!棺材里一定要有空调……
十六、我每个细胞都需要空调……
十七、宁可在空调房里哭,也不要在电风扇下笑……
十八、泸州将上演一部重口味写实电影:《全城热死》…
十九、如果我死了,请在每年这个时候给我烧一台空调。

--
言念君子 温其如玉

WEB.XML配置说明

1 定义头和根元素 部署描述符文件就像所有XML文件一样,必须以一个XML头开始。这个头声明可以使用的XML版本并给出文件的字符编码。 
DOCYTPE声明必须立即出现在此头之后。这个声明告诉服务器适用的servlet规范的版本(如2.2或2.3)并指定管理此文件其余部分内容的语法的DTD(Document Type Definition,文档类型定义)。 
所有部署描述符文件的顶层(根)元素为web-app。请注意,XML元素不像HTML,他们是大小写敏感的。因此,web-App和WEB-APP都是不合法的,web-app必须用小写。 

2 部署描述符文件内的元素次序 

XML 元素不仅是大小写敏感的,而且它们还对出现在其他元素中的次序敏感。例如,XML头必须是文件中的第一项,DOCTYPE声明必须是第二项,而web- app元素必须是第三项。在web-app元素内,元素的次序也很重要。服务器不一定强制要求这种次序,但它们允许(实际上有些服务器就是这样做的)完全拒绝执行含有次序不正确的元素的Web应用。这表示使用非标准元素次序的web.xml文件是不可移植的。 
下面的列表给出了所有可直接出现在web-app元素内的合法元素所必需的次序。例如,此列表说明servlet元素必须出现在所有servlet-mapping元素之前。请注意,所有这些元素都是可选的。因此,可以省略掉某一元素,但不能把它放于不正确的位置。 
l icon icon元素指出IDE和GUI工具用来表示Web应用的一个和两个图像文件的位置。 
l display-name display-name元素提供GUI工具可能会用来标记这个特定的Web应用的一个名称。 
l description description元素给出与此有关的说明性文本。 
l context-param context-param元素声明应用范围内的初始化参数。 
l filter 过滤器元素将一个名字与一个实现javax.servlet.Filter接口的类相关联。 
l filter-mapping 一旦命名了一个过滤器,就要利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。 
l listener servlet API的版本2.3增加了对事件监听程序的支持,事件监听程序在建立、修改和删除会话或servlet环境时得到通知。Listener元素指出事件监听程序类。 
l servlet 在向servlet或JSP页面制定初始化参数或定制URL时,必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的。 
l servlet-mapping 服务器一般为servlet提供一个缺省的URL:http://host/webAppPrefix/servlet/ServletName。但是,常常会更改这个URL,以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时,使用servlet-mapping元素。 
l session-config 如果某个会话在一定时间内未被访问,服务器可以抛弃它以节省内存。可通过使用HttpSession的setMaxInactiveInterval方法明确设置单个会话对象的超时值,或者可利用session-config元素制定缺省超时值。 
l mime-mapping 如果Web应用具有想到特殊的文件,希望能保证给他们分配特定的MIME类型,则mime-mapping元素提供这种保证。 
l welcom-file-list welcome-file-list元素指示服务器在收到引用一个目录名而不是文件名的URL时,使用哪个文件。 
l error-page error-page元素使得在返回特定HTTP状态代码时,或者特定类型的异常被抛出时,能够制定将要显示的页面。 
l taglib taglib元素对标记库描述符文件(Tag Libraryu Descriptor file)指定别名。此功能使你能够更改TLD文件的位置,而不用编辑使用这些文件的JSP页面。 
l resource-env-ref resource-env-ref元素声明与资源相关的一个管理对象。 
l resource-ref resource-ref元素声明一个资源工厂使用的外部资源。 
l security-constraint security-constraint元素制定应该保护的URL。它与login-config元素联合使用 
l login-config 用login-config元素来指定服务器应该怎样给试图访问受保护页面的用户授权。它与sercurity-constraint元素联合使用。 
l security-role security-role元素给出安全角色的一个列表,这些角色将出现在servlet元素内的security-role-ref元素的role-name子元素中。分别地声明角色可使高级IDE处理安全信息更为容易。 
l env-entry env-entry元素声明Web应用的环境项。 
l ejb-ref ejb-ref元素声明一个EJB的主目录的引用。 
l ejb-local-ref ejb-local-ref元素声明一个EJB的本地主目录的应用。 

3 分配名称和定制的UL 

在web.xml中完成的一个最常见的任务是对servlet或JSP页面给出名称和定制的URL。用servlet元素分配名称,使用servlet-mapping元素将定制的URL与刚分配的名称相关联。 
3.1 分配名称 
为了提供初始化参数,对servlet或JSP页面定义一个定制URL或分配一个安全角色,必须首先给servlet或JSP页面一个名称。可通过 servlet元素分配一个名称。最常见的格式包括servlet-name和servlet-class子元素(在web-app元素内),如下所示: 
<servlet> 
<servlet-name>Test</servlet-name> 
<servlet-class>moreservlets.TestServlet</servlet-class> 
</servlet> 
这表示位于WEB-INF/classes/moreservlets/TestServlet的servlet已经得到了注册名Test。给 servlet一个名称具有两个主要的含义。首先,初始化参数、定制的URL模式以及其他定制通过此注册名而不是类名引用此servlet。其次,可在 URL而不是类名中使用此名称。因此,利用刚才给出的定义,URL http://host/webAppPrefix/servlet/Test 可用于 http://host/webAppPrefix/servlet/moreservlets.TestServlet 的场所。 
请记住:XML元素不仅是大小写敏感的,而且定义它们的次序也很重要。例如,web-app元素内所有servlet元素必须位于所有servlet- mapping元素(下一小节介绍)之前,而且还要位于5.6节和5.11节讨论的与过滤器或文档相关的元素(如果有的话)之前。类似地,servlet 的servlet-name子元素也必须出现在servlet-class之前。5.2节"部署描述符文件内的元素次序"将详细介绍这种必需的次序。 
例如,程序清单5-1给出了一个名为TestServlet的简单servlet,它驻留在moreservlets程序包中。因为此servlet是扎根在一个名为deployDemo的目录中的Web应用的组成部分,所以TestServlet.class放在deployDemo/WEB- INF/classes/moreservlets中。程序清单5-2给出将放置在deployDemo/WEB-INF/内的web.xml文件的一部分。此web.xml文件使用servlet-name和servlet-class元素将名称Test与TestServlet.class相关联。图 5-1和图5-2分别显示利用缺省URL和注册名调用TestServlet时的结果。 

程序清单5-1 TestServlet.java 
package moreservlets; 

import java.io.*; 
import javax.servlet.*; 
import javax.servlet.http.*; 

/** Simple servlet used to illustrate servlet naming 
* and custom URLs. 
* <P> 
* Taken from More Servlets and JavaServer Pages 
* from Prentice Hall and Sun Microsystems Press, 
* http://www.moreservlets.com/
* ? 2002 Marty Hall; may be freely used or adapted. 
*/ 

public class TestServlet extends HttpServlet { 
public void doGet(HttpServletRequest request, 
HttpServletResponse response) 
throws ServletException, IOException { 
response.setContentType("text/html"); 
PrintWriter out = response.getWriter(); 
String uri = request.getRequestURI(); 
out.println(ServletUtilities.headWithTitle("Test Servlet") + 
"<BODY BGCOLOR=\"#FDF5E6\">\n" + 
"<H2>URI: " + uri + "</H2>\n" + 
"</BODY></HTML>"); 




程序清单5-2 web.xml(说明servlet名称的摘录) 
<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd"> 

<web-app> 
<!-- … --> 
<servlet> 
<servlet-name>Test</servlet-name> 
<servlet-class>moreservlets.TestServlet</servlet-class> 
</servlet> 
<!-- … --> 
</web-app> 

3.2 定义定制的URL 
大多数服务器具有一个缺省的serlvet URL: 
http://host/webAppPrefix/servlet/packageName.ServletName。虽然在开发中使用这个URL很方便,但是我们常常会希望另一个URL用于部署。例如,可能会需要一个出现在Web应用顶层的URL(如,http: //host/webAppPrefix/Anyname),并且在此URL中没有servlet项。位于顶层的URL简化了相对URL的使用。此外,对许多开发人员来说,顶层URL看上去比更长更麻烦的缺省URL更简短。 
事实上,有时需要使用定制的URL。比如,你可能想关闭缺省URL映射,以便更好地强制实施安全限制或防止用户意外地访问无初始化参数的servlet。如果你禁止了缺省的URL,那么你怎样访问servlet呢?这时只有使用定制的URL了。 
为了分配一个定制的URL,可使用servlet-mapping元素及其servlet-name和url-pattern子元素。Servlet- name元素提供了一个任意名称,可利用此名称引用相应的servlet;url-pattern描述了相对于Web应用的根目录的URL。url- pattern元素的值必须以斜杠(/)起始。 
下面给出一个简单的web.xml摘录,它允许使用URL http://host/webAppPrefix/UrlTest而不是http://host/webAppPrefix/servlet/Test或 
http: //host/webAppPrefix/servlet/moreservlets.TestServlet。请注意,仍然需要XML头、 DOCTYPE声明以及web-app封闭元素。此外,可回忆一下,XML元素出现地次序不是随意的。特别是,需要把所有servlet元素放在所有 servlet-mapping元素之前。 
<servlet> 
<servlet-name>Test</servlet-name> 
<servlet-class>moreservlets.TestServlet</servlet-class> 
</servlet> 
<!-- ... --> 
<servlet-mapping> 
<servlet-name>Test</servlet-name> 
<url-pattern>/UrlTest</url-pattern> 
</servlet-mapping> 
URL模式还可以包含通配符。例如,下面的小程序指示服务器发送所有以Web应用的URL前缀开始,以..asp结束的请求到名为BashMS的servlet。 
<servlet> 
<servlet-name>BashMS</servlet-name> 
<servlet-class>msUtils.ASPTranslator</servlet-class> 
</servlet> 
<!-- ... --> 
<servlet-mapping> 
<servlet-name>BashMS</servlet-name> 
<url-pattern>/*.asp</url-pattern> 
</servlet-mapping> 
3.3 命名JSP页面 
因为JSP页面要转换成sevlet,自然希望就像命名servlet一样命名JSP页面。毕竟,JSP页面可能会从初始化参数、安全设置或定制的URL中受益,正如普通的serlvet那样。虽然JSP页面的后台实际上是servlet这句话是正确的,但存在一个关键的猜疑:即,你不知道JSP页面的实际类名(因为系统自己挑选这个名字)。因此,为了命名JSP页面,可将jsp-file元素替换为servlet-calss元素,如下所示: 
<servlet> 
<servlet-name>Test</servlet-name> 
<jsp-file>/TestPage.jsp</jsp-file> 
</servlet> 
命名JSP页面的原因与命名servlet的原因完全相同:即为了提供一个与定制设置(如,初始化参数和安全设置)一起使用的名称,并且,以便能更改激活 JSP页面的URL(比方说,以便多个URL通过相同页面得以处理,或者从URL中去掉.jsp扩展名)。但是,在设置初始化参数时,应该注意,JSP页面是利用jspInit方法,而不是init方法读取初始化参数的。 
例如,程序清单5-3给出一个名为TestPage.jsp的简单JSP页面,它的工作只是打印出用来激活它的URL的本地部分。TestPage.jsp放置在deployDemo应用的顶层。程序清单5-4给出了用来分配一个注册名PageName,然后将此注册名与http://host/webAppPrefix/UrlTest2/anything 形式的URL相关联的web.xml文件(即,deployDemo/WEB-INF/web.xml)的一部分。 

程序清单5-3 TestPage.jsp 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 
<HTML> 
<HEAD> 
<TITLE> 
JSP Test Page 
</TITLE> 
</HEAD> 
<BODY BGCOLOR="#FDF5E6"> 
<H2>URI: <%= request.getRequestURI() %></H2> 
</BODY> 
</HTML> 


程序清单5-4 web.xml(说明JSP页命名的摘录) 
<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd"> 

<web-app> 
<!-- ... --> 
<servlet> 
<servlet-name>PageName</servlet-name> 
<jsp-file>/TestPage.jsp</jsp-file> 
</servlet> 
<!-- ... --> 
<servlet-mapping> 
<servlet-name> PageName </servlet-name> 
<url-pattern>/UrlTest2/*</url-pattern> 
</servlet-mapping> 
<!-- ... --> 
</web-app> 


4 禁止激活器servlet 

对servlet 或JSP页面建立定制URL的一个原因是,这样做可以注册从 init(servlet)或jspInit(JSP页面)方法中读取得初始化参数。但是,初始化参数只在是利用定制URL模式或注册名访问 servlet或JSP页面时可以使用,用缺省URL http://host/webAppPrefix/servlet/ServletName 访问时不能使用。因此,你可能会希望关闭缺省URL,这样就不会有人意外地调用初始化servlet了。这个过程有时称为禁止激活器servlet,因为多数服务器具有一个用缺省的servlet URL注册的标准servlet,并激活缺省的URL应用的实际servlet。 
有两种禁止此缺省URL的主要方法: 
l 在每个Web应用中重新映射/servlet/模式。 
l 全局关闭激活器servlet。 
重要的是应该注意到,虽然重新映射每个Web应用中的/servlet/模式比彻底禁止激活servlet所做的工作更多,但重新映射可以用一种完全可移植的方式来完成。相反,全局禁止激活器servlet完全是针对具体机器的,事实上有的服务器(如ServletExec)没有这样的选择。下面的讨论对每个Web应用重新映射/servlet/ URL模式的策略。后面提供在Tomcat中全局禁止激活器servlet的详细内容。 
4.1 重新映射/servlet/URL模式 
在一个特定的Web应用中禁止以http://host/webAppPrefix/servlet/ 开始的URL的处理非常简单。所需做的事情就是建立一个错误消息servlet,并使用前一节讨论的url-pattern元素将所有匹配请求转向该 servlet。只要简单地使用: 
<url-pattern>/servlet/*</url-pattern> 
作为servlet-mapping元素中的模式即可。 
例如,程序清单5-5给出了将SorryServlet servlet(程序清单5-6)与所有以http://host/webAppPrefix/servlet/ 开头的URL相关联的部署描述符文件的一部分。 

程序清单5-5 web.xml(说明JSP页命名的摘录) 
<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd"> 

<web-app> 
<!-- ... --> 
<servlet> 
<servlet-name>Sorry</servlet-name> 
<servlet-class>moreservlets.SorryServlet</servlet-class> 
</servlet> 
<!-- ... --> 
<servlet-mapping> 
<servlet-name> Sorry </servlet-name> 
<url-pattern>/servlet/*</url-pattern> 
</servlet-mapping> 
<!-- ... --> 
</web-app> 


程序清单5-6 SorryServlet.java 
package moreservlets; 

import java.io.*; 
import javax.servlet.*; 
import javax.servlet.http.*; 

/** Simple servlet used to give error messages to 
* users who try to access default servlet URLs 
* (i.e., http://host/webAppPrefix/servlet/ServletName
* in Web applications that have disabled this 
* behavior. 
* <P> 
* Taken from More Servlets and JavaServer Pages 
* from Prentice Hall and Sun Microsystems Press, 
* http://www.moreservlets.com/
* ? 2002 Marty Hall; may be freely used or adapted. 
*/ 

public class SorryServlet extends HttpServlet { 
public void doGet(HttpServletRequest request, 
HttpServletResponse response) 
throws ServletException, IOException { 
response.setContentType("text/html"); 
PrintWriter out = response.getWriter(); 
String title = "Invoker Servlet Disabled."; 
out.println(ServletUtilities.headWithTitle(title) + 
"<BODY BGCOLOR=\"#FDF5E6\">\n" + 
"<H2>" + title + "</H2>\n" + 
"Sorry, access to servlets by means of\n" + 
"URLs that begin with\n" + 
"http://host/webAppPrefix/servlet/\n" + 
"has been disabled.\n" + 
"</BODY></HTML>"); 


public void doPost(HttpServletRequest request, 
HttpServletResponse response) 
throws ServletException, IOException { 
doGet(request, response); 




4.2 全局禁止激活器:Tomcat 
Tomcat 4中用来关闭缺省URL的方法与Tomcat 3中所用的很不相同。下面介绍这两种方法: 
1.禁止激活器: Tomcat 4 
Tomcat 4用与前面相同的方法关闭激活器servlet,即利用web.xml中的url-mapping元素进行关闭。不同之处在于Tomcat使用了放在 install_dir/conf中的一个服务器专用的全局web.xml文件,而前面使用的是存放在每个Web应用的WEB-INF目录中的标准 web.xml文件。 
因此,为了在Tomcat 4中关闭激活器servlet,只需在install_dir/conf/web.xml中简单地注释出/servlet/* URL映射项即可,如下所示: 
<!-- 
<servlet-mapping> 
<servlet-name>invoker</servlet-name> 
<url-pattern>/servlet/*</url-pattern> 
</servlet-mapping> 
--> 
再次提醒,应该注意这个项是位于存放在install_dir/conf的Tomcat专用的web.xml文件中的,此文件不是存放在每个Web应用的WEB-INF目录中的标准web.xml。 
2.禁止激活器:Tomcat3 
在Apache Tomcat的版本3中,通过在install_dir/conf/server.xml中注释出InvokerInterceptor项全局禁止缺省 servlet URL。例如,下面是禁止使用缺省servlet URL的server.xml文件的一部分。 
<!-- 
<RequsetInterceptor 
className="org.apache.tomcat.request.InvokerInterceptor" 
debug="0" prefix="/servlet/" /> 
--> 

5 初始化和预装载servlet与JSP页面 

这里讨论控制servlet和JSP页面的启动行为的方法。特别是,说明了怎样分配初始化参数以及怎样更改服务器生存期中装载servlet和JSP页面的时刻。 
5.1 分配servlet初始化参数 
利用init-param元素向servlet提供初始化参数,init-param元素具有param-name和param-value子元素。例如,在下面的例子中,如果initServlet servlet是利用它的注册名(InitTest)访问的,它将能够从其方法中调用getServletConfig(). getInitParameter("param1")获得"Value 1",调用getServletConfig().getInitParameter("param2")获得"2"。 
<servlet> 
<servlet-name>InitTest</servlet-name> 
<servlet-class>moreservlets.InitServlet</servlet-class> 
<init-param> 
<param-name>param1</param-name> 
<param-value>value1</param-value> 
</init-param> 
<init-param> 
<param-name>param2</param-name> 
<param-value>2</param-value> 
</init-param> 
</servlet> 
在涉及初始化参数时,有几点需要注意: 
l 返回值。GetInitParameter的返回值总是一个String。因此,在前一个例子中,可对param2使用Integer.parseInt获得一个int。 
l JSP中的初始化。JSP页面使用jspInit而不是init。JSP页面还需要使用jsp-file元素代替servlet-class。 
l 缺省URL。初始化参数只在通过它们的注册名或与它们注册名相关的定制URL模式访问Servlet时可以使用。因此,在这个例子中,param1和 param2初始化参数将能够在使用URL http://host/webAppPrefix/servlet/InitTest 时可用,但在使用URL http://host/webAppPrefix/servlet/myPackage.InitServlet 时不能使用。 
例如,程序清单5-7给出一个名为InitServlet的简单servlet,它使用init方法设置firstName和emailAddress字段。程序清单5-8给出分配名称InitTest给servlet的web.xml文件。 
程序清单5-7 InitServlet.java 
package moreservlets; 

import java.io.*; 
import javax.servlet.*; 
import javax.servlet.http.*; 

/** Simple servlet used to illustrate servlet 
* initialization parameters. 
* <P> 
* Taken from More Servlets and JavaServer Pages 
* from Prentice Hall and Sun Microsystems Press, 
* http://www.moreservlets.com/
* ? 2002 Marty Hall; may be freely used or adapted. 
*/ 

public class InitServlet extends HttpServlet { 
private String firstName, emailAddress; 

public void init() { 
ServletConfig config = getServletConfig(); 
firstName = config.getInitParameter("firstName"); 
emailAddress = config.getInitParameter("emailAddress"); 


public void doGet(HttpServletRequest request, 
HttpServletResponse response) 
throws ServletException, IOException { 
response.setContentType("text/html"); 
PrintWriter out = response.getWriter(); 
String uri = request.getRequestURI(); 
out.println(ServletUtilities.headWithTitle("Init Servlet") + 
"<BODY BGCOLOR=\"#FDF5E6\">\n" + 
"<H2>Init Parameters:</H2>\n" + 
"<UL>\n" + 
"<LI>First name: " + firstName + "\n" + 
"<LI>Email address: " + emailAddress + "\n" + 
"</UL>\n" + 
"</BODY></HTML>"); 




程序清单5-8 web.xml(说明初始化参数的摘录) 
<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd"> 

<web-app> 
<!-- ... --> 
<servlet> 
<servlet-name>InitTest</servlet-name> 
<servlet-class>moreservlets.InitServlet</servlet-class> 
<init-param> 
<param-name>firstName</param-name> 
<param-value>Larry</param-value> 
</init-param> 
<init-param> 
<param-name>emailAddress</param-name> 
<param-value>Ellison@Microsoft.com</param-value> 
</init-param> 
</servlet> 
<!-- ... --> 
</web-app> 

5.2 分配JSP初始化参数 
给JSP页面提供初始化参数在三个方面不同于给servlet提供初始化参数。 
1)使用jsp-file而不是servlet-class。因此,WEB-INF/web.xml文件的servlet元素如下所示: 
<servlet> 
<servlet-name>PageName</servlet-name> 
<jsp-file>/RealPage.jsp</jsp-file> 
<init-param> 
<param-name>...</param-name> 
<param-value>...</param-value> 
</init-param> 
... 
</servlet> 
2) 几乎总是分配一个明确的URL模式。对servlet,一般相应地使用以http://host/webAppPrefix/servlet/ 开始的缺省URL。只需记住,使用注册名而不是原名称即可。这对于JSP页面在技术上也是合法的。例如,在上面给出的例子中,可用URL http://host/webAppPrefix/servlet/PageName 访问RealPage.jsp的对初始化参数具有访问权的版本。但在用于JSP页面时,许多用户似乎不喜欢应用常规的servlet的URL。此外,如果 JSP页面位于服务器为其提供了目录清单的目录中(如,一个既没有index.html也没有index.jsp文件的目录),则用户可能会连接到此 JSP页面,单击它,从而意外地激活未初始化的页面。因此,好的办法是使用url-pattern(5.3节)将JSP页面的原URL与注册的 servlet名相关联。这样,客户机可使用JSP页面的普通名称,但仍然激活定制的版本。例如,给定来自项目1的servlet定义,可使用下面的 servlet-mapping定义: 
<servlet-mapping> 
<servlet-name>PageName</servlet-name> 
<url-pattern>/RealPage.jsp</url-pattern> 
</servlet-mapping> 
3)JSP页使用jspInit而不是init。自动从JSP页面建立的servlet或许已经使用了inti方法。因此,使用JSP声明提供一个init方法是不合法的,必须制定jspInit方法。 
为了说明初始化JSP页面的过程,程序清单5-9给出了一个名为InitPage.jsp的JSP页面,它包含一个jspInit方法且放置于 deployDemo Web应用层次结构的顶层。一般,http://host/deployDemo/InitPage.jsp 形式的URL将激活此页面的不具有初始化参数访问权的版本,从而将对firstName和emailAddress变量显示null。但是, web.xml文件(程序清单5-10)分配了一个注册名,然后将该注册名与URL模式/InitPage.jsp相关联。 

程序清单5-9 InitPage.jsp 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 
<HTML> 
<HEAD><TITLE>JSP Init Test</TITLE></HEAD> 
<BODY BGCOLOR="#FDF5E6"> 
<H2>Init Parameters:</H2> 
<UL> 
<LI>First name: <%= firstName %> 
<LI>Email address: <%= emailAddress %> 
</UL> 
</BODY></HTML> 
<%! 
private String firstName, emailAddress; 

public void jspInit() { 
ServletConfig config = getServletConfig(); 
firstName = config.getInitParameter("firstName"); 
emailAddress = config.getInitParameter("emailAddress"); 

%> 


程序清单5-10 web.xml(说明JSP页面的init参数的摘录) 
<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd"> 

<web-app> 
<!-- ... --> 
<servlet> 
<servlet-name>InitPage</servlet-name> 
<jsp-file>/InitPage.jsp</jsp-file> 
<init-param> 
<param-name>firstName</param-name> 
<param-value>Bill</param-value> 
</init-param> 
<init-param> 
<param-name>emailAddress</param-name> 
<param-value>gates@oracle.com</param-value> 
</init-param> 
</servlet> 
<!-- ... --> 
<servlet-mapping> 
<servlet-name> InitPage</servlet-name> 
<url-pattern>/InitPage.jsp</url-pattern> 
</servlet-mapping> 
<!-- ... --> 
</web-app> 


5.3 提供应用范围内的初始化参数 
一般,对单个地servlet或JSP页面分配初始化参数。指定的servlet或JSP页面利用ServletConfig的 getInitParameter方法读取这些参数。但是,在某些情形下,希望提供可由任意servlet或JSP页面借助ServletContext 的getInitParameter方法读取的系统范围内的初始化参数。 
可利用context-param元素声明这些系统范围内的初始化值。context-param元素应该包含param-name、param-value以及可选的description子元素,如下所示: 
<context-param> 
<param-name>support-email</param-name> 
<param-value>blackhole@mycompany.com</param-value> 
</context-param> 
可回忆一下,为了保证可移植性,web.xml内的元素必须以正确的次序声明。但这里应该注意,context-param元素必须出现任意与文档有关的元素(icon、display-name或description)之后及filter、filter-mapping、listener或 servlet元素之前。 
5.4 在服务器启动时装载servlet 
假如servlet或JSP页面有一个要花很长时间执行的init (servlet)或jspInit(JSP)方法。例如,假如init或jspInit方法从某个数据库或ResourceBundle查找产量。这种情况下,在第一个客户机请求时装载servlet的缺省行为将对第一个客户机产生较长时间的延迟。因此,可利用servlet的load-on- startup元素规定服务器在第一次启动时装载servlet。下面是一个例子。 
<servlet> 
<servlet-name> … </servlet-name> 
<servlet-class> … </servlet-class> <!-- Or jsp-file --> 
<load-on-startup/> 
</servlet> 
可以为此元素体提供一个整数而不是使用一个空的load-on-startup。想法是服务器应该在装载较大数目的servlet或JSP页面之前装载较少数目的servlet或JSP页面。例如,下面的servlet项(放置在Web应用的WEB-INF目录下的web.xml文件中的web-app元素内)将指示服务器首先装载和初始化SearchServlet,然后装载和初始化由位于Web应用的result目录中的index.jsp文件产生的 servlet。 
<servlet> 
<servlet-name>Search</servlet-name> 
<servlet-class>myPackage.SearchServlet</servlet-class> <!-- Or jsp-file --> 
<load-on-startup>1</load-on-startup> 
</servlet> 
<servlet> 
<servlet-name>Results</servlet-name> 
<servlet-class>/results/index.jsp</servlet-class> <!-- Or jsp-file --> 
<load-on-startup>2</load-on-startup> 
</servlet> 

6 声明过滤器 

servlet版本2.3引入了过滤器的概念。虽然所有支持servlet API版本2.3的服务器都支持过滤器,但为了使用与过滤器有关的元素,必须在web.xml中使用版本2.3的DTD。 
过滤器可截取和修改进入一个servlet或JSP页面的请求或从一个servlet或JSP页面发出的相应。在执行一个servlet或JSP页面之前,必须执行第一个相关的过滤器的doFilter方法。在该过滤器对其FilterChain对象调用doFilter时,执行链中的下一个过滤器。如果没有其他过滤器,servlet或JSP页面被执行。过滤器具有对到来的ServletRequest对象的全部访问权,因此,它们可以查看客户机名、查找到来的cookie等。为了访问servlet或JSP页面的输出,过滤器可将响应对象包裹在一个替身对象(stand-in object)中,比方说把输出累加到一个缓冲区。在调用FilterChain对象的doFilter方法之后,过滤器可检查缓冲区,如有必要,就对它进行修改,然后传送到客户机。 
例如,程序清单5-11帝国难以了一个简单的过滤器,只要访问相关的servlet或JSP页面,它就截取请求并在标准输出上打印一个报告(开发过程中在桌面系统上运行时,大多数服务器都可以使用这个过滤器)。 

程序清单5-11 ReportFilter.java 
package moreservlets; 

import java.io.*; 
import javax.servlet.*; 
import javax.servlet.http.*; 
import java.util.*; 

/** Simple filter that prints a report on the standard output 
* whenever the associated servlet or JSP page is accessed. 
* <P> 
* Taken from More Servlets and JavaServer Pages 
* from Prentice Hall and Sun Microsystems Press, 
* http://www.moreservlets.com/
* ? 2002 Marty Hall; may be freely used or adapted. 
*/ 

public class ReportFilter implements Filter { 
public void doFilter(ServletRequest request, 
ServletResponse response, 
FilterChain chain) 
throws ServletException, IOException { 
HttpServletRequest req = (HttpServletRequest)request; 
System.out.println(req.getRemoteHost() + 
" tried to access " + 
req.getRequestURL() + 
" on " + new Date() + "."); 
chain.doFilter(request,response); 


public void init(FilterConfig config) 
throws ServletException { 


public void destroy() {} 


一旦建立了一个过滤器,可以在web.xml中利用filter元素以及filter-name(任意名称)、file-class(完全限定的类名)和(可选的)init-params子元素声明它。请注意,元素在web.xml的web-app元素中出现的次序不是任意的;允许服务器(但不是必需的)强制所需的次序,并且实际中有些服务器也是这样做的。但这里要注意,所有filter元素必须出现在任意filter-mapping元素之前, filter-mapping元素又必须出现在所有servlet或servlet-mapping元素之前。 
例如,给定上述的ReportFilter类,可在web.xml中作出下面的filter声明。它把名称Reporter与实际的类ReportFilter(位于moreservlets程序包中)相关联。 
<filter> 
<filter-name>Reporter</filter-name> 
<filter-class>moresevlets.ReportFilter</filter-class> 
</filter> 
一旦命名了一个过滤器,可利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。关于此项工作有两种选择。 
首先,可使用filter-name和servlet-name子元素把此过滤器与一个特定的servlet名(此servlet名必须稍后在相同的 web.xml文件中使用servlet元素声明)关联。例如,下面的程序片断指示系统只要利用一个定制的URL访问名为SomeServletName 的servlet或JSP页面,就运行名为Reporter的过滤器。 
<filter-mapping> 
<filter-name>Reporter</filter-name> 
<servlet-name>SomeServletName</servlet-name> 
</filter-mapping> 
其次,可利用filter-name和url-pattern子元素将过滤器与一组servlet、JSP页面或静态内容相关联。例如,相面的程序片段指示系统只要访问Web应用中的任意URL,就运行名为Reporter的过滤器。 
<filter-mapping> 
<filter-name>Reporter</filter-name> 
<url-pattern>/*</url-pattern> 
</filter-mapping> 
例如,程序清单5-12给出了将ReportFilter过滤器与名为PageName的servlet相关联的web.xml文件的一部分。名字 PageName依次又与一个名为TestPage.jsp的JSP页面以及以模式http: //host/webAppPrefix/UrlTest2/ 开头的URL相关联。TestPage.jsp的源代码已经JSP页面命名的谈论在前面的3节"分配名称和定制的URL"中给出。事实上,程序清单5- 12中的servlet和servlet-name项从该节原封不动地拿过来的。给定这些web.xml项,可看到下面的标准输出形式的调试报告(换行是为了容易阅读)。 
audit.irs.gov tried to access 
http://mycompany.com/deployDemo/UrlTest2/business/tax-plan.html 
on Tue Dec 25 13:12:29 EDT 2001. 

程序清单5-12 Web.xml(说明filter用法的摘录) 
<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd"> 

<web-app> 
<filter> 
<filter-name>Reporter</filter-name> 
<filter-class>moresevlets.ReportFilter</filter-class> 
</filter> 
<!-- ... --> 
<filter-mapping> 
<filter-name>Reporter</filter-name> 
<servlet-name>PageName</servlet-name> 
</filter-mapping> 
<!-- ... --> 
<servlet> 
<servlet-name>PageName</servlet-name> 
<jsp-file>/RealPage.jsp</jsp-file> 
</servlet> 
<!-- ... --> 
<servlet-mapping> 
<servlet-name> PageName </servlet-name> 
<url-pattern>/UrlTest2/*</url-pattern> 
</servlet-mapping> 
<!-- ... --> 
</web-app> 


7 指定欢迎页 

假如用户提供了一个像http: //host/webAppPrefix/directoryName/ 这样的包含一个目录名但没有包含文件名的URL,会发生什么事情呢?用户能得到一个目录表?一个错误?还是标准文件的内容?如果得到标准文件内容,是 index.html、index.jsp、default.html、default.htm或别的什么东西呢? 
Welcome-file-list 元素及其辅助的welcome-file元素解决了这个模糊的问题。例如,下面的web.xml项指出,如果一个URL给出一个目录名但未给出文件名,服务器应该首先试用index.jsp,然后再试用index.html。如果两者都没有找到,则结果有赖于所用的服务器(如一个目录列表)。 
<welcome-file-list> 
<welcome-file>index.jsp</welcome-file> 
<welcome-file>index.html</welcome-file> 
</welcome-file-list> 
虽然许多服务器缺省遵循这种行为,但不一定必须这样。因此,明确地使用welcom-file-list保证可移植性是一种良好的习惯。 

8 指定处理错误的页面 

现在我了解到,你在开发servlet和JSP页面时从不会犯错误,而且你的所有页面是那样的清晰,一般的程序员都不会被它们的搞糊涂。但是,是人总会犯错误的,用户可能会提供不合规定的参数,使用不正确的URL或者不能提供必需的表单字段值。除此之外,其它开发人员可能不那么细心,他们应该有些工具来克服自己的不足。 
error-page元素就是用来克服这些问题的。它有两个可能的子元素,分别是:error-code和exception- type。第一个子元素error-code指出在给定的HTTP错误代码出现时使用的URL。第二个子元素excpetion-type指出在出现某个给定的Java异常但未捕捉到时使用的URL。error-code和exception-type都利用location元素指出相应的URL。此 URL必须以/开始。location所指出的位置处的页面可通过查找HttpServletRequest对象的两个专门的属性来访问关于错误的信息,这两个属性分别是:javax.servlet.error.status_code和javax.servlet.error.message。 
可回忆一下,在web.xml内以正确的次序声明web-app的子元素很重要。这里只要记住,error-page出现在web.xml文件的末尾附近,servlet、servlet-name和welcome-file-list之后即可。 

8.1 error-code元素 
为了更好地了解error-code元素的值,可考虑一下如果不正确地输入文件名,大多数站点会作出什么反映。这样做一般会出现一个404错误信息,它表示不能找到该文件,但几乎没提供更多有用的信息。另一方面,可以试一下在www.microsoft.comwww.ibm.com 处或者特别是在www.bea.com 处输出未知的文件名。这是会得出有用的消息,这些消息提供可选择的位置,以便查找感兴趣的页面。提供这样有用的错误页面对于Web应用来说是很有价值得。事实上rm-error-page子元素)。由form-login-page给出的HTML表单必须具有一个j_security_check的 ACTION属性、一个名为j_username的用户名文本字段以及一个名为j_password的口令字段。 
例如,程序清单5-19指示服务器使用基于表单的验证。Web应用的顶层目录中的一个名为login.jsp的页面将收集用户名和口令,并且失败的登陆将由相同目录中名为login-error.jsp的页面报告。 

程序清单5-19 web.xml(说明login-config的摘录) 
<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd"> 

<web-app> 
<!-- ... --> 
<security-constraint> ... </security-constraint> 
<login-config> 
<auth-method> FORM </auth-method> 
<form-login-config> 
<form-login-page>/login.jsp</form-login-page> 
<form-error-page>/login-error.jsp</form-error-page> 
</form-login-config> 
</login-config> 
<!-- ... --> 
</web-app> 


9.2 限制对Web资源的访问 
现在,可以指示服务器使用何种验证方法了。"了不起,"你说道,"除非我能指定一个来收到保护的 URL,否则没有多大用处。"没错。指出这些URL并说明他们应该得到何种保护正是security-constriaint元素的用途。此元素在 web.xml中应该出现在login-config的紧前面。它包含是个可能的子元素,分别是:web-resource-collection、 auth-constraint、user-data-constraint和display-name。下面各小节对它们进行介绍。 
l web-resource-collection 
此元素确定应该保护的资源。所有security-constraint元素都必须包含至少一个web-resource-collection项。此元素由一个给出任意标识名称的web-resource-name元素、一个确定应该保护的URL的url-pattern元素、一个指出此保护所适用的 HTTP命令(GET、POST等,缺省为所有方法)的http-method元素和一个提供资料的可选description元素组成。例如,下面的 Web-resource-collection项(在security-constratint元素内)指出Web应用的proprietary目录中所有文档应该受到保护。 
<security-constraint> 
<web-resource-coolection> 
<web-resource-name>Proprietary</web-resource-name> 
<url-pattern>/propritary/*</url-pattern> 
</web-resource-coolection> 
<!-- ... --> 
</security-constraint> 
重要的是应该注意到,url-pattern仅适用于直接访问这些资源的客户机。特别是,它不适合于通过MVC体系结构利用 RequestDispatcher来访问的页面,或者不适合于利用类似jsp:forward的手段来访问的页面。这种不匀称如果利用得当的话很有好处。例如,servlet可利用MVC体系结构查找数据,把它放到bean中,发送请求到从bean中提取数据的JSP页面并显示它。我们希望保证决不直接访问受保护的JSP页面,而只是通过建立该页面将使用的bean的servlet来访问它。url-pattern和auth-contraint元素可通过声明不允许任何用户直接访问JSP页面来提供这种保证。但是,这种不匀称的行为可能让开发人员放松警惕,使他们偶然对应受保护的资源提供不受限制的访问。 
l auth-constraint 
尽管web-resource-collention元素质出了哪些URL应该受到保护,但是auth-constraint元素却指出哪些用户应该具有受保护资源的访问权。此元素应该包含一个或多个标识具有访问权限的用户类别role- name元素,以及包含(可选)一个描述角色的description元素。例如,下面web.xml中的security-constraint元素部门规定只有指定为Administrator或Big Kahuna(或两者)的用户具有指定资源的访问权。 
<security-constraint> 
<web-resource-coolection> ... </web-resource-coolection> 
<auth-constraint> 
<role-name>administrator</role-name> 
<role-name>kahuna</role-name> 
</auth-constraint> 
</security-constraint> 
重要的是认识到,到此为止,这个过程的可移植部分结束了。服务器怎样确定哪些用户处于任何角色以及它怎样存放用户的口令,完全有赖于具体的系统。 
例如,Tomcat使用install_dir/conf/tomcat-users.xml将用户名与角色名和口令相关联,正如下面例子中所示,它指出用户joe(口令bigshot)和jane(口令enaj)属于administrator和kahuna角色。 
<tomcat-users> 
<user name="joe" password="bigshot" roles="administrator,kahuna" /> 
<user name="jane" password="enaj" roles="kahuna" /> 
</tomcat-users> 
l user-data-constraint 
这个可选的元素指出在访问相关资源时使用任何传输层保护。它必须包含一个transport-guarantee子元素(合法值为NONE、 INTEGRAL或CONFIDENTIAL),并且可选地包含一个description元素。transport-guarantee为NONE值将对所用的通讯协议不加限制。INTEGRAL值表示数据必须以一种防止截取它的人阅读它的方式传送。虽然原理上(并且在未来的HTTP版本中),在 INTEGRAL和CONFIDENTIAL之间可能会有差别,但在当前实践中,他们都只是简单地要求用SSL。例如,下面指示服务器只允许对相关资源做 HTTPS连接: 
<security-constraint> 
<!-- ... --> 
<user-data-constraint> 
<transport-guarantee>CONFIDENTIAL</transport-guarantee> 
</user-data-constraint> 
</security-constraint> 
l display-name 
security-constraint的这个很少使用的子元素给予可能由GUI工具使用的安全约束项一个名称。 
9.3 分配角色名 
迄今为止,讨论已经集中到完全由容器(服务器)处理的安全问题之上了。但servlet以及JSP页面也能够处理它们自己的安全问题。 
例如,容器可能允许用户从bigwig或bigcheese角色访问一个显示主管人员额外紧贴的页面,但只允许bigwig用户修改此页面的参数。完成这种更细致的控制的一种常见方法是调用HttpServletRequset的isUserInRole方法,并据此修改访问。 
Servlet的 security-role-ref子元素提供出现在服务器专用口令文件中的安全角色名的一个别名。例如,假如编写了一个调用 request.isUserInRole("boss")的servlet,但后来该servlet被用在了一个其口令文件调用角色manager而不是boss的服务器中。下面的程序段使该servlet能够使用这两个名称中的任何一个。 
<servlet> 
<!-- ... --> 
<security-role-ref> 
<role-name>boss</role-name> <!-- New alias --> 
<role-link>manager</role-link> <!-- Real name --> 
</security-role-ref> 
</servlet> 
也可以在web-app内利用security-role元素提供将出现在role-name元素中的所有安全角色的一个全局列表。分别地生命角色使高级IDE容易处理安全信息。 

10 控制会话超时 

如果某个会话在一定的时间内未被访问,服务器可把它扔掉以节约内存。可利用HttpSession的setMaxInactiveInterval方法直接设置个别会话对象的超时值。如果不采用这种方法,则缺省的超时值由具体的服务器决定。但可利用session-config和session- timeout元素来给出一个适用于所有服务器的明确的超时值。超时值的单位为分钟,因此,下面的例子设置缺省会话超时值为三个小时(180分钟)。 
<session-config> 
<session-timeout>180</session-timeout> 
</session-config> 

11 Web应用的文档化 

越来越多的开发环境开始提供servlet和JSP的直接支持。例子有Borland Jbuilder Enterprise Edition、Macromedia UltraDev、Allaire JRun Studio(写此文时,已被Macromedia收购)以及IBM VisuaAge for Java等。 
大量的web.xml元素不仅是为服务器设计的,而且还是为可视开发环境设计的。它们包括icon、display-name和discription等。 
可回忆一下,在web.xml内以适当地次序声明web-app子元素很重要。不过,这里只要记住icon、display-name和description是web.xml的web-app元素内的前三个合法元素即可。 
l icon 
icon元素指出GUI工具可用来代表Web应用的一个和两个图像文件。可利用small-icon元素指定一幅16 x 16的GIF或JPEG图像,用large-icon元素指定一幅32 x 32的图像。下面举一个例子: 
<icon> 
<small-icon>/images/small-book.gif</small-icon> 
<large-icon>/images/tome.jpg</large-icon> 
</icon> 
l display-name 
display-name元素提供GUI工具可能会用来标记此Web应用的一个名称。下面是个例子。 
<display-name>Rare Books</display-name> 
l description 
description元素提供解释性文本,如下所示: 
<description> 
This Web application represents the store developed for 
rare-books.com, an online bookstore specializing in rare 
and limited-edition books. 
</description> 

12 关联文件与MIME类型 

服务器一般都具有一种让Web站点管理员将文件扩展名与媒体相关联的方法。例如,将会自动给予名为mom.jpg的文件一个image/jpeg的MIME 类型。但是,假如你的Web应用具有几个不寻常的文件,你希望保证它们在发送到客户机时分配为某种MIME类型。mime-mapping元素(具有 extension和mime-type子元素)可提供这种保证。例如,下面的代码指示服务器将application/x-fubar的MIME类型分配给所有以.foo结尾的文件。 
<mime-mapping> 
<extension>foo</extension> 
<mime-type>application/x-fubar</mime-type> 
</mime-mapping> 
或许,你的Web应用希望重载(override)标准的映射。例如,下面的代码将告诉服务器在发送到客户机时指定.ps文件作为纯文本(text/plain)而不是作为PostScript(application/postscript)。 
<mime-mapping> 
<extension>ps</extension> 
<mime-type>application/postscript</mime-type> 
</mime-mapping> 


13 定位TLD 

JSP taglib元素具有一个必要的uri属性,它给出一个TLD(Tag Library Descriptor)文件相对于Web应用的根的位置。TLD文件的实际名称在发布新的标签库版本时可能会改变,但我们希望避免更改所有现有JSP页面。此外,可能还希望使用保持taglib元素的简练性的一个简短的uri。这就是部署描述符文件的taglib元素派用场的所在了。Taglib包含两个子元素:taglib-uri和taglib-location。taglib-uri元素应该与用于JSP taglib元素的uri属性的东西相匹配。Taglib-location元素给出TLD文件的实际位置。例如,假如你将文件chart-tags- 1.3beta.tld放在WebApp/WEB-INF/tlds中。现在,假如web.xml在web-app元素内包含下列内容。 
<taglib> 
<taglib-uri>/charts.tld</taglib-uri> 
<taglib-location> 
/WEB-INF/tlds/chart-tags-1.3beta.tld 
</taglib-location> 
</taglib> 
给出这个说明后,JSP页面可通过下面的简化形式使用标签库。 
<%@ taglib uri="/charts.tld" prefix="somePrefix" %> 

14 指定应用事件监听程序 

应用事件监听器程序是建立或修改servlet环境或会话对象时通知的类。它们是servlet规范的版本2.3中的新内容。这里只简单地说明用来向Web应用注册一个监听程序的web.xml的用法。 
注册一个监听程序涉及在web.xml的web-app元素内放置一个listener元素。在listener元素内,listener-class元素列出监听程序的完整的限定类名,如下所示: 
<listener> 
<listener-class>package.ListenerClass</listener-class> 
</listener> 
虽然listener元素的结构很简单,但请不要忘记,必须正确地给出web-app元素内的子元素的次序。listener元素位于所有的servlet 元素之前以及所有filter-mapping元素之后。此外,因为应用生存期监听程序是serlvet规范的2.3版本中的新内容,所以必须使用 web.xml DTD的2.3版本,而不是2.2版本。 
例如,程序清单5-20给出一个名为ContextReporter的简单的监听程序,只要Web应用的Servlet-Context建立(如装载Web应用)或消除(如服务器关闭)时,它就在标准输出上显示一条消息。程序清单5-21给出此监听程序注册所需要的web.xml文件的一部分。 

程序清单5-20 ContextReporterjava 
package moreservlets; 

import javax.servlet.*; 
import java.util.*; 

/** Simple listener that prints a report on the standard output 
* when the ServletContext is created or destroyed. 
* <P> 
* Taken from More Servlets and JavaServer Pages 
* from Prentice Hall and Sun Microsystems Press, 
* http://www.moreservlets.com/
* ? 2002 Marty Hall; may be freely used or adapted. 
*/ 

public class ContextReporter implements ServletContextListener { 
public void contextInitialized(ServletContextEvent event) { 
System.out.println("Context created on " + 
new Date() + "."); 


public void contextDestroyed(ServletContextEvent event) { 
System.out.println("Context destroyed on " + 
new Date() + "."); 




程序清单5-21 web.xml(声明一个监听程序的摘录) 
<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE web-app 
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd"> 

<web-app> 
<!-- ... --> 
<filter-mapping> … </filter-mapping> 
<listener> 
<listener-class>package.ListenerClass</listener-class> 
</listener> 
<servlet> ... </servlet> 
<!-- ... --> 
</web-app> 


15 J2EE元素 

本节描述用作J2EE环境组成部分的Web应用的web.xml元素。这里将提供一个简明的介绍,详细内容可以参阅http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf的Java 2 Plantform Enterprise Edition版本1.3规范的第5章。 
l distributable 
distributable 元素指出,Web应用是以这样的方式编程的:即,支持集群的服务器可安全地在多个服务器上分布Web应用。例如,一个可分布的应用必须只使用 Serializable对象作为其HttpSession对象的属性,而且必须避免用实例变量(字段)来实现持续性。distributable元素直接出现在discription元素之后,并且不包含子元素或数据,它只是一个如下的标志。 
<distributable /> 
l resource-env-ref 
resource -env-ref元素声明一个与某个资源有关的管理对象。此元素由一个可选的description元素、一个resource-env-ref- name元素(一个相对于java:comp/env环境的JNDI名)以及一个resource-env-type元素(指定资源类型的完全限定的类),如下所示: 
<resource-env-ref> 
<resource-env-ref-name> 
jms/StockQueue 
</resource-env-ref-name> 
<resource-env-ref-type> 
javax.jms.Queue 
</resource-env-ref-type> 
</resource-env-ref> 
l env-entry 
env -entry元素声明Web应用的环境项。它由一个可选的description元素、一个env-entry-name元素(一个相对于java: comp/env环境JNDI名)、一个env-entry-value元素(项值)以及一个env-entry-type元素(java.lang程序包中一个类型的完全限定类名,java.lang.Boolean、java.lang.String等)组成。下面是一个例子: 
<env-entry> 
<env-entry-name>minAmout</env-entry-name> 
<env-entry-value>100.00</env-entry-value> 
<env-entry-type>minAmout</env-entry-type> 
</env-entry> 
l ejb-ref 
ejb -ref元素声明对一个EJB的主目录的应用。它由一个可选的description元素、一个ejb-ref-name元素(相对于java: comp/env的EJB应用)、一个ejb-ref-type元素(bean的类型,Entity或Session)、一个home元素(bean的主目录接口的完全限定名)、一个remote元素(bean的远程接口的完全限定名)以及一个可选的ejb-link元素(当前bean链接的另一个 bean的名称)组成。 
l ejb-local-ref 
ejb-local-ref元素声明一个EJB的本地主目录的引用。除了用local-home代替home外,此元素具有与ejb-ref元素相同的属性并以相同的方式使用。


--
言念君子 温其如玉

2011年2月28日星期一


人生就是一出肥皂剧,一个折腾接着一个折腾
--
言念君子 温其如玉

2011年1月24日星期一

MYECLIPSE9 SN

 Subscriber: www.1cn.biz Subscription Code: jLR8ZC-855550-6756755080661717

--
言念君子 温其如玉

2010年12月21日星期二

VI指令

老要忘记
vi指令說明(完整版)
 .vi 的操作模式 ==============         vi 提供兩種操作模式:輸入模式(insert mode)和指令模式(command mode)         。當使用者進入 vi 後,即處在指令模式下,此刻鍵入之任何字元皆被視為         指令。在此模式下可進行刪除、修改等動作。若要輸入資料,則需進入輸入         模式。
.輸入模式 =========         如何進入輸入模式                 a (append)      由游標之後加入資料。                 A               由該行之末加入資料。                 i (insert)      由游標之前加入資料。                 I               由該行之首加入資料。                 o (open)        新增一行於該行之下供輸入資料之用。                 O               新增一行於該行之上供輸入資料之用。
        如何離開輸入模式                 《ESC》 結束輸入模式。
.指令模式 ========= 游標之移動         h       向左移一個字元。         j       向上移一個字元。         k       向下移一個字元。         l       向右移一個字元。         0       移至該行之首         $       移至該行之末。         ^       移至該行的第一個字元處。         H       移至視窗的第一列。         M       移至視窗的中間那列。         L       移至視窗的最後一列。         G       移至該檔案的最後一列。         +       移至下一列的第一個字元處。         -       移至上一列的第一個字元處。         (       移至該句之首。 (註一)         )       移至該句之末。         {       移至該段落之首。 (註二)         }       移至該段落之末。         nG      移至該檔案的第 n 列。         n+      移至游標所在位置之後的第 n 列。         n-      移至游標所在位置之前的第 n 列。         <Ctrl><g>       會顯示該行之行號、檔案名稱、檔案中最末行之行號、游標                         所在行號佔總行號之百分比。
        註一:句子(sentence)在vi中是指以『!』、『.』或『?』結束的一串字。         註二:段落(paragraph)在vi中是指以空白行隔開的文字。
.視窗的移動 ===========         <Ctrl><f>       視窗往下捲一頁。         <Ctrl><b>       視窗往上捲一頁。         <Ctrl><d>       視窗往下捲半頁。         <Ctrl><u>       視窗往上捲半頁。         <Ctrl><e>       視窗往下捲一行。         <Ctrl><y>       視窗往上捲一行。
.刪除、複製及修改指令介紹 (此單元較少使用) =========================         d(delete)、c(change)和y(yank)這一類的指令在 vi 中的指令格式為:         Operator + Scope = command         (運算子)   (範圍)         運算子:         d       刪除指令。刪除資料,但會將刪除資料複製到記憶體緩衝區。         y       將資料(字組、行列、句子或段落)複製到緩衝區。         p       放置(put)指令,與 d 和 y 配和使用。可將最後delete或yank的資                 料放置於游標所在位置之行列下。         c       修改(change)指令,類似delete與insert的組和。刪除一個字組、句                 子等之資料,並插入新鍵資料。
        範圍:         e       由游標所在位置至該字串的最後一個字元。         w       由游標所在位置至下一個字串的第一個字元。         b       由游標所在位置至前一個字串的第一個字元。         $       由游標所在位置至該行的最後一個字元。         0       由游標所在位置至該行的第一個字元。         )       由游標所在位置至下一個句子的第一個字元。         (       由游標所在位置至該句子的第一個字元。         {       由游標所在位置至該段落的最後一個字元。         }       由游標所在位置至該段落的第一個字元。
        整行動作         dd      刪除整行。         D       以行為單位,刪除游標後之所有字元。         cc      修改整行的內容。         yy      yank整行,使游標所在該行複製到記憶體緩衝區。
.刪除與修改 ===========         x       刪除游標所在該字元。         X       刪除游標所在之前一字元。         dd      刪除游標所在該行。         r       用接於此指令之後的字元取代(replace)游標所在字元。                 如: ra 將游標所在字元以 a 取代之。         R       進入取代狀態,直到《ESC》為止。         s       刪除游標所在之字元,並進入輸入模式直到《ESC》。         S       刪除游標所在之該行資料,並進入輸入模式直到《ESC》。
.搬移與複製 ==========         利用 delete 及 put 指令可完成資料搬移之目的。         利用 yank 及 put 指令可完成資料複製之目的。         yank 和 delete 可將指定的資料複製到記憶體緩衝區,而藉由 put 指令         可將緩衝區內的資料複製到螢幕上。         例:         搬移一行        ‧在該行執行 dd                         ‧游標移至目的地                         ‧執行 p         複製一行        ‧在該行執行 yy                         ‧游標移至目的地                         ‧執行 p
.指令重複 =========         在指令模式中,可在指令前面加入一數字 n,則此指令動作會重複執行 n         次。         例:         刪除10行                ‧10dd         複製10行                ‧10yy                                 ‧游標移至目的地                                 ‧p         指標往下移10行  ‧10j
.取消前一動作(Undo) ===================         即復原執行上一指令前的內容。
        u       恢復最後一個指令之前的結果。         U       恢復游標該行之所有改變。
.搜尋 =====         在vi中可搜尋某一字串,使游標移至該處。
        /字串           往游標之後尋找該字串。         ?字串           往游標之前尋找該字串。         n               往下繼續尋找下一個相同的字串。         N               往上繼續尋找下一個相同的字串。
.資料的連接 ===========         J       句子的連接。將游標所在之下一行連接至游標該行的後面。
        若某行資料太長亦可將其分成兩行,只要將游標移至分開點,進入輸入模式         (可利用 a、i等指令)再按《Enter》即可。
.環境的設定 ===========         :set nu                設定資料的行號。         :set nonu              取消行號設定。         :set ai                自動內縮。         :set noai              取消自動內縮。
        自動內縮(automatic indentation)         在編輯文件或程式時,有時會遇到需要內縮的狀況,『:set ai』即提供自         動內縮的功能,用下例解釋之:         ‧vi test         ‧(進入編輯視窗後)           this is the test for auto indent           《Tab》start indent           ← :set ai (設自動內縮)           《Tab》data           《Tab》data           《Tab》data                   ← :set noai (取消自動內縮)         the end of auto indent.         ‧註:<Ctrl><d> 可刪除《Tab》字元。
.ex指令 =======         讀寫資料         :w                     將緩衝區的資料寫入磁碟中。         :10,20w test   將第10行至第20行的資料寫入test檔案。         :10,20w>>test  將第10行至第20行的資料加在test檔案之後。         :r test                將test檔案的資料讀入編輯緩衝區的最後。
        刪除、複製及搬移         :10,20d                刪除第10行至第20行的資料。         :10d                   刪除第10行的資料。         :%d                    刪除整個編輯緩衝區。         :10,20co30             將第10行至第20行的資料複製至第30行之後。         :10,20mo30             將第10行至第20行的資料搬移至第30行之後。
        字串搜尋與取代         s(substitute)指令可搜尋某行列範圍。         g(global)指令則可搜尋整個編輯緩衝區的資料。         s指令以第一個滿足該條件的字串為其取代的對象,若該行有數個滿足該條         件的字串,也僅能取代第一個,若想取代所有的字串則需加上g參數。         :1,$s/old/new/g                將檔案中所有的『old』改成『new』。         :10,20s/^/   /         將第10行至第20行資料的最前面插入5個空白。         :%s/old/new/g          將編輯緩衝區中所有的『old』改成『new』。
.恢復編輯時被中斷的檔案 =======================         在編輯過程中,若系統當掉或連線中斷,而緩衝區的資料並還未         被寫回磁碟時,當再度回到系統,執行下列指令即可回復中斷前         的檔案內容。         %vi -r filename
.編輯多個檔案 =============         vi亦提供同時編輯多個檔案的功能,方法如下:         %vi file1 file2 ..
        當第一個檔案編修完成後,可利用『:w』將該緩衝區存檔,而後         再利用 『:n』載入下一個檔案。

--
言念君子 温其如玉