[MVC]适合ASP.NET MVC的视图片断缓存方式(上)

mikel阅读(488)

  说到网站性能优化,没有什么比“缓存”更重要了。即便是某些朋友口中念念不忘的“静态页”,说到底也只是缓存了整张页面内容而已。但是,显然这 样大粒度的缓存策略,在如今“牵一发而动全身”的Web 2.0站点中几乎是无法使用的。试想,在Twitter中的某个名人被数十万人订阅,那么他发一条消息,难道此时网站要去修改数十万用户的静态页面?因 此,我们需要粒度更小的缓存。而比“整页缓存”粒度小一号的缓存,便是所谓“视图片断缓存”了。

  视图片断缓存非常重要,因为它缓存的 也是页面内容,这表示它比更低级别的缓存更有效率,也比静态页等整页内容缓存的适用面要大得多。在ASP.NET WebForm模型中提供了控件级别的缓存,我们可以为控件标记输出缓存策略,这样控件便不会每次都完整执行一遍。当然这个策略还不够灵活,因为它缓存的 最小单元是“控件”,而不是页面中任意的部分。因此我在一年多前提出了一个CachePanel, 由它包装的页面内容都可以被缓存,无论其内部是控件还是普通输出的内容。在实际生产过程中,CachePanel起到了非常重要的作用,许多场景下只要在 页面中包裹一个<ext:CachePanel runat="server" />,性能立即就有了质的飞跃。

  只可 惜,在如今ASP.NET MVC的时代无法直接使用CachePanel这样的服务器端控件。因为CachePanel需要服务器端代码的配合,而ASP.NET MVC中的页面只是“视图模板”,除了呈现之外就不应该有其他职责。因此,我们必须提出一种脱离于后端代码的“标记”方式,将视图中的内容片断进行随意地 缓存。在RailsDjango中都有类似的特性,但ASP.NET MVC甚至在2.0的Road Map中还没有包含这一功能,于是我们只能自己动手丰衣足食。不过有了ASP.NET WebForm作为强大的视图引擎,加这样的功能简直是举手之劳:

public static class CacheExtensions
{
public static string Cache(
this HtmlHelper htmlHelper,
string cacheKey,
CacheDependency cacheDependencies,
DateTime absoluteExpiration,
TimeSpan slidingExpiration,
Func<object> func)
{
var cache = htmlHelper.ViewContext.HttpContext.Cache;
var content = cache.Get(cacheKey) as string;
if (content == null)
{
content = func().ToString();
cache.Insert(cacheKey, content, cacheDependencies, absoluteExpiration, slidingExpiration);
}
return content;
}
}

  我们为HtmlHelper增加了一个Cache扩展方法,接受一些缓存参数(缓存键,绝对过期时间,偏移过期时间),以及一个生成缓存内容的 Func<object>委托。Cache方法的逻辑非常简单:首先根据缓存键来获取内容,如果存在则直接返回,否则即调用委托对象获得新内 容,并将其放入缓存。这样在缓存命中的情况下,委托的开销便可以节省下来了。

  例如,我们可以使用这样的代码进行测试:

Before Rendering:
<%= DateTime.Now %>
<br />
Rendering:
<%= Html.Cache("Now", null, DateTime.Now.AddSeconds(60), Cache.NoSlidingExpiration,
() => { System.Threading.Thread.Sleep(5000); return DateTime.Now; }) %>
<br />
After Rendering:
<%= DateTime.Now %>

  在实际情况中,我们是不会在代码中调用Thread.Sleep方法的,不过这里我们需要模拟一段开销,因此通过暂停当前线程来实现时间消耗。于是我们第一次打开页面:

Before Rendering: 2009/9/17 16:52:37
Rendering: 2009/9/17 16:52:42
After Rendering: 2009/9/17 16:52:42

  从结果中可以看出,Before Rendering和After Rendering相差了5秒钟,这就是Thread.Sleep(5000)的效果。但是如果您在60秒以内再次刷新页面,便可以看到缓存的效果:

Before Rendering: 2009/9/17 16:52:55
Rendering: 2009/9/17 16:52:42
After Rendering: 2009/9/17 16:52:55

  可以看出,Rendering阶段显示的还是刚才的时间,而Before Rendering和After Rendering是即时更新的。此外,由于Cache方法将Thread.Sleep(5000)的开销节省了下来,因此Before Rendering和After Rendering两个阶段打印出的时间完全相同。

  怎么样,简单吧。不过您应该会感到疑惑,这不是我们想要的结果啊,我们想缓存的是页面上的一个片断,但是现在必须将被缓存的内容作为一个完整的字符串输出,那么我们又该如何实现呢?难道我们要这么写吗?

