[Lucene]并发性、线程安全性以及锁机制

mikel阅读(926)

2.9  并发性、线程安全性以及锁机制

这部分内容 将介绍三个紧密联系的主题:索引文件的并发访问、IndexReader和IndexWriter的线程安全性,以及Lucene用于避免索引被破坏而使 用的锁机制。通常,Lucene的初学者们对这几个主题都存在一定的误解。而准确地理解这些内容是十分重要的,因为,当索引应用程序同时服务于大量不同的 用户时,或为了满足一些突发性的请求、而需要通过对某些操作进行并行处理时,这些内容会帮助你消除在构建应用程序过程中所遇到的疑问。

2.9.1  并发访问的规则

Lucene 提供了一些修改索引的方法,例如索引新文档、更新文档和删除文档;在执行这些操作时,为了避免对索引文件造成损坏,需要遵循一些特定的规则。这类问题通常 会在web应用程序中突显出来。因为web应用程序是同时为多个请求而服务的。Lucene的并发性规则虽然比较简单,但我们必须严格遵守:

— 任意数量的只读操作都可以同时执行。例如,多个线程或进程可以并行地对同一个索引进行搜索。

— 在索引正在被修改时,我们也可以同时执行任意数量的只读操作。例如,当某个索引文件正在被优化,或正在对索引执行文档的添加、更新或删除操作时,用户仍然可以对这个索引进行搜索。

— 在某一时刻,只允许执行一个修改索引的操作。也就是说,在同一时间,一个索引文件只能被一个IndexWriter或IndexReader对象打开。

基于以上的并发性规则,我们可以构造一些关于并发性的更全面的例子,如表2.2中所示。表中说明了是否允许我们对一个索引文件进行各种并发性的操作。

表2.2  是否允许对某个Lucene索引进行并发性操作的举例

   

是否允许

对同一个索引运行多个并行的搜索进程

允许

对一个正在生成、被优化或正在与另一索引合并的索引运行多个并行的搜索进程,或该索引正在进行删除、更新文档等操作时,对索引运行多个并行的搜索进程

允许

对同一个索引用多个IndexWriter对象执行添加、更新文档的操作

不允许

当一个从索引中删除文档的IndexReader对象没有成功关闭时,打开一个IndexWriter对象用于在这个索引中添加新的文档

不允许

IndexWriter对象向索引中添加新文档后,未成功关闭;在此之后,打开一个IndexReader对象用于从这个索引中删除文档

不允许

注:当正在修改一个索引时,请记住在某一时刻,在同一个索引上只能执行一个修改操作。

2.9.2  线程安全性

尽管 Lucene不允许使用多个IndexWriter或IndexReader实例同时对一个索引进行修改,如表2.2所示,但是这两个类都是线程安全 (thread-safe)的,了解这一点相当重要。因此,这两个类的实例都可以被多线程共享,Lucene会对各个线程中所有对索引进行修改的方法的调 用进行恰当的同步处理,以此来确保修改操作能一个接着一个地有序进行。图2.7描述了这样的一个场景:

图2.7  一个IndexWriter或IndexReader对象可以被多个线程所共享

应用程序不 需要进行额外的同步处理。尽管IndexReader和IndexWriter这两个类都是线程安全的,使用Lucene的应用程序还是必须确保这两个类 的对象对索引的修改操作不能重叠。也就是说,在使用IndexWriter对象将新文档被添加至索引中之前,必须关闭所有已经完成在同一个索引上,进行删 除操作的IndexReader实例。同样地,在IndexReader对象对索引中的文档进行删除和更新之前,必须关闭此前已经打开该索引的 IndexWriter实例。

表2.3是 一个关于并发操作的矩阵,它向我们展示了一些具体操作是否能并发地执行。该表假定应用程序只使用了一个IndexWriter或IndexReader实 例。请注意,在此我们并没有将对索引的更新视为一个单独的操作列出,因为它实际上可以被看成是在删除操作后再进行一个添加操作。

表2.3  使用同一个IndexWriter或IndexReader实例时的并发操作矩阵,表中打叉的部分表示两个操作不能同时执行

 

查找

读文档

添加

删除

优化

合并

查找

 

 

 

 

 

 

读文档

 

 

 

 

 

 

添加

 

 

 

×

 

 

删除

 

 

×

 

×

×

优化

 

 

 

×

 

 

合并

 

 

 

×

 

 

这个矩阵可以归纳为:

—  IndexReader对象在从索引中删除一个文档时,IndexWriter对象不能向其中添加文档。

—  IndexWriter对象在对索引进行优化时,IndexReader对象不能从其中删除文档。

—  IndexWriter对象在对索引进行合并时,IndexReader对象也不能从其中删除文档。

从上面的矩 阵及其归纳中,我们可以得到这样一个使用模式:当IndexWriter对象在对索引进行修改操作时,IndexReader对象不能对索引进行修改。这 个操作模式是对称的:当IndexReader对象正在对索引进行修改操作时,IndexWriter对象同样也不能对索引进行修改。

这里读者可 以感到,Lucene的并发性规则和社会中的那些良好的习惯以及合理的法规具有相通之处。我们不一定非得严格地遵守这些规则,但是如果违反这些规则将会造 成相应的后果。在现实生活中,违反法律法规也许得锒铛入狱。在使用Lucene时,违背这些规则,则会损坏你的索引文件。Lucene使用者可能会对并发 性有错误的理解甚至误用,但Lucene的创造者们对此早已有所预料,因此他们通过锁机制尽可能地避免应用程序对索引造成意外的损坏。本书将在2.9.3 节中对Lucene索引的锁机制进行进一步的介绍。

2.9.3  索引锁机制

在 Lucene中,锁机制是与并发性相关的一个主题。在同一时刻只允许执行单一进程的所有代码段中,Lucene都创建了基于文件的锁,以此来避免误用 Lucene 的API造成对索引的损坏。各个索引都有其自身的锁文件集;在默认的情况下,所有的锁文件都会被创建在计算机的临时目录中,这个目录由Java的 java.io.tmpdir中的系统属性所指定。

如果在索引 文档时,观察一下那个临时目录,就可以看到Lucene的write.lock文件;在段(segment)进行合并时,还可以看到 commit.lock文件。你可以通过设定org.apache.lucene.lockDir中的系统属性,使锁文件存放的目录改至指定的位置。这个 系统属性可以通过使用Java API在程序中进行设定,还可以通过命令行进行设定,如:-Dorg.apache.lucene.lockDir=/path/to/lock /dir。若有多台计算机需要访问存储在共享磁盘中的同一个索引,则应该在程序中显式地设定锁目录,这样位于不同计算机上的应用程序才能访问到彼此的锁文 件。根据已知的锁文件以及网络文件系统(NFS)出现的问题,锁目录应该选择放在一个不依赖于网络的文件系统卷上。以下就是上面提到的两个锁文件:

write.lock 文件用于阻止进程试图并发地修改一个索引。更精确地说,IndexWriter对象在实例化时获得write.lock文件,直到IndexWriter 对象关闭之后才释放。当IndexReader对象在删除、恢复删除文档或设定域规范时,也需要获得这个文件。因此,write.lock会在对索引进行 写操作时长时间地锁定索引。

当对段进行 读或合并操作时,就需要用到commit.lock文件。在IndexReader对象读取段文件之前会获取commit.lock文件,在这个锁文件中 对所有的索引段进行了命名,只有当IndexReader对象已经打开并读取完所有的段后,Lucene才会释放这个锁文件。IndexWriter对象 在创建新的段之前,也需要获得commit.lock文件,并一直对其进行维护,直至该对象执行诸如段合并等操作,并将无用的索引文件移除完毕之后才释 放。因此,commit.lock的创建可能比write.lock更为频繁,但commit.lock决不能过长时间地锁定索引,因为在这个锁文件生存 期内,索引文件都只能被打开或删除,并且只有一小部分的段文件被写入磁盘里。表2.4对Lucene 中各种使用Lucene API来锁定索引的情况进行了概括。

表2.4  Lucene中所有锁及创建和释放锁的操作

锁文件

何时获取

何时释放

描述

write.lock

IndexWriter

构造函数

close()

在关闭IndexWriter对象时释放锁

write.lock

IndexReader

delete(int)

close()

在关闭IndexReader对象时释放锁

write.lock

IndexReader

undeleteAll(int)

close()

在关闭IndexReader对象时释放锁

write.lock

IndexReader

setNorms (int,String,byte)

close()

在关闭IndexReader对象时释放锁

commit.lock

IndexWriter

构造函数

构造函数

段信息被读取或写入后立即释放锁

commit.lock

IndexWriter

