[转载]电子商务网站搜索架构方案

mikel阅读(1095)

[转载]电子商务网站搜索架构方案 – 叶鹏 – 博客园.

说是电子商务搜索架构方案,其实就是lucene.net的应用,公司庙小,人少,也就自己平时看看,以前做过一点例子,这样就被拉上去写架构方案了。 我这个懒惰的家伙,在网上疯狂的搜集搜索架构方面的东西,因为做做架构,暂时没写代码,每天就看人家博客,结果两个星期了才弄了个大概的草图,这不清明节 过后就要详细方案了,现在只能把我的草图分享一下,希望大家板砖伺候,闷在家里鼓捣比较郁闷啊,效率太低。

基于lucene的搜索方案

一、            Lucene 简介

Lucene是apache的一个顶级开源项目,由java实现的全文检索引擎,能基于各种文档格式的全文索引和检索,包括word、pdf,不包括图形类。

Lucene.net 是C#版的lucene 是由java的lucene翻译过来的,也被apache列为开源项目对外发布,功能和java的基本一样,但是由于缺乏良好的技术支持和社区活跃度,目前已被apache放入孵化器

Lucene写入:源文件经过analyzer处理,包括分词,权重处理、生成document记录,写入存储器(硬盘或者内存)。

Lucene 读出:对搜索关键词进行analyzer处理,包括分词、权重、范围匹配处理.源码结构图如下:

具体流程如下图:

数据流图如下:

二、常用推荐引擎算法问题

采用基于数据挖掘的算法来实现推荐引擎是各大电子商务网站、SNS社区最为常用的方法,推荐引擎常用Content-Based 推荐算法及协同过 滤算法(Item-Based 、User-based)。但从实际应用来看,对于大部分中小型企业来说,要在电子商务系统完整采用以上算法还有很大的难 度。

1)、相对成熟、完整、现成的开源解决方案较少

粗略分来,目前与数据挖掘及推荐引擎相关的开源项目主要有如下几类:

数据挖掘相关:主要包括Weka、R-Project、Knime、RapidMiner、Orange 等

文本挖掘相关:主要包括OpenNLP、LingPipe、FreeLing、GATE 、Carrot2 等,具体可以参考LingPipe’s Competition

推荐引擎相关:主要包括Apache Mahout、Duine framework、Singular Value Decomposition (SVD) ,其他包可以参考Open Source Collaborative Filtering Written in Java

搜索引擎相关:Lucene、Solr、Sphinx、Hibernate Search等

2)、常用推荐引擎算法相对复杂,入门门槛较高

3)、常用推荐引擎算法性能较低,并不适合海量数据挖掘

以上这些包或算法,除了Lucene/Sor相对成熟外,大部分都还处于学术研究使用,并不能直接应用于互联网规模的数据挖掘及推荐引擎引擎使用。

(以上都是基于java的,需要自己去研究实现,有很大难度)

备注:除了分类查找和主动搜索,推荐系统也是用户浏览商品的重要途径,能帮助用户发现类似并感兴趣的产品,增加商品的访问量,将访问者转化为购买者,引导用户购买。最终产生的价值是提升用户购物体验和用户粘度,提高订单量,如Amazon30%的订单来自推荐系统。

采用Lucene实现推荐引擎的优势

对很多众多的中小型网站而言,由于开发能力有限,如果有能够集成了搜索、推荐一体化的解决方案,这样的方案肯定大受欢迎。采用Lucene来实现推荐引擎具有如下优势:

1)、Lucene 入门门槛较低,大部分网站的站内搜索都采用了Lucene

2)、相对于协同过滤算法,Lucene性能较高

3)、Lucene对Text Mining、相似度计算等相关算法有很多现成方案

在开源的项目中,Mahout或者Duine Framework用于推荐引擎是相对完整的方案,尤其是Mahout 核心利用了Lucene,因此其架构很值得借鉴。只不过Mahout目前功能还不 是很完整,直接用其实现电子商务网站的推荐引擎尚不是很成熟。只不过从Mahout实现可以看出采用Lucene实现推荐引擎是一种可行方案。

3、采用Lucene实现推荐引擎需要解决的核心问题

Lucene对于Text Mining较为擅长,在contrib包中提供了MoreLikeThis功能,可以较为容易实现Content-Based的推荐,但对于涉及用户协 同过滤行为的结果(所谓的Relevance Feedback),Lucene目前并没有好的解决方案。需要在Lucene中内容相似算法中加入用户协同过滤行为对因素,将用户协同过滤行为结果转化 为Lucene所支持的模型。

推荐引擎的数据源

电子商务网站与推荐引擎相关典型的行为:

购买本商品的顾客还买过

浏览本商品的顾客还看过

浏览更多类似商品

喜欢此商品的人还喜欢

用户对此商品的平均打分

因此基于Lucene实现推荐引擎主要要处理如下两大类的数据

1)、内容相似度

例如:商品名称、作者/译者/制造商、商品类别、简介、评论、用户标签、系统标签

2)、用户协同行为相似度

例如:打标签、购买商品、点击流、搜索、推荐、收藏、打分、写评论、问答、页面停留时间、所在群组等等

5、实现方案

5.1、内容相似度 基于Lucene MoreLikeThis实现即可。

5.2、对用户协同行为的处理

1)、用户每一次协同行为都使用lucene来进行索引,每次行为一条记录

2)、索引记录中包含如下重要信息:

商品名、商品id、商品类别、商品简介、标签等重要特征值、用户关联行为的其他商品的特征元素、商品缩略图地址、协同行为类型(购买、点击、收藏、评分等)、Boost值(各协同行为在setBoost时候的权重值)

3)、对评分、收藏、点击等协同行为以商品特征值(标签、标题、概要信息)来表征

4)、不同的协同行为类型(例如购买、评分、点击)设置不同的值setBoost

5)、搜索时候采用Lucene MoreLikeThis算法,将用户协同转化为内容相似度

以上方案只是基于Lucene来实现推荐引擎最为简单的实现方案,方案的准确度及细化方案以后再细说。

更为精细的实现,可以参考Mahout的算法实现来优化。

其他搜索引擎开源工具推荐:Sphinx,目前是基于出自俄罗斯的开源全文搜索引擎软件Sphinx,单一索引最大可包含1亿条记 录,在1千万条记录情况下的查询速度为0.x秒(毫秒级)。Sphinx创建索引的速度为:创建100万条记录的索引只需3~4分钟,创建1000万条记 录的索引可以在50分钟内完成,而只包含最新10万条记录的增量索引,重建一次只需几十秒。

Sphinx 是一个基于 GPL 2 协议颁发的免费开源的全文搜索引擎.它是专门为更好的整合脚本语言和SQL数据库而设计的.当前内置的数据源支持直接从连接到 的 MySQL 或 PostgreSQL获取数据, 或者你可以使用 XML 通道结构(XML pipe mechanism , 一种基于 Sphinx 可识别的特殊xml格式的索引通道)

基于LAMP架构的应用很广泛,目前了解的商业应用有康盛的Discuz企业版。

三、手机之家的搜索方案(参考用)

手机之家目前的Lucene应用,采用的是Lucene 2.4.1 + JDK 1.6(64 bit)的组合,运行在8 CPU, 32G内存的机器上,数据量超过3300万条,原始数据文件超过14G,每天需要支持超过35万次的查询,高峰时期QPS超过20。单看这些数据可能并没 有大的亮点,但它的重建和更新都是自动化完成,而且两项任务可以同时运行,另一方面,在不影响服务可靠性的前提下,尽可能快地更新数据(如果两者发生冲 突,则优先保证可用性,延迟更新),其中的工作量还是非常大的

PPT连接 http://www.slideshare.net/tangfl/lucene-1752150

在大规模的应用中,Lucene更适合用于狭义的“搜索”,而不应当负责数据的存储。我们看看Lucene的源代码也可以知道,Document和 Field的存储效率是不够好看的。手机之家的团队也发现了这一点,他们的办法是,用Lucene存放索引,用Memcache + Berkeley DB(Java Edition)负责存储。这样有两个好处,一是减轻了Lucene的数据规模,提高了程序的效率;另一方面,这套系统也可以提供某些类似SQL的查询功 能。实际上,Lucene本身似乎也注意到了这个问题,在Store中新增了一个db的选项,其实也是利用的Berkeley DB。