<%= Html.Cache(..., () => "<span style=\"color:red;\">" + Model.Title + "</span>") %>

  当然不可能这样。如果只是这样的话,那么这个Cache的可用性毫无疑问会非常低。因此,我们还需要寻找更好的解决方案——关于这点,我们下次 再聊。而目前的Cache方法,最方便的输出大端页面内容的做法则是将内容放在一个Partial View中,然后使用Html.Partial方法输出内容:

<%= Html.Cache(..., () => Html.Partial("MyPartialViewToCache")) %>

  请注意,我们这里使用的是扩展后的Partial方法,而不是自带的RenderPartial。之前我们谈过WebForm页面的输出方式,而RenderPartial方法是直接向Response.Output输出页面内容,因此我们无法将其捕捉为一个字符串。不过,之前文章中的Partial方法是“山寨”版本,而符合“标准”的Partial方法实现已经包含在MvcPatch项目中。如果您感兴趣的话,可以获取它的源代码并编译。我这段时间在一部分一部分地将以前项目中较为通用的扩展及修改提取至MvcPatch中,希望可以使MvcPatch成为一个可复用的强大组件。

[资源]开发生涯中经常"溜达"的网站

mikel阅读(505)

作为软件开发人员,在做项目的时候难免会碰上一会技术的问题,如因项目中需要添加一些特殊的样式、动画效果或使用些现在的第三方控件等,
这时就开始上网狂“百度”或“google”,现在收集了一些自任为对软件开发时挺有参考价值的网站,与IT同仁们分享下:
1、http://www.dynamicdrive.com/
2、http://www.codeproject.com/
3、http://mochaui.com/demo/
4、http://www.asp.net/AJAX/AjaxControlToolkit/
5、http://www.coolite.com/
6、http://aspnetajax.componentart.com/
7、http://flexigrid.info/
8、http://jqueryui.com/themeroller/
9、http://examples.coolite.com/
10、http://extasp.net/
11、http://www.51aspx.com/
12、http://www.ajaxasp.net.cn/
13、http://www.walterzorn.com/tooltip/tooltip_e.htm

[Flex]Mate框架应该成为Flex4的新标准吗?

