[Flex]Flash Builder 4 beta中五个重要的新特性

mikel阅读(677)

我曾撰文介绍Flash Builder 4 beta的主要特点——使用Flash Builder 4 beta进行以数据为中心的开发。 具体来说,这个特点是通过很多新增加的特性来体现的。不过,其他很多广受期待且颇具价值的特性也包含在这个版本中了。在本文中,我将向你介绍其中最为突出 的五个特性。这些特性都是我们是通过开发社区、缺陷和建议收集系统以及技术会议等其他活动中的交流等收集到的直接需求。我们将这个产品奉献给大家,希望这 些新特性能兑现我们对大家的承诺。

特性1:存取函数(accessor functions)的生成

软件开发有时会相当乏味。在很多应用中,常常需要来回重复相同的编码实践或模式,开发人员将大量时间花费在了重复编码上——而这些时间本可以用 在实现更让人感兴趣的程序逻辑工作上。在Flash Builder 4 beta中,我们为尽量降低这类重复性工作花费的时间,引入了快速完成这些工作的解决办法。例如存取函数的自动生成。开发人员希望开发环境能自动生成 getter和setter方法(这两个方法实现了类的私有成员的公开存取接口)。在Flash Builder 4 beta中,生成这些函数的方法非常简单——将光标移动到类的变量名上,然后选择主菜单或右键菜单“Source|Generate Getter/Setter”,在接着弹出的“Generate Getter/Setter”对话框中,你就可对存取函数做详细配置,并预览Flash Builder 4 beta将对你的代码所做的改变了(参见图1)。

图1 预览新的getter/setter特性生成的代码

特性2:事件代码的生成

开发环境自动生成事件代码,是广大开发者又一个迫切愿望。无论是对希望在重复编码上花的时间更少、有经验的Flex开发人员,还是对不熟悉事 件驱动开发的新手而言,这个特性都大有用处。比如过去主要和过程式的Web脚本技术(如PHP、ColdFusion)打交道的开发者,也许从来就用不上 处理事件(如按钮被点击)的事件监听器(event listener)。在Flash Builder 4 beta中,能通过Flex属性视图、设计视图中元素的右键菜单,或代码视图中的内容助手,为UI对象自动生成事件处理函数。

每个UI元素(按钮、列表、滚动条等等),都有一个缺省事件。比如对按钮来说,它的缺省事件是点击。如果设计视图中选中一个按钮并点击右键,在 右键菜单中你就能看到菜单项“Generate Click Handler”。而在属性管理器(Property Inspector)中,也会为这个按钮显示一个标记为“on click”的属性。此外,通过选择右键菜单中的“Show All Events”,或展开属性管理器中该元素的Events节点,你可以生成这个UI元素的所有事件的处理函数。每生成一个事件处理函数,Flash Builder 4 beta就会根据UI对象的类名、属性为这个函数自动指定一个唯一的名字(当然也可以由你自己指定)。事件处理函数被放在文件的第一个脚本块中;通过代码 视图,我们可以直接定位这些函数。另外,在代码视图中,也可以为组件生成事件。具体方法是:将光标移入组件标签中,在组件类名后键入一空格,就可显示出包 含此组件全部属性的内容助手。而事件(如Click)也是属性,自然包含在内容助手里了。在内容助手中选择要处理的事件,再利用“Generate Event Handler”就可生成事件函数了。

如果你不熟悉ActionScript和事件驱动编程,事件代码自动生成特性无疑可帮助你理解组件事件与对应处理代码的关联方法。如果你已是一个有经验的Flex开发者,那么利用这个特性可快速为你生成所有事件函数的模型,也可节省你的时间。

特性3:命令行构建

不少用户告诉我们,他们的Flex项目日益复杂,利用Flex将他们的开发过程和所开发的系统整合起来, 已经十分迫切。其中最常见的要求之一,就是将Flex应用纳入到每日自动构建过程中去。不幸的是,在先前的版本中实现每个开发人员的单独构建与每日自动构 建设置的同步非常困难。Flash Builder 4 beta通过引入新的<fb.ExportReleaseBuild>和<mxmlc>任务(在自定义的每日构建脚本中使用 它),解决了这个问题。

即使在执行每日构建的机器上没有安装Flash Builder 4 beta,也可以使用命令行构建。如果安装了Flash Builder 4 beta,<fb.ExportReleaseBuild>任务可确保每日构建的设置与开发者日常工作中的所用的构建设置完全相同。此外,利 用它还可以实现Flash Builder 4 beta构建中的一些常见任务的自动化,比如自动编译相关的库、将JPEG等格式的资源文件复制到输出文件夹等。如果Flash Builder 4 beta没有被安装在构建机上,你可以编写脚本(如Ant),在其中利用<mxmlc>任务实现命令行构建,当然前提是构建机器上有Flex SDK。你还需要保证两套构建设置的同步。一个保存在Flash Builder 4 beta中,供开发人员日常工作中使用;另一个维护在你的每日构建机器上。具体可参考Adobe Flex 4 Features and Migration Guide

特性4:调试器的改进

能提供功能强大的调试器,是集成开发环境的最重要优势之一。Flex Builder 3的调试功能已相当出色,但大家希望能更上一层楼。因此在Flash Builder 4 beta中,我们投入了大量精力,努力将调试器水平带上新的高度。

你可能希望当指定条件得到满足时,调试器能暂停代码的执行。在Flash Builder 4 beta中,我们已能通过定义条件断点停止调试器的执行,这些条件包括表达式运算结果为真、表达式的值发生变化,或代码执行次数达到指定值等等。表达式求 值观察功能在此版本中也有了提升。你可在表达式视图中观察从变量视图中选择的变量,也可在调试程序过程中新增要观察的表达式,或对这些表达式求值。

在调试应用时,你可能还想知道特定变量的值什么时候会发生变化。Flash Builder 4 beta支持了这项功能,具体通过一项叫做观察点的特性实现。调试过程中,你可从变量视图中选择某个变量,并在其上设置一个观察点。当被观察的变量的值发 生变化时,执行过程就会自动被挂起。

最后值得一提的是,如果曾在要重复执行很多次的循环体中设置过断点,你可能也会喜欢新增的“run-to-line”命令,通过它可在调试过程中跳出循环。

特性5:网络监视器

几乎所有Flex应用都会和服务器或某种类型的服务交换数据。请求与响应在客户端和服务器之间来回传输,其格式取决于开发者使用的技术。在 Flex 3中,无论使用什么技术,你对这些交换过程的内部情况都知之甚少。你可以调试你的Flex应用,看执行了什么远程调用,但必须等到服务端的数据(如果有的 话)返回。同样,你也可以调试服务端逻辑,但数据一旦向Flex应用发出,你就无法跟踪它的变化了。监控实际传输的网络包——包括请求和响应的数据,在 Flex Builder中是不可能的。