在大规模应用中,Cache是非常重要的。PPT中也提到,可以在程序提供服务之前,进行几次”预热“搜索,填充Searcher的Cache。据 我们(银杏搜索)的经验,也可以在应用程序中,再提供针对Document的Cache,这样对性能有较大的改善。Lucene自己似乎也注意到了这个问 题,在2.4版本中提供了Cache,并提供了一个LRU Cache实现。不过据我们测试,在极端情况下,这个Cache可能会突破大小限制,一路膨胀最后吃光内存,甚至从网络上找的许多LRU Cache实现在极端条件下都有可能出现这样的问题,最终自己写了一个LRU Cache,并修改多次,目前来看是稳定的。

在编写Java服务程序的时候,记得设置退出的钩子函数(RunTime.getRunTime.addShutdownHook)是一个非常好的 习惯。许多Java程序员都没有这种意识,或者有,也只是写一个finalize函数,结果程序非正常退出时,可能造成某些外部资源的状态不稳定。拿 Lucene来说,之前的IndexWriter是默认autoCommit的,这样每添加一条记录,就提交一次,好处是如果中断,则之前添加的记录都是 可用的,坏处则是,索引的速度非常低。在新版本中autoCommit默认为False,速度提升明显(我们测试的结果是,提高了大约8倍),但如果中途 异常退出,则前功尽弃。如果我们添加了退出的钩子函数,捕获到退出信号则自动调用writer.close()方法,就可以避免这个问题。

目前的Lucene是兼容JDK 1.4的,它的binary版本也是JDK1.4编译的,如果对性能要求比较高,可以自行下载Lucene Source Code,用更新版本的JDK编译出.jar文件,据我测试,速度大约有30%的提升。

四、            XX网搜索方案

4.1 初步解决方案:

实现站内产品的分词搜索、推荐关键词和简单排序,定时自动更新,索引读写分离。

基于服务器的搜索压力大,用户的搜索体验不够有好,初步解决方案目标是解决服务器的搜索压力,实现初步的分词搜索,索引的自动定时维护。

4.1.1 数据库产品表分析:

l        大类基表

l        产品分类扩展基表

l        品牌基表,品牌系列表基表

l        产品基表(主表)

l        颜色基表

产品基表的数据大概在8万条左右,占用空间40m左右,单表数据量相对来书还是比较小的。

4.1.2  Lucene索引程序:

通过lucene的索引程序将库里的数据读入流,然后写入lucene自定义的索引文件,这个索引文件不进行搜索操作,需要完成后替换到搜索索引。 在建立索引的过程中进行分词处理,分词组件采用eaglet开发的盘古分词组件(已基于apache开源协议开源,进一步功能需要自己二次开发)。

4.1.3  Lucene索引库:

基表的索引文件大概在100m左右,分为写入时的库和搜索时用的库,写入库完成后并入搜索库,考虑到新索引合覆盖就索引的瞬间可能产生的索引程序错误或者索引文件损坏,在覆盖的同时通过程序控制让搜索程序读取写索引里的文件。

l        搜索处理services:基于产品库的的搜索,如品牌,分类,价格区间。搜索程序依赖于接口,基于数据库的搜索和基于文件的搜索要按需要随时切换。搜索的同时需要利用分词组件分词处理,对分词后的结果进行检索,数据库检索的暂时不做分词处理。

l        查询处理:查询前台程序使用mvc,实现产品的分词高亮显示,按照类别分类查询,品牌分类查询,价格区间查询。

4.2 第二步关键词统计:

搜索关键词的搜集和搜索的联合处理,实现简单的搜索推荐功能。主要是对前台的搜索关键字进行统计分析,并与搜索的排序进行关联,关键词的处理和与主表的关联索引方案等初步处理完成后再做完整解决方案。

4.3 第三步优化完善:

实现索引文件的基于消息的增量自动更新,权重计算,推荐产品计算研究,实时搜索的研究。权重计算,需要重新开发自己的向量算法引擎,考虑当中。

实时搜索目前在学习当中。

4.3.1 权重计算

权重计算方法会将前台用户的统计数据和产品库进行关联开发一套天天网产品的权重排序计算方法,以下算法流程图只是一个构思。

权重计算设计

4.3.2 索引自动化更新

建立基于消息机制的一个索引更新与维护机制。

基于消息队列的索引生成程序

[转载]用Eclipse开发和调试Android应用程序(一)

mikel阅读(886)

[转载]用Eclipse开发和调试Android应用程序(一) – Android – mobile – JavaEye论坛.

前面介绍了Windows环境下,基于Android SDK(2.3) 和 Eclipse(helios)的Android开发环境的搭建,并创建了第一个应用程序Hello Android World。具体挺参考小生的blog:http://blog.sina.com.cn/deaboway 或者http://blog.csdn.net/deaboway 。

现在,我们已经可以使用Eclipse来创建和开发Android应用程序,本文将仍以Hello Android World工程来深入解析Eclipse中Android工程的结构以及调试。

写上篇的时候,刚好Android SDK Platform Honeycomb Preview, revision 1(android-3.0_pre_r01-linux.zip)已经加入http://dl-ssl.google.com/android /repository/repository.xml,却无法下载,因此我们的第一个Android应用程序是用的Android SDK Platform 2.3.1,即Android 9 AVD进行演示。现在Android SDK Platform Honeycomb Preview已经放到http://dl-ssl.google.com/android/repository/android- 3.0_pre_r01-linux.zip,敢为天下先是我等求知若渴的程序员的优秀品质,因此,本次我们使用最新版本的Android SDK Platform Honeycomb Preview来进行我们本次教程。

先看看最新的Honeycomb Preview的样子吧(由于是Preview版本,启动确实不敢恭维,根据传闻,前几天之所以该版本一度无法下载安装是因为google发现这个Preview版本太烂,面子上挂不住,所以又撤掉了,呵呵):

相比手机上目前使用的最高Android 2.3版本而言,Android 3.0 Honeycomb更适合平板电脑使用,是专门为Android平板电脑进行优化的系统版本。随着SDK的发布,更加有利于开发者和厂商针对 Android 3.0 Honeycomb平板电脑进行开发,包括Android平板电脑应用和匹配。

一、 Android 应用程序概述

1. Android 的嫡系组件

Android有四项一等公民(或称为嫡系组件),包括:Activity(活动)、ContentProvider(内容提供程序)、 BroadcastReceiver(广播接收器)与Service(服务)。它们都必须宣告于AndroidManifest.xml档案里。

Activity 活动

活动是最常用的 Android 应用程序形式。活动在一个称为视图(后文将介绍)的类的帮助下,为应用程序提供 UI。视图类实现各种 UI 元素,比如文本框、标签、按钮和计算平台上常见的其他 UI 元素。

一个应用程序可以包含一个或多个活动。这些活动通常与应用程序中的屏幕形成一对一关系。

应用程序通过调用 startActivity() 或 startSubActivity() 方法从一个活动转移到另一个活动。如果应用程序只需“切换”到新的活动,就应该使用前一个方法。如果需要异步的调用/响应模式,就使用后一个方法。在这两 种情况下,都需要通过方法的参数传递一个 intent。

由操作系统负责决定哪个活动最适合满足指定的 intent(后文将介绍)。

对于Activity,关键是其生命周期的把握(后文将介绍),其次就是状态的保存和恢复(onSaveInstanceState onRestoreInstanceState),以及Activity之间的跳转和数据传输(intent)。

Activity几乎承接着用户对应用程序(Application)的所有操作,Activity应该有一个窗口(Window),这个窗口是 可以通过不用的主题(Theme)改变样子的。Activity应该要注意它的生命周期(Lifecycle)、设备状态(Configuration) 改变时的影响以及运行状态和数据的保存,这个在一个应用程序是否可靠和人性化上至关重要。Activity里还应该要申明一些许可 (Permissions),以便使用Android的一些软硬件功能,这些申明可以由代码或者Manifest.xml给出。最后,每个 Activity(的入口)一定要在Manifest当中申明。