addIndexes (IndexReader[])

addIndexes (IndexReader[])

写入新的段时获取锁文件

commit.lock

IndexWriter

addIndexes (Directory[])

addIndexes (Directory[])

写入新的段时获取锁文件

commit.lock

IndexWriter

mergeSegment (int)

mergeSegments (int))

写入新的段时获取锁文件

commit.lock

IndexReader

open(Direcory)

Open(Direcory)

所有段被读取后获取锁文件

commit.lock

SegmentReader

doClose()

doClose()

段的文件被写入或重写后获取锁文件

commit.lock

SegmentReader

undeleteAll()

undeleteAll()

移除段.del文件后获取锁文件

请注意另外两个与锁相关的方法:

—  IndexReader的isLocked(Directory) ——这个方法可以判断参数中指定的索引是否已经被上锁。在想要对索引进行某种修改操作之前,应用程序需要检查索引是否被锁保护时,通过使用这个方法可以很方便地得到结果。

—  IndexReader的unlock(Directory) ——该方法的作用正如其命名那样。尽管通过这个方法可以使你在任意时刻对任意的Lucene索引进行解锁,然而它的使用具有一定的危险性。因为 Lucene创建锁自有其理由,此外,在修改一个索引时对其解锁可能导致这个索引被损坏,从而使得这个索引失效。

虽然知 道Lucene使用了哪些锁文件,何时、为什么要使用它们,以及在文件系统的何处存放这些锁文件,但是你不能直接在文件系统对它们进行操作。你应该通过 Lucene的API对它们进行操作。否则,如果将来Lucene开始启用一种不同的锁机制,或者Lucene改变了锁文件的命名或存储位置时,应用程序 可能会受到影响而不能顺利执行。

锁机制的实例

为了演示锁是如何使用的,程序2.7演示了Lucene如何利用锁来避免在同一时刻对同一索引文件进行多个修改操作。在testWriteLock( )方法中,Lucene对一个已经被IndexWriter对象打开的索引上锁,阻止第二个IndexWriter对象对这个索引进行修改。在这个例子中使用了write.lock文件:

程序2.7  使用基于文件的锁以防止索引被损坏

testCommitLock( )方法展示了应用程序是如何使用commit.lock文件,程序通过IndexReader的open(Directory)方法获得这个锁文件,并在 读取了所有的索引段之后就通过同样的方式立即释放它。因为程序是通过与获得锁文件相同的方法释放的。因此,甚至在关闭第一个IndexReader对象之 前,我们仍可以用第二个IndexReader对象来访问同一个目录。(你可能对这个方法中的IndexWriter对象感到诧异:它的惟一目的在于通过 创建程序所需的段文件,这个段文件包含了已经存在的所有索引段的信息。若没有这些段文件,IndexReader对象就会成为无的之矢,因为那样的话,它 就不知道该从索引目录中读取哪些段的信息了)。

当运行这段代码时,可以看到已被上锁的索引造成了类似如下异常的堆栈跟踪信息:

如同我们先 前提到的,Lucene的初学者们有时对这一章中介绍的并发性没有很好理解,从而陷入到本小节中提到的关于锁的问题里,以至在程序中出现了上面所示的异 常。在你的应用程序中如果出现了类似的异常,而索引的一致性对用户而言又十分重要,那么请不要漠视这些异常。与锁相关的异常通常是误用了Lucene API的一个标志;若在应用程序中出现了这种异常,应该妥善地处理它们。

2.9.4  禁用索引锁

我们强烈地 建议读者不要对Lucene的锁机制进行随意修改,不要漠视与锁相关的异常。然而在一些情况下,你也许想禁用Lucene当中的锁机制,并且这样做不会破 坏索引文件。例如,应用程序可能需要访问存储在CD-ROM上的Lucene索引。因为CD是一种只读介质,这意味着应用程序对索引的操作也是只读模式 的。换句话说,该应用程序只使用Lucene来搜索索引而不需要对索引进行任何形式的修改。尽管Lucene已经将锁文件保存在系统的临时目录(这个目录 通常可以被系统的所有用户打开以用于写操作)中,但是你仍可以通过将disableLuceneLocks这个系统属性设定为“true”,从而禁用 write.lock和commit.lock文件。

[MVC]MVC模式结合Mediator模式的运用

mikel阅读(949)

Mediator模式有一种本事,就是可以让本身需要互相协作的对方,可以不用知道彼此,而把两者之间的联系,转交给Mediator来处理。换句 话说,Mediator模式解除了需要互相协调的对象之间的依赖。这也是Mediator(调停者)模式名字的由来。一个颇为形象的例子是聊天室。进入聊 天室的用户总是要彼此通信的,这些对象如果直接进行交互,就会彼此连接,最后织成一张纷繁复杂的大网。要分清彼此之间的关系,真可以说是“剪不断理还乱” 了。所以,引入一个聊天室对象来管理用户间的交流,就势成必然。

Mediator模式与Facade模式都是管理复杂对象的行家里手,不过 二者在运用上还是有本质的不同。Facade是门面,通过它隔断了客户端与复杂对象之间的直接关系。Mediator是仲裁者,哪里出现纠纷哪里就有它的 身影。Facade对象对于客户端来说是可见的,而隐藏了复杂对象;Mediator对象对于客户端来说则是隐藏的,客户端直接调用复杂对象,而复杂对象 之间的关系,则转交给了Mediator。

MVC模式则是职责分离的典范,就好似三权分立一般,各司其职。Model负责提供数 据,View则负责显示数据,Controller则负责控制Model与View之间的交互,封装了领域逻辑。这样的职责分离形式,能够有效地解除数 据、业务逻辑与UI界面之间的耦合关系。但是,在MVC模式中,由于业务逻辑的问题,很有可能在Controller之间还需要进行交互。这种交互一旦增 多,就可能出现在一个Controller中出现不同的Controller,导致代码出现分散,形成霰弹式修改的坏味道。

Marlon在其博客上发表了一篇文章, 有效地将MVC模式与Mediator模式两者结合,创造出一种称之为MVC+M的模式,有效地解决了Controller对象之间相互依赖的问题。 Marlon实现了一个文件浏览器来展示这一模式。运行程序,当我们点击左边的目录树时,在右边就会显示当前目录下的所有文件。UI如图所示:

左 边视图对应的控制对象为DirectorySelectorController,而右边视图对应的则为FileSelectorController对 象。Marlon统一定义了一个接口IColleague,作为Mediator模式中参与者的抽象接口,并让相关的Controller实现它。类图如 下所示:

每个Controller对象所接收的Mediator对象都是相同的,因为Mediator对象作为BaseController基类的属性存在,并利用了Singleton模式,保证了Mediator对象只能存在一个:

public abstract class BaseController : INotifyPropertyChanged, IColleague

{

    static Mediator mediatorInstance = new Mediator();

    public Mediator Mediator { get; private set; }

 

    public BaseController()

    {

        //set the mediator to be the same one for every controller.

        Mediator = mediatorInstance;

    }

     //rest of implementation

}

 

在子类的构造函数中,通过调用Mediator对象的Register方法,建立了消息与Controller对象之间的映射关系。以FileSelectorController类为例:

public FileSelectorController()

{

    Mediator.Register(this, new[]

    {

        Messages.DirectorySelectedChanged

    });

}

Mediator类完成Controller对象之间的协调,其定义如下:

public class Mediator

{

    MultiDictionary<string, IColleague> internalList

        = new MultiDictionary<string, IColleague>();


    public void Register(IColleague colleague, IEnumerable<string> messages)

    {

        foreach (string message in messages)

            internalList.AddValue(message, colleague);

    }

 

    public void NotifyColleagues(string message, object args)

    {

        if (internalList.ContainsKey(message))

        {

            //forward the message to all listeners

            foreach (IColleague colleague in internalList[message])

                colleague.MessageNotification(message, args);

        }

    }

}

Register() 方法会将消息与Controller对象的映射注册到内部字典internalList中。而NotifyColleagues()方法则会遍历整个 internalList,然后执行Controller对象(体现为IColleague类型)的MessageNotification()方法。通 过MessageNotification()方法,每个Controller对象根据传输的消息字符串,做出相应的响应操作。例如在 FileSelectorController类中,就是根据Message的值,执行装载文件的业务逻辑:

public override void MessageNotification(string message, object args)

{

    switch (message)

    {

        case Messages.DirectorySelectedChanged:

            //load all files for the directory specified

            LoadFiles((DirectoryDisplayItem)args);

            break;

    }

}