Flash Builder 4 beta引入了网络监视器。利用这个工具,你可以监控在Flex应用、服务应用间传输的SOAP、AMF、RO(Remote Object)、XML和HTTP包。这样,从调试角度看,有了大量直观、实时的监控和调试信息,这让我们构建以数据为中心的应用变得容易得多。

要使用这个工具,只需先在网络监控器工具条上点击“Enable Network Monitor”图标,然后和平时一样运行应用的调试版本就可以了。你和应用程序交互时,网络监视器会按时间顺序捕获并存储所有对远程服务的调用。任何时 刻,你都可以切换到网络监视视图,查看每次调用的结果——所有结果都包含在一个表格中,逐一列出了请求的发生时间、被请求的服务、要执行的操作和 URL(如果有)、响应的发生时间和处理所消耗的时间。你还可以检查每个响应,包括检查发回的实际数据。你可在应用运行时现场分析这些信息,也可以点击 “Save”图标,将所有捕获到的信息保存到一个XML文件,供未来分析用。

总结

仔细看过Flash Builder 4 beta的新特性表后,我发现其实可能需要十到二十篇,甚至更多文章,才能将这个版本中这么多令人称奇的特性讨论清楚。无论你是新手,还是一个经验丰富的 Flex开发人员,这个版本都会让开发变得更为容易。如果想充分了解其他重要特性,请大家千万不要错过如下内容:

同时,请留意Adobe Developer Connection接下来的文章,它们将更为详细说明本文介绍过的特性,或向你介绍Flah Builder 4 beta中其他有价值的特性。

作者简介

Tim Buntel:Flash Builder(前身为Flex Builder)高级产品经理。在2007年加入Flex团队前,已担任Adobe ColdFusion高级产品经理多年。

阅读英文原文Five great new features in Flash Builder 4 beta

[Flex]用Flex构建地图应用 — 利用Google Map API制作自己的地图(2)

mikel阅读(512)

Silver 撰写  

接着上期的,这里用两个实例,给大家介绍一下Flex自定义地图制作的流程,看看是怎么从TileLayBase扩展成自定义的地图

首先是live的地图

01.package com.ityao.map
02.{
03.    import com.google.maps.CopyrightCollection;
04.    import com.google.maps.TileLayerBase;
05. 
06.    import flash.display.DisplayObject;
07.    import flash.display.Loader;
08.    import flash.events.IEventDispatcher;
09.    import flash.events.IOErrorEvent;
10.    import flash.geom.Point;
11.    import flash.net.URLRequest;
12. 
13.    public class LiveDituTileLayerBase extends TileLayerBase
14.    {
15.        private var serviceUrls:Array=["http://r0.tiles.ditu.live.com/tiles/r",
16.                                       "http://r1.tiles.ditu.live.com/tiles/r",
17.                                       "http://r2.tiles.ditu.live.com/tiles/r",
18.                                       "http://r3.tiles.ditu.live.com/tiles/r"];
19.        private var serviceUrlSuffix:String = ".png?g=29";
20. 
21.        public function LiveDituTileLayerBase()
22.        {
23.            super(new CopyrightCollection("http://cn.bing.com/ditu/"),0,19)
24.        }
25. 
26.        private function getTileUrl(p:Point,zoom:int):String{          
27. 
28.            var c:Number=Math.pow(2,zoom);
29.            var d:Number=p.x;
30.            var e:Number=p.y;
31.            var f:String="";
32.            for(var g:int=0;g<zoom;g++){
33.                c=c/2;
34.                if(e<c){
35.                    if(d<c){
36.                        f+="0"
37.                    }else{
38.                        f+="1";
39.                        d-=c
40.                    }
41.                }else{
42.                    if(d<c){
43.                        f+="2";
44.                        e-=c
45.                    }else{
46.                        f+="3";
47.                        d-=c;
48.                        e-=c
49.                    }
50.                }
51.            }
52.            var h:int=(p.x+p.y)%serviceUrls.length;
53.            return serviceUrls[h]+f+serviceUrlSuffix;
54. 
55.        }  
56. 
57.        public override function loadTile(tilePos:Point, zoom:Number):DisplayObject{
58. 
59.            var loader:Loader = new Loader();
60.            configureListeners(loader.contentLoaderInfo);
61.            var url:String = getTileUrl(tilePos,zoom);
62.            var tileUrl:URLRequest = new URLRequest(url);
63.            trace(tilePos.toString()+" z:"+zoom + " url:"+url);
64.            loader.load(tileUrl);
65.            return loader;
66. 
67.        }
68. 
69.        private function configureListeners(dispatcher:IEventDispatcher):void{
70.            dispatcher.addEventListener(IOErrorEvent.IO_ERROR,_secondaryLoad);
71.        }
72. 
73.        private function _secondaryLoad(event:IOErrorEvent):void{
74.            //image fail to load handler
75.        }
76.    }
77.}

然后是mapABC的地图

01.package com.ityao.map
02.{
03.    import com.google.maps.CopyrightCollection;
04.    import com.google.maps.TileLayerBase;
05. 
06.    import flash.display.DisplayObject;
07.    import flash.display.Loader;
08.    import flash.events.IEventDispatcher;
09.    import flash.events.IOErrorEvent;
10.    import flash.geom.Point;
11.    import flash.net.URLRequest;
12. 
13.    public class MapABCDituTileLayerBase extends TileLayerBase{
14. 
15.        public function MapABCDituTileLayerBase(){
16.            super(new CopyrightCollection("http://www.mapabc.com"),0,17)
17.        }
18. 
19.        private function getTileUrl(p:Point,zoom:int):String{
20.            var url:String = "http://emap" + ((p.x + p.y) % 4) + ".mapabc.com/mapabc/maptile?v=";
21.            url += "w2.99" ;
22.            url += "&x=" + p.x + "&y=" + p.y + "&zoom=" + (17-zoom);
23.            return url;
24.        }  
25. 
26.        public override function loadTile(tilePos:Point, zoom:Number):DisplayObject{
27. 
28.            var loader:Loader = new Loader();
29.            configureListeners(loader.contentLoaderInfo);
30.            var url:String = getTileUrl(tilePos,zoom);
31.            var tileUrl:URLRequest = new URLRequest(url);
32.            trace(tilePos.toString()+" z:"+zoom + " url:"+url);
33.            loader.load(tileUrl);
34.            return loader;
35. 
36.        }
37. 
38.        private function configureListeners(dispatcher:IEventDispatcher):void{
39.            dispatcher.addEventListener(IOErrorEvent.IO_ERROR,_secondaryLoad);
40.        }
41. 
42.        private function _secondaryLoad(event:IOErrorEvent):void{
43.            //image fail to load handler
44.        }
45.    }
46.}

在上面的例子可以看见,其实只要重载loadTile方法就可以了,是不是非常简单?