Service 服务

与其他多任务计算环境一样,“在后台”运行着一些应用程序,它们执行各种任务。Android 把这种应用程序称为“Service服务”。

Service是没有界面的程序,它是所谓的服务,也叫后台程序。应该要非常注意Service的启动(startService)和绑定 (bindService)这两种开启Service的方法之间的关系以及Service对应的生命周期,两种开户Service的方法对Service 的生命周期效果是不同的。还有就是申明许可以及申明Service,也是在代码内或者Manifest内申明。

BroadcastReceiver 广播接收器

广播接收器是一个应用程序组件,它接收请求并处理 intent。与服务一样,接收器在一般情况下也没有 UI 元素。广播接收器通常在 AndroidManifest.xml 文件中注册。广播接收器的类属性是负责实现这个接收器的 Java 类。

广播接收并不是通常所说的无线电广播,而是指由sendBroadcast()所发送出来的意图(Intent),即广播在这里的意思是意 图,BroadcastReceiver在注册(Registe)之后可以自动监听符合预先给定的条件的意图,如果有则会通知此 BroadcastReceiver的持有程序。

ContentProvider 内容提供程序 ——数据管理

内容提供程序是 Android 的数据存储抽象机制。我们以移动设备上常见的一种数据为例:地址簿或联系人数据库。地址簿包含所有联系人及其电话号码,用户在使用手机时可能需要使用这些 数据。内容提供程序对数据存储的访问方法进行抽象。内容提供程序在许多方面起到数据库服务器的作用。对数据存储中数据的读写操作应该通过适当的内容提供程 序传递,而不是直接访问文件或数据库。可能还有内容提供程序 的 “客户机” 和 “实现”。

ContentProvider是作保存应用程序数据和建立维持数据库之用,以便程序重新启动时回到以前的状态或者保存信息。应该注意应用程序的使用权限以及SQL语言的使用,Android用的是一个轻量级的数据库系统SQLite。

2. Android 生命周期

Android 程序的生命周期是由系统控制而非程序自身直接控制,这与桌面应用程序在程序自身收到关闭请求后执行一个特定的动作(比如从 main 函数中 return)而导致进程结束的思维不同。

在Android系统中,当某个activity调用startActivity(myIntent)时,系统会在所有已经安装的程序中寻找其 intentfilter和myIntent最匹配的一个activity,启动这个进程,并把这个intent通知给这个activity。这就是一个 程序的“生”。在Android中,所有的应用程序“生来就是平等的”,所以不光Android的核心程序甚至第三方程序也可以发出一个intent来启 动另外一个程序中的一个activity。Android的这种设计非常有利于“程序部件”的重用。

Android根据其重要性在内存不足的时候移去重要性最低的进程。重要性由高到低为:

1.前台进程。这样的进程拥有一个在屏幕上显示并和用户交互的activity或者它的一个IntentReciver正在运行。这样的程序重要性最高,只有在系统内存非常低,万不得已时才会被结束。

2.可见进程。在屏幕上显示,但是不在前台的程序。比如一个前台进程以对话框的形式显示在该进程前面。这样的进程也很重要,它们只有在系统没有足够内存运行所有前台进程时,才会被结束。

3.服务进程。这样的进程在后台持续运行,比如后台音乐播放、后台数据上传下载等。这样的进程对用户来说一般很有用,所以只有当系统没有足够内存来维持所有的前台和可见进程时,才会被结束。

4.后台进程。这样的程序拥有一个用户不可见的activity。这样的程序在系统内存不足时,按照LRU的顺序被结束。

5.空进程。这样的进程不包含任何活动的程序部件。系统可能随时关闭这类进程。

从某种意义上讲,垃圾收集机制把程序员从“内存管理噩梦”中解放出来,而Android的进程生命周期管理机制把用户从“任务管理噩梦”中解放出 来。Android使用Java作为应用程序API,并且结合其独特的生命周期管理机制同时为开发者和使用者提供最大程度的便利。

Activity 生命周期

Activity中常用的函数有SetContentView() findViewById() finish() startActivity(),其生命周期涉及的函数有:

void onCreate(Bundle savedInstanceState)

void onStart()

void onRestart()

void onResume()

void onPause()

void onStop()

void onDestroy()

注意的是,Activity的使用需要在Manifest文件中添加相应的,并设置其属性和intent-filter。

Service 生命周期

Service可以通过Context.startService()或Context.bindService()创建,通过 Context.stopService()、Service.stopSelf()、Service.stopSelfResult()或 Context.unbindService()来关闭。其生命周期涉及的函数有:

void onCreate()

void onStart(Intent intent)

void onDestroy()

其中onCreate()和onDestroy()可以被所有服务调用,无论是由Context.startService()还是 Context.bindService()发起的Service。但是,onStart()只能被由startService()发起的Service 调用。

如果一个Service运行其它对象绑定它,需要扩展如下callback方法:

IBinder onBind(Intent intent)

boolean onUnbind(Intent intent)

void onRebind(Intent intent)

BroadcastReceiver 生命周期

只包含一个方法:void onReceive(Context curContext, Intent broadcastMsg)

包含活动的组件的BroadcastReceiver将不会被系统关闭,但是仅包含不活动的组件的进程将随时会背系统关闭(当其它组建需要内存时)。

3. Intent 简介—— Android 的创新导航与触发机制

前文介绍了Android的四项一等公民:Activity(活动)、ContentProvider(内容提供程序)、 BroadcastReceiver(广播接收器)与Service(服务)。这四种组件是独立的,它们之间可以互相调用,协调工作,最终组成一个真正的 Android应用。

在这些组件之间的通讯中,主要是由Intent协助完成的。Intent是Android应用开发里很重要的一个元件,通过Intent可以从一 个Activity来启动另一个任意的Activity,不管是自己定义的还是系统定义的。在ActivityGroup(extends Activity)里面,Intent的flag设置对于子Activity的启动方式至关重要。

Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。

因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。

Android应用程序框架的强大之处在于它将Web习惯引入到移动应用程序中。这并不意味着该平台提供了一个强大的浏览器,也不仅限于使用 JavaScript和服务器端资源,而是涉及Android平台的工作原理以及该平台的用户如何与移动设备交互这一核心问题。互联网的强大之处一言以蔽 之,在于一切事物通过一次单击即可获得。这些单击的内容对于用户来说就是URL(UniformResource Locator,统一资源定位符)或URI(Uniform Resource Identifier,统一资源标识符)。有效使用URI可帮助用户方便快捷地访问所需的日常信息。“把链接发给我”就说明了一切。

在移动设备上复制桌面设备体验的平台只能吸引一小部分忠实的用户。多级菜单、多次单击在移动市场中通常都不被人所接受。移动应用程序对直观易用的 要求比其他任何市场中的应用程序都要高。Intent和IntentFilter将“单击”范例引入到了Android平台移动应用程序使用和开发的核心 中。

Intent 结构

Intent是执行某操作的一个抽象描述,它描述了如下内容:

首先, 要执行的动作(action)的一个简要描述,如VIEW_ACTION(查看)、EDIT_ACTION(修改)等,Android为我们定义了一套标准动作:

MAIN_ACTION

VIEW_ACTION

EDIT_ACTION

PICK_ACTION

GET_CONTENT_ACTION

DIAL_ACTION

CALL_ACTION

SENDTO_ACTION

ANSWER_ACTION

INSERT_ACTION

DELETE_ACTION

RUN_ACTION

LOGIN_ACTION

CLEAR_CREDENTIALS_ACTION

SYNC_ACTION

PICK_ACTIVITY_ACTION

WEB_SEARCH_ACTION

此外,我们还可以根据应用的需要,定义我们自己的动作,并可定义相应的Activity来处理我们的自定义动作。

其次, 执行动作要操作的数据(data),Android中采用指向数据的一个URI来表示,如在联系人应用中,一个指向某联系人的URI可能 为:content://contacts/1。这种URI表示,通过 ContentURI这个类来描述,具体可以参考android.net.ContentURI类的文档。