mikel阅读(492)

   Flex开发领域有许多框架来创建可扩展的企业级RIA应用,在我看来有两个主要框架:Cairngorm和Mate。二者都为企业级RIA提供了 一个坚实的基础。根据我使用Cairngorm和Mate在企业Java应用的情况来看,Mate对于小型和大型项目来说都是不错的选择。 Cairngorm使用一个单件模式,这使得它难于使用modules,在编译时间、SWF文件尺寸、开发速度上会耗费巨大的资源。相比之下,Mate使 用注入方式使得其易于并快速创建、维护和调试应用。我不是说你使用Cairngorm就错了,但是我的第一选择是Mate。

 

 

  Cairngorm开发走到了尽头而Mate方兴未艾

 

    Cairngorm被Adobe购买(编者注:此处不实)而且最终开源,自从2008年7月在SVN代码库开放源码,Cairngorm总共有0个 新的release,总共15个提交,而且自从2008年11月就没有新的提交,自从Flex2以后就没有一次Cairngorm代码发布。相 反,Mate也是开源的,Mate光去年就有17个新的版本,并伴随有几百个提交到代码库中,没有其他的Flex框架有如此的活跃度。

 

 

  Mate和总线结构

 

    Mate有一些不足之处,而且代码上没有任何处理,这就是总线结构。Mate由asfusion的几个人来维护,他们确实在更新论坛、提供文档、在 各种Flex活动中做演示等方面做的很好。但是,如果他们决定改变他们的职业或者仅仅过度维护Mate,那么可能没有人会继续涉足并保持这个框架不断前 进。我希望看到Mate在它的代码层面获得广泛的支持,有更多的人提交代码而且在框架的发展方向上能做出决定。希望能发布一个Mate1.0的版本(编者 注:目前版本为0.8.8.1),这个版本的代码要非常稳定,但是1.0版本对于想使用它来开发企业项目的人来说要让人觉得放心。

 

 

  支持两个框架或者都不支持

 

    Adobe几年前买了Cairngorm,这对于帮助Flex RIAs来说是个好的主意。现在FlexSDK和Cairngorm是开源的,但现在游戏规则完全改变了。看起来没人在使用Cairngorm,或者寻找 在Cairngorm下对于modules的增强。而且看起来没有社区在对该项目进行参与(编者注:这个说法不正确,有来自UniversalMind的 Extensions for the Adobe Cairngorm MVC,http://code.google.com/p/flexcairngorm/)。有什么因素会使Adobe改变它对一个框架的方 向?Cairngorm在5年后仍然使Adobe的框架吗?Flex4的时候是该去改变了。一个选择就是提供Cairngorm和Mate作为Flex的 专属框架。但是问题来了,谁来维护这些框架?第二个选择是不支持任何一个框架。这种方式社区会驱动RIA发展的方向,通过使用最好用的框架。这种方式已经 存在了数年,例如Struts, Spring, Hibernate, Apache等等。通过支持仅仅一个框架,框架创新的大门就关上了,FlexSDK持续改进并让社区兴奋,其中的关键是让社区参与改进,这是一个巨大的进 步。

 

 

原文在这里:
http://www.flexpasta.com/index.php/2009/07/16/mate-framework-should-it-b…

中文翻译原文:http://www.riameeting.com/node/416

[SEO]小欧:搜索引擎优化的最终“三成”

mikel阅读(639)

搜索引擎优化(或称SEO) 是通常被划分到网络营销的技术范畴,这是因为搜索引擎优化有助于也有利于网络营销的成单率。况且掌握它也很简单,甚至有人认为这玩意根本就不是一项正经技 术,因为看得懂HTML就完全可以上手操作。小欧也觉得SEO也不单单是一种很肤浅的技术,它更是一种全面优化每张网页或整个网站的活动,致使它们与搜索 引擎更加友好,从而在搜索结果排名中更能被访客发现(未必就一定要靠前,一定要到第1页)。

搜索引擎优化的唯一不变就是:即使你做了所有的事情,那也是应该的。你不能用这种“应该”来跟搜索引擎来讨价还价。更不能抱怨它为什么没有给你相应的排名和位置。小欧最近优化的这个有关北京工商代理项目就是这样,略加修改整体网站的结构和链接,结果,在30个小时内,Google就成功收录并检索到。

说到这儿,可能有人就问了,搜索引擎优化跟网络广告是怎么一回事呢?注意!SEO是不是广告,有待深入探讨,但SEO肯定不是为了广告而去优化的。当然,你可以把你要宣传的这些关键词都融入其中,比方说,前些天有个北京短信群发网站让小欧去做优化评估,打开一看,全是堆砌。从头到脚都是那几个词,可能这样的操作,也许就是为了广告而操作吧~~ 但是,这肯定不是在优化。

SEO可以说是一个非常锻炼人耐心与细心的一种长期活动。有时,为了一热门词能更好的被搜索 引擎所接受,奋斗几个月太正常了,而且结果往往也不是我们意料中的那么理想。如果,你做的是一个非常罕见的词,可能会轻松一些,基本上一周左右就能见到成 效。但大多数情况下是这样的,客户让你做,就是做一些难度大的、竞争度高的、排名浮度不稳定的(比如:北京办照),这个时候,就需要我们投入很大的时间和精力来脚踏实地的从头开始了。

既然是从头,那何为头?头就是根~ 何为根?根就是原理?好,接下来就看看搜索引擎的工作原理是什么?

首先我们得清楚搜索引擎与我们的大脑是不同的,它没有我们这么聪明(至少目前没有),它是靠 文本信息为驱动的,也就是说,你的网站行不行,能不能被搜索引擎找到,你得先看一下你的网站上有没有文字?如果没有,对不起,它不认识你。你与它无缘。随 着技术的迅速进步,搜索引擎不会像以往那么“单纯”了,比如:看到了“”,它不会只很单纯的认为此网站就是“牛”站,因为“牛”太多了,可以说人,可以说物,可以说此人很牛(牛逼),可以说此站有牛(肉牛), 还可以说此处产牛(牛厂),更可以说牛原来如此好吃(某某牛肉馆)。。。。。等等等等,太多了。。相反,搜索引擎在抓取网页时,会考虑在特定的时间和特定 的地点出现某些特定的关键词,这还不算,它还要把这些抓取到的东西拿“回家”再进行“加工”和计算,最后,才能被我们在搜索框中检索到。

大概过程为:爬行>>索引>>审核>>计算>>检索

先来看爬行,这项工作主要是靠搜索引擎蜘蛛来 完成,小蜘蛛遵循从一个网页的索引到另一个页面的索引。等网络上的页面超过20亿万张之后,小蜘蛛无需要天天爬行,只看哪些页面是新添加的?哪些页面是最 新修改过的?所以,我们一再强调,为什么要时常更新自己的网站,就是这个道理,有的网站一个月甚至几个月蜘蛛都不去,就是因为他的网站自从建成之后,闻所 未闻从未管理过。

接下来,我们就要知道,如何才能被蜘蛛发现我们这里有它喜欢吃的食物。如前所述,抓取工作不 是人,小蜘蛛它们是看不到图片、Flash、JavaScript、框架、密码保护的网页和目录的。因此,如果你的网站上全是这些内容,小欧建议你最好运 行一下蜘蛛模拟器。免得来了之后,又走了。(至于具体如何使用蜘蛛模拟器,小欧下次介绍)

在抓取网页时,小蜘蛛就会把从网页上的数据记录到索引页,我们知道,索引页存储在一个庞大的 数据库里,小蜘蛛就是在那里完成检索。从本质上讲,其实索引过程就是确定网页的描述和关键词的过程。对我们人来说,是根本无法处理如此大量的数据信息。有 时,它们可能得不到某些网页的正确描述世解释,这时,就需要我们通过优化来帮助它们,这将会使小蜘蛛们更容易更正确地定位自己所爬行的页面,并为下一步的 排名作好准备。

当用户的搜索请求来到时,搜索引擎进程先会与索引到数据库中的网页搜索请求的字符串进行比较。因为它很可能超过1个亿(包括搜索字符串),这时搜索引擎启动“计算关联”来对其索引中的每个搜索字符串。

有多种搜索算法来 计算搜索字符串的相关性。而且每种算法都有自己对关键词密度、链接和元标记的不同权重。这就是为什么不同的搜索引擎能提供“关键词”相同,但“检索结果” 不同的网页来。说到这儿,我们也知道为什么那些著名的搜索引擎:如Google、百度等会定期改变他们的算法,我们如果想得到很好的排名,就必须要适应他 们的最新变化,这是其一;其二就是你的竞争对手,如果你想立于不败之地,那就要深入持久的进行搜索引擎优化。

最后,就是检索结果了。通过上述我们一系列各个环节的努力,搜索引擎用户能够最快捷最简单最有效的找到他想要的信息,我们就成功了。搜索引擎就成功了。用户也成功了。此谓“三成”啊。。。呵呵~~ 好了,今天就到这儿。

小欧原创:关注最新搜索引擎算法&SEO排名

如需转载:请以链接形式注明来自小欧博客 http://blog.sina.com.cn/seo4

[Flex]基于Flex的界面组合SDK

mikel阅读(564)

转载:http://www.cnblogs.com/baihmpgy/archive/2009/09/16/1567387.html
以下是界面类似我们正在开发的一个产品的主界面,前端展示采用Flex开发,后端系统是基于Java的SOA框架。界面左边是导航条,右边是内容区(当然 还有其它栏目,在此忽略)。内容区一般由多个UI Part组成,每一个Part利用异步机制从后端获取数据,此外,它还将接收来自后端的通知消息。整个界面非常符合微软CAB思想,不过Flex没有 CAB组建,但是可以采用Microsoft用户控件方式定义一块一块内容。界面内容区的UI Part可能会被重用。

在 设计中,我想利用界面组合思想来设计,采用该思想的优点有:1)界面分割成不同的组成部分,每一部分实现一个功能,更加符合SRP原则;2)实现每一个 UI Part时,只需专注复杂界面中的一块内容的实现,比较简单;3)容易实现重用;其缺点有:1)每一个界面由多个UI Part组成,需要维护UI Part之间的联系;2)新手不太容易看懂界面的实现。
鉴于微软界面组合诸多优点,我决定将其思想引入到Flex,自己实现一个Composition SDK based on Flex,该SDK实现过程中参考了CAB & SCSF和Prism。
考虑到该软件需要实现的功能,这个SDK将支持如下功能:
1 UI Part生命周期管理。每一个UI Part在显示的时候,需要从后端获取数据,然后监听数据更新消息,当点击界面的“Tab 2”时,Tab 1被隐藏并停止监听消息,Tab 2被显示。在我看来每一个UI Part具有Activated、Deactivated和Closed生命周期状态,当处于Activated状态时,UI Part显示呈现所需数据,当处于Deactivated状态时,UI Part被隐藏并停止更新数据,当处于Closed状态时,UI Part被关闭并停止更新数据,它将被销毁。生命周期管理功能提出的目的是为了实现生命周期变更驱动数据更新,也就是每一个组件数据更新是由其自身的生命 周期状态决定的,不需要由父节点控制,从而实现更大粒度复用。
2 UI Part组合和动态注入。这个功能允许直接在视图容器类中定义每一个UI Part,在这种方式中,一旦容器被显示,则所有的UI Part将被显示;或者是其中某些UI Part是在运行时被动态注入并呈现的,当容器呈现时,根据需要注入特定的UI Part。
3 Master-Details UI Part支持。Master-Details UI Part是一对特殊的UI Part,当Master UI Part的数据发生变更后,Details UI Part也需要更新,和.NET的Master-Details View是一样的。
4 采用Hook机制实现,使得在实现1~3功能的时候,可以尽量与标准控件兼容,不必创建自定义控件或者仅需创建非常简单的自定义控件。Hook机制原理如 下:A)每一个功能由一个Hook实现;B)比如LifecycleHook,对于一个叶子节点的组件,当其被显示/隐藏/关闭时,该Hook要维护其状 态;对于一个容器节点,它除了要维护自己的状态,还要维护子控件的状态,比如VBox容器,当VBox被显示时,其状态为Activated且其所有一级 子节点状态也是Activated;而对于TabNavigator容器,当其被显示时,其状态为Activated且当前选中的Tab的状态也是 Activated,其余Tab的状态都是Deactivated;C)Hook的创建过程是递归的监听界面根节点 onChildAdded/Removed事件;D)SDK提供Hook注册表和Hook管理器,Hook注册表定义了每一类型的组件对应的Hook,而 Hook管理器定义了每一个控件对应的Hook实例。
5 基于该SDK,每一个视图的设计由Workspace和UI Part组成,Workspace使用Flex标准容器控件定义了界面的布局;UI Part是界面每一部分功能的实现,自己封装了生命周期驱动的数据更新。
代码的设计比较简单,其结构如下:

ComponentTreeHook是整个Hook机制的核心类,它将递归监听根节点控件的onChildAdded/Removed,当有子节点添加时,递归挂载整个控件树,挂载过程代码如下:

Code

附件是该SDK的测试文件,包含UI测试和Unit测试。测试文件

[DeBug]System.Threading.ThreadAbortException中第一次偶然

mikel阅读(440)

开发环境为VS2005,OS 为Windows 2003,系统登录后在跳转到另一页面时会报此错误:
在 System.Threading.ThreadAbortException 中第一次偶然出现的“mscorlib.dll”类型的异常
“System.Threading.ThreadAbortException”类型的异常在 mscorlib.dll 中发生,但未在用户代码中进行处理
但不影响程序的正常运行。于是在网上查了查,发现相关资料不多。后来找到微软的官方解释,搞定。
————————————————————————————————————–

症状

如果使用 Response.EndResponse.Redirect Server.Transfer 方法,则出现 ThreadAbortException 异常。 可使用 try-catch 语句捕捉此异常。

原因

Response.End 方法停止页的执行,并将该执行变换到应用程序的事件管线中的 Application_EndRequest 事件。 Response.End 后面的代码行将不执行。
此问题出现在 Response.Redirect Server.Transfer 方法中,这是由于这两种方法都在内部调用 Response.End

解决方案

若要解决此问题,请使用下列方法之一:

  • 对于 Response.End,调用 ApplicationInstance.CompleteRequest 方法而不调用 Response.End,以便跳过 Application_EndRequest 事件的代码执行。
  • 对于 Response.Redirect,使用重载 Response.Redirect(String url, bool endResponse),对 endResponse 参数它传递 false以取消对 Response.End 的内部调用。例如:
      Response.Redirect ("nextpage.aspx", false);

    如果使用这种解决方法,Response.Redirect 后面的代码将得到执行。

  • 对于 Server.Transfer,请改用 Server.Execute 方法。

状态

这种现象是设计使然。

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

mikel阅读(416)

我曾撰文介绍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阅读(303)

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阅读(463)

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阅读(510)

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/