[MVC]Asp.net MVC 示例项目"Suteki.Shop"分析之---安装篇

mikel阅读(763)

转载:http://www.cnblogs.com/daizhj/archive/2009/05/11/1451925.html

Asp.net MVC 示例项目"Suteki.Shop"分析之—安装篇

      声明:作为这个系列的开篇,本系统会将我在研究这个项目源码中的一些思考和心得介绍给大家。
当然本系统决不是那种所谓的“最佳示范”,里面所提到的使用技巧或设计思路只是给大家在实际工
作中提供一个参考,所谓“最好”之类的词汇都是“矬子里拔将军”,相信大家在成功的分析了几个
MVC示例之后,会找到适合自己所在团队或公司使用的方式或思路的。 其实在找一个合适的MVC示
例上我已花费了“一些”时间,而这个例子对于我来说,还是相对不错的(除了文档和相关说明较少
之外)。另外,该项目还使用了其他一些框架或DLL文件,比如castle, MvcContrib, NVelocity
这些内容会在后续文章中讲到。

     首先要解释一下这是个什么东东,其实说明了,Suteki就是一个在线商店一个B2C示例,用户可
以在这里挑选自己喜欢的商品并通过在线支付功能进行购买。同时它还提供了一套相对完备的管理机
制让管理员可以轻松管理自己的商品信息,分类信息,定单信息。总之这是一个相对完备的系统,尽
管Suteki还没有被广泛安装和使用,并已有一些网站在使用它了,大家可以通过这个地址来看一下其
运行实例:
http://sutekishop.co.uk/

     这个项目源码下载地址:
    
http://code.google.com/p/sutekishop/downloads/list
   
     关于该项目的BLOG:http://mikehadlow.blogspot.com/search/label/Suteki%20Shop, 只
可惜内容少的可怜:(

     下面我们就看一下如何安装和实始化一个sutekishop。
   
     首先,我们要运行下载包中的SQL脚本以生成数据库并初始化相应数据。SQL文件位于Database
件夹下的create_database.sql(创建数据库和表),insert_static_data(初始化数据)。
     因为作者是个英国人,其所使用的数据库脚本与我们国内的中文版SQL会有所不同,而本人所运行
的SQL2005是中文的,所以如直接运行create_database中的内容可能会出现一些异常。好在后来我
其中的一些导致出错的内容从create_database中摘了出来发现能安装了,所以下面就将我修改过的
sql脚本内容发上来(文章末尾),大家下载运行一下就可完成数据库的安装了。

    注:项目中的一些“数据库链接串”要批量替换成我们本地的数据库。
   
    接着,我们就在来一下最终的运行效果:)

    
        
    当点击页面右下方的Login链接时,会显示登陆提示框,我们在这里填入:      

    Email : admin@sutekishop.co.uk
    Password: 123123

    
    点击“SubmitQuery”按钮:
    
        
   

     这样我们就以管理员身份登入系统了,这时在顶部会出现相关的管理菜单,我们可以使用它来创建
商品分类,商品信息,所在地信息,User信息等等。
   
       
 

      这里以创建User信息为例进行说明,点击“User”链接:
    
     

      大家看到这里我之前已创建了几个用户信息,同时还包括管理员信息“admin@sutekishop.co.uk”,
(注:目前列表只显示Role为Administrator或Order Processor的信息)

 

    我们点击其中的“New User”链接,进入到添加用户页,并添入下列信息:        
    Email:
test@sample.com
    Password :123123
    Role:Customer
   
    然后点击“Save”按钮:)

       
    
     这样我们就可以在前台以该用户身份进行登陆了。  
    
     同理,我们再去添加“Categories”,“Countries”等信息之后,相应的结果如下所示:    
    
        
       
   

     完成相关的设置之后,就可以购买商品了。
   
     下面以刚才新创建的
test@sample.com帐号登陆系统,点击“Movie”–>“动作片”:
    
        
    
    我们点击该分类下的电影,比如这个“勇闯夺命岛”之后,进入到“购买流程”。
    
        
   

     点击“Add to basket”之后,就会显示一个购买清单:  

    
   

      我们在确认当前的购买信息之后,就可以点击“Checkout ”链接了:
       
      在接下来的付款环节里,就要填写相应的支付卡,地址等信息了。这个流程只要在线买过东西
的朋友应该不会陌生。

        
 

    注:这里对信用卡校验的逻辑可能会麻烦一些,如果想跳这该校验,可以注释下面代码,位于:
     Suteki.Shop\Suteki.Common\Validation\ValidationExtensions.cs    