此外, 除了action和data这两个重要属性外,还有一些附加属性:

category(类别),被执行动作的附加信息。例如 LAUNCHER_CATEGORY 表示Intent 的接受者应该在Launcher中作为顶级应用出现;而ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选动作中的一个,这 些动作可以在同一块数据上执行。

type(数据类型),显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。

component(组件),指定Intent的的目标组件的类名称。通常 Android会根据Intent 中包含的其它属性的信息,比如action、data/type、category进行查找,最终找到一个与之匹配的目标组件。但是,如果 component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent的其它所有属性都是可选的。

extras(附加信息),是其它所有附加信息的集合。使用extras可以为组件提供扩展信息,比如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。

总之, action、 data/type、category和extras 一起形成了一种语言。这种语言使系统能够理解诸如“查看某联系人的详细信息”之类的短语。随着应用不断的加入到系统中,它们可以添加新的action、 data/type、category来扩展这种语言。应用也可以提供自己的Activity来处理已经存在的这样的“短语”,从而改变这些“短语”的行 为。

解析 Intent

在应用中,我们可以以两种形式来使用Intent:

· 显式(直接)Intent:指定了component属性的Intent(调用setComponent(ComponentName)或者setClass(Context,Class)来指定)。通过指定具体的组件类,通知应用启动对应的组件。

· 隐式(间接)Intent:没有指定comonent属性的Intent。这些Intent需要包含足够的信息,这样系统才能根据这些信息,在在所有的可用组件中,确定满足此Intent的组件。

对于显式(直接)Intent,Android不需要去做解析,因为目标组件已经很明确,Android需要解析的是那些隐式(间 接)Intent,通过解析,将Intent映射给可以处理此Intent的Activity、BroadcastReceiver或Service。

Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的 Intent,最终找到匹配的Intent。在这个解析过程中,Android是通过Intent的action、type、category这三个属性 来进行判断的,判断方法如下:

· 如果Intent指明定了action,则目标组件的IntentFilter的action列表中就必须包含有这个action,否则不能匹配;

· 如果Intent没有提供type,系统将从data中得到数据类型。和action一样,目标组件的数据类型列表中必须包含Intent的数据类型,否则不能匹配。

· 如果Intent中的数据不是content:类型的URI,而且Intent也没有明确指定它的type,将根据Intent中数据的scheme(比 如http:或者mailto:)进行匹配。同上,Intent的scheme必须出现在目标组件的scheme列表中。

· 如果Intent指定了一个或多个category,这些类别必须全部出现在组建的类别列表中。比如Intent中包含了两个类别:LAUNCHER_CATEGORY和ALTERNATIVE_CATEGORY,解析得到的目标组件必须至少包含这两个类别。

Intent 和 IntentFilter

Intent是对需要的声明。

IntentFilter是在需要时有能力和有兴趣提供协助的声明。

Intent由一系列描述所需动作或服务的信息构成。本节将介绍所请求的动作以及与之相关的数据。

IntentFilter可以是通用的,也可以特定于向某些Intent提供服务。

Intent的动作属性通常为动词,例如VIEW、PICK或EDIT。很多内置的Intent动作都是作为Intent类的成员定义的。应用程 序开发人员也可以创建新动作。要查看信息,应用程序可以采用以下Intent动作:Intent的数据部分采用URI的形式表示,并且可以是信息的任何部 分,例如联系人记录、网站位置或对媒体剪辑的引用。

IntentFilter定义Intent与应用程序之间的关系。IntentFilter可以与Intent的数据部分或动作部分相关,或同时 与两者相关。IntentFilter还包含一个category(类别)字段。类别可以帮助对动作进行分类。例如,CATEGORY_LAUNCHER 类别指示Android包含此Intent-Filter的Activity在主应用程序启动器或主界面上应该处于可见状态。

分发Intent后,系统会计算可用的Activity、Service,以及已注册的BroadcastReceiver,并将 Intent分发给大多数适当的接收者。

IntentFilter通常在应用程序的AndroidManifest.xml中使用标记进行定义。从本质上说,AndroidManifest.xml文件就是一个应用程序描述符文件。

下一节介绍,这是 Android 在移动设备屏幕上显示 UI 元素的机制。

4. Android 视图——显示用户界面( UI )元素

Android 活动通过视图显示UI元素。视图采用以下布局设计之一:

· LinearVertical – 后续的每个元素都排在前一个元素下面,形成一个单一列。

· LinearHorizontal – 后续的每个元素都排在前一个元素右边,形成一个单一行。

· Relative – 后续的每个元素相对于前一个元素有一定的偏移量。

· Table – 与 HTML 表相似的一系列行和列。每个单元格可以包含一个视图元素。

选择一种布局(或布局的组合)之后,就可以用各个视图显示 UI。

视图元素由大家熟悉的 UI 元素组成,包括:

· Button

· ImageButton

· EditText

· TextView(与标签相似)

· CheckBox

· Radio Button

· Gallery 和 ImageSwitcher(用来显示多个图像)

· List

· Grid

· DatePicker

· TimePicker

· Spinner(与组合框相似)

· AutoComplete(具有文本自动补全特性的 EditText)

视图是在一个 XML 文件中定义的。每个元素都有一个或多个属于 Android 名称空间的属性。

[转载]ASP.NET MVC HtmlHelper中的Form和Link的小扩展

mikel阅读(1314)

[转载]我对ASP.NET MVC HtmlHelper中的Form和Link的小扩展 – 迭戈 – 博客园.

项目中碰到的问题,或多或少的记录下来,一是积累,二是各位大牛给提供更好的建议。

1、HtmlHelper中的Link

您在开发web程序的时候很有可能会定义一个执行JavaScript的伪链接(这是我起的名字),例如:


<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>

之所以我喊它为伪链接是因为它并不会跳转页面(当然那种定义location.href的除外)。

问题出现在这个伪链接并不是一成不变的,是根据数据状态来确定的,例如,当某一列的值为0的时候显示该连接,为1的时候不显示该连接,

那么我们可以这么写(示例而已):

&lt;%if (1 == 1) {%&gt;
<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>
&lt;%} %&gt;
&lt;%else { %&gt;
其它的东西。。。
&lt;%} %&gt;

很好,假如我们的状态有很多种呢,你可能要用到switch,然后还会套嵌if else,那么我们的view无疑会变得Tag soup,使维护变得异常的麻烦。

还好,我们可以为HtmlHelper扩展一个方法,将这些逻辑都写到扩展方法里面。(可能有朋友说将这些链接放到独立的ViewUserControl中,但是依然不能解决问题,因为那会使我们的ViewUserControl变得和view一样)

写到方法里面的链接必然要用到HtmlHelper的方法:Html.LinkExtensions.ActionLink,这个方法几乎能够提供我们使用html标签时所有形式。为什么

要用几乎,是因为对应上面的伪链接的形式,它支持的并不好。我在查看了起源码之后,并没有找到合适的方法能让ActionLink生成类似:

<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>

的链接。所以我决定实现一个专门生成这种伪链接的ActionLink方法。和MVC自带的ActionLink一样,使用其TagBuilder很容易实现该操作:

1 ///
2  /// 生成类似a href="javascript:void(0) onclick="alert('click me');"&gt;Click Me /a 链接
3  ///
4  ///
<span> </span> 5  ///
6  ///
7  ///
8  public static string ActionLinkForJS(this HtmlHelper htmlHelper, string linkText, object htmlAttributes)
9 {
10 return ActionLinkForJS(htmlHelper, linkText, new RouteValueDictionary(htmlAttributes));
11 }
12
13  ///
14  /// 生成类似a href="javascript:void(0) onclick="alert('click me');"&gt;Click Me /a 链接
15  ///
16  ///
17  ///
///
///
public static string ActionLinkForJS(this HtmlHelper htmlHelper, string linkText, IDictionary htmlAttributes)
{
if (String.IsNullOrEmpty(linkText))
{
throw new ArgumentException("linkText");
}

TagBuilder linkTag = new TagBuilder("a");
linkTag.InnerHtml = linkText;
linkTag.MergeAttribute("href", "javascript:void(0)");
linkTag.MergeAttributes(htmlAttributes);

return linkTag.ToString(TagRenderMode.Normal);
}