loadTile的第一个参数是图块坐标,第二个参数是zoom的图层深度
这里有篇很好的文章和实例演示告诉你这些参数是怎么来的,
http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/

使用这两个参数,我们要针对不用的图瓦(live或mapABC)去构造图瓦的链接,从而用一块块图瓦拼接出完整的地图。

图瓦的链接是怎么获得的呢?
呵呵,可以是根据不同地图的文档说明(不过通常都很少),通常我在看一个地图的时候,用firefox进行浏览,然后打开”工具”->”页面信息”,如下图所示:
bingditu

然后就发挥你的小宇宙,去猜猜那串图瓦链接怎么来的,呵呵!
我把live的猜出来了,欢迎大家补充别的链接。

[Flex]用Flex构建地图应用 — 利用Google Map API制作自己的地图(1)

mikel阅读(672)

Silver 撰写  

现 在地图应用已经成为网络应用的一个大类了,各个大的网站几乎都有自己的地图产品。最出名的莫过于国外的Google Map和国内的都市圈地图,前面Daniel Yang介绍了都市圈的Flex源代码,小弟也来一个介绍Flex构建地图的系列,希望能够让大家分享到地图开发的乐趣。

不过自己毕竟不是GIS科班出身,也没从事过GIS或者地图的真正商业开发,研究地图应用开发,纯属兴趣,所以不足之处,敬请斧正:)

构建Flex地图应用,首选Google的地图API来实现,有以下原因:

  1. 支持自定义扩展地图类型
  2. 有丰富的图形标注工具
  3. 有多种数据接口
  4. 详细的文档支持

Google map API的这些特点,可以使我们快速地开发出各式各样的地图web应用,由于本帖不是替google map打广告,就不一一介绍这些特点的详细情况了,本帖更关注于第一个特点,利用Google map api来构建属于自己的地图。

或者大家会问:构建自己的地图?可以是什么样子的呢?
小弟天马行空地替大家想象了一下,我初步想大家可以构建这样的一些应用:

  • 在专业的地图服务器里写script导出图瓦(动态或静态),然后制作自己的地图应用,最好的例子就是google地图本身
  • 利用网络的地图图瓦资源,构造地图应用,如利用API来显示e都市的三维地图,或者如后面演示的显示别的厂商如google的对手bingo的地图,mapABC的地图等
  • 通过修改现成的地图图瓦,来创造自己的地图。呵呵,站在巨人的肩膀上啊,例如你可以抓取google的图瓦,把上面的藏南地区全改回中文,然后发布出去
  • 发布大型的图画作品,例如你是卖画或者什么别的艺术品,或者你要做游戏地图,可以把照片割成图瓦,挂到网上去,让大家可以在不同分辨层次下欣赏作品
  • 协同进行艺术创作,把地图想象成大图画,大家可以在一个图画上创作,通过Map API可以进行宏观创作或者细节创作
  • … 更多更多好点子,欢迎在评论里面留言

首先贴一个swf,给大家看看用Google Map API来显示Live地图和MapABC地图的效果。


实现这个效果的步骤如下:

  1. 使用Flex的google map api,首先要去这里 下载
  2. 注册一个api使用的key,在这个页面进行注册
  3. 创建flex项目,项目目录结构如下图所示:
    mapsampleproject
    前面下载的SDK里面的map_flex_1_16.swc(下载时间不同,可能版本号不一致)需要放在项目的lib目录里面去。
  4. 创建mapsample.mxml主程序,代码如下:
    01.<?xml version="1.0" encoding="utf-8"?>
    02.<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    03.    <maps:Map xmlns:maps="com.google.maps.*" language="zh-CN" id="map"
    04.        mapevent_mapready="onMapReady(event)"
    05.        width="100%" height="100%" key="{mapKey}"/>
    06.    <mx:Script>
    07.        <![CDATA[
    08.            import com.ityao.map.MapABCDituTileLayerBase;
    09.            import com.ityao.map.GoogleDituTileLayerBase;
    10.            import com.ityao.map.LiveDituTileLayerBase;        
    11. 
    12.            import com.google.maps.overlays.TileLayerOverlay;
    13.            import com.google.maps.controls.MapTypeControl;
    14.            import com.google.maps.controls.PositionControl;
    15.            import com.google.maps.controls.ZoomControl;
    16.            import com.google.maps.LatLng;
    17.            import com.google.maps.Map;
    18.            import com.google.maps.MapEvent;
    19.            import com.google.maps.MapType;   
    20. 
    21.            //key for http://blog.ityao.com/
    22.            private static const mapKey:String = "ABQIAAAAjg2LNPeLd2SY_LMC4kTfyhREhvxbmPPYdzuafsMTRfCiNgtm-xT_QN9uPU6M7JTAKA4l_ycXr_8HOg";
    23.            private function onMapReady(event:Event):void {                  
    24. 
    25.                map.addControl(new ZoomControl());
    26.                map.addControl(new PositionControl());
    27.                map.addControl(new MapTypeControl());
    28.                map.removeMapType(MapType.PHYSICAL_MAP_TYPE);
    29.                map.removeMapType(MapType.SATELLITE_MAP_TYPE);
    30.                map.removeMapType(MapType.HYBRID_MAP_TYPE);
    31. 
    32.                //Live地图
    33.                var liveTileBase:LiveDituTileLayerBase = new LiveDituTileLayerBase();
    34.                var liveTileLayers:Array = new Array();
    35.                liveTileLayers.push(liveTileBase);
    36.                var liveMapType:MapType = new MapType(liveTileLayers,map.MERCATOR_PROJECTION,"Live地图");
    37.                liveTileBase.setMapType(liveMapType);
    38.                map.addMapType(liveMapType);
    39. 
    40.                //mapABC地图
    41.                var mapABCDituTileLayerBase:MapABCDituTileLayerBase = new MapABCDituTileLayerBase();
    42.                var mapABCDituTileLayers:Array = new Array();
    43.                mapABCDituTileLayers.push(mapABCDituTileLayerBase);
    44.                var mapABCDituMapType:MapType = new MapType(mapABCDituTileLayers,map.MERCATOR_PROJECTION,"mapABC地图");
    45.                mapABCDituTileLayerBase.setMapType(mapABCDituMapType);
    46.                map.addMapType(mapABCDituMapType);
    47.                //设置缺省的地图中心和地图类型
    48.                map.setCenter(new LatLng(23.09656,113.19219), 10);
    49.            }
    50.        ]]>
    51.    </mx:Script>
    52.</mx:Application>

    注意需要在程序中修改mapKey变量成为你前面注册的google map api key。

  5. 在主程序里面,我们创建了两种自定义的地图类型,并且添加了这两种类型进google地图中进行显示

定制自定义地图,如果地图的投影方法和google map一致的话,那只要继承TileLayerBase并重载里面的loadTile(加载图瓦)方法就可以了,下一篇将用live地图和mapABC地图为大家做介绍。