public ValidationProperty<T> IsCreditCard()
{
    
if (IsString)
    {
        var trimmedValue 
= Regex.Replace(value.ToString(), "[^0-9]""");
        
        trimmedValue.Label(label).IsNumeric().WithLengthRange(
13.To(19));
        var numbers 
= trimmedValue.Trim().Reverse().Select(c => int.Parse(c.ToString()));
        var oddSum 
= numbers.AtOddPositions().Sum();
        var doubleEvenSum 
= numbers.AtEvenPositions().SelectMany(i => new[] { (i * 2% 10, (i * 2/ 10 }).Sum();
        
//if ((oddSum + doubleEvenSum) % 10 != 0)
        
//{
        
//    throw new ValidationException(label,"{0} is not a valid credit card number".With(label));
        
//}
    }
    
return this;
}

    这样,系统在成功提交定单信息之后,就会将详细信息显示出来。
    
        
    
      到这里,用户购买并下单的流流程就走完了,但整个业务流程并没结束,我们还要切换回管理员
身份去查看并进行相应操作:
    
        
   

     注:此时系统还会对用户的信用卡信息进行有效性校验等。
   
   
     好了,主要的业务流程就介绍到这里了。

     下面简单介绍一下产品的项目文件,该产品共包括四个项目:
     Suteki.Common:该项目包括一些基础的功能类,扩展方法,以及Controller,Model,Filter的
基类声明(会在以后文章中分别说明),还包括一些Service接口定制,第三方插件扩展。另外还有相
应的ViewData基类和相关附属类型声明。

     Suteki.Common.Tests:该项目主要是针对上面的Suteki.Common项目的单元测试。
   
     Suteki.Shop:该项目包括对 Controller,Model,Filter等的具体设计和功能实现。Service,
ViewData具体定义和实现,HtmlHelpers扩展,Repositories(CRUD)封装,Views文件夹等等。

     Suteki.Shop.Tests:该项目主要是针对上面的Suteki.Shop项目的单元测试。
  

     今天的内容就先到这里了。在下篇中,将会介绍一下该项目中的Controller的继承结构和实现方式,
感兴趣的朋友敬请关注:)
       

     SQL安装脚本下载: http://files.cnblogs.com/daizhj/suteki_Database.rar 
   

     原文链接:http://www.cnblogs.com/daizhj/archive/2009/05/07/1451925.html

     作者: daizhj, 代震军, LaoD

     Tags: mvc,Suteki

     网址: http://daizhj.cnblogs.com/

[C#]博客园电子期刊

mikel阅读(909)

MVP专家区

.NET技术

.NET 3.5新技术

Web开发

软件工程

其他

热点新闻

[REST]REST构架风格介绍之二:CRUD

mikel阅读(863)

上一节我们通过两个例子初步体会了REST状态表述转移的味道,但应该指出这两个例子还仅仅是简单的资源获取。REST是以资源为核心的,没有服务的概念,这的确让人怀疑REST能否像ORBSOA一样支持复杂的应用?在回答这个问题之前,让我们先暂时离开REST,把眼光转向基于关系数据库的3层构架。

通常业务逻辑层对外提供若干的功能接口(如图中定义的IOrderService),对内通过数据访问层访问数据库。我们知道,关系数据库只定义了CRUD(Create, Read, Update, Delete)四种标准的数据操作,分别对应于insert/select/update/delete四种SQL语句。经验告诉我们,关系数据库在若干张表上进行关系运算是足以支持各种复杂业务逻辑的,因为所有业务功能最终都会被映射到数据库上的CRUD四种标准操作。下面这个有趣的三角形能帮助我们理解这个问题:

图中的三角分别代表:数据类型、操作、实例。可以把他们想象成可以调节的按钮,业务逻辑层的方式是:定义了少量的服务实例,把大量的操作放在服务实例下面,形象地比喻为“一扇小门,里面装了很多东西”;而数据库的方式则是提供了大量数据实例和CRUD四种标准操作,可比喻为“很多门,每扇门里面装少量的东西”。

以资源为核心的REST和以数据为核心的关系数据库是类似的。数据和资源本质上都是状态,对状态的操作CRUD少一个不行,多一个多余。因此,REST也采用CRUD四种标准操作,分别对应于HTTP协议的POST/GET/PUT/Delete方法。虽然HTTP协议支持POST/GET/PUT/Delete以外的HEAD等方法,可以把这些非标准方法作为有用的补充,但不应影响REST模型的纯洁性。上一节中,我们看到REST风格的应用像一个状态机;而这里我们则看到它像一个数据库。REST方式定义出的资源(Url)和相应的操作就像下面这个样子(值得重申的是,从Url的含义“统一资源定位符”就可以看出其通用性,这也是REST资源表示的优势所在):

REST完美地结合了HTTP协议,所以更容易无缝接入互联网。另外,有人提到 “一个网站对外暴露的网页数可以作为衡量它为互联网所做贡献的指标”,如果从这个角度来看,以资源为核心的REST方式比服务为核心的SOA互联网更加友好。但 应该采用哪种风格的构架还是取决于应用本身的特点,一般来讲,对于以提供和管理数据为主的,且希望做SEO的应用适合REST风格,这包括大多数 WEB2.0的应用;而以计算和业务逻辑为主,且强调安全性的应用不太适合REST风格。但应避免不加分析先入为主的采用面向服务的思维,有时候恰当运用 状态表述转移模式的REST构架不但可以实现业务逻辑,而且具有更好的伸缩性,正如上一节谈到的心理测试服务和Google搜索一样。REST的价值就在 于让我们在设计构架的时候多了一种视角,所谓“眼界决定世界”。

Cache

由于RESTUrl表示资源和无状态服务特点,使得Cache机制变得异常简单,且HTTP协议中有直接支持。服务器响应可以通过cache-control:max-age,expires指定资源缓存时间;还可以在响应头的last-modified参数标明资源的最后修改时间,客户端请求可以带上if-modified-since参数,如果资源未过期,服务器只需用返回304 not modified状态即可,这样就避免了服务器端重复工作,也节省网络带宽;etag参数也是常用的cache控制参数,可以解决last-modified时间精度不够的问题。另外,HTTP协议还对Proxy机制有直接的支持,与Cache机制结合,在需要高性能的应用中,可以在服务器与客户端之间部署若干专门用于Cache目的Caching Proxy Server提高系统吞吐量

总结

最后总结一下REST的要点:1. Url表示资源;2.  CRUD操作;3. 状态表述转移。至于无状态服务、Http状态码、Cache控制、Proxy等则属于上面几个要点的推论,理解REST的关键还在于理解以资源为核心的模型。本文是我接触REST不到一年时间的一些体会和总结,深知对REST的掌握和应用还需继续努力,希望得到高手的指点!

相关链接

1.《如何获取一杯咖啡——星巴克REST案例分析》

2.《深入浅出REST》

[Flash]Flash和Flash的通信

mikel阅读(906)

转载:http://www.blueidea.com/tech/multimedia/2004/1712_3.asp

Flash和Flash的通信
通过上面两种方法的混和使用,同一HTML中两个或者更多的Flash直接可以相互传送消息. 从一个flash使用fscommand传送消息给JavaScript,使用Flash的JavaScript methods把消息传给另外一个flash
详细的看这里:Flash影片之间的通信示例
从Flash MX开始,local connection对象可以用来在flash之间传送消息. 这使得同一HTML中的或者位于两个浏览器窗口中的两个flash影片可以相互发送消息,而不必使用Javascript或者fscommand
详细的看这里:在Flash MX中使用local connection对象(英文)

本站的localConnection教程:http://www.blueidea.com/tech/multimedia/2003/739.asp
附可控制Flash Player的Javascript方法:
一览表:
Play() —————————————- 播放动画
StopPlay()————————————停止动画
IsPlaying()———————————– 动画是否正在播放
GotoFrame(frame_number)—————- 跳转到某帧
TotalFrames()——————————- 获取动画总帧数
CurrentFrame()——————————回传当前动画所在帧数-1
Rewind()————————————-使动画返回第一帧
SetZoomRect(left,top,right,buttom)——-放大指定区域
Zoom(percent)——————————改变动画大小
Pan(x_position,y_position,unit)————使动画在x,y方向上平移
PercentLoaded()—————————-返回动画被载入的百分比
LoadMovie(level_number,path)———– 加载动画
TGotoFrame(movie_clip,frame_number)- movie_clip跳转到指定帧数
TGotoLabel(movie_clip,label_name)—— movie_clip跳转到指定标签
TCurrentFrame(movie_clip)————— 回传movie_clip当前帧-1
TCurrentLabel(movie_clip)—————–回传movie_clip当前标签
TPlay(movie_clip)—————————播放movie_clip
TStopPlay(movie_clip)———————-停止movie_clip的播放
GetVariable(variable_name)—————–获取变量
SetVariable(variable_name,value)———–变量赋值
TCallFrame(movie_clip,frame_number)—call指定帧上的action
TCallLabel(movie_clip,label)—————-call指定标签上的action
TGetProperty(movie_clip,property)——–获取movie_clip的指定属性
TSetProperty(movie_clip,property,number)-设置movie_clip的指定属性

在 flash mx 以后,由于一系列的安全问题,比如载入另一个站点的 flash文件,然后用javascript控制 flash 跳转到不同的帧,让一些 flash 编写者在安全防范上防不胜防。为此 macromedia 改进了 flash player 和一些交互接口。引入了安全沙箱的概念,也就是可以设置一个可以进行控制的站点列表。

当然在同一个域名下,可以不考虑这个安全沙箱的问题。

更详细的接口和用法还有安全限制,请查看下面的PDF文件

另外我再提供一个 flash4 时代最顶尖的闪客 Dean 利用 javascript 和 flash进行交互的例子,这可是当时,最最眩目的页面了,html和flash结合紧密,而且保证了和 netscape 的兼容。

点击查看 看看我们4年前的闪客,在做什么?

另外,我在今年也有类似的应用,大家可以查看 bt 的专栏动画部分 ,在打开一个flash动画弹出框时,为了不影响音乐杂乱,我关闭了主场景的音乐开关。关闭弹出框时,打开主场景的音乐开关,这点,也主要是依靠 javascript 来进行对 flash 的控制的。

出处:蓝色理想
责任编辑:qhwa

[Flash]Flash到Javascript的通信

mikel阅读(684)

Flash到JavaScript的通信
从HTML可以发送数据到Flash,反过来也可以. 这个例子演示了如何应用Flash的Fscommand来发送数据到JavaScript.

查看示例:示例2
下载源文件: flash_to_JavaScript.zip(10K)
简要步骤:
Flash中
新建一个文件,保存为flash_to_javascript.fla
创建一个文本域,设置成输入文本(Input Text),选择"border"以便我们能看到他,指定他的变量为inputVar
创建一个按钮,在按钮上添加如下的as:

on (release) {
  fscommand ("send_var", inputVar);
}

保存文件,导出HTML和SWF
Dreamweaver中
1.打开导出HTML文件,修改<OBJECT>和<EMBED>标签,结果同上:
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/
flash/swflash.cab#version=5,0,0,0"
width=366 height=142 id="myFlash">
<embed src="javascript_to_flash.swf" quality=high
width=366 height=142
type="application/x-shockwave-flash"
pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?
P1_Prod_Version=ShockwaveFlash" name="myFlash" swLiveConnect="true">
</embed>

 2. 插入如下的Javascript到<Body>标签内:
<SCRIPT LANGUAGE=JavaScript>
<!–
var InternetExplorer = navigator.appName.indexOf("Microsoft") != -1;
function myFlash_DoFSCommand(command, args)                {
  var myFlashObj = InternetExplorer ? myFlash : document.myFlash;
  alert (args);
}

if (navigator.appName && navigator.appName.indexOf("Microsoft") != -1 &&
  navigator.userAgent.indexOf("Windows") != -1 && navigator.userAgent.indexOf("Windows 3.1") == -1) {
  document.write('<SCRIPT LANGUAGE=VBScript\> \n');
  document.write('on error resume next \n');
  document.write('Sub myFlash_FSCommand(ByVal command, ByVal args)\n');
  document.write(' call myFlash_DoFSCommand(command, args)\n');
  document.write('end sub\n');
  document.write('</SCRIPT\> \n');
}
//–>
</SCRIPT>

出处:蓝色理想
责任编辑:qhwa

[Flash]JavaScript 和 Flash 的通信

mikel阅读(671)

转载:http://www.blueidea.com/tech/multimedia/2004/1712.asp

JavaScript和Macromedia Flash的通信示例
原文地址: www.macromedia.com/support/flash/ts/documents/java_script_comm.htm
说明: 略作修改,主要是一些很初级的操作; 又很多相似的文章,不过这个很权威
下面是一些在Flash和使用JavaScript的HTML文件直接通信的示例,每个示例都有简略的步骤
本文讨论了3种基本的Flash/Javascript通信方式:
Javascript 到 Flash的通信—-使用Flash播放器的javascript方法
Flash 到 Javascript的通信—-使用Flash的fscommand
Flash 到 Flash的通信———-使用本地连接对象或综合上2种技术
并不是所有的浏览器都很重视脚本.为了和Flash播放器通信,浏览器必须有内置的钩子以便Flash播放器可以'监听'.浏览器必须是下列的几种:
Netscape Navigator 3.0-4.7x, 和 Netscape 6.2或更高
(Windows 95/98/NT/2000/XP 或 MacOS; 允许Java和LiveConnect)
Internet Explorer 3.0 或更高
(仅Windows 95/98/NT/2000/XP; 允许ActiveX)
注意:Macintosh上的Internet Explorer和早期版本的Netscape6不支持这种方法.请查看本文的附加信息
Javascript到Flash的通信

这个例子演示了如何使用Flash的method把变量从HTML的input text 发送到该页面中的Flash文件中.HTML input的数据通过Flash的SetVariable方法传送到Flash文件中.

查看示例:示例
下载源文件: javascript_to_flash.zip(17k)
步骤:

Flash中
1.新建一个文件,保存为javascript_to_flash.fla
2.用文字工具在舞台上创建一个文本域
3.选择这个文本域,在属性面板中,从下拉列表中选择动态文本(Dynamic Text),在变量(variable)栏填上"myVar"
注意:最好的习惯是使用Instance,用myVar.text更改myVar的值.为了简单起见和兼容Flash4和Flash5,我们使用的是变量名的形式.
4.保存文件
5.发布HTML文件和SWF文件

Dreamweaver中
下一步的工作转移到Dreamweaver中了,当然也可以是其他的HTML编辑器
1.打开上一步发布的HTML文件
2.插入生成的SWF文件和OBJECT/EMBED标签
(1) Insert>Media>Flash,并选择这个Flash
(2) 切换到代码视图,我们需要修改被选中的<OBJECT>和<EMBED>标签
(3) 在OBJECT标签中,插入id="myFlash"

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/
flash/swflash.cab#version=5,0,0,0"
width=366 height=142 id="myFlash">

注意:如果你是粘贴复制代码的话,确保删除不必要的换行.否则可能会引起错误; id也可以在属性面板里直接输入
(4) 在EMBED标签中,插入name="myFlash"和swLiveConnect="true",确保没有使用id属性!代码应当是这样子的:

<embed src="javascript_to_flash.swf" quality=high width=366 height=142
type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?
P1_Prod_Version=ShockwaveFlash"
name="myFlash" swLiveConnect="true">
</embed>

3.创建表单域
(1) 回到设计视图
(2) 插入文本域(Insert> Form Object> Text Field),如果询问是否添加表单域,选择是
(3) 把文本域的HTML标签修改成这样:

<input type="text" name="sendText" maxlength="45" onChange="doPassVar(this)">
每当文本域内容发生变化时,onChange就被触发,doPassVar()函数就被调用

4.创建传递变量值的Javascript函数
复制下面的Javascript到<head></head>标签内

<SCRIPT LANGUAGE=JavaScript>
<!–
function doPassVar(args){
var sendText = args.value;
   window.document.myFlash.SetVariable("myVar", sendText);
}
//–>
</SCRIPT>

5.保存文件,测试一下(F12)

出处:蓝色理想
责任编辑:qhwa

[MVC]ASP.NET MVC雕虫小技 1-2

mikel阅读(805)

转载:http://www.cnblogs.com/chsword/archive/2009/05/08/mvcskill_1.html

看到AnyTao和TerryLee分享的关于ASP.NET MVC使用和优化的技巧,不免手痒,也分享一下这一年多来ASP.NET MVC开发的积累。

其中未必是一些高效的技巧,但是的确是能解决问题,也未必有什么高深的原理,只是我觉得值得分享。

1.Controller来控制HTML的Title

我想大部分朋友都有在Controller里面指定Html页面Title的需求。

我习惯于先写使用的代码再去完善其实现,而指定一个Title最方便的形式莫过于:

   1: public ActionResult Index(int id) {

   2:     var article=Db.GetArticle(id);//获取数据库里的文章

   3:     Title=article.Name;

   4:     return View();

   5: }

当然,这段代码是不能执行的,因为Controller并没有内建的Title属性,不过没关系,我们可以自定义一个:

   1: abstract public class MyBaseController : Controller {

   2:        public string Title {

   3:            set {

   4:                ViewData["Page_Title"] = value;

   5:            }

   6:        }

   7: }

然后将我们的Controller换为这个MyBaseController,之后在Master中写ViewData[“Page_Title”]的输出就好了。

   1: <title><%=ViewData["Page_Title"] %></title>

OK,这个愿意实现了。

当然做SEO的话Keyword和Description也可以这样来搞。

2.ViewModel中传递Controller中定义的上下文

老赵十分推ViewModel于是我也做了不少这方面的实践,发现的确不错。但是有个问题,就是Controller中产生的上下文怎么传到View中去,比如说自定义的用户信息,等一些非static的类型,而我又不想到View中再实例化一遍。

解决方法:ViewModel中另加一上下文属性(在我和程序中这些上下文继承于IContext接口,而在Controller中它的属性是CHContext)

   1: public class HomeIndexViewModel {

   2:     public IContext Context { get; set; }//这个属性就是解决它的方法

   3:     public string Message { get; set; }

   4: }

而我在Controller中:

   1: public ActionResult Index() {

   2:     HomeIndexViewModel model = new HomeIndexViewModel {

   3:         Context = CHContext,//这里传递

   4:         Message="Welcome to ASP.NET MVC!"

   5:     };

   6:     return View(model);

   7: }

而View中:

   1: <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"

   2: Inherits="System.Web.Mvc.ViewPage<HomeIndexViewModel>" %>

   3: <asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">

   4:     Home Page

   5: </asp:Content>

   6: <asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">

   7:     <h2><%= Html.Encode(Model.Message) %></h2>

   8: </asp:Content>

这样我们就可以实现将Controller中产生的自定义上下文传递了。不过每个ViewModel都初始化一个IContext,未免太过频繁, 也累人,于是进一步改进,我们利用作用在Controller上的Filter,在Controller的基类我们自定义的 MyBaseController中写如下Filter,而实现这个功能则要所有的ViewModel继承于一个类:MyBaseViewModel:

MyBaseViewModel与Model:

   1: public class MyBaseViewModel {

   2:     public IContext Context { get; set; }

   3: }

   4:  

   5: public class HomeIndexViewModel:MyBaseViewModel {

   6:     public string Message { get; set; }

   7: }

Controller与Filter

   1: abstract public class BaseController : Controller {

   2:     protected override void OnResultExecuting(ResultExecutingContext filterContext) {

   3:         var m = ViewData.Model as BaseViewModel;

   4:         if (m != null){

   5:             m.Context = CHContext;//在这里初始化

   6:         }

   7:     }

   8: }

这回我们在Controller里使用时就清爽了,不用再传递CHContext了。

[Flash]纯AS代码实现可预览本地图片的flash上传客户端

mikel阅读(758)

转载:http://www.klstudio.com/post/182.html
[AS3]纯AS代码实现可预览本地图片的flash上传客户端
    需要Flash Player 10+版本的支持,原理就是主要利用fp10中的FileReference.load(),FileReference.data和 Loader.loadBytes()三个方法通过图片加载到内存中,来实现预览本地图片,但这个方式不太适用大图片预览,图片越大内存消耗就越大。

[注意]
1.我这边图片上传路径是无效的,所以图片上传失败是正常的,你们可以改一下上传路径即可;
2.需要Flash Player 10的支持;
3.这次主要研究是预览本地图片功能。

演示效果

实现代码

  1. package project.test   
  2. {  
  3.     import flash.display.*;  
  4.     import flash.geom.Rectangle;  
  5.     import flash.net.*;  
  6.     import flash.text.*;  
  7.     import flash.filters.*;  
  8.     import flash.events.*;  
  9.     import flash.system.Security;  
  10.       
  11.     import fl.controls.Button;  
  12.     import fl.controls.ProgressBar;  
  13.     import fl.controls.ProgressBarMode;  
  14.       
  15.     /** 
  16.      * @link kinglong@gmail.com 
  17.      * @author Kinglong 
  18.      * @playerversion fp10    
  19.      */  
  20.     [SWF(width="500", height="300", frameRate="24", backgroundColor="#FFFFFF")]  
  21.     public class TestUpload extends Sprite {  
  22.           
  23.         private const DEFAULT_UPLOAD_PAGE:String = "http://test.klstudio.com/upload.asp";         
  24.         private const BOX_WIDTH:uint = 500;  
  25.         private const BOX_HEIGHT:uint = 300;  
  26.           
  27.         private const STATE_CACHE:String = "cache";  
  28.         private const STATE_UPLOAD:String = "upload";  
  29.           
  30.         private var _filters:Array;  
  31.         private var _file:FileReference;  
  32.         private var _loader:Loader;  
  33.         private var _progress:ProgressBar;  
  34.         private var _state:String;  
  35.         private var _buttons:Array;  
  36.         private var _labels:Array;  
  37.         private var _txts:Array;  
  38.         private var _rect:Rectangle;  
  39.         private var _state_txt:TextField;  
  40.           
  41.         public function TestUpload() {  
  42.             Security.allowDomain("*");  
  43.               
  44.             _buttons = [];  
  45.             _txts = [];  
  46.             _labels = ["文件名称:","文件类型:","文件大小:","修改时间:"];  
  47.               
  48.             _rect = new Rectangle(2080180180);  
  49.             _state = STATE_CACHE;  
  50.               
  51.             //背景;  
  52.             this.graphics.beginFill(0x333333);  
  53.             this.graphics.drawRoundRect(00, BOX_WIDTH, BOX_HEIGHT, 1010);  
  54.             this.graphics.endFill();  
  55.             this.graphics.beginFill(0xEFEFEF);  
  56.             this.graphics.drawRoundRect(11, BOX_WIDTH – 2, BOX_HEIGHT – 21010);  
  57.             this.graphics.endFill();  
  58.             this.graphics.beginFill(0x666666);  
  59.             this.graphics.drawRoundRect(1030, BOX_WIDTH – 20, BOX_HEIGHT – 602020);             
  60.             this.graphics.endFill();  
  61.             this.graphics.beginFill(0xFEFEFE);  
  62.             this.graphics.drawRoundRect(1131, BOX_WIDTH – 22, BOX_HEIGHT – 622020);  
  63.             this.graphics.endFill();  
  64.               
  65.             this.graphics.beginFill(0xCCCCCC);  
  66.             this.graphics.drawRect(1170, BOX_WIDTH – 221);  
  67.             this.graphics.endFill();  
  68.               
  69.             this.graphics.beginFill(0x000000);  
  70.             this.graphics.drawRect(_rect.x-1, _rect.y-1, _rect.width+2, _rect.height+2);  
  71.             this.graphics.endFill();              
  72.             this.graphics.beginFill(0xEEEEEE);  
  73.             this.graphics.drawRect(_rect.x, _rect.y, _rect.width, _rect.height);  
  74.             this.graphics.endFill();  
  75.               
  76.               
  77.             //标题;  
  78.             var label:TextField;              
  79.             label = getLabel("图片上传(预览图片版) by Kinglong", getTextFormat(0xFFFFFF14true));  
  80.             label.x = 10;  
  81.             label.y = 5;  
  82.             label.filters = [getLabelFilter(0x000000)];  
  83.             this.addChild(label);  
  84.               
  85.             for (var i:uint = 0; i < _labels.length; i++ ) {           
  86.                 label = getLabel(_labels[i], getTextFormat(0x33333312), falsefalse);                  
  87.                 label.x = _rect.right+5;  
  88.                 label.y = _rect.y + 25 * i;  
  89.                 label.width = 280;  
  90.                 label.height = 20;  
  91.                 _txts.push(label);  
  92.                 this.addChild(label);  
  93.             }             
  94.               
  95.             _state_txt = getLabel("状态:", getTextFormat(0x33333312));  
  96.             _state_txt.x = 10;  
  97.             _state_txt.y = BOX_HEIGHT – _state_txt.height – 5;  
  98.             this.addChild(_state_txt);  
  99.               
  100.             //按钮;  
  101.             var button:Button;  
  102.             button = getButton("选择文件"80);           
  103.             button.move(2040);  
  104.               
  105.             button = getButton("上传文件"80);           
  106.             button.move(10540);  
  107.             button.enabled = false;  
  108.               
  109.             //进度条;  
  110.             _progress = new ProgressBar();  
  111.             _progress.move(19040);  
  112.             _progress.setSize(290,22);  
  113.             _progress.mode = ProgressBarMode.MANUAL;                          
  114.             this.addChild(_progress);  
  115.               
  116.             //文件类型;  
  117.             _filters = [];  
  118.             var filter:FileFilter;            
  119.             filter = new FileFilter("所有支持图片文件(*.jpg,*.jpeg,*.gif,*.png)""*.jpg;*.jpeg;*.gif;*.png");  
  120.             _filters[_filters.length] = filter;  
  121.             filter = new FileFilter("JPEG files(*.jpg,*.jpeg)","*.jpg;*.jpeg");  
  122.             _filters[_filters.length] = filter;  
  123.             filter = new FileFilter("GIF files (*.gif)","*.gif");  
  124.             _filters[_filters.length] = filter;  
  125.             filter = new FileFilter("PNG files(*.png)","*.png");  
  126.             _filters[_filters.length] = filter;   
  127.               
  128.             _file = new FileReference();   
  129.             _file.addEventListener(Event.COMPLETE, fileHandler);  
  130.             _file.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, fileHandler);  
  131.             _file.addEventListener(Event.Select, fileHandler);  
  132.             _file.addEventListener(Event.OPEN, fileHandler);              
  133.             _file.addEventListener(ProgressEvent.PROGRESS, fileHandler);  
  134.             _file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, fileHandler);  
  135.             _file.addEventListener(IOErrorEvent.IO_ERROR, fileHandler);  
  136.             _file.addEventListener(HTTPStatusEvent.HTTP_STATUS, fileHandler);  
  137.               
  138.             _loader = new Loader();  
  139.             _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadHandler);  
  140.             this.addChild(_loader);  
  141.         }  
  142.           
  143.         public function get state():String {  
  144.             return _state;  
  145.         }  
  146.           
  147.         private function clickHandler(event:MouseEvent):void {  
  148.             switch(event.target) {  
  149.                 case _buttons[0]:  
  150.                     _file.browse(_filters);  
  151.                     break;  
  152.                 case _buttons[1]:  
  153.                     _file.upload(new URLRequest(DEFAULT_UPLOAD_PAGE));  
  154.                     _state = STATE_UPLOAD;                    
  155.                     _buttons[0].enabled = false;  
  156.                     _buttons[1].enabled = false;  
  157.                     break;  
  158.             }  
  159.         }  
  160.           
  161.         private function loadHandler(event:Event):void {  
  162.             _loader.scaleX = _loader.scaleY = 1;  
  163.             var w:uint = _loader.width;  
  164.             var h:uint = _loader.height;  
  165.             if (w > _rect.width || h > _rect.height) {                  
  166.                 var ip:Number = w / h;  
  167.                 var lp:Number = _rect.width / _rect.height;           
  168.                 _loader.width = (ip > lp)?_rect.width:_rect.height*ip;  
  169.                 _loader.height = (ip > lp)?_rect.width / ip:_rect.height;  
  170.             }  
  171.             _loader.x = _rect.x + (_rect.width – _loader.width) / 2;  
  172.             _loader.y = _rect.y + (_rect.height – _loader.height) / 2;            
  173.             _loader.visible = true;  
  174.         }  
  175.           
  176.         private function fileHandler(event:Event):void {  
  177.             switch(event.type) {  
  178.                 case Event.COMPLETE:  
  179.                     if(state == STATE_CACHE){  
  180.                         _loader.loadBytes(_file.data);  
  181.                     }  
  182.                     break;  
  183.                 case DataEvent.UPLOAD_COMPLETE_DATA:  
  184.                     Debug("图片上传完成!");  
  185.                     _buttons[0].enabled = true;  
  186.                     _buttons[1].enabled = false;  
  187.                     _progress.setProgress(01);  
  188.                     break;  
  189.                 case Event.Select:  
  190.                     _txts[0].text = _labels[0] + _file.name;  
  191.                     _txts[1].text = _labels[1] + _file.type;  
  192.                     _txts[2].text = _labels[2] + ((_file.size > 1024 * 1024)?Math.round(_file.size * 10 / (1024*1024))/10 + "MB":Math.round(_file.size * 10 / 1024)/10 + "KB");                    
  193.                     _txts[3].text = _labels[3] + date2str(_file.modificationDate);  
  194.                     _buttons[0].enabled = true;  
  195.                     _buttons[1].enabled = true;  
  196.                     _file.load();  
  197.                     _state = STATE_CACHE;  
  198.                     _loader.visible = false;  
  199.                     Debug("图片已经准备!");  
  200.                     break;  
  201.                 case Event.OPEN:  
  202.                     if(state == STATE_UPLOAD){  
  203.                         debug("正在上传图片…");  
  204.                     }  
  205.                     break;  
  206.                 case ProgressEvent.PROGRESS:  
  207.                     if (state == STATE_UPLOAD) {  
  208.                         var pEvent:ProgressEvent = event as ProgressEvent;  
  209.                         _progress.setProgress(pEvent.bytesLoaded, pEvent.bytesTotal);  
  210.                     }  
  211.                     break;  
  212.                 case SecurityErrorEvent.SECURITY_ERROR:  
  213.                 case IOErrorEvent.IO_ERROR:  
  214.                 case HTTPStatusEvent.HTTP_STATUS:                     
  215.                     if (state == STATE_UPLOAD) {  
  216.                         debug("图片上传失败!");  
  217.                         _buttons[0].enabled = true;  
  218.                         _buttons[1].enabled = true;  
  219.                     }else {  
  220.                         debug("图片缓冲失败!");  
  221.                     }  
  222.                     _progress.setProgress(01);  
  223.                     break;  
  224.                   
  225.             }  
  226.         }  
  227.           
  228.         private function getButton(lbl:String,width:uint=120):Button {  
  229.             var button:Button = new Button();  
  230.             button.label = lbl;  
  231.             button.setSize(width, 22);    
  232.             button.setStyle("textFormat", getTextFormat());  
  233.             button.setStyle("disabledTextFormat", getTextFormat(0x999999));  
  234.             button.setStyle("textPadding",4);  
  235.             button.addEventListener(MouseEvent.CLICK, clickHandler);              
  236.             this.addChild(button);  
  237.             _buttons.push(button);  
  238.             return button;  
  239.         }  
  240.           
  241.         private function getLabel(label:String, format:TextFormat, selectable:Boolean = false, autoSize:Boolean = true):TextField {           
  242.             var lbl:TextField = new TextField();  
  243.             lbl.selectable = selectable;  
  244.             lbl.defaultTextFormat = format;  
  245.             if(autoSize){  
  246.                 lbl.autoSize = TextFieldAutoSize.LEFT;  
  247.             }  
  248.             lbl.text = label;  
  249.             return lbl;  
  250.         }  
  251.           
  252.         private function getTextFormat(color:uint=0x000000,size:uint = 12,bold:Boolean=false):TextFormat {  
  253.             var format:TextFormat = new TextFormat();  
  254.             format.font = "宋体";  
  255.             format.color = color;  
  256.             format.size = size;  
  257.             format.bold = bold;  
  258.             return format;  
  259.         }  
  260.           
  261.         private function getLabelFilter(color:uint=0xFFFFFF):BitmapFilter {  
  262.             var alpha:Number = 0.8;  
  263.             var blurX:Number = 2;  
  264.             var blurY:Number = 2;  
  265.             var strength:Number = 3;  
  266.             var inner:Boolean = false;  
  267.             var knockout:Boolean = false;  
  268.             var quality:Number = BitmapFilterQuality.HIGH;  
  269.   
  270.             return new GlowFilter(color,  
  271.                                   alpha,  
  272.                                   blurX,  
  273.                                   blurY,  
  274.                                   strength,  
  275.                                   quality,  
  276.                                   inner,  
  277.                                   knockout);  
  278.         }  
  279.           
  280.         private function date2str(day:Date):String {  
  281.             var str:String = day.getFullYear() + "-";  
  282.             str += num2str(day.getMonth() + 1) + "-";  
  283.             str += num2str(day.getDate()) + " ";  
  284.             str += num2str(day.getHours()) + ":";  
  285.             str += num2str(day.getMinutes()) + ":";  
  286.             str += num2str(day.getSeconds());  
  287.             return str;  
  288.         }  
  289.           
  290.         private function num2str(val:Number):String {  
  291.             var str:String = "00" + val;  
  292.             return str.substr(str.length – 22);             
  293.         }  
  294.           
  295.         private function debug(message:String):void {  
  296.             _state_txt.text = message;  
  297.         }  
  298.           
  299.     }  
  300.       