这样就实现了让ActionLink生成伪链接。
2、HtmlHelper中的BeginForm

曾几何时,我一直在用HtmlHelper中的BeginForm来生成一个Form表单。最近的一次使用出现了问题,代码是这样的:

<%using (Html.BeginForm("List", "Complaint", null, FormMethod.Post, null))

因为页面有不少查询条件,类似于搜索。我会把搜索条件Post到Action里面:

public ActionResult List(ComplaintInfo paramComplaint)

页面的查询条件类似于:

请求List这个Action的时候如果传递一个id过去,会查询出来对应的一条数据,对应的URL是这样的:http://localhost:8886/Complaint/List/220

问题就出现在这里,页面生成Form标签的action属性是这样的:

<form action="/Complaint/List/220" method="post">

这种在Post到action的时候(请注意上面的List方法),会对参数进行ModelBinder,进而相当于传递了一个参数id过去,这样其它的查询条件

就失去了作用(因为id是主键)。我尝试将BeginForm的参数routeValues显示定义为null,问题依然存在。我现在就想根据传递的actionName,controllerName

进而拼接对应Form的action属性。例如,我上面的BeginForm方法应该生成统一的形式:

<form action="/Complaint/List" method="post">

而不是在把RouteValue一起放置在Form的action属性里面。

我仔细的查看了BeginForm的源码,发现问题出现在

UrlHelper方法

中使用Route组件得到VirtualPath方法,会自动将RouteData匹配到相应的URL,导致生成的Form的action属性并不会随我们所欲。知道了问题,

改起来也很容易:

public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues, FormMethod method, object htmlAttributes)
 {
      return BeginForm(htmlHelper, actionName, controllerName, new RouteValueDictionary(routeValues), method, new RouteValueDictionary(htmlAttributes));
  }
 
  public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, FormMethod method, IDictionary<string, object> htmlAttributes)
  {
      TagBuilder tagBuilder = new TagBuilder("form");
      tagBuilder.MergeAttributes(htmlAttributes);
     // action is implicitly generated, so htmlAttributes take precedence.
      tagBuilder.MergeAttribute("action", string.Format("/{0}/{1}", controllerName, actionName));
     // method is an explicit parameter, so it takes precedence over the htmlAttributes.
      tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
 
     HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
     httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
     return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
 }

其实还有一种更简单直接的方法,就是不用BeginForm方法,而是直接写html:

<form action=”/Complaint/List” method=”post”>

到此便结束了(其实您可以利用tagbuilder类扩展很多东西出来),不知道您是否有更好的方案呢?欢迎在回复中写出来。

[转载]ASP.NET MVC HtmlHelper中的Form和Link的小扩展

mikel阅读(1364)

[转载]我对ASP.NET MVC HtmlHelper中的Form和Link的小扩展 – 迭戈 – 博客园.

项目中碰到的问题,或多或少的记录下来,一是积累,二是各位大牛给提供更好的建议。

1、HtmlHelper中的Link

您在开发web程序的时候很有可能会定义一个执行JavaScript的伪链接(这是我起的名字),例如:


<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>

之所以我喊它为伪链接是因为它并不会跳转页面(当然那种定义location.href的除外)。

问题出现在这个伪链接并不是一成不变的,是根据数据状态来确定的,例如,当某一列的值为0的时候显示该连接,为1的时候不显示该连接,

那么我们可以这么写(示例而已):

&lt;%if (1 == 1) {%&gt;
<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>
&lt;%} %&gt;
&lt;%else { %&gt;
其它的东西。。。
&lt;%} %&gt;

很好,假如我们的状态有很多种呢,你可能要用到switch,然后还会套嵌if else,那么我们的view无疑会变得Tag soup,使维护变得异常的麻烦。

还好,我们可以为HtmlHelper扩展一个方法,将这些逻辑都写到扩展方法里面。(可能有朋友说将这些链接放到独立的ViewUserControl中,但是依然不能解决问题,因为那会使我们的ViewUserControl变得和view一样)

写到方法里面的链接必然要用到HtmlHelper的方法:Html.LinkExtensions.ActionLink,这个方法几乎能够提供我们使用html标签时所有形式。为什么

要用几乎,是因为对应上面的伪链接的形式,它支持的并不好。我在查看了起源码之后,并没有找到合适的方法能让ActionLink生成类似:

<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>

的链接。所以我决定实现一个专门生成这种伪链接的ActionLink方法。和MVC自带的ActionLink一样,使用其TagBuilder很容易实现该操作:

1 ///
2  /// 生成类似a href="javascript:void(0) onclick="alert('click me');"&gt;Click Me /a 链接
3  ///
4  ///
<span> </span> 5  ///
6  ///
7  ///
8  public static string ActionLinkForJS(this HtmlHelper htmlHelper, string linkText, object htmlAttributes)
9 {
10 return ActionLinkForJS(htmlHelper, linkText, new RouteValueDictionary(htmlAttributes));
11 }
12
13  ///
14  /// 生成类似a href="javascript:void(0) onclick="alert('click me');"&gt;Click Me /a 链接
15  ///
16  ///
17  ///
///
///
public static string ActionLinkForJS(this HtmlHelper htmlHelper, string linkText, IDictionary htmlAttributes)
{
if (String.IsNullOrEmpty(linkText))
{
throw new ArgumentException("linkText");
}

TagBuilder linkTag = new TagBuilder("a");
linkTag.InnerHtml = linkText;
linkTag.MergeAttribute("href", "javascript:void(0)");
linkTag.MergeAttributes(htmlAttributes);

return linkTag.ToString(TagRenderMode.Normal);
}

这样就实现了让ActionLink生成伪链接。
2、HtmlHelper中的BeginForm

曾几何时,我一直在用HtmlHelper中的BeginForm来生成一个Form表单。最近的一次使用出现了问题,代码是这样的:

<%using (Html.BeginForm("List", "Complaint", null, FormMethod.Post, null))

因为页面有不少查询条件,类似于搜索。我会把搜索条件Post到Action里面:

public ActionResult List(ComplaintInfo paramComplaint)

页面的查询条件类似于:

请求List这个Action的时候如果传递一个id过去,会查询出来对应的一条数据,对应的URL是这样的:http://localhost:8886/Complaint/List/220

问题就出现在这里,页面生成Form标签的action属性是这样的:

<form action="/Complaint/List/220" method="post">

这种在Post到action的时候(请注意上面的List方法),会对参数进行ModelBinder,进而相当于传递了一个参数id过去,这样其它的查询条件

就失去了作用(因为id是主键)。我尝试将BeginForm的参数routeValues显示定义为null,问题依然存在。我现在就想根据传递的actionName,controllerName

进而拼接对应Form的action属性。例如,我上面的BeginForm方法应该生成统一的形式:

<form action="/Complaint/List" method="post">

而不是在把RouteValue一起放置在Form的action属性里面。

我仔细的查看了BeginForm的源码,发现问题出现在

UrlHelper方法

中使用Route组件得到VirtualPath方法,会自动将RouteData匹配到相应的URL,导致生成的Form的action属性并不会随我们所欲。知道了问题,

改起来也很容易:

public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues, FormMethod method, object htmlAttributes)
 {
      return BeginForm(htmlHelper, actionName, controllerName, new RouteValueDictionary(routeValues), method, new RouteValueDictionary(htmlAttributes));
  }
 
  public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, FormMethod method, IDictionary<string, object> htmlAttributes)
  {
      TagBuilder tagBuilder = new TagBuilder("form");
      tagBuilder.MergeAttributes(htmlAttributes);
     // action is implicitly generated, so htmlAttributes take precedence.
      tagBuilder.MergeAttribute("action", string.Format("/{0}/{1}", controllerName, actionName));
     // method is an explicit parameter, so it takes precedence over the htmlAttributes.
      tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
 
     HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
     httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
     return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
 }

其实还有一种更简单直接的方法,就是不用BeginForm方法,而是直接写html:

<form action=”/Complaint/List” method=”post”>