如 果没有引入Mediator模式,由于需要在点击目录时显示当前目录的文件,因此在DirectorySelectorController类的 ItemSelected事件中,必须调用FileSelectorController对象获取文件信息,然后通过对应视图显示这些文件信息。这就导致 了DirectorySelectorController和FileSelectorController之间的依赖。现在,在 DirectorySelectorController的ItemSelected事件中,就可以通过Mediator来实现文件信息的读取与显示:

//event handler for the selecting changed

void ItemSelected(object sender, RoutedEventArgs e)

{

    TreeView treeView = (TreeView)e.OriginalSource;

    //Send a message that an item is selected and pass the object selected

    Mediator.NotifyColleagues(Messages.DirectorySelectedChanged, treeView.SelectedItem);

}

Marlon实现的MVC+M模式有效地解除了Controller对象之间的耦合关系,其中,他引入了IColleague接口对Controller的相关方法进行了抽象。不过,这样的接口并非必须,正如我在《Strategy模式与Delegate委托》 一文中提到的接口与委托之间的关系,我们完全可以用委托来代替IColleague接口的定义,使整个结构变得更加的灵活。由于引入了委托与消息对象的映 射关系,因此在Controller类的MessageNotification()方法中,不再需要用switch语句来判断消息的值,而是直接根据映 射关系,调用委托对象所指代的方法逻辑。Mediator类可以修改为:

public class Mediator

{

    IDictionary<string,Action<object>> m_List = new Dictionary<string,Action<object>>();

 

    public void Register(string message,Action<object> callback)

    {

        m_List.Add(message,callback);

    }

 

    public void NotifyColleagues(string message, object args)

    {

        if (m_List.ContainsKey(message))

        {

            m_List[message](args);

        }

    }

}

与之对应的,FileSelectorController可以修改为:

public FileSelectorController()

{

    Mediator.Register(Messages.DirectorySelectedChanged,

        (obj) =>

        {

            LoadFiles((DirectoryDisplayItem)obj);

        });

}

至于最初定义在Controller类的MessageNotification()方法,则被匿名函数所代替,已经不再需要了。

本文已在ITPub上全文发表

[资源]20个让Web Developer开发生涯更加轻松的工具

mikel阅读(733)

源文:  http://net.tutsplus.com/articles/web-roundups/20-tools-to-make-the-life-of-a-web-developer-easier/

简译:  PuterJam

 

Typetester

一个在线对比字体的工具,可以很直观得看到不同字体的差异

 

pForm

创建HTML表单的工具,能在瞬间创建很美观的表单,并输出html代码

 

ColourLovers

在线的调色板工具,你能够搜索到很多配色方案或提交你的配色方案

 

Firebug

无所不能的firebug,不多介绍了

 

HTML Entity Character Lookup

HTML 实体 查询工具

 

960 Grid System

960 是个神奇的数字,960 是横向尺寸,960 网格系统是能够让设计师快速创建网页原型的辅助系统。可以比喻成网页的黄金分割线

pfvyzisv.jpg

 

 

Em Calculator

EM换算器~ ,可以把像素换算成 em 单位。

 

Browser Shots

多浏览器截屏工具,可以提供多个平台,不同浏览器的页面截屏效果

 

Icon Finder

还在为找图标发愁么,一个不错的图片搜索工具。

 

WhatTheFont

当你图片里看到一个好看的文字而不知道字体名称时,可以用它来帮你分析字体类型

 

MeasureIt

firefox插件,可以在页面上显示一个尺子

 

ColorZilla

同样是firefox插件,可以在页面上取色,前端开发必备

 

Pingdom

一个在线的抓包工具

 

Test Everything

Test Everything 提供了很多测试工具来测试你的站点。从css html 到SEO ,从网络工具到优化应有尽有。

 

CSS Sprite Generator

样式精灵,这类工具很多了,就是把图片分割并且输出成css

 

Web Developer Toolbar

也是一个非常强大的web开发工具。

 

Domainr

域名查询工具,很方面查询域名的使用情况,并且给出未注册域名的建议。(需要翻墙)

 

Font Burner

字体查询工具,并且提供在线的字体解决方案。仅限英文。

 

Smush.It

图片优化工具,能够优化你的图片尺寸

 

Load Impact

可以模拟不同地区的用户访问你的站点的情况。并且以图表的情况反馈结果。

[ASP.NET]重提URL Rewrite(1):IIS与ASP.NET

mikel阅读(668)

  之前觉得这个话题已经被谈滥了。URL Rewrite早已经被广大开发人员所接受,网上关于URL Rewrite的组件和文章也层出不穷,但是总是让我感觉意犹未尽,于是最终还是忍不住提笔写了这系列文章。这些文章不会谈论URL Rewrite的价值与意义,而只会谈论纯技术的内容。文章中也不会有详尽地实现分析,而是结合了我的经验,从应用角度来讲解这个话题。您已经知道的,您 还不知道的,别处已经讲过的,或者还没有讲过的,希望这系列文章的“旧事重提”不会让您觉得沉闷,并且能让您了解ASP.NET中URL Rewrite的方方面面。如果您以后再遇到URL Rewrite方面的问题是能够想到这几篇文章,估计我做梦也会笑出声来。

  要充分理解文章后面谈到的话题,我们必须简单的了解一下IIS与ASP.NET的通信过程。我在这里讲解的是IIS 6服务器。至于IIS 5和IIS 7,前者可以说已经被淘汰了,而后者的“经典模式”与IIS 6可谓如出一辙,而新的“管道模式”其实是讲ASP.NET中的某些概念与IIS进行了深度集成。我相信,如果您了解了IIS 6和ASP.NET,在IIS 7的集成模式下也不会有任何问题。

  首先我们来看一幅简单的示意图,展示了IIS从收到Request开始,到返回Response整个过程中的几个主要步骤:

  1. IIS收到请求。
  2. 选择器根据URL的特点与IIS中的配置,选择一个ISAPI用于处理该请求——现在自然会选择ASP.NET ISAPI。
  3. ASP.NET执行引擎接收到请求,于是初始化数据(例如构建各种对象)。
  4. 开始触发各种Pipeline事件,自然先从BeginRequest开始。
  5. 经过了多个Pipeline事件,ASP.NET根据配置为当前请求选择一个合适的Handler或HandlerFactory进行处理(当然特殊情况例外,例如已经在之前的事件中直接输出结果并结束请求了)。
  6. 经过了Handler处理之后又经过几个Pipeline事件,以EndRequest结束。
  7. 输出Response。

  在一个ASP.NET应用中如果要进行URL Rewrite,那么一般就是在BeginRequest事件中调用HttpContext的RewritePath方法,将该请求重新“定位”至一个目 标URL。例如我们就可以在Global.asax中重写Application_BeginRequest方法来实现这一点:

  之所以在BeginRequest中进行Rewrite,是因为这个事件是在所有Pipeline事件中最早被触发的。在这时进行了重新“定位 ”之后,当前HttpContext中的一些属性也就发生了相应的变化(例如HttpContext.Request.Path)。这样,接下来的 Pipeline事件的处理程序逻辑就会受到影响。例如在需要根据目录进行权限判断时,就会使用“定位”后的路径,而不是ASP.NET所收到的请求。自 然最“显著”的变化就是对Handler的选择,例如上例,我们把请求重新定位至“CustomerList.aspx”文件,这样ASP.NET引擎就 会选择*.aspx所对应的System.Web.UI.PageHandlerFactory类对请求进行处理。

public class Global : System.Web.HttpApplication
{
    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        HttpContext context = HttpContext.Current;
 
        if (context.Request.Path.Equals("/Customers",
            StringComparison.InvariantCultureIgnoreCase))
        {
            context.RewritePath("~/CustomerList.aspx");
        }
    }
}

  最后插句提外话,有两个概念需要区分开来,那就是“ASP.NET Pipeline”与“Web Forms”。两者都是ASP.NET里的重要模型,但是差别还是非常大的:

  • ASP.NET Pipeline:作为每个ASP.NET应用所接受到的请求来说,都会经过这个“管道”进行处理。这是一个ASP.NET级别的模型。
  • Web Forms:在ASP.NET Pipeline的执行过程中,其中有一个步骤是选择一个合适的Handler(或HandlerFactory)来处理请求。如果是aspx页 面,ASP.NET就会选择System.Web.UI.PageHandlerFactory类,在这个类中才最终形成了WebForms模型。

  其实上面这句话的“形成”二字可能也不太确切。因为Web Forms可能应该是一个可以独立使用的执行引擎和模型,而System.Web.UI.PageHandlerFactory中也只是利用了这个模型而 已。我们在编写ASP.NET应用时,完全可以根据我们的需要,在其他地方使用这个模型。例如在《技巧:使用User Control做HTML生成》一文中,我们就在一个Generic Handler中把ascx当作模板来生成内容。