[Flash]Flash实现多文件上传

mikel阅读(739)

转载:http://blog.iyi.cn/start/2007/06/ajaxflash.html

FancyUpload,用flash和mootools实现的一款多文件无刷新上传工具。
最大的特点是可以一次选择多个文件,无刷新上传。
早些时候曾想过一次选择多个文件的问题,浏览器默认的file标签一次只能选择一个文件,要浏览并读取本地文件就必须调用本地的组件或命令,所以单纯用JavaScript+html无解。
今天查看订阅的feeds时,无意中在Ajaxian看到这个演示图片上选择了多个文件:

非常好奇,过去看了一下demo,果然可以一次选择多个文件!

Browsfile的button没什么特别,就是一个button,肯定是通过js触发了某个动作。前面说过js和html是不能实现这个功能的,那么肯定是flash实现了这个功能。

文件里面有个Swiff.Uploader.swf,就是这个swf实现了文件浏览的功能,as在这:http://digitarald.de/workspace/packages/Uploader/Swiff.Uploader.as

google了一下flash filebrowserflash fileupload果然找到很多内容

这片中文的详细说明了那个flash的原理:
http://www.cnblogs.com/walkingboy/archive/2007/02/09/Flash_FileUpload_FileReference.html
出处可能是这个:
http://www.codeproject.com/aspnet/FlashUpload.asp

原理是用了flash的FileReferenceList API实现的多文件选取。
http://markshu.ca/imm/flash/tutorial/fileReference.html

另外还有几个实例:
http://www.betriebsraum.de/blog/2006/01/13/download-flash-8-file-browser/

http://www.extremefx.com.ar/blog/flash-textarea