到此便结束了(其实您可以利用tagbuilder类扩展很多东西出来),不知道您是否有更好的方案呢?欢迎在回复中写出来。

[转载]跨平台iPhone中调用WCF服务

mikel阅读(1496)

[转载]跨平台iPhone中调用WCF服务 – 用自己的语言写个Hello World – 博客园.

由于对移动平台充满着好奇与兴趣,最近着手了iPhone开发和学习。学习的路线是从objective-c到cococa。方法是看了两本入门的英文书,还有就是学习apple的sdk。对于产品的基本想法是服务端用.net,手机客户端用iPhone。

一些复杂的逻辑处理放到服务端实现,客户端与服务端通过XML交互,在iPhone客户端解析XML通过cocoa展示数据。由于iPhone和 DoNet是两个完全不同的平台。iPhone依靠mac系统平台,donet依赖windows系统平台。这篇文章我将通过一个hello world程序讲述一下通过WCF实现从mac系统到windows的跨平台的调用。

1、创建简单的WCF服务

服务契约代码如下:

实现如下:

2、在iPhone中调用WCF

与donet调用wcf服务不同,这里使用NSURLConnection去获取WCF服务端的数据,代码如下:

NSURLConnection的委托方法:

解析XML的中hello world的委托方法,对于objective-c解析xml可以看我的上一篇博客:

运行:

总结:本文通过一个简单的例子,说明了iPhone调用WCF的方法。用wcf实现跨平台还是蛮简单的!

代码:

wcf code:http://files.cnblogs.com/zhuqil/WcfService1.rar

cocoa code:http://files.cnblogs.com/zhuqil/wcf2.zip

[原创]SQLServer2008跨数据库导入数据配置教程

mikel阅读(839)

SQL SERVER企业管理器—>服务器—>服务器对象—>链接服务器—>新建—>常规选项页—>填写链接服务器名或IP,服务器类型选SQL SERVER
—>安全性选项页—>用此安全上下文进行,填写登陆数据库的登录名和密码,就可以了。

–查询示例
select * from 链接服务器名.数据库名.dbo.表名

–导入示例
select * into 表 from 链接服务器名.数据库名.dbo.表名

–创建链接服务器
exec sp_addlinkedserver ‘ITSV ‘, ‘ ‘, ‘SQLOLEDB ‘, ‘远程服务器名或ip地址 ‘
exec sp_addlinkedsrvlogin ‘ITSV ‘, ‘false ‘,null, ‘用户名 ‘, ‘密码 ‘

–查询示例
select * from ITSV.数据库名.dbo.表名

–导入示例
select * into 表 from ITSV.数据库名.dbo.表名

–以后不再使用时删除链接服务器
exec sp_dropserver ‘ITSV ‘, ‘droplogins ‘

–连接远程/局域网数据(openrowset/openquery/opendatasource)
–1、openrowset

–查询示例
select * from openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)

–生成本地表
select * into 表 from openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)

–把本地表导入远程表
insert openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)
select *from 本地表

–更新本地表
update b
set b.列A=a.列A
from openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)as a inner join 本地表 b
on a.column1=b.column1

–openquery用法需要创建一个连接

–首先创建一个连接创建链接服务器
exec sp_addlinkedserver ‘ITSV ‘, ‘ ‘, ‘SQLOLEDB ‘, ‘远程服务器名或ip地址 ‘
–查询
select *
FROM openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘)
–把本地表导入远程表
insert openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘)
select * from 本地表
–更新本地表
update b
set b.列B=a.列B
FROM openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘) as a
inner join 本地表 b on a.列A=b.列A

–3、opendatasource/openrowset
SELECT *
FROM opendatasource( ‘SQLOLEDB ‘, ‘Data Source=ip/ServerName;User ID=登陆名;Password=密码 ‘ ).test.dbo.roy_ta
–把本地表导入远程表
insert opendatasource( ‘SQLOLEDB ‘, ‘Data Source=ip/ServerName;User ID=登陆名;Password=密码 ‘).数据库.dbo.表名

[转载]推荐8个超棒的学习 jQuery 的网站

mikel阅读(953)

[转载]推荐8个超棒的学习 jQuery 的网站 – 梦想天空 – 博客园.

根据国外科技网站 W3Techs 一项调查了近100万个网站数据显示,JQuery是目前最流行的 JavaScript 库。对于初学者来说,有的时候很难找到一个好的学习JQuery网站,所以本文收集了8个很棒的 JQuery 学习网站推荐给大家。

1. Learning jQuery

8 Great Websites to Learn Step-by-Step jQuery

最好的 jQuery 资源博客之一,从 jQuery 高手那里获得宝贵的经验。

2. jQuery Mix

8 Great Websites to Learn Step-by-Step jQuery

一个内容非常丰富的网站,有关 jQuery 的各种各样的信息。

3. jQuery for Designers

8 Great Websites to Learn Step-by-Step jQuery

非常棒的一个 jQuery 资源和教程网站,帮助你成长为 jQuery 高手。

4. 15 Days of jQuery

8 Great Websites to Learn Step-by-Step jQuery

这个网站虽然更新不定时,你仍然可以从他们的文章中学到很多东西。

5. jQuery4u

8 Great Websites to Learn Step-by-Step jQuery

jQuery4U 是另外一个有关 jQuery 资源、技巧和发展趋势的博客。

6. jQuery King

8 Great Websites to Learn Step-by-Step jQuery

jQuery King 让你学习 jQuery 更容易、更有趣。

7. jQFundamentals

8 Great Websites to Learn Step-by-Step jQuery

这是一本在线书籍,介绍 jQuery 库的基本内容。

8. jQuery How To

8 Great Websites to Learn Step-by-Step jQuery

这个网站不是每天都更新,不过你可以从他们的教程中学到很多有用的技巧。