相关链接:

(2)使用已有组件进行URL Rewrite

(3)在URL Rewrite后保持PostBack地址

(4)不同级别URL Rewrite的一些细节与特点

[JQuery]JQuery自动提示插件

mikel阅读(1116)

页面代码: 

  1. <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>  
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  3. <html xmlns="http://www.w3.org/1999/xhtml" >  
  4. <head id="Head1" runat="server">  
  5. <mce:script language="JavaScript" src="JavaScript/JQuery1.2.js" mce_src="javascript/JQuery1.2.js"></mce:script>  
  6. <mce:script language="javascript"><!–  
  7.     var __moveIndex = -1;  
  8.     var _x;  
  9.     var _y;  
  10.     var _w;  
  11.     var _data=[];  
  12.     var eSrc = null;  
  13.     var _searchUrl = '<%=ResolveClientUrl("~/search/?k=") %>';  
  14.     $(function(){  
  15.         eSrc = $('#<%=TKeyWord.ClientID %>');  
  16.         addChoseDiv();  
  17.         $("body").click(function(){  
  18.             var target = event.srcElement || event.target;  
  19.             var eID = $(target).attr("id");  
  20.             if(eID!="TKeyWord")  
  21.             {  
  22.                 $("#matchLay").hide();     
  23.             }  
  24.         });  
  25.     });  
  26.       
  27.     //keydown事件  
  28.     function keydown()  
  29.     {  
  30.         if(event.keyCode==13)//回车键  
  31.         {  
  32.             if(__moveIndex>0)  
  33.             {  
  34.                 eSrc.val(_data[__moveIndex-1]["colKeyName"]);  
  35.                 $("#matchLay").hide();  
  36.                 document.location.href=_searchUrl+encodeURI(_data[__moveIndex-1]["colKeyName"]);  
  37.             }  
  38.             else if($.trim(eSrc.val())!=="")  
  39.             {  
  40.                 $("#matchLay").hide();  
  41.                 document.location.href=_searchUrl+encodeURI(eSrc.val());  
  42.             }  
  43.              
  44.            return false;  
  45.         }  
  46.     }  
  47.       
  48.     //初始化层  
  49.     function addChoseDiv()  
  50.     {  
  51.         _x = pageX(eSrc[0]);  
  52.         _y = pageY(eSrc[0])+eSrc.height()+5;  
  53.         _w =eSrc.width()+4;  
  54.           
  55.         $("<div id='matchLay' z-index='500'   style='background-color:#ffffff;display:none;width:"  
  56.         +_w+"px;position:absolute;left:"+_x+"px;top:"+_y  
  57.         +"px;border-left:1px solid #000000;border-bottom:1px solid #000000;border-right:1px solid #000000;' ></div>").appendTo($("body"));  
  58.     }  
  59.       
  60.     //选定匹配项导航函数  
  61.     function SelKey(obj)  
  62.     {  
  63.        eSrc.val($(obj).children().filter(":nth-child(1)").text());  
  64.        document.location.href=_searchUrl+encodeURI(eSrc.val());  
  65.        $("#matchLay").hide();    
  66.     }  
  67.       
  68.     //匹配函数  
  69.     function IsMatch()  
  70.     {  
  71.       
  72.         var rs = $.ajax({  
  73.             type:"GET",  
  74.             cache:false,  
  75.             url:"SearchPro.aspx",  
  76.             success:function(data,status){  
  77.                 //alert(data);  
  78.             }  
  79.         });  
  80.   
  81.         var v = eSrc.val();  
  82.         if(v=="")//输入为空,返回  
  83.         {  
  84.             $("#matchLay").hide();     
  85.             return false;  
  86.         }  
  87.           
  88.         _data = _Default.GetSkeys(v).value;  
  89.           
  90.         if(_data!=null && _data.length>0)//生成匹配div  
  91.         {  
  92.             var shtm = "<table width='100%' cellspacing='0' id='sList' >";  
  93.             for(var i=0;i<_data.length;i++)  
  94.             {  
  95.                 shtm+="<tr  onmouSEOver='mouSEOver(this)'  onclick='SelKey(this)'><td align='left'>"+_data[i]["colKeyName"]+"</td>";  
  96.                 shtm+="<td align='right' style="color:green" mce_style="color:green">"+RelNumber(parseInt(_data[i]["colResults"],10))+" 结果</td>";  
  97.                 shtm+="</tr>"  
  98.             }  
  99.             shtm+="</table>";  
  100.             $("#matchLay").html(shtm);  
  101.             $("#matchLay").show();     
  102.             return true;  
  103.         }else //没有匹配隐藏div  
  104.         {  
  105.             $("#matchLay").hide();     
  106.             return false;  
  107.         }  
  108.     }  
  109.   
  110.     //search Button click事件  
  111.     function goSearch(k)  
  112.     {  
  113.         document.location.href=_searchUrl+encodeURI(k);  
  114.     }  
  115.       
  116.     //onkeyup事件  
  117.     function matchBase()  
  118.     {  
  119.         if(!IsMatch()) return false;//没有匹配返回  
  120.          
  121.          if(event.keyCode==38)//上箭头  
  122.         {  
  123.             if(__moveIndex==-1 || __moveIndex==1)  
  124.             {  
  125.                 mouSEOver($("#sList tr").length);  
  126.             }else  
  127.             {  
  128.                 mouseOver(__moveIndex-1,__moveIndex);  
  129.             }  
  130.         }  
  131.         else if(event.keyCode==40)//下箭头  
  132.         {  
  133.             if(__moveIndex==$("#sList tr").length)  
  134.             {  
  135.                 mouseOver(1,$("#sList tr").length);  
  136.             }else  
  137.             {  
  138.                 if(__moveIndex==-1)  
  139.                 {  
  140.                     mouseOver(1,1);  
  141.                 }else  
  142.                 {  
  143.                     mouseOver(__moveIndex+1,__moveIndex);  
  144.                 }  
  145.             }  
  146.              
  147.         }  
  148.     }  
  149.       
  150.     //提示层mouseover事件  
  151.     function mouseOver()  
  152.     {  
  153.         var obj = null;  
  154.         var n = __moveIndex ;  
  155.         if(n==-1) n=1;  
  156.         var oldObj =$("#sList tr:nth-child("+n+")");  
  157.         if(typeof arguments[0]=="object")  
  158.         {  
  159.             obj = $(arguments[0]);  
  160.         }else  
  161.         {  
  162.             obj = $("#sList tr:nth-child("+arguments[0]+")");  
  163.             oldObj =$("#sList tr:nth-child("+arguments[1]+")");  
  164.         }  
  165.           
  166.         oldObj.css("backgroundColor","#ffffff");  
  167.         oldObj.children().filter(":nth-child(1)").css("color","#000000");  
  168.         oldObj.children().filter(":nth-child(2)").css("color","green");  
  169.           
  170.         obj.css("backgroundColor","#3366CC");  
  171.         obj.children().filter(":nth-child(1)").css("color","#ffffff");  
  172.         obj.children().filter(":nth-child(2)").css("color","#ffffff");  
  173.           
  174.         __moveIndex = obj[0].rowIndex+1;  
  175.     }  
  176.       
  177.     //格式化正整数123,456  
  178.     function RelNumber(num)  
  179.     {  
  180.         var t=num>0?num:Math.abs(num);  
  181.         var str=num.toString();  
  182.         var il = str.length;  
  183.         var n = 1;  
  184.         while(t>1000)  
  185.         {    
  186.             t/=1000;  
  187.             str=str.substring(0,il-n*3)+","+str.substr(il-n*3);  
  188.             ++n;  
  189.         }  
  190.         return str;  
  191.     }  
  192.       
  193.     //取得元素x坐标  
  194.     function pageX(elem)  
  195.     {  
  196.         return elem.offsetParent?(elem.offsetLeft+pageX(elem.offsetParent)):elem.offsetLeft;  
  197.     }  
  198.     //取得元素y坐标  
  199.     function pageY(elem)  
  200.     {  
  201.         return elem.offsetParent?(elem.offsetTop+pageY(elem.offsetParent)):elem.offsetTop;  
  202.     }  
  203. // –></mce:script>  
  204. </head>  
  205. <body>  
  206. <form runat="server">  
  207. <asp:TextBox AutoCompleteType="Disabled"  runat="server" ID="TKeyWord" Width="250px" ></asp:TextBox>  
  208. <asp:Button runat="server" ID="Btn_search" Text="Search"  />  
  209. </form>  
  210. </body>  
  211. </html>  

   