[UI]BLOG首页展示的几种方式

mikel阅读(744)

Blog的首页是一个重要的入口,所以如何能够做好入口的整理和展示非常重要。
大约在多年以前,按照日志的时间格式进行排列的类似于编年史样的风格非常流行,但是最近,摘要形式的首页展示开始变得流行起来,还有一些其他的展现形式,我们的Blogger们利用自己的聪明才智,充分的发挥了BLOG在互联网中的作用。
今天,就来介绍几种BLOG首页的展现形式。
首先,我们应该都了解首页是非常重要的,任何一个新的访客都希望从首页上获得足够多的信息,并且从易用性和导航的角度来考虑,首页也是一个站点中浏览次数最多的页面。
我们能够使用的BLOG展现形式有三种:全文形式、摘要形式、杂志形式。下面就其优缺点分别介绍一下:
1、全文形式。全文形式是指将日志文章的内容以时间为顺序全部展示出来,并不进行删减和截断。优点:
    用户可以不用离开页面而阅读全部的文章:现在已经越来越少人这么做了,但是这种方法仍保留着吸引读者的优势,唯一的缺点就是发表评论了(也许我们可以借助Ajax解决发表评论问题);
    与短文章配合的很好:如果你的日志基本上是在500字以内的短文章,那么这种全文的方式也许就非常适合;
    没有打断用户的浏览:用户不必文章看到一半再点击下一页或者全文去浏览剩余的部分;
    
2、摘要形式。摘要形式就是显示一部分文字内容,或者显示文章摘要的形式。优点:
    扫描更加容易:任何浏览者都有扫描页面的浏览习惯,而这种摘要的方式更加方便读者扫描最近的新作(想想Google Reader);
    控制表现力(Control of Design):摘要的形式更利于设计师们控制他们的设计(设计元素单元变小了,更容易组合,不必担心破坏整个布局);
    带来更多的PV:因为用户不能在首页完成全部的阅读,所以必然会被引导到另外一个全文页,这样能够增加整个站点的PV;
    避免重复的内容:全文的首页和全文页带来了内容的重复,而这是搜索引擎所不喜欢的,我们应该尽量避免;
    
3、杂志形式。这有点类似与摘要形式,但是日志的内容出现并不需要按照时间的顺序来排布,可以根据分类或者其他的指标来灵活的进行日志内容的排布。优点:
    更好的内容组织:可以将相似的内容组织在一起,有利于集中读者的注意力;
    控制表现力(Control of Design):同2;
    看起来更像典型的新闻站点;
    
任何一种BLOG的布局方式都有起特点,我们应该根据自己站点的情况和发展状况,选择合适的形式并且进行动态的调整,因为适度的变化才能更加的吸引读者。
参考资料:
1、Blog Front Page        http://www.webdesignerdepot.com/2009/09/how-to-display-your-content-on-a-blogs-front-page/

[MVC]MVC+Jquery开发B/S系统:③表单提交

mikel阅读(736)

说起表单提交,是无人不知,无人不晓哇。今天我们就谈如何用JQuery+MVC来处理表单的提交。
想达到的效果:
1、提交前的表单验证
2、表单验证
3、提交后的反馈信息
ok,先说一下工作的原理。
前台<form action='xxx.aspx' method='post'></form>,action指定了接受表单的处理页面。method这里我们只说post
如果用ajax提交表单,自然xxx.aspx便是请求的url。ajax请求后的callback便是响应表单的提交结果(错误、成功),我们提交的反馈信息用一个 浮层(lightbox)来表示。 不至于用 alert(""); 这样铛铛铛很囧。
我们引入一个JQuery的插件http://www.malsup.com/jquery/form/#api 这是一个略有名气的插件,方便易用。
关于其用法,大家可以搜索下。
那么我们需要做的就是
1、jQuery.form.js的使用 
2、lightbox的实现 
3、如何验证


//注册form的ajaxForm 此方法需要调用jQuery.ajaxwindow.js的方法
//一般form里有action,所以参数有可能只需要传一个callback,
//如果一个表单有多个提交按钮,那么则需要 提交不同的url
// 这个方法是用来注册form提交,如果有多个提交按钮时,最好默认注册一个,否则验证方法就不起到作用
$.fn.submitForm = function(args) {
    
var url, id, callback, before;
    id 
= this.attr("id");
    
if (typeof (args) == "string") {//只传一个url
        url 
= args;
        before 
= undefined;
        callback 
= undefined;
    }
    
else {
        args 
= args || new Object();
        url 
= args.url || this.attr("action");
        
if (typeof (args) == "function") {//只传一个callback
            callback 
= args;
        }
        
else {
            before 
= args.before;
            callback 
= args.callback;
        }
    }
    
//输入验证
    this.inputValidate();//这是我们需要实现的一个“输入时的验证”,
    
this.ajaxForm({ //这里调用jquery.form.js表单注册方法。
        url: url,
        beforeSubmit: 
function(a, f, o) {//提交前的处理
            
//提交验证
            if ($("#" + id).submitValidate() == false)//这里我们需要实现的“提交时的验证”。
                
return false;
            
if (before != undefined && before() == false) {
                
return false;
            }
            o.dataType 
= "json";//指定返回的数据为json格式。
        },
        success: 
function(data) {//提交后反馈信息处理
            
if (data == "" || data == null) {
                
return false;
            }
            
var msg = new ajaxMsg(data);//这个ajaxMsg便是我们需要实现的Lightbox
            msg.show(callback);//show这个反馈的结果。
            
return false;
        }
    });
    
return this;
}


上面的方法很简单,就是form插件的使用,还有几个我们需要实现的方法。(inputValidate,submitValiedate,ajaxMsg)
既然是ajax提交,我们则需要给客户端一个反馈信息,然后用Lightbox呈现。