(编译来源:梦想天空 原文来自:8 Great Websites to Learn Step-by-Step jQuery

[转载]推荐8个超棒的学习 jQuery 的网站

mikel阅读(0)

[转载]推荐8个超棒的学习 jQuery 的网站 – 梦想天空 – 博客园.

根据国外科技网站 W3Techs 一项调查了近100万个网站数据显示,JQuery是目前最流行的 JavaScript 库。对于初学者来说,有的时候很难找到一个好的学习JQuery的网站,所以本文收集了8个很棒的 jQuery 学习网站推荐给大家。

1. Learning jQuery

8 Great Websites to Learn Step-by-Step jQuery

最好的 jQuery 资源博客之一,从 jQuery 高手那里获得宝贵的经验。

2. jQuery Mix

8 Great Websites to Learn Step-by-Step jQuery

一个内容非常丰富的网站,有关 jQuery 的各种各样的信息。

3. jQuery for Designers

8 Great Websites to Learn Step-by-Step jQuery

非常棒的一个 jQuery 资源和教程网站,帮助你成长为 jQuery 高手。

4. 15 Days of jQuery

8 Great Websites to Learn Step-by-Step jQuery

这个网站虽然更新不定时,你仍然可以从他们的文章中学到很多东西。

5. jQuery4u

8 Great Websites to Learn Step-by-Step jQuery

jQuery4U 是另外一个有关 jQuery 资源、技巧和发展趋势的博客。

6. jQuery King

8 Great Websites to Learn Step-by-Step jQuery

jQuery King 让你学习 jQuery 更容易、更有趣。

7. jQFundamentals

8 Great Websites to Learn Step-by-Step jQuery

这是一本在线书籍,介绍 jQuery 库的基本内容。

8. jQuery How To

8 Great Websites to Learn Step-by-Step jQuery

这个网站不是每天都更新,不过你可以从他们的教程中学到很多有用的技巧。

(编译来源:梦想天空 原文来自:8 Great Websites to Learn Step-by-Step jQuery

[转载]MongoDB - 分布式文档存储数据库

mikel阅读(869)

[转载]MongoDB – 分布式文档存储数据库 – 开源中国社区.

MongoDB是一个介于关系数据库和非关系数据库之间的产品, 是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bjson格式,因此可以存储比较复杂的数据类型。 Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持 对数据建立索引。

官方网站http://www.mongodb.org/

它的特点是高性能、易部署、易使用,存储数据非常方便。主要功能特性有:

  • 面向集合存储,易存储对象类型的数据。
  • 模式自由。
  • 支持动态查询。
  • 支持完全索引,包含内部对象。
  • 支持查询。
  • 支持复制和故障恢复。
  • 使用高效的二进制数据存储,包括大型对象(如视频等)。
  • 自动处理碎片,以支持云计算层次的扩展性
  • 支持RUBY,PYTHON,JAVA,C++,PHP等多种语言。
  • 文件存储格式为BSON(一种JSON的扩展)
  • 可通过网络访问

所谓“面向集合”(Collenction-Orented),意思是数据被分组存储在数据集中,被称为一个集合(Collenction)。每个 集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似关系型数据库(RDBMS)里的表(table),不同的是它不需要定 义任何模式(schema)。
模式自由(schema-free),意味着对于存储在mongodb数据库中的文件,我们不需要知道它的任何结构定义。如果需要的话,你完全可以把不同结构的文件存储在同一个数据库里。
存储在集合中的文档,被存储为键-值对的形式。键用于唯一标识一个文档,为字符串类型,而值则可以是各中复杂的文件类型。我们称这种存储形式为BSON(Binary Serialized dOcument Format)。

MongoDB服务端可运行在Linux、Windows或OS X平台,支持32位和64位应用,默认端口为27017。推荐运行在64位平台,因为MongoDB

在32位模式运行时支持的最大文件尺寸为2GB。

MongoDB把数据存储在文件中(默认路径为:/data/db),为提高效率使用内存映射文件进行管理。

[转载]Table锁定行列

mikel阅读(1493)

[转载]Table锁定行列 – KenshinCui’s Blog – 博客园.

摘要:在使用表格显示数据时我们经常会遇到数据过多无法一屏完全显示的问题,这个时候我们就会给用户显示滚动条来拖动。但是多数情况下表格是带有表 头的,纵向拖动往往就看不到表头;而横向拖动又会出现看不到主题列(例如统计某人基本信息时姓名就是主题列),这个时候怎么办呢?答案就是行列锁定。

主要内容:

1.行列锁定的常用方法

2.IE下实现行列锁定

3.使用JQuery开发一个简单的行列锁定插件

一、行列锁定的常用方法

从使用上来看,要实现行列锁定的效果无非就是使用第三方组件和自己从零做起一步步实现。第三方组件一般比较强大,除了行列锁定的功能之外一般还包括 排序、筛选等(例如Ext的Locking-grid扩展组件),但是使用第三方组件也会造成一些其他的问题,或者说有些时候你根本就没有办法使用第三方 组件(我遇到的就是这种情况)。今天我们主要讨论的是如何利用基本的html来自己实现行列锁定。自己实现table锁定行列的方法基本上有两种:一种是 利用多个table拼接,最终”拼”成一个大的table。这种情况一般将表头和主题列分别放到单独的table中,数据行放到另一个table,拖动数 据所在的table时利用js动态实现其他table的同步拖动。第二种就是利用单独的table,通过设置table行和列相对位置来实现行列锁定。两 种方式相比较而言,第一种的方式更加容易控制一些,而且由于它将一个大表格分散到多个table中更有利于完成其他复杂功能;第二种实现比第一种效果要好 一些,而且更有利于封装和扩展。由于我所遇到的情况是必须在原有html基础上实现行列锁定,因此这里就主要说一下第二种方式。

二、IE下实现行列锁定

由于我们下面说的方法主要利用tr、td的position:relative样式,而在新的css标准中没有对tr进行 position:relative定义,因此除了IE在firefox4、chrome等新版本浏览器中都无法使用我们下面所说的方法(事实上IE9也 是使用新标准,只不过其对兼容性做了处理,因此我们这种方法基本在IE所有版本中都是可行的)。我们的实现原理很简单:首先在table最外层包装一个 div用来显示滚动条,接着设置tr和td的position和z-index样式控制其相对显示,然后在滚动的时候动态修改tr和td的top和 left属性使其相对位置保持不表。下面我们来看一下具体的实现:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Table锁定行列</title>
<mce:style type="text/css"><!--
.LockRow /*固定行的样式*/
{
	position: relative;
	top: expression(this.parentElement.parentElement.parentElement.scrollTop);
	/*top:0px;*/
	z-index:2;
}
.LockCell /*固定列的样式*/
{
	position: relative;
	left: expression(this.parentElement.parentElement.parentElement.parentElement.scrollLeft);
	/*left:0px;*/
	z-index:0;
}
.LockCross /*行列交叉处样式*/
{
	z-index:3;
}
.divBoxing /*外出div样式*/
{
	clear:both;
	overflow: scroll;
	position:relative;
}
.tbLock /*设置单元格间隙的样式*/
{
	border-collapse:collapse;
}
.lockRowBg
{
	background-color:#CFF;
}
.lockColumnBg
{
	background-color:#CFF;
}
--></mce:style><style type="text/css" mce_bogus="1">.LockRow /*固定行的样式*/
{
	position: relative;
	top: expression(this.parentElement.parentElement.parentElement.scrollTop);
	/*top:0px;*/
	z-index:2;
}
.LockCell /*固定列的样式*/
{
	position: relative;
	left: expression(this.parentElement.parentElement.parentElement.parentElement.scrollLeft);
	/*left:0px;*/
	z-index:0;
}
.LockCross /*行列交叉处样式*/
{
	z-index:3;
}
.divBoxing /*外出div样式*/
{
	clear:both;
	overflow: scroll;
	position:relative;
}
.tbLock /*设置单元格间隙的样式*/
{
	border-collapse:collapse;
}
.lockRowBg
{
	background-color:#CFF;
}
.lockColumnBg
{
	background-color:#CFF;
}</style>
</head>
<body>
<div class="divBoxing" id:="divBoxing" style="width: 100%; height: 300px;">
	<table width="800" border="0" id="lockTable" class="tbLock">
		  <tbody>
		  <tr class="LockRow lockRowBg">
			<td width="100" align="center" class="LockCell LockCross lockRowBg">第一列</td>
			<td width="100" align="center" class="LockCell LockCross lockRowBg">第二列</td>
			<td width="100" align="center">第三列</td>
			<td width="100" align="center">第四列</td>
			<td width="100" align="center">第五列</td>
			<td width="100" align="center">第六列</td>
			<td width="100" align="center">第七列</td>
			<td width="100" align="center">第八列</td>
		  </tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-2</td>
			<td align="center" class="LockCell lockColumnBg">2-2</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
		  </tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-3</td>
			<td align="center" class="LockCell lockColumnBg">2-3</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
		  </tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-4</td>
			<td align="center" class="LockCell lockColumnBg">2-4</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
		  </tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-5</td>
			<td align="center" class="LockCell lockColumnBg">2-5</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
		  </tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-6</td>
			<td align="center" class="LockCell lockColumnBg">2-6</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-7</td>
			<td align="center" class="LockCell lockColumnBg">2-7</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-8</td>
			<td align="center" class="LockCell lockColumnBg">2-8</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-9</td>
			<td align="center" class="LockCell lockColumnBg">2-9</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-10</td>
			<td align="center" class="LockCell lockColumnBg">2-10</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-11</td>
			<td align="center" class="LockCell lockColumnBg">2-11</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-12</td>
			<td align="center" class="LockCell lockColumnBg">2-12</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-13</td>
			<td align="center" class="LockCell lockColumnBg">2-13</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-14</td>
			<td align="center" class="LockCell lockColumnBg">2-14</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		  <tr>
			<td align="center" class="LockCell lockColumnBg">1-15</td>
			<td align="center" class="LockCell lockColumnBg">2-15</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			<td align="center">--</td>
			</tr>
		</tbody>
	</table>
</div>
</body>
</html>

三、使用JQuery开发一个简单的行列锁定插件

如果仅仅从实现上来说,到了第二部我们今天的内容就结束了。但是聪明的读者或许已经发现上面的用法存在的问题:第一我们需要手动的添加很多的class样式、需要对原有布局修改;第二我们上面使用了expression这个IE所特有的样式(虽然我们上面说过这个差距不适用于其他浏览器新版本,但是不代表不适用于旧版本,如果我们修改expression为纯js方式也就可以使用于其他低版本浏览器)。我们刚才说过第二种方式有一个优点就是便于封装而且几乎不必对原table布局作出修改,因此我们不妨对整个应用进行一下简单的封装,使其只需要简单的添加一行js就能够完美的运行。虽然在这个过程中我们只是将手动添加class样式换成动态添加、将expression表达换成onscroll事件,但是一切看起来确实那么的不一样。

下面就是我们使用JQuery进行封装的代码TableLock.js:

/*
author:KenshinCui
date:2011.03.29
example:$.fn.TableLock({table:'lockTable',lockRow:1,lockColumn:2,width:'100%',height:'300px'});
*/
(function($) {
    $.extend($.fn, {
        TableLock: function(options) {
            var tl = $.extend({
                table:'lockTable',//table的id
				lockRow:1,//固定行数
				lockColumn:1,//固定列数
				width:'100%',//表格显示宽度(实质是外出div宽度)
				height:'100%',//表格显示高度(实质是外出div高度)
				lockRowCss:'lockRowBg',//锁定行的样式
				lockColumnCss:'lockColumnBg'//锁定列的样式
            }, options);

			var tableId=tl.table;
			var table=$('#'+tableId);
			var rowSpan=function(tr){

			}
			if(table){
				var box=$("<div id:='divBoxing' class='divBoxing'></div>").scroll(function(){//在此处添加事件
					$('.LockRow').css('top',$(this).attr('scrollTop')+'px');
					$('.LockCell').css('left',$(this).attr('scrollLeft')+'px');
				});
				box.css('width',tl.width).css('height',tl.height);//设置高度和宽度
				table.wrap(box);
				table.addClass('tbLock');
				var crossNum=tl.lockRow*tl.lockColumn;
				if(tl.lockRow>0){
					var tr;
					for(var r=0;r<tl.lockRow;++r){//添加行锁定
						tr=table.find('tr:eq('+r+')').addClass('LockRow').addClass(tl.lockRowCss);
						for(var c=0;c<tl.lockColumn;++c){//设置交叉单元格样式,除了锁定单元格外还有交叉单元格自身样式
							if(tr)
							tr.find('td:eq('+c+')').addClass('LockCell LockCross').addClass(tl.lockRowCss);
						}
					}
				}
				if(tl.lockColumn>0){
					var rowNum=$('#'+tableId+' tr').length;
					var tr;
					for(var r=(tl.lockRow);r<rowNum;++r){
						tr=table.find('tr:eq('+r+')');
						for(var c=0;c<tl.lockColumn;++c){//添加列锁定
							tr.find('td:eq('+c+')').addClass('LockCell').addClass(tl.lockColumnCss);
						}
					}
				}

				//box.live('scroll',func);
			}else{
				alert('没有找到对应的table元素,请确保table属性正确性!');
			}
        }
    });
})(jQuery);

具体的样式表文件TableLock.css:

.LockRow /*固定行的样式*/
{
	position: relative;
	/*top: expression(this.parentElement.parentElement.parentElement.scrollTop);*/
	top:0px;
	z-index:2;
}
.LockCell /*固定列的样式*/
{
	position: relative;
	/*left: expression(this.parentElement.parentElement.parentElement.parentElement.scrollLeft);*/
	left:0px;
	z-index:0;
}
.LockCross /*行列交叉处样式*/
{
	z-index:3;
}
.divBoxing /*外出div样式*/
{
	clear:both;
	overflow: scroll;
	position:relative;
}
.tbLock /*设置单元格间隙的样式*/
{
	border-collapse:collapse;
}
.lockRowBg
{
	background-color:#CFF;
}
.lockColumnBg
{
	background-color:#CFF;
}

假设现在你有有这样一个页面,当然它不具备锁定行列的功能:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>不具备锁定行列功能的Table</title>
</head>
<body>
<table width="800" border="0">
	  <tbody>
	  <tr>
		<td width="100" align="center" >第一列</td>
		<td width="100" align="center" >第二列</td>
		<td width="100" align="center">第三列</td>
		<td width="100" align="center">第四列</td>
		<td width="100" align="center">第五列</td>
		<td width="100" align="center">第六列</td>
		<td width="100" align="center">第七列</td>
		<td width="100" align="center">第八列</td>
	  </tr>
	  <tr>
		<td align="center" >1-2</td>
		<td align="center" >2-2</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
	  </tr>
	  <tr>
		<td align="center" >1-3</td>
		<td align="center" >2-3</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
	  </tr>
	  <tr>
		<td align="center" >1-4</td>
		<td align="center" >2-4</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
	  </tr>
	  <tr>
		<td align="center" >1-5</td>
		<td align="center" >2-5</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
	  </tr>
	  <tr>
		<td align="center" >1-6</td>
		<td align="center" >2-6</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-7</td>
		<td align="center" >2-7</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-8</td>
		<td align="center" >2-8</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-9</td>
		<td align="center" >2-9</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-10</td>
		<td align="center" >2-10</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-11</td>
		<td align="center" >2-11</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-12</td>
		<td align="center" >2-12</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-13</td>
		<td align="center" >2-13</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-14</td>
		<td align="center" >2-14</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	  <tr>
		<td align="center" >1-15</td>
		<td align="center" >2-15</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		<td align="center">--</td>
		</tr>
	</tbody>
</table>
</body>
</html>

如果你需要让它拥有锁定行列的功能,只需要引入TableLock.js和TableLock.css(当然不要忘了jQuery类库),然后添加一句简单的代码即可:

<mce:script type="text/javascript" language="javascript"><!--
	$(function(){
		$.fn.TableLock({table:'lockTable',lockRow:1,lockColumn:2,width:'100%',height:'300px'});
	});
// --></mce:script>

下面是完整的页面代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>TableLock插件演示</title>
<link rel="stylesheet" href="TableLock.css" mce_href="TableLock.css" />
<mce:script type="text/javascript" language="javascript" src="jquery-1.5.1.js" mce_src="jquery-1.5.1.js"></mce:script>
<mce:script type="text/javascript" language="javascript" src="TableLock.js" mce_src="TableLock.js"></mce:script>
<mce:script type="text/javascript" language="javascript"><!--
	$(function(){
		$.fn.TableLock({table:'lockTable',lockRow:1,lockColumn:2,width:'100%',height:'300px'});
	});
// --></mce:script>
</head>
<body>
<table id="lockTable" width="800" border="0">
  <tr>
    <td width="100" align="center">第一列</td>
    <td width="100" align="center">第二列</td>
    <td width="100" align="center">第三列</td>
    <td width="100" align="center">第四列</td>
    <td width="100" align="center">第五列</td>
    <td width="100" align="center">第六列</td>
    <td width="100" align="center">第七列</td>
    <td width="100" align="center">第八列</td>
  </tr>
  <tr>
    <td align="center">1-2</td>
    <td align="center">2-2</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
  </tr>
  <tr>
    <td align="center">1-3</td>
    <td align="center">2-3</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
  </tr>
  <tr>
    <td align="center">1-4</td>
    <td align="center">2-4</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
  </tr>
  <tr>
    <td align="center">1-5</td>
    <td align="center">2-5</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
  </tr>
  <tr>
    <td align="center">1-6</td>
    <td align="center">2-6</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-7</td>
    <td align="center">2-7</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-8</td>
    <td align="center">2-8</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-9</td>
    <td align="center">2-9</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-10</td>
    <td align="center">2-10</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-11</td>
    <td align="center">2-11</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-12</td>
    <td align="center">2-12</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-13</td>
    <td align="center">2-13</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-14</td>
    <td align="center">2-14</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
  <tr>
    <td align="center">1-15</td>
    <td align="center">2-15</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    <td align="center">--</td>
    </tr>
</table>
</body>
</html>

下面是运行后的效果:

注意:请确保在IE下.divBoxing具有position:relative;样式,否则在IE6和IE7中锁定行列将会溢出外层div,具体参见IE6 bug with overflow and position:relative 。