后台代码: 

  1. using System;  
  2. using System.Data;  
  3. using System.Configuration;  
  4. using System.Web;  
  5. using System.Web.Security;  
  6. using System.Web.UI;  
  7. using System.Web.UI.WebControls;  
  8. using System.Web.UI.WebControls.WebParts;  
  9. using System.Web.UI.HtmlControls;  
  10. using AjaxPro;  
  11.   
  12. public partial class _Default : System.Web.UI.Page   
  13. {  
  14.     private string NowKey = string.Empty;  
  15.     SHOPBill.SmartSearch.SearchBill sBill = new SHOPBill.SmartSearch.SearchBill();  
  16.   
  17.     protected void Page_Load(object sender, EventArgs e)  
  18.     {  
  19.         Utility.RegisterTypeForAjax(typeof(_Default));  
  20.         if (!IsPostBack)  
  21.         {  
  22.             TKeyWord.Attributes.Add("onkeyup""matchBase();");  
  23.             TKeyWord.Attributes.Add("onkeydown""keydown();");  
  24.             Btn_search.Style.Add("cursor""hand");  
  25.             Btn_search.Attributes.Add("align""absmiddle");  
  26.             Btn_search.Attributes.Add("onclick""if($.trim($('#" + TKeyWord.ClientID + "').val())==''){alert('关键字不能为空!',false);return false};document.location.href='" + ResolveClientUrl("~/search/?k=") + "'+encodeURI($('#" + TKeyWord.ClientID + "').val())");  
  27.           
  28.             List<SHOPModule.SmartSearch.SearchItem> list = sBill.SelectKeys();  
  29.             HttpContext.Current.Cache["SEARCHKEYS"] = list;  
  30.         }  
  31.   
  32.     }  
  33.   
  34.   
  35.   
  36.     [AjaxPro.AjaxMethod]  
  37.     public List<SHOPModule.SmartSearch.SearchItem> GetSkeys(string inputKey)  
  38.     {  
  39.         NowKey = inputKey;  
  40.         List<SHOPModule.SmartSearch.SearchItem> list = null;  
  41.         List<SHOPModule.SmartSearch.SearchItem> result = null;  
  42.         if (HttpContext.Current.Cache.Get("SEARCHKEYS") == null)  
  43.         {  
  44.             list = sBill.SelectKeys();  
  45.             HttpContext.Current.Cache["SEARCHKEYS"] = list;  
  46.         }  
  47.         else  
  48.         {  
  49.             list = HttpContext.Current.Cache.Get("SEARCHKEYS"as List<SHOPModule.SmartSearch.SearchItem>;  
  50.         }  
  51.   
  52.         result = list.FindAll(ListMatch);  
  53.         return result;  
  54.     }  
  55.   
  56.     private bool ListMatch(SHOPModule.SmartSearch.SearchItem m)  
  57.     {  
  58.         string k = SHOPCommUtility.Hz2Py.GetWholePinyin(m.colKeyName);  
  59.         return (MatchKeys(NowKey.ToLower(), m.colKeyName.ToLower()) || MatchKeys(NowKey.ToLower(), k.ToLower()));  
  60.   
  61.     }  
  62.   
  63.     private bool MatchKeys(string iKey, string K)  
  64.     {  
  65.         return K.Length >= iKey.Length && K.Substring(0, iKey.Length) == iKey;  
  66.     }  
  67. }  

 

汉字转拼音算法: 

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text.RegularExpressions;  
  4. using System.Text;  
  5.   
  6. namespace SHOPCommUtility  
  7. {  
  8.     /// <summary>  
  9.     /// 汉字转拼音类  
  10.     /// </summary>  
  11.     public class Hz2Py  
  12.     {  
  13.         private static int[] pyValue = new int[]  
  14.         {  
  15.             -20319,-20317,-20304,-20295,-20292,-20283,-20265,-20257,-20242,-20230,-20051,-20036,  
  16.             -20032,-20026,-20002,-19990,-19986,-19982,-19976,-19805,-19784,-19775,-19774,-19763,  
  17.             -19756,-19751,-19746,-19741,-19739,-19728,-19725,-19715,-19540,-19531,-19525,-19515,  
  18.             -19500,-19484,-19479,-19467,-19289,-19288,-19281,-19275,-19270,-19263,-19261,-19249,  
  19.             -19243,-19242,-19238,-19235,-19227,-19224,-19218,-19212,-19038,-19023,-19018,-19006,  
  20.             -19003,-18996,-18977,-18961,-18952,-18783,-18774,-18773,-18763,-18756,-18741,-18735,  
  21.             -18731,-18722,-18710,-18697,-18696,-18526,-18518,-18501,-18490,-18478,-18463,-18448,  
  22.             -18447,-18446,-18239,-18237,-18231,-18220,-18211,-18201,-18184,-18183, -18181,-18012,  
  23.             -17997,-17988,-17970,-17964,-17961,-17950,-17947,-17931,-17928,-17922,-17759,-17752,  
  24.             -17733,-17730,-17721,-17703,-17701,-17697,-17692,-17683,-17676,-17496,-17487,-17482,  
  25.             -17468,-17454,-17433,-17427,-17417,-17202,-17185,-16983,-16970,-16942,-16915,-16733,  
  26.             -16708,-16706,-16689,-16664,-16657,-16647,-16474,-16470,-16465,-16459,-16452,-16448,  
  27.             -16433,-16429,-16427,-16423,-16419,-16412,-16407,-16403,-16401,-16393,-16220,-16216,  
  28.             -16212,-16205,-16202,-16187,-16180,-16171,-16169,-16158,-16155,-15959,-15958,-15944,  
  29.             -15933,-15920,-15915,-15903,-15889,-15878,-15707,-15701,-15681,-15667,-15661,-15659,  
  30.             -15652,-15640,-15631,-15625,-15454,-15448,-15436,-15435,-15419,-15416,-15408,-15394,  
  31.             -15385,-15377,-15375,-15369,-15363,-15362,-15183,-15180,-15165,-15158,-15153,-15150,  
  32.             -15149,-15144,-15143,-15141,-15140,-15139,-15128,-15121,-15119,-15117,-15110,-15109,  
  33.             -14941,-14937,-14933,-14930,-14929,-14928,-14926,-14922,-14921,-14914,-14908,-14902,  
  34.             -14894,-14889,-14882,-14873,-14871,-14857,-14678,-14674,-14670,-14668,-14663,-14654,  
  35.             -14645,-14630,-14594,-14429,-14407,-14399,-14384,-14379,-14368,-14355,-14353,-14345,  
  36.             -14170,-14159,-14151,-14149,-14145,-14140,-14137,-14135,-14125,-14123,-14122,-14112,  
  37.             -14109,-14099,-14097,-14094,-14092,-14090,-14087,-14083,-13917,-13914,-13910,-13907,  
  38.             -13906,-13905,-13896,-13894,-13878,-13870,-13859,-13847,-13831,-13658,-13611,-13601,  
  39.             -13406,-13404,-13400,-13398,-13395,-13391,-13387,-13383,-13367,-13359,-13356,-13343,  
  40.             -13340,-13329,-13326,-13318,-13147,-13138,-13120,-13107,-13096,-13095,-13091,-13076,  
  41.             -13068,-13063,-13060,-12888,-12875,-12871,-12860,-12858,-12852,-12849,-12838,-12831,  
  42.             -12829,-12812,-12802,-12607,-12597,-12594,-12585,-12556,-12359,-12346,-12320,-12300,  
  43.             -12120,-12099,-12089,-12074,-12067,-12058,-12039,-11867,-11861,-11847,-11831,-11798,  
  44.             -11781,-11604,-11589,-11536,-11358,-11340,-11339,-11324,-11303,-11097,-11077,-11067,  
  45.             -11055,-11052,-11045,-11041,-11038,-11024,-11020,-11019,-11018,-11014,-10838,-10832,  
  46.             -10815,-10800,-10790,-10780,-10764,-10587,-10544,-10533,-10519,-10331,-10329,-10328,  
  47.             -10322,-10315,-10309,-10307,-10296,-10281,-10274,-10270,-10262,-10260,-10256,-10254  
  48.         };  
  49.   
  50.         private static string[] pyName = new string[]  
  51.         {  
  52.             "A","Ai","An","Ang","Ao","Ba","Bai","Ban","Bang","Bao","Bei","Ben",  
  53.             "Beng","Bi","Bian","Biao","Bie","Bin","Bing","Bo","Bu","Ba","Cai","Can",  
  54.             "Cang","Cao","Ce","Ceng","Cha","Chai","Chan","Chang","Chao","Che","Chen","Cheng",  
  55.             "Chi","Chong","Chou","Chu","Chuai","Chuan","Chuang","Chui","Chun","Chuo","Ci","Cong",  
  56.             "Cou","Cu","Cuan","Cui","Cun","Cuo","Da","Dai","Dan","Dang","Dao","De",  
  57.             "Deng","Di","Dian","Diao","Die","Ding","Diu","Dong","Dou","Du","Duan","Dui",  
  58.             "Dun","Duo","E","En","Er","Fa","Fan","Fang","Fei","Fen","Feng","Fo",  
  59.             "Fou","Fu","Ga","Gai","Gan","Gang","Gao","Ge","Gei","Gen","Geng","Gong",  
  60.             "Gou","Gu","Gua","Guai","Guan","Guang","Gui","Gun","Guo","Ha","Hai","Han",  
  61.             "Hang","Hao","He","Hei","Hen","Heng","Hong","Hou","Hu","Hua","Huai","Huan",  
  62.             "Huang","Hui","Hun","Huo","Ji","Jia","Jian","Jiang","Jiao","Jie","Jin","Jing",  
  63.             "Jiong","Jiu","Ju","Juan","Jue","Jun","Ka","Kai","Kan","Kang","Kao","Ke",  
  64.             "Ken","Keng","Kong","Kou","Ku","Kua","Kuai","Kuan","Kuang","Kui","Kun","Kuo",  
  65.             "La","Lai","Lan","Lang","Lao","Le","Lei","Leng","Li","Lia","Lian","Liang",  
  66.             "Liao","Lie","Lin","Ling","Liu","Long","Lou","Lu","Lv","Luan","Lue","Lun",  
  67.             "Luo","Ma","Mai","Man","Mang","Mao","Me","Mei","Men","Meng","Mi","Mian",  
  68.             "Miao","Mie","Min","Ming","Miu","Mo","Mou","Mu","Na","Nai","Nan","Nang",  
  69.             "Nao","Ne","Nei","Nen","Neng","Ni","Nian","Niang","Niao","Nie","Nin","Ning",  
  70.             "Niu","Nong","Nu","Nv","Nuan","Nue","Nuo","O","Ou","Pa","Pai","Pan",  
  71.             "Pang","Pao","Pei","Pen","Peng","Pi","Pian","Piao","Pie","Pin","Ping","Po",  
  72.             "Pu","Qi","Qia","Qian","Qiang","Qiao","Qie","Qin","Qing","Qiong","Qiu","Qu",  
  73.             "Quan","Que","Qun","Ran","Rang","Rao","Re","Ren","Reng","Ri","Rong","Rou",  
  74.             "Ru","Ruan","Rui","Run","Ruo","Sa","Sai","San","Sang","Sao","Se","Sen",  
  75.             "Seng","Sha","Shai","Shan","Shang","Shao","She","Shen","Sheng","Shi","Shou","Shu",  
  76.             "Shua","Shuai","Shuan","Shuang","Shui","Shun","Shuo","Si","Song","Sou","Su","Suan",  
  77.             "Sui","Sun","Suo","Ta","Tai","Tan","Tang","Tao","Te","Teng","Ti","Tian",  
  78.             "Tiao","Tie","Ting","Tong","Tou","Tu","Tuan","Tui","Tun","Tuo","Wa","Wai",  
  79.             "Wan","Wang","Wei","Wen","Weng","Wo","Wu","Xi","Xia","Xian","Xiang","Xiao",  
  80.             "Xie","Xin","Xing","Xiong","Xiu","Xu","Xuan","Xue","Xun","Ya","Yan","Yang",  
  81.             "Yao","Ye","Yi","Yin","Ying","Yo","Yong","You","Yu","Yuan","Yue","Yun",  
  82.             "Za""Zai","Zan","Zang","Zao","Ze","Zei","Zen","Zeng","Zha","Zhai","Zhan",  
  83.             "Zhang","Zhao","Zhe","Zhen","Zheng","Zhi","Zhong","Zhou","Zhu","Zhua","Zhuai","Zhuan",  
  84.             "Zhuang","Zhui","Zhun","Zhuo","Zi","Zong","Zou","Zu","Zuan","Zui","Zun","Zuo"  
  85.         };  
  86.   
  87.         /// <summary>  
  88.         /// 把汉字转换成拼音(全拼)  
  89.         /// </summary>  
  90.         /// <param name="hzString">汉字字符串</param>  
  91.         /// <returns>转换后的拼音(全拼)字符串</returns>  
  92.         public static string GetWholePinyin(string hzString)  
  93.         {  
  94.             // 匹配中文字符  
  95.             Regex regex = new Regex("^[\u4e00-\u9fa5]$");  
  96.             byte[] array = new byte[2];  
  97.             string pyString = "";  
  98.             int chrAsc = 0;  
  99.             int i1 = 0;  
  100.             int i2 = 0;  
  101.             char[] noWChar = hzString.ToCharArray();  
  102.   
  103.             for (int j = 0; j < noWChar.Length; j++)  
  104.             {  
  105.                 // 中文字符  
  106.                 if (regex.IsMatch(noWChar[j].ToString()))  
  107.                 {  
  108.                     array = System.Text.Encoding.Default.GetBytes(noWChar[j].ToString());  
  109.                     i1 = (short)(array[0]);  
  110.                     i2 = (short)(array[1]);  
  111.                     chrAsc = i1 * 256 + i2 – 65536;  
  112.                     if (chrAsc > 0 && chrAsc < 160)  
  113.                     {  
  114.                         pyString += noWChar[j];  
  115.                     }  
  116.                     else  
  117.                     {  
  118.                         // 修正部分文字  
  119.                         if (chrAsc == -9254)  // 修正"圳"字  
  120.                             pyString += "Zhen";  
  121.                         else  
  122.                         {  
  123.                             for (int i = (pyValue.Length – 1); i >= 0; i–)  
  124.                             {  
  125.                                 if (pyValue[i] <= chrAsc)  
  126.                                 {  
  127.                                     pyString += pyName[i];  
  128.                                     break;  
  129.                                 }  
  130.                             }  
  131.                         }  
  132.                     }  
  133.                 }  
  134.                 // 非中文字符  
  135.                 else  
  136.                 {  
  137.                     pyString += noWChar[j].ToString();  
  138.                 }  
  139.             }  
  140.             return pyString;  
  141.         }  
  142.     }  
  143. }  

 

 

[JQuery]仿google 的输入提示框JS类下载(jQuery plugin: Autocom

mikel阅读(759)

JQuery plugin: Autocomplete

Autocomplete an input field to enable users quickly finding and selecting some value, leveraging searching and filtering.

By giving an autocompleted field focus or entering something into it, the plugin starts searching for matching entries and displays a list of values to choose from. By entering more characters, the user can filter down the list to better matches.

This can be used to enter previous selected values, eg. for tags, to complete an address, eg. enter a city name and get the zip code, or maybe enter email addresses from an addressbook.

Current version: 1.0.2
Compressed filesize: 7596 bytes
License: MIT/GPL
Tested in: Firefox 2, IE 6 & 7, Opera 9, Safari 3

Files:

Download
Changelog
Demos
Documentation (Plugin Options)

Dependencies

Required

Optional

  • optional: bgiframe plugin to fix select-problems in IE, just include to apply to autocomplete

Support

  • Please post questions to the jQuery discussion list, putting [autocomplete] into the subject of your post, making it easier to spot it and respond quickly. Keep your question short and succinct and provide code when possible; a testpage makes it much more likely that you get an useful answer in no time.
  • Please post bug reports and other contributions (enhancements, features) to the jQuery bug tracker (requires registration). Please put [autocomplete] into the title of a ticket.

JQuery plugin: Autocomplete

Autocomplete an input field to enable users quickly finding and selecting some value, leveraging searching and filtering.

By giving an autocompleted field focus or entering something into it, the plugin starts searching for matching entries and displays a list of values to choose from. By entering more characters, the user can filter down the list to better matches.

This can be used to enter previous selected values, eg. for tags, to complete an address, eg. enter a city name and get the zip code, or maybe enter email addresses from an addressbook.

Current version: 1.0.2
Compressed filesize: 7596 bytes
License: MIT/GPL
Tested in: Firefox 2, IE 6 & 7, Opera 9, Safari 3

 

官方JS下载地址:http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/

[hadoop]Hadoop相关网络资源汇总

mikel阅读(1023)

(NOTE: 之前研究过的一些hadoop相关资料,在这里汇总起来,方便他人学习)
第一手资源
hadoop官方网站

最权威的官方资源之一

hadoop.cn(偶尔有一些有用信息)
手册

相关Blog
facebook工程师blog
hadoop0.19特性归纳
这个家伙很有意思,并且是研究hadoop的

http://www.blogjava.net/killme2008/archive/2008/06/05/206043.html


hadoop源码剖析不错的

http://caibinbupt.javaeye.com/blog/292073

也研究MapReduce的家伙



相关主题和文档



http://zkl-1987.javaeye.com/blog/365172

http://www.javaeye.com/topic/365172
hadoop namenode 高可用性(容灾)(Redundant Network Architecture, 相关软件有: Linux bonding, heartbeat
, DRBD Disk
)
http://www.hadoop.org.cn/document/Hadoop%20Namenode%20High%20Availability.pdf
图书

<<Pro hadoop>>
<<hadoop: the definitive guide>> (hadoop作者写的)
MISC

清华大学的分布式相关课程




[Flex]Flex与.NET互操作系列文章

mikel阅读(722)

    本系列文章主要介绍了关于Flex与.NET结合开发中的一些互操作性,包括网络通信、数据加载、数据传输、文件传输、以及应用于Flex与.NET协作开发的通信网关开源项目FluorineFx的相关知识点。

     开源项目FluorineFx就是专门针对.NET平台与Flex通信提供的AMF协议通信网关,我们可以通过FluorineFx很方便的完成与.NET的通信。 另外还可以轻松的实现及时文字沟通、视频语音通信等及时交互系统的开发。

     FluorineFx官方提供了安装包的下载和在线文档,可以帮助我们有效的利用FluorineFx来开发。 

     FluroineFx官方网站http://www.fluorinefx.com/    

     FluroineFx下载地址:http://www.fluorinefx.com/download.html

     FluroineFx在线文档:http://www.fluorinefx.com/docs/fluorine/index.html

     

     本系列文章的程序开发环境选择如下:

     .NET:Microsoft Visual Studio 2008 + .NET Framework 3.5

     Flex:Adobe Flex Builder CS3 + Flex SDK 3.2

     FluroineFx:FluorineFx v1.0.0.15 (点击可下载)

     文章目录如下:

     1、Flex与.NET互操作(一):基于Socket的网络连接

     2、Flex与.NET互操作(二):基于WebService的数据访问(上)

     3、Flex与.NET互操作(三):基于WebService的数据访问(下)

     4、Flex与.NET互操作(四):使用HttpService、URLReqeust和URLLoader加载/传输数据 

     5、Flex与.NET互操作(五):使用FileReference+HttpHandler实现文件上传/下载

     6、Flex与.NET互操作(六):Flex和.NET协同开发利器FluorineFx

     7、Flex与.NET互操作(七):了解FluorineFx的环境配置(远程对象、网关、通道、目的地)

     8、Flex与.NET互操作(八):使用FluorineFx网关实现远程访问

     9、Flex与.NET互操作(九):FluorineFx.NET的认证(Authentication )与授权(Authorization) 

   10、Flex与.NET互操作(十):FluorineFx.Net的及时通信应用(ApplicationAdapter)(一)  

   11、Flex与.NET互操作(十一):FluorineFx.Net的及时通信应用(Remote Procedure Call)(二)

   12、Flex与.NET互操作(十二):FluorineFx.Net的及时通信应用(Remote Shared Objects)(三)

   13、Flex与.NET互操作(十三):FluorineFx.Net实现视频录制与视频回放 (回复中有视频聊天的实现)

   14、Flex与.NET互操作(十四):FluorineFx的AMF(Action Message Format)协议通信

   15、Flex与.NET互操作(十五):使用FluorineFx中的字节数组(ByteArray)实现图片上传

 

      本系列文章暂时就写到这里,希望对学习基于.NET后台的Flex开发的朋友起到一定的帮助作用。另外在此谢谢长期以来支持我这一系列文章的朋友。

 

版权说明

  本文属原创文章,欢迎转载,其版权归作者和博客园共有。  

  作      者:Beniao

 文章出处:http://beniao.cnblogs.com/  或  http://www.cnblogs.com/

 

[Mobile]Windows Mobile开发资源文章列表

mikel阅读(643)

智能手机

手机词汇

研发手机基本流程

我理解的Windows moblie

J2ME,CompactFramework,c++,我该如何取舍

Windows Mobile Jump Start Guide

从0开始Windows Mobile 开发

3G 手机流媒体应用,看上去很美

基于rtsp的手机视频点播实现和研究

手机流媒体 
 

UI开发 

WINCE应用的UI实现方案 —— 上篇:几种UI实现方案比较

Windows Mobile 和 Wince 下的 WTL(Windows Template Library) 界面开发

Mobile个人开发(绘制背景图片)

怎样在Windows Mobile上设计一个美观的用户界面程序(Win32)

EVC中的图片背景透明处理

Windows Mobile载入位图的方法

[翻译]Windows Mobile应用程序设计指导-软键和菜单

创建Windows Mobile上兼容性好的UI 程序

windows mobile 5.0 下创建菜单

在Visual Studio 2005下创建WM for Smartphone/Standard 软键菜单的问题

AP的全屏与非全屏的切换

如何创建在 PocketPC 全屏幕应用程序(转)

关于wince中的全屏显示

用本地代码实现屏幕方向自适应的Windows Mobile程序

mobile手机上窗体最小化后置icon在消息栏的处理.

 

GPRS开发系列 

GPRS入门知识

GPRS开发系列文章之入门篇(转)

GPRS开发系列文章之进阶篇

GPRS开发系列文章之实战篇(转)

GPRS技术在配电监控系统中的应用[转载]

WM5.0下连接移动GPRS

Windows Mobile中如何建立GPRS连接以便Socket能正常通信

PDA/PPC下如何获取GPRS的网络流量(ZT)

windows ce gprs 拨号程序(转)

C# wm6通过udp协议和pc通讯

 

.NET Compact Framework

.NET Compact Framework 多线程下的等待事件

.NET Compact Framework 多线程环境下的UI异步刷新

定时关闭窗口 For Windows Mobile SP/PPC

Microsoft .NET CF 与非托管代码交互注意事项

.NET Compact Framework 下的3G应用

在.NET Compact Framework调用PPC设备的震动功能

.Net Compact Framework 基础篇(1)

.Net Compact Framework 基础篇(4)

.Net Compact Framework 高级篇(1)

列车时刻表 开发回顾 (一):后台线程更新前端界面

 

开发环境 + 模拟器使用 + 疑难杂症 

VS无法调试智能设备程序的解决方案

在Windows Mobile Emulator建立网络连接

配置PPC模拟器网络环境,调试TCP/UDP套接字程序

Windows Mobile 2003 SE 模拟器上网设置

Ring Tone Manager on Windows Mobile

Windows Mobile Device Emulator In-Depth–(1)

Windows Mobile Device Emulator In-Depth–(2)

在Visual Studio 2005里,用ActiveSync来同步模拟器(Windows Mobile 5.0 For Smartphone)

也谈EVC工程移植

手机音频流媒体应用与优化指南

ANSI码和UNICODE码转化

WCHAT、TCHAT、CString和char*的转换(WM5.0)

WinCe和Windows Mobile下的字符串转换

【转】使用 AYGShell 实现 Windows CE .NET 和 Pocket PC 2002 外壳兼容性

[转]从AP中获取电池和电源信息变更通知的方法

中文问题-Mobile-UrlEncode

如何判断当前WM系统是否是Smartphone?

利用tmail.exe 命令参数来发送邮件

 

其它资源 

Wince 

Windows Mobile

Windows Mobile 开发工具和资源

移动开发索引贴  

平时收获,供需及取(PPC)

Mobile开发之路_之小总结

WINCE 开发资料汇集

iPhone开发知识介绍

symbian中的新手问题整理(均有解答)

Mobile.ConnectionMonitor

Windows Mobile-Bookmarks

Windows Mobile 系列文章索引—不断整理中(2009-04-04)

H.264系列视频编解码器代码下载(Windows和Windows CE/Windows Mobile版本)

手机音视频流媒体开发一些有用资料

水煮TCPMP

WinCE开发流媒体播放器--MPEG4

Windows Mobile 开发资源

Windows Mobile 常用键值(VK)对应表及系统文件夹简单介绍

 

 

具体应用开发文章 

WM性能优化的一些经验

Windows Mobile SP/PPC 中 Menu Bar 使用完美方案

Windows Mobile平台上重写Back健的行为

也谈Windows Mobile中打开/关闭WIFI

VC通用控件自适应屏幕类

在非纯色背景上,叠加背景透明的BUTTON和STATIC_TEXT控件

在Windows mobile 5.0下操作INI文件

WinMoblie 利用EVC读写INI,XML配置文件

windows mobile 5.0 下创建菜单

Windows Mobile 发送短信的问题

3G应用—windows mobile和symbian平台下rtsp流媒体播放器

[流媒体]实例解析MMS流媒体协议,下载LiveMediaVideo[1][修正版,增加了带宽测试包]

[J2ME]手机看交通监视器实时录像 实现说明

[J2ME]手机流媒体之实作[附源码][与RTSP/MMS协议无关]

【蛙蛙推荐】手机通讯录实现

[Flex]Flex与.NET互操作(十五):使用FluorineFx中的字节数组(ByteArra

mikel阅读(878)

     前几天一位朋友问我一个问题,他说:“我用HTTP接口或是WebService接口可以实现图片上传功能,那么用FluorineFx 如何实现图片上传功能呢?”,其实仔细看官方文档和示例程序的自己都可以找到答案,实现上传可以有很多种实现,这里我以官方所提供是示例为基础稍加改动, 通过ByteArray类实现图片上传。

      首先建立FluorineFx库和网站,在远程服务器类里添加一个处理文件上传的方法,详细代码如下:

namespace ByteStream.Services
{
    [RemotingService]
    
public class ByteStreamService
    {
        
public ByteArray UploadImage(ByteArray ba)
        {
            MemoryStream ms 
= new MemoryStream(ba.GetBuffer());
            Image img 
= Bitmap.FromStream(ms);

            Bitmap newImage 
= new Bitmap(img);
            MemoryStream tempStream 
= new MemoryStream();
            newImage.Save(tempStream, System.Drawing.Imaging.ImageFormat.Png);
            
string path = HttpContext.Current.Server.MapPath("UpLoad/ByteArray.png");
            FileStream fs 
= new FileStream(path, FileMode.Create);
            tempStream.WriteTo(fs);
            fs.Close();
            ByteArray result 
= new ByteArray(tempStream);
            
return result;
        }
    }
}

 

      处理图片上传的方法通过把flex客户端传递来的字节数组包装为内存流,然后通过写文件的形式将图片保存到指定的目录下。示例中提供了 一个画图板,用户可以通过选择颜色自画不同的图象,然后保存到服务器上指定的目录。画图板的实现是根据鼠标按下的移动路线做的,代码如下:

private function doMouseDown():void
{
    x1 
= myCanvas.mouseX;
    y1 
= myCanvas.mouseY;
    isDrawing 
= true;
}
private function doMouseMove():void
{
    x2 
= myCanvas.mouseX;
    y2 
= myCanvas.mouseY;
    
if (isDrawing)
    {
        myCanvas.graphics.lineStyle(
2, drawColor);
        myCanvas.graphics.moveTo(x1, y1);
        myCanvas.graphics.lineTo(x2, y2);
        x1 
= x2;
        y1 
= y2;
    }
}
private function doMouseUp():void
{
    isDrawing 
= false;
}
//清空画图板
private function onErase(event:MouseEvent):void
{
    myCanvas.graphics.clear();
}

      

      在官方实例中是使用的RemoteObject实现的,这里我将其修改为通过编程实现AMF通信实现当程序初始化的时候就建立与FluorineFx网关的AMF通信连接:

private var nc:NetConnection;
private var rs:Responder;
private function init():void
{
    rs 
= new Responder(onResult,onFault);
    nc 
= new NetConnection();
    nc.connect(
"http://localhost:2453/FluorineFxWeb/Gateway.aspx")
    nc.client 
= this;
}

 

      在Flex客户端通过当前网络连接的call()方法实现远程方法调用,并指定通过Responder来处理服务器端方法的返回结果。

private function onSaveImage(event:MouseEvent):void
{
    var bd:BitmapData 
= new BitmapData(myCanvas.width,myCanvas.height);
    bd.draw(myCanvas);
    var ba:ByteArray 
= new PNGEncoder().encode(bd);
    nc.call(
"ByteStream.Services.ByteStreamService.UploadImage",rs,ba);
}

 

小提示

      在进行Flex开发中,能够通过编程实现的最好通过编程实现,尽量少的去使用Flex组件,这样可以有效的给Flex程序瘦身。

 

      服务器端将传递过去的ByteArray数据返回到了客户端,客户端接收到这些数据通过处理将字节数组转化为显示对象后显示到界面上。

private function onResult(result:ByteArray):void
{
    var loader:Loader 
= new Loader();
    loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loaderCompleteHandler);
    loader.loadBytes(result);
}
private function loaderCompleteHandler(event:Event):void
{
    var loader:Loader 
= (event.target as LoaderInfo).loader;
    loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,loaderCompleteHandler);
    var pictureHolder:UIComponent 
= new UIComponent();
    pictureHolder.addChild(loader);
    
this.resultImage.width = myCanvas.width;
    
this.resultImage.height = myCanvas.height;
    
this.resultImage.addChild(pictureHolder);
}
private function onFault(event:Object):void
{}

 

      到此就完成了图片上传功能,下面是完整的Flex客户端代码:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" fontSize="12" creationComplete="init()">
    
<mx:Script>
        
<![CDATA[
            import mx.core.UIComponent;
            import mx.controls.Alert;
            import mx.events.ResizeEvent;
            import mx.graphics.codec.PNGEncoder;
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
            
            
private var isDrawing:Boolean=false;
            
private var x1:int;
            
private var y1:int;
            
private var x2:int;
            
private var y2:int;
            
private var drawColor:uint;
            
            
private var nc:NetConnection;
            
private var rs:Responder;
            
private function init():void
            
{
                rs 
= new Responder(onResult,onFault);
                nc 
= new NetConnection();
                nc.connect(
"http://localhost:2453/FluorineFxWeb/Gateway.aspx")
                nc.client 
= this;
            }

            
            
private function onSaveImage(event:MouseEvent):void
            
{
                var bd:BitmapData 
= new BitmapData(myCanvas.width,myCanvas.height);
                bd.draw(myCanvas);
                var ba:ByteArray 
= new PNGEncoder().encode(bd);
                nc.call(
"ByteStream.Services.ByteStreamService.UploadImage",rs,ba);
            }

            
            
private function onResult(result:ByteArray):void
            
{
                var loader:Loader 
= new Loader();
                loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loaderCompleteHandler);
                loader.loadBytes(result);
            }

            
private function loaderCompleteHandler(event:Event):void
            
{
                var loader:Loader 
= (event.target as LoaderInfo).loader;
                loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,loaderCompleteHandler);
                var pictureHolder:UIComponent 
= new UIComponent();
                pictureHolder.addChild(loader);
                
this.resultImage.width = myCanvas.width;
                
this.resultImage.height = myCanvas.height;
                
this.resultImage.addChild(pictureHolder);
            }

            
            
private function onFault(event:Object):void
            
{}
            
            
private function doMouseDown():void
            
{
                x1 
= myCanvas.mouseX;
                y1 
= myCanvas.mouseY;
                isDrawing 
= true;
            }

            
private function doMouseMove():void
            
{
                x2 
= myCanvas.mouseX;
                y2 
= myCanvas.mouseY;
                
if (isDrawing)
                
{
                    myCanvas.graphics.lineStyle(
2, drawColor);
                    myCanvas.graphics.moveTo(x1, y1);
                    myCanvas.graphics.lineTo(x2, y2);
                    x1 
= x2;
                    y1 
= y2;
                }

            }

            
private function doMouseUp():void
            
{
                isDrawing 
= false;
            }

            
//清空画图板
            private function onErase(event:MouseEvent):void
            
{
                myCanvas.graphics.clear();
            }

        ]]
>
    
</mx:Script>
    
    
<mx:Panel x="10" y="10" width="348" height="306" layout="absolute">
        
<mx:Canvas x="10" y="10" width="315" height="210" id="myCanvas"
            mouseDown
="doMouseDown()"
            mouseMove
="doMouseMove()"
            mouseUp
="doMouseUp()">
        
</mx:Canvas>
        
<mx:ControlBar>
            
<mx:ColorPicker change="drawColor = event.target.selectedColor"/>
            
<mx:Button label="清除" click="onErase(event)"/>
            
<mx:Button label="保 存" click="onSaveImage(event)"/>
        
</mx:ControlBar>
    
</mx:Panel>
    
<mx:Image x="382" y="10" id="resultImage"/>
</mx:Application>

 

      本文示例程序下载:ByteStreamDemo.rar

版权说明

  本文属原创文章,欢迎转载,其版权归作者和博客园共有。  

  作      者:Beniao

 文章出处:http://beniao.cnblogs.com/  或  http://www.cnblogs.com/