一:我们定义一个JsonMessage类


    public class JsonMessage
    {
        
public int result { getset; } //0错误 1正确 2提示 3警告
        public string title { getset; }//Lightbox窗口的标题
        
public string content { getset; }//message的具体内容
        
public string redirect { getset; }//弹出后自动跳转的到哪里?
        
public object callBackData { getset; }//客户端需要的数据 比如 一个新增的id或整个model


MVC返回Json(jsonmsg1),客户端的callback便可以得到这个对象的json格式。
(注 意:如果是附件的表单提交,则不能识别JsonResult格式。具体我还没有研究怎么回事,这种情况只能response一个json字符串,可以用 System.Web.Script.Serialization.JavaScriptSerializer来序列化对象,也很方便。)

二:我们写一个ajaxMsg来实现lightbox,这是我自己写的Lightbox,比较简陋,如果不喜欢,也可以用一些知名的插件。


var ajaxMsg = function(msg) {
    
if (msg != undefined) {
        
//提示框的属性
        this.result = msg.result || 0//0错误 1正确 2提示 3警告
        this.title = msg.title || ""//提示框的标题
        this.redirect = msg.redirect || null;
        
this.content = msg.content || ""//窗口的内容 通过后台json数据获得
        this.callBackData = msg.callBackData;
    }
}
//创建一个win
ajaxMsg.prototype.open = function(parentElement) {
    
//创建Mask遮罩层
    $("body").append("<div id=\"MsgMask\" class=\"mask\"></div>");
    
//设置Mask高度
    var bodyheight = document.body.offsetHeight;
    
var clientheight = document.documentElement.clientHeight;
    
if (bodyheight > clientheight)
        clientheight 
= bodyheight;
    
else
        bodyheight 
= clientheight;
    $(
"#MsgMask").height(bodyheight + "px");
    
//创建窗口
    $("body").append("<div id=\"MsgFrame\" class=\"frame\"></div>");
    
var frameId = "#MsgFrame";
    
//不同的style 不同的frame  frame由mask来控制
    switch (this.result) {
        
case 0:
            $(frameId).addClass(
"msg_error");
            
break;
        
case 1:
            $(frameId).addClass(
"msg_right");
            
break;
        
case 2:
            $(frameId).addClass(
"msg_tips");
            
break;
        
case 3:
            $(frameId).addClass(
"msg_warning");
            
break;
        
default:
            $(frameId).addClass(
"msg_default");
            
break;
    }
    
//创建内容div
    $(frameId).append("<div id=\"MsgContent\" class=\"content\">" + this.content + "</div>");
    
//设置Mask的宽高
    if (this.width > 0)
        $(frameId).width(
this.width);
    
if (this.height > 0)
        $(frameId).height(
this.height);
    
//设置窗口的定位
    var frame_width = $(frameId).width();
    
var frame_height = $(frameId).height();
    
var css_top = parseInt((document.documentElement.clientHeight  frame_height) / 2 100;
    
if (css_top <= 0)
        css_top 
= 80;
    
var css_left = (document.documentElement.clientWidth  frame_width) / 2;
    
var css_right = css_left;
    $(frameId).css(
"top", css_top + "px").css("left", css_left + "px").css("right", css_right + "px");
    hideSelects();
}
//显示方式
ajaxMsg.prototype.show = function(callBack) {
    
if (this.result == undefined) {
        
if (callBack != undefined)
            callBack(
this.callBackData);
        
return;
    }
    
if (this.result == 1) {
        
if (this.content != undefined && this.content != "") {
            
//this.open();
            //setTimeout(this.close, 1000);
            alert(this.content);
        }
        
if (callBack != undefined)
            callBack(
this.callBackData);
    }
    
else {
        
//this.open();
        //setTimeout(this.close, 2000);
        alert(this.content);
    }
}
//关闭
ajaxMsg.prototype.close = function() {
    removeMsg();
}
function removeMsg() {
    $(
"div").remove("#MsgMask");
    $(
"div").remove("#MsgFrame");
    showSelects();
}

不 知道有没有人能理解我这里的callback,我说一下他的用到的情况。 实际应用中我还有一个ajaxWin来实现弹窗,弹窗里的表单提交后一般需要关闭弹窗,然后更新一些数据(比如刷新列表)。这时就需要 submit后的callback动作。另外就是我目前还有使用到redirect这个属性。呵呵,我之前的系统需要大量的跳转处理,这些跳转也是无刷新 的,有一个数组来记录访问的地址。可以实现后退和前进。
下面是他的css

Code


三:好了,Lightbox已经实现了,也能show出各种类型的信息了。
下面还剩下表单验证。 其实表单验证大有文章可做。我这也不能一一做到。目前只做了些简单的验证。以后会实现比较复杂的错误提示效果。其实这都是 体力活,上面没要求我也懒的弄-。-

验证我采用的是给control一些自定义属性,然后再判断其值是否合法。


//输入验证
$.fn.inputValidate = function() {
    $(
"input,select,textarea"this).each(function() {
        
var isnull = $(this).attr("isnull");
        
var regexValue = $(this).attr("regex");
        
var defautValue = $(this).attr("dvalue");
        
//            //①非空注册焦点事件
        //            if (isnull == "0") {
        //                $(this).blur(function() {
        //                    if (this.value == "" || this.value == defautValue)
        //                        $(this).addClass("focus").focus();
        //                    else
        //                        $(this).removeClass("focus");
        //                });
        //            }

        
//②正则注册onchange事件
        if (regexValue != undefined) {
            
var thisValue = this.value;
            
//检查类型绑定不同事件
            if ($(this).attr("type"== "text") {
                $(
this).bind("keyup"function() {
                    
if ($(this).val() == "")
                        
return;
                    
var re = new RegExp(regexValue, "ig");
                    
var newValue = this.value;
                    
if (!re.test(newValue)) {
                        $(
this).val(thisValue).focus();
                    }
                    
else {
                        thisValue 
= newValue;
                        $(
this).val(newValue);
                    }
                });
            }
        }
        
function checkRegex(value, re) {
        }
        
//③最小长度

        
//④其他

    });
}
//提交验证
$.fn.submitValidate = function() {
    
var result = true;
    $(
"input:visible,select:visible,textarea:visible"this).each(function() {
        result 
= true;
        
var thisValue = "";
        
if ($(this).attr("type"== "radio" || $(this).attr("type"== "checkbox") {
            thisValue 
= $("input[name='" + this.name + "']:checked").val();
        }
        
else
            thisValue 
= $(this).val();
        
//判断是否违法

        
if ($(this).attr("isnull"== "0") {//① 是否必填 且不能为空或缺省值
            result = (thisValue != "" && thisValue != $(this).attr("dvalue"));
        }
        
else if (thisValue != "") {//② 是否符合格式 属性为 regex 正则
            var reValue = $(this).attr("regex");
            
if (reValue != undefined) {
                re 
= new RegExp(reValue, "ig");
                result 
= re.test(thisValue);
            }
        }
        
//        //③ 是否符合最大长度
        //        var maxLength = $(this).attr("maxLen");
        //        if (maxLength != undefined && maxLength != "-1") {
        //            if (thisValue.length > parseInt(maxLength))
        //                result = false;
        //        }
        //        //④ 是否符合最小长度

        
//返回false

        
if (result == false) {
            $(
this).addClass("focus").focus().blur(function() {
                
if (this.value != "" && this.value != $(this).attr("dvalue")) {
                    $(
this).removeClass("focus");
                }
            });
            
//alert($(this).attr("name"));
            return false;
        }
    });
    
return result;
}


这些都是比较简单的东西,拿出来献丑了。 下面是我之前写的关于绑定的,有兴趣的可以看看。

MVC+Jquery开发B/S系统:①列表绑定

[Linq]LINQ & Lambda, Part 4: Lucene.Net

mikel阅读(885)

Lucene is a jewel in the open source world – its a highly scalable, fast search engine written in Java. Its class-per-class C# cousin – Lucene.Net – is also a precious stone in the .NET universe. Over the years, Lucene.Net has gained considerable popularity and is used in a wide range of products.

C|NET, Fogbugz on Demand and Wikipedia are just a few sites that use Lucene.Net for indexing and searching their vast content. Even Microsoft has been forced to deal with a Lucene powered competitor Outlook extension that embarrasses the built-in search engine.

It's an extremely useful tool in the belt of any software engineer. Not just for it's design and implementation of modern information retrieval theories, but for it's simple API too.

From my experiences, libraries with simple concepts have simple API's. Lucene is no different because the search engine concept is very simple. A search engine is a system for finding text from a large set very quickly.

At the heart of the engine is the index (similar to a database table) with fields (like database columns) that contains documents (like database rows). To search one must write a query and give it to the engine to finding matching documents. The query language for a database is SQL and for Lucene it's a query object (you can construct complex queries by composing an object graph of query instances).

Search engines are super fast for finding text because documents are stored in an inverted index (where the terms of each field is tokenized, hashed and sorted at index time).

In contrast to database queries, search engines can calculate relevance scores when searching. This is because they use a better querying model called the vector space model instead of the classical boolean model. In the vector model, documents and queries are represented as vectors. The similarity between a query and any document can be calculated with simple vector operations. Documents with a higher similarity will appear higher in the results. Conversely, databases only know if rows meets the where criteria or not and cannot compute a relevance score – this true/false classification is how the boolean model got it's name.

Search engines are rad!! And with Lucene any developer can easily add a search engine to their application.

To satiate the rampant LINQ junkie within, I've been contributing to the LINQ to Lucene project – an open source LINQ provider framework.

My recent contribution to the project makes creating indexes and searching them even easier. Today, I'm going to demonstrate some features I've added so you too can easily Lucene-ify your application.

A common use of Lucene in applications is to complement the database with a Lucene index for searching. LINQ to Lucene offers this functionality out of the box with LINQ to SQL from data generated classes.

Let's start with the Northwind database. By following Scott Gu's instructions, you can create a DBML file with generated classes from the database schema. This demonstration only needs the Customer and order table.

linq to sql

The next step is to inform LINQ to Lucene which classes to index and how they are indexed using attributes. We do this extending the Customer and order generated classes and decorating them with attributes. If you don't know how to create partial classes, see Chris Sainty's post.

  1. [Document]  
  2. public partial class Customer {  
  3. }  
  4.   
  5. [Document]  
  6. public partial class Order {  
  7. }  

Now we've marked these two classes as documents for indexing. The next step is to specify how each field is indexed. But, there is a bit of a problem with properties in generated classes. There is no way to add attributes to generated properties without spoiling the automatically generated files.

Our solution to this is to add the MetadataType property on the DocumentAttribute which tells Lucene to look at another class for the field attributes it needs. Like so:

  1. [Document(Metadatatype= typeof(CustomerMetadata))]  
  2. public partial class Customer {  
  3. }  
  4.   
  5. [Document(Metadatatype= typeof(OrderMetadata))]  
  6. public partial class Order {  
  7. }  

Now we can create fake properties on our metadata types to specify field characteristics. The return type of the fake properties doesn't matter, only the name has to match.

  1. public class CustomerMetadata {  
  2.   
  3.     [Field(FieldIndex.Tokenized, FieldStore.Yes, IsDefault = true)]  
  4.     public object ContactName { getset; }  
  5.   
  6.     [Field(FieldIndex.Tokenized, FieldStore.Yes, IsKey= true)]  
  7.     public object CustomerID { getset; }  
  8.   
  9.     [Field(FieldIndex.Tokenized, FieldStore.Yes)]  
  10.     public object ContactTitle { getset; }  
  11.   
  12.     [Field(FieldIndex.Tokenized, FieldStore.Yes)]  
  13.     public object CompanyName { getset; }  
  14. }  
  15.   
  16. public class OrderMetadata {  
  17.   
  18.     [Field(FieldIndex.Tokenized, FieldStore.Yes, IsKey = true)]  
  19.     public object OrderID { getset; }  
  20.   
  21.     [Field(FieldIndex.Tokenized, FieldStore.Yes, IsDefault = true)]  
  22.     public object CustomerID { getset; }  
  23.   
  24.     [Field(FieldIndex.Tokenized, FieldStore.Yes)]  
  25.     public object ShipName { getset; }  
  26.   
  27.     [Field(FieldIndex.Tokenized, FieldStore.Yes)]  
  28.     public object ShipAddress { getset; }  
  29.   
  30.     [Field(FieldIndex.Tokenized, FieldStore.Yes)]  
  31.     public object ShipCity { getset; }  
  32.   
  33.     [Field(FieldIndex.Tokenized, FieldStore.Yes)]  
  34.     public object ShipCountry { getset; }  
  35. }  

Now we've told Lucene.Net which properties to index and how to index them.

  • The FieldIndex property indicates whether or not the field is tokenized (i.e. split into parts). By default, this is UnTokenized to save index space.
  • The FieldStore property tells Lucene whether or not to store the original value in the index. Again, by default, this is NO to save index space.
  • IsKey should be true for the fields primary key. Only one property can be marked as the key, so LINQ to SQL classes with composite keys should have a new uniquely identifying property.
  • IsDefault tells Lucene which field is the default field for searching.

Now we're ready to create the index.

To create the index from a LINQ to SQL Data Context, we use the DatabaseIndexSet like so:

  1. var dbi = new DatabaseIndexSet(  
  2.                                                      @"C:\index\",                  // index path                                            
  3.                                                      new NorthwindDataContext()     // data context instance                                            
  4.                                                      );   
  5. dbi.Write();  

By running this code, we'll create an index for the entire contents of the Customer and order tables. LINQ to Lucene is smart enough to collect all the relevant data from the Northwind database, convert each row to a Lucene Document and add it to the index.

Linq to lucene sample indexing

Sweet! We've got an index of the Customer and order tables.

Now we can search for Customers or orders.

Let's find all the Customers who are Marketing Managers…

  1. var mmCustomers = from c in dbi.Get()  
  2.                       where c.ContactTitle == "Marketing Manager"                         
  3.                       select c;  
  4.    
  5. Console.WriteLine("Marketing Manager Customers: Found {0}", mmCustomers.Count());  
  6.   
  7. foreach (var customer in mmCustomers) {  
  8.     Console.WriteLine(customer.ContactName);  
  9. }  

Linq to lucene sample marketing search

This very simple example demonstrates the query equality operator, but many other types of query are possible (including wildcards, prefixes, proximities). You can find more ways to query on the LINQ to Lucene homepage.

In future posts, I'll demonstrate more complex query examples and how to supply custom formatters for properties.

To see the source of LINQ to Lucene, you can get the latest release. The sample project from this post is available for download here.

NOTE: The sample project uses the Northwind database as a data source. Northwind can be downloaded and installed to your SQL Server instance from here.

[Linq]Linq to Lucene

mikel阅读(942)

    lucene是在JAVA中比较有名的开源项目,也有.NET移植版lucene.net,不过在apache的官方网站上还是一个孵化器项目,而且好像2007年就不更新了,现在codeplex上推出了LINQ To Lucene,真是一个好消息。
linq to lucene采用attribute的方式,非常简单方便。

C#代码
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using Lucene.Linq.Mapping;  
  6. using Lucene.Net.Analysis;  
  7. using Lucene.Linq;  
  8.   
  9. namespace LinqToLucene1  
  10. {  
  11.     [Document]  
  12.     public class Book : IIndexable, IHit  
  13.     {  
  14.         [Field(FieldIndex.Tokenized,FieldStore.Yes, IsDefault = true)]  
  15.         public string Title { getset; }  
  16.   
  17.         [Field(FieldIndex.Tokenized, FieldStore.Yes)]  
  18.         public string Author { getset; }  
  19.   
  20.         [Field(FieldIndex.Tokenized, FieldStore.Yes)]  
  21.         public string PubTime { getset; }  
  22.   
  23.         [Field(FieldIndex.Tokenized, FieldStore.Yes)]  
  24.         public string Publisher { getset; }  
  25.  
  26.         #region IHit Members  
  27.   
  28.         public int DocumentId { getset; }  
  29.   
  30.         public float Relevance { getset; }  
  31.          
  32.         #endregion  
  33.     }  
  34. }  

然后就可以用linq的方式查询了,真是方便啊

C#代码
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using Lucene.Net.Documents;  
  6. using Lucene.Linq.Mapping;  
  7. using Lucene.Linq;  
  8. using Lucene.Net.Analysis;  
  9.   
  10. namespace LinqToLucene1  
  11. {  
  12.     public class Program  
  13.     {  
  14.         static void Main(string[] args)  
  15.         {  
  16.             IIndex<Book> bookIndex = new Index<Book>();  
  17.             bookIndex.Add(new Book()  
  18.             {  
  19.                 Title = "谁都逃不掉的金融危机",  
  20.                 Author = "xxx",  
  21.                 Publisher = "东方出版社",  
  22.                 PubTime = "2008年12月"  
  23.             });  
  24.             bookIndex.Add(new Book()  
  25.             {  
  26.                 Title = "许我向你看(“暖伤青春代言人” 辛夷坞《致我们终将逝去的青春》完美续作)",  
  27.                 Author = "辛夷坞",  
  28.                 Publisher = "河南文艺出版社",  
  29.                 PubTime = "2008年12月"  
  30.             });  
  31.             bookIndex.Add(new Book()  
  32.             {  
  33.                 Title = "大猫儿的TT奋斗史(都市小白领的爆雷囧事录)",  
  34.                 Author = "阿巳",  
  35.                 Publisher = "国际文化出版公司",  
  36.                 PubTime = "2008年12月"  
  37.             });  
  38.             bookIndex.Add(new Book()  
  39.             {  
  40.                 Title = "佳期如梦之海上繁花(匪我思存最新作品上市)",  
  41.                 Author = "匪我思存",  
  42.                 Publisher = "新世界出版社",  
  43.                 PubTime = "2008年12月"  
  44.             });  
  45.   
  46.             var result = from book in bookIndex  
  47.                          where book.Author == "xxx"  
  48.                          select book;  
  49.   
  50.             foreach (Book book in result)  
  51.             {  
  52.                 System.Console.WriteLine(book.Title);  
  53.             }  
  54.   
  55.             System.Console.ReadLine();  
  56.         }  
  57.     }  
  58. }  

不过有个bug,如果写成from Book book in bookIndex 的话,就会报异常。

引用
一个未找到类型 “Lucene.Linq.Expressions.Query`1[[LinqToLucene1.Book, LinqToLucene1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]”上的构造函数。

[MVC]mvc实用集锦(3)

mikel阅读(794)

      这段时间非常忙,所以上一篇没有及时回复留言,请大家谅解。
      由于时间比较长了,先简单回顾一下集锦(2) 中的内容。其中主要讨论了3个问题:view与Mvc view user control中使用强类型,UpdateModel与TryUpdateModel的使用方法及排错处理,还有就是在Action中使用 FormCollection来访问请求页面标签元素的值。
      view与Mvc view user control使用强类型不仅会使页面看起来很舒服而且更具有可读性。下面的例子供大家比较一下
      使用了强类型不需要在页面中进行转换,Model就是一个Account对象

System.Web.Mvc.ViewPage<Account>
<% if (Model != null) { %>
      <div><%= Model.Name %></div>
      <div><%= Model.Age %></div>
<% } %

      没有使用强类型,这里使用了ViewData存储对象account

System.Web.Mvc.ViewPage
<% if (ViewData["account"]) != null { %>
      <% var account = ViewData["account"] as Account ;%>
      <div><%= account.Name %></div>
      <div><%= account.Age %></div>
<%}%>

      UpdateModel与TryUpdateModel有一些重载方法可以帮助我们准确的将数据装入对象,其他的就没什么了。
      下面就把今天的几个实用技巧介绍给大家,按照上一篇的顺序往下进行
8. 使用SelectList填充DropDownList
    view:

<%= Html.DropDownList("AccountType") %>

   
    controller:

List<AccountType> accountType = GetAll();
ViewData["AccountType"] = new SelectList(accountType, "ID", "Name");

    可以再后面加上默认选中的参数:

ViewData["AccountType"] = new SelectList(accountType, "ID", "Name",selectedValue);

9. 使用Html.RenderPartial调用mvc usercontrol

<% Html.RenderPartial(ViewData["PartialViewName"] as string, Model); %>

在开发中将页面分成几个usercontrol,不仅使页面逻辑更加清晰而且被定义的usercontrol可以被重用。
10. ajax请求controller返回集合
集锦1介绍了一个ajax请求controller删除记录并返回成功与否信息的实例,而这次需要返回一个数据的集合,由于ASP.NET mvc集成了JQuery框架,所以使用getJson方法实现
    controller:

public ActionResult GetAllAccount()
{
    List<Account> list = this.GetAllAccount();
    return Json(list);
}

    view:

$.getJSON('<%= Url.Action("GetAllAccount", "Account") %>',
          function(json) {
              var $container = $("#container");
              $.each(json, function() {
              $container.append('<div><a href='detail?id=' + this.Id>this.Name</a></div>');
          });
 });

controller 中的代码行 return Json(list) 将所有的信息传输到客户端,最好不要这样做,创建一个 JsonAccount 类型,其中有两个属性分别是ID,Name,只将这两个信息返回到客户端即可,当然也可以使用 KeyValuePair,这样就不用额外的定义JsonAccount 类型,使用起来更方便!

return Json(list.ConvertAll(a => new KeyValuePair<Guid, string>(a.ID, a.UserName)));

在客户端脚本也要相应的变化

$container.append('<div><a href='detail?id=' + this.Key>this.Value</a></div>');

mvc实用集锦就写到这了,希望对大家开发ASP.NET mvc程序能够有所帮助。谢谢大家的支持!!!!!

[Lucene]用lucene为数据库搜索建立增量索引

mikel阅读(742)

用 lucene 建立索引不可能每次都重新开始建立,而是按照新增加的记录,一次次的递增
建立索引的IndexWriter类,有三个参数

IndexWriter writer = new IndexWriter(path, new StandardAnalyzer(),isEmpty);


其中第三个参数是bool型的,指定它可以确定是增量索引,还是重建索引.
对于从数据库中读取的记录,譬如要为文章建立索引,我们可以记录文章的id号,然后下次再次建立索引的时候读取存下的id号,从此id后往下继续增加索引,逻辑如下.
建立增量索引,主要代码如下

public void createIndex(String path)
{
     Statement myStatement 
= null;
     String articleId
="0";
     
//读取文件,获得文章id号码,这里只存最后一篇索引的文章id
    try { 
        FileReader fr 
= new FileReader("**.txt");
        BufferedReader br 
= new BufferedReader(fr);                 
        articleId
=br.readLine();
        
if(articleId==null||articleId=="")
        articleId
="0";
        br.close();
        fr.close(); 
      } 
catch (IOException e) { 
        System.out.println(
"error343!");
        e.printStackTrace();
      }
    
try {
        
//SQL语句,根据id读取下面的内容
        String SQLText = "*****"+articleId;
        myStatement 
= conn.createStatement();
        ResultSet rs 
= myStatement.executeQuery(sqlText);
       
//写索引
        while (rs.next()) {
         Document doc 
= new Document();
         doc.add(Field.Keyword(
"**", DateAdded));
         doc.add(Field.Keyword(
"**", articleid));
         doc.add(Field.Text(
"**", URL));    
         doc.add(Field.Text(
"**", Content));
         doc.add(Field.Text(
"**", Title));    
         
try{
            writer.addDocument(doc);
          }
          
catch(IOException e){
            e.printStackTrace();
         }
           
//将我索引的最后一篇文章的id写入文件
          try { 
           FileWriter fw 
= new FileWriter("**.txt");
           PrintWriter out 
= new PrintWriter(fw);    
           out.close();
           fw.close();
           } 
catch (IOException e) { 
             e.printStackTrace();
           }
         }
            ind.Close();
            System.out.println(
"ok.end");
         }
         
catch (SQLException e){
            e.printStackTrace();
        }
        
finally {
            
//数据库关闭操作
        }        
    }

然后控制是都建立增量索引的时候根据能否都到id值来设置IndexWriter的第三个参数为true 或者是false

 boolean isEmpty = true;
 
try { 
    FileReader fr 
= new FileReader("**.txt");
    BufferedReader br 
= new BufferedReader(fr);                 
    
if(br.readLine()!= null) {
        isEmpty 
= false;
     }
     br.close();
     fr.close(); 
    } 
catch (IOException e) { 
       e.printStackTrace();
  }
            
  writer 
= new IndexWriter(Directory, new StandardAnalyzer(),isEmpty);

[SEO]SEO Google算法解析系列之HillTop算法

mikel阅读(819)

   上一篇我们介绍了潜在语义索引(LSI),今天我们将介绍超链分析的颠峰之作:HillTop算法,作为现在Google现在最核心的排名算法之一,网上不乏大量介绍她的文献。本文侧重于原始算法的分析,不考虑过多复杂因素,让您更容易理解算法本质。

      HillTop算法集PageRank,HITs、相关性算法大成于一身,由康柏系统研究中心的Krishna Bharat和多伦多大学的George A.Mihaila2001年提出并申请了专利,后授权于Google200312Google算法更新,其成为Google核心排名算法之一。

     HillTop是一种查询相关性链接分析算法,克服了的PageRank的查询无关性的缺点。简单的说HillTop算法是针对热门查询关键词来对搜索结果重新排序的一种算法。之所以针对热门关键词,这是因为HillTop算法运行效率较低的原因。算法主要分为两个过程:

一、              专家页面的寻找和评分;搜索引擎根据用户查询日志发现热门关键词后,开始针对这些热门关键词寻找专家页面,成为专家页的2个必要因素,1)必须拥有足够多而且不存在隶属关系的出链,2)至少存在一个短语包含该热门关键词的所有术语。确定专家页以后,在该页面上找出所有全部包含热门关键词中术语、或者差12两个术语的短语,将这些短语分为三个等级,分别为全部包含,差1个和差2个术语,分别对这个三等级计算等级分,等级是分对各个等级中所有短语得分的 和,而短语得分取决于这个短语在页面中位置,分数从高到低依次标题、头部和锚文本等等,然后的综合计算这个三个等级得分就得到专家分。以下举个简单的以 “汽车消费”这个热门关键词为例,“中国汽车消费网”的首页和友情链接页就是这个关键词的专家页面,因为他具有足够多而且不隶属315che.com主机域名和同Cip的出链,同时标题中的“中国汽车消费网”也包含“汽车”和“消费”这两个术语。接下来评分,先算第一等级(包含所有术语的短语)的得分,短语“中国汽车消费网”在标题中得到16分(假设),以及在锚文本中“中国汽车消费理财倾向大调查”得了1分,那么第一等级得分为17分,再算第二等级(差一个术语),第三等级(差两个术语)。这样再算三个等级得分的加权和,就是专家分,注意这三个等级权重相差非常大,在原算法的等级1到等级3的权重分别是2^32,2^16和1,因为HillTop更喜欢完全匹配。

二、              对目标页评分;一个专家页对目标页的评分等于专家本身分值×专家页可区分的短语数量取前N个指向目标页的专家页,对于多个同一隶属的专家页指向该目标页,取分值最高的专家页,然后这些专家页对目标网页的评分的和就得到,这个页面对应这个热门关键词的得分,有人称之为行业得分

我们可以看到HillTop算法通过不同等级的评分确保了评价结果对关键词的相关性,通过不同位置的评分确保了主题(行业)的相关性,通过可区分短语数防止了关键词的堆砌。

 

总结:HillTop算法存在一种博弈的思想,在链接方面同行业的网站既需要竞争更需要合作,只有被同行“认可”的网站对热门关键关键词的查询才会被排在前面。HillTop基本毁灭了小网站对热门关键词的奢望,除非你对热门关键词有超强的预期能力,但是这种流量只会持续很短的时间。当然HillTop只是排名的一个重要因素,并不是全部。

本文由中国汽车消费网(http://www.315che.com/) SEO研究中心撰写。转载请注明。