翻译(How to pass data to Flex application)

参考地址:http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=2&postId=12166

问题描述

Flex程序编译成SWF文件之后,你想让SWF基于外部的数据有不同的表现,或是你想显示这些数据。

解决方案

可以通过Flash vars,query String或者URL向Flex程序传参。

1. 通过Flash vars传参

在HTML wrapper中添加以键值对形式出现的Flash vars。在Flex程序中读取变量Application.application.parameters,类型是Object。比如,你在Flash vars中添加名为”key1″的key,在程序中可通过Application.application.parameters.key1访问。更多信息参考http://livedocs.adobe.com/flex/3/html/passingarguments_3.html

2. 通过query字符串传参

query字符串亦以键值对形式出现,不过现在是将该字符串添加到HTML wrapper中SWF文件的src属性后面。与Flash vars一样通过变量Application.application.parameters访问。更多信息参考http://livedocs.adobe.com/flex/3/html/passingarguments_3.html

3. 通过URL信息片段(fragment)传参

上述俩种方法在HTMl wrapper页面中完成传参过程,而通过URL fragment方式它允许你给指向嵌入SWF的HTML页面的URL传参。你所需要做的是在URL后面添加”#”,并在”#”后添加键值对形式的数据。比如你想给程序传递键名为”key1″的值”value1″,URL如下:http://www.yourdomian.com/webappcontext/yourhtml.html#key1=value1.在Flex程序中可通过BrowseManager和URLUtil类访问。BrowseManager的fragment属性即表示”#”后面的字符串,本例中fragment即为key1=value1, 然后通过URLUtil类的静态方法stringToObject可将fragment转为对象。更多信息参考http://livedocs.adobe.com/flex/3/html/deep_linking_5.html#245869

//================================================================//

以下部分摘自Adobe Livedocs

例1.直接修改template文件在HTML wrapper页面的<object>和<embed>标签中都添加flashVars。(因为浏览器兼容的原因)

<html>
<head>
<title>/flex2/code/wrapper/SimplestFlashVarTestWrapper.html</title>
<style>
body { margin: 0px;
 overflow:hidden }
</style>
</head>
<body scroll='no'>
<table width='100%' height='100%' cellspacing='0' cellpadding='0'><tr><td valign='top'>

<h1>Simplest FlashVarTest Wrapper</h1>

    <object id='mySwf' classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' codebase='http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab' height='100%' width='100%'>
        <param name='src' value='FlashVarTest.swf'/>
        <param name='flashVars' value='firstName=Nick&lastName=Danger'/>
        <embed name='mySwf' src='FlashVarTest.swf' pluginspage='http://www.adobe.com/go/getflashplayer' height='100%' width='100%' flashVars='firstName=Nick&lastName=Danger'/>
    </object>

</td></tr></table>
</body>
</html>

例2. 修改template中JS

AC_FL_RunContent(
    "src", "TestApp",
    "flashVars", "myName=Danger&myHometown=Los%20Angeles",
    "width", "100%",
    "height", "100%",
    "align", "middle",
    "id", "TestApp",
    "quality", "high",
    "name", "TestApp",
    "allowScriptAccess","sameDomain",
    "type", "application/x-shockwave-flash",
    "pluginspage", "http://www.adobe.com/go/getflashplayer"
);

例3.给swf的src属性传值

<object ... >
    <param name='src' value='TitleTest.mxml.swf?myName=Danger'>
    ...
    <embed src='TitleTest.mxml.swf?myName=Danger' ... />
</object>

上述3例在Flex程序中访问:

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://www.adobe.com/2006/mxml"
creationComplete="handleCreationComplete(event)">
<Script>
<![CDATA[
import mx.managers.BrowserManager;
import mx.controls.Alert;
import mx.events.FlexEvent;
private function handleCreationComplete(event:FlexEvent):void
{
BrowserManager.getInstance().init(
var param:Object = Application.application.parameters;
for (var prop:String in param)
{
trace([prop, param[prop]]);
}
}
]]>
</Script>
</Application>

例4.利用URL fragment

http://www.mydomain.com/MyApp.html#firstName=Nick;lastName=Danger
<?xml version="1.0" encoding="utf-8"?>
<!-- deeplinking/PassURLParamsAsFragments.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="vertical"
    historyManagementEnabled="false"
    creationComplete="init(event);"
>
    <mx:Script>
    <![CDATA[
        import mx.managers.BrowserManager;
        import mx.managers.IBrowserManager;
        import mx.utils.URLUtil;

        private var bm:IBrowserManager;
        [Bindable]
        private var fName:String;
        [Bindable]
        private var lName:String;            

        private function init(e:Event):void {
            bm = BrowserManager.getInstance();
            bm.init("", "Welcome!");

            /* The following code will parse a URL that passes firstName and lastName as
               query string parameters after the "#" sign; for example:
               http://www.mydomain.com/MyApp.html#firstName=Nick&lastName=Danger */
            var o:Object = URLUtil.stringToObject(bm.fragment, "&");
            fName = o.firstName;
            lName = o.lastName;
        }
    ]]>
    </mx:Script>

    <mx:Form>
        <mx:FormItem label="First name:">
            <mx:Label id="ti1" text="{fName}"/>
        </mx:FormItem>
        <mx:FormItem label="Last name:">
            <mx:Label id="ti2" text="{lName}"/>
        </mx:FormItem>
    </mx:Form>

</mx:Application>
Advertisements

翻译(The spring actionscript framework)

作者:CHRISTOPHE COENRAETS

Part 1基本概念

Spring AS框架是Java中Spring IoC框架的AS版本。它也是众多围绕依赖注入提供解决方案的Flex框架之一(还包括SwizMate等框架).最近我花了一些时间研究”Spring ActionScript”。目前关于此框架的资源还不是很多,所以我想和大家分享下我的心得。

NOTE:为了不引起混淆,本该项目和我之前写过的Spring/BlazeDS整合项目是完全独立的(它们也可以很好的融合在一起)。:

在本文中,我将介绍一些基本的概念…想象一下如果你的应用程序使用RemoteObject访问后台,除非你的程序只是由少数几个组件构成,并且一直与相同的server交互,否则你迟早会遇到下面的俩个问题:

怎样在外部而不是在代码里面配置service?

怎样将程序的组件的引用提供给service?

NOTE:1.第一个例子有意的保持了简单。在更为细分的应用中,你也许只想提供一个更抽象的控制器而不是某个特定的RemoteObject。关于这点将在第三部分介绍。

2.Spring AS是一种控制反转框架:你可以不用RemoteObject,或任何数据访问策略,或甚至连接后台…这里我只是创建了一个测试用例.

对象的配置与装配

Spring AS使用xml文件来配置它的组件。它的优点是能够让你改变组件的配置,或切换组件的实现过程,而不需要重新编译,这样我们就会在产品的开发和测试过程中获得极大的灵活性。另一方面,当你在xml配置文件声明你的类时,编译器是不知道你在做什么的:组件的配置在编译时不会被检查,更为重要的是xml配置文件中定义的类如果在代码中没有被直接引用,它们是不会被链接到swf里去的。但无论如何这不会是主要的问题,因为我们可以告诉编译器去引用这些类。(参考第三部分)

在第一个例子中,我们将配置一个简单的RemoteObject对象…

<?xml version="1.0" encoding="utf-8"?>
<objects>

	<object id="channelSet" class="mx.messaging.ChannelSet">
		<method-invocation name="addChannel">
			<arg>
				<object id="amfChannel" class="mx.messaging.channels.AMFChannel">
					<property name="url" value="http://localhost:8400/lcds-samples/messagebroker/amf"/>
				</object>
			</arg>
		</method-invocation>
	</object>

	<object id="contactRemoteObject" class="mx.rpc.remoting.mxml.RemoteObject">
		<property name="channelSet" ref="channelSet" />
		<property name="destination" value="contacts" />
		<property name="showBusyCursor" value="true" />
	</object>

</objects>

注意我们首先配置一个ChannelSet对象。在此例中,我们定义了一个单独的AMF channel,之后配置我们需要的RemoteObject对象,并将我们之前配置的ChannelSet注入到RemoteObject对象中。

在外部配置RemoteObject和ChannelSet有很多好处…你可以不用重新编译而做以下事情:

1. 改变AMFChannel的URL,使其指向别的server,别的端口,别的endpoint

2. 给ChannelSet添加更多的候选channel

3. 改变channel的类型,例如把AMFChannel改成RTMPChannel

4. 改变目标destination。

作为一种更简单的选择,我们可以象下面这样配置RemoteObject对象:

<?xml version=”1.0″ encoding=”utf-8″?>

<objects>

<object id=”remoteObject” class=”mx.rpc.remoting.mxml.RemoteObject” abstract=”true”>

<property name=”endpoint” value=”http://localhost:8400/lcds-samples/messagebroker/amf&#8221; />

<property name=”showBusyCursor” value=”true” />

</object>

<object id=”contactRemoteObject” parent=”remoteObject”>

<property name=”destination” value=”contacts” />

</object>

</objects>

注意,为了避免重复,你可以配置一个伪的抽象对象(本例中即”remoteObject”)

在应用程序中获取配置的对象

现在RemoteObject已经配置好了,那就在程序中开始使用他们吧

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*"
	initialize="applicationCompleteHandler()">

	<mx:Script>
		<![CDATA[
			import mx.rpc.AsyncResponder;
			import mx.controls.Alert;
			import mx.rpc.events.FaultEvent;
			import mx.rpc.events.ResultEvent;
			import mx.rpc.AsyncToken;
			import mx.rpc.remoting.mxml.RemoteObject;

			import org.springextensions.actionscript.context.support.FlexXMLApplicationContext;

			private var applicationContext:FlexXMLApplicationContext;

			private var remoteObject:RemoteObject;

			private function applicationCompleteHandler():void
			{
				applicationContext = new FlexXMLApplicationContext("applicationContext.xml");
				applicationContext.addEventListener(Event.COMPLETE, applicationContextLoaded);
				applicationContext.load();
			}

			private function applicationContextLoaded(event:Event):void
			{
				remoteObject = applicationContext.getObject("contactRemoteObject");
				var token:AsyncToken = remoteObject.getContacts();
				token.addResponder(new AsyncResponder(resultHandler, faultHandler, token));
			}

			private function resultHandler(event:ResultEvent, token:AsyncToken):void
			{
				dg.dataProvider = event.result;
			}

			private function faultHandler(event:FaultEvent, token:AsyncToken):void
			{
				Alert.show(event.fault.faultString);
			}

		]]>
	</mx:Script>

	<mx:DataGrid id="dg" width="100%" height="100%"/>

</mx:Application>

使用Spring AS框架的第一步就是创建一个新的ApplicationContext去加载配置文件。当加载完成时,就可以通过ApplicationContext对象的getObject方法得到你配置的对象,之后就是和普通程序一样的逻辑了。

下一步

在这第一个例子里,我们看到了Spring ActionScript框架是怎样在外部通过配置文件来配置和分配对象的,也看到了怎样通过ApplicationContext对象的getObject方法来得到配置的对象。

接下来的第二步,我们将讨论怎样在view中以非紧耦合的方式得到这些配置好的对象,而非让这些对象通过层层的视图组件来传递。

Part 2 自动封装(AutoWiring)

在第一部分中我们介绍了“Spring AS”框架怎样帮助我们在外部配置和封装组件,并通过applicationContext.getObject方法来使用这些配置好的对象。

在第二部分里,我们将要讨论怎样让view以非紧耦合的方式使用这些对象,并且不用通过多层级的引用传递来传递这些对象的引用。

现在我们来创建基于“Spring AS”框架的”InSync contact management“程序。该程序包含2个view:Mainview和ContactForm。它们都需要使用RemoteObject对象的引用。

注意:.这个例子有意的保持了简单。在更为细分的应用中,你也许只想提供一个更抽象的控制器而不是某个特定的RemoteObject。关于这点将在第三部分介绍。

视图可以使用applicationContext.getObject()来访问它们所需要的依赖物(本例中指RemoteObject对象),但这种方式有一些问题:

因为依赖于applicationContext, view可能会和框架紧耦合在一起,但我们仍然需要将applicationContext对象的引用传给views,当然这种问题通常都是通过使用单例模式来解决的。更好的办法是使用注入方式将依赖关系注入到views中,而不是实例化视图让视图自己查找依赖关系。

与Swiz不同的是,“Spring AS”目前不支持内建的[Autowire]注释,但Christophe Herreman(SPRING ACTIONSCRIPT框架的创始人)曾今暗示该特性将来可能会出现,与此同时他还提供了一些简单的例子来说明“Spring ActionScript”框架的自动封装特性。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	applicationComplete="applicationCompleteHandler()">

	<mx:Script>
	<![CDATA[

	import insync.views.MainView;
	import mx.utils.DescribeTypeCacheRecord;
	import mx.utils.DescribeTypeCache;
	import as3reflect.ClassUtils;
	import org.springextensions.actionscript.context.support.FlexXMLApplicationContext;

	private var applicationContext:FlexXMLApplicationContext;

	private function applicationCompleteHandler():void
	{
		applicationContext = new FlexXMLApplicationContext("applicationContext.xml");
		applicationContext.addEventListener(Event.COMPLETE, applicationContextComplete);
		applicationContext.load();
	}

	private function applicationContextComplete(event:Event):void
	{
		systemManager.addEventListener(Event.ADDED, addedEventHandler);
		var mainView:MainView = new MainView();
		addChild(mainView);
	}

	private function addedEventHandler(event:Event):void 
	{
		var autowiredObject:Object = event.target;
		trace("Added to display list: " + autowiredObject);
		var typeInfo:DescribeTypeCacheRecord = DescribeTypeCache.describeType(autowiredObject);
		for each (var metaDataNode:XML in typeInfo.typeDescription..metadata) 
		{
			if (metaDataNode.attribute("name") == "Autowired") 
			{
				var propertyNode:XML = metaDataNode.parent();
				var property:String = propertyNode.@name.toString();
				trace("Found Autowired property: " + property);
				var objectName:String = property;
				var autowireByType:Boolean = true;

				for each (var arg:XML in metaDataNode.arg) 
				{
					if (arg.attribute("value") == "byName") 
					{ 
						autowireByType = false;
					}
				}

				if (autowireByType) 
				{
					var clazz:Class = ClassUtils.forName(propertyNode.@type.toString());
					var objectNames:Array = applicationContext.getObjectNamesForType(clazz);
					if (objectNames.length == 1) 
					{
						objectName = objectNames[0];
					}
				}
				trace("Autowiring: " + property + " in " + autowiredObject);
				autowiredObject[property] = applicationContext.getObject(objectName);
			}
		}
	}

	]]>
	</mx:Script>

	<mx:Style source="styles.css"/>

</mx:Application>

为了能够通过Autowired注释达到注入属性的目标,我们给systemManager的ADDED事件添加一监听器, 在监听器中我们通过AS的内省机制来分析每个添加到显示列表的对象,如果对象含有[Autowired]属性,这些就会被注入相关的值。这种方式也是Swiz采用的方式。

时机

在注入对象到view之前,你必须确定applicationContext.xml文件被加载完成并且文件中定义的对象已经被实例化。applicationContext 在它准备好之后派发Event.COMPLETE事件,为了确保程序能正确的被注入属性,我一般都会在Event.COMPLETE事件的处理器中实例化MainView。

视图

如果上面的基础已经ok,InSync程序的视图就很容易编写了。

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">

	<mx:Script>
		<![CDATA[

			import mx.rpc.remoting.mxml.RemoteObject;

			[Autowired]			
			public var contactRemoteObject:RemoteObject;

		]]>
	</mx:Script>

</mx:Canvas>

安装指南

注意,如果你已经安装了Swiz版本的InSync, 你可以直接跳过第1,3,4,5,6步。

1. 安装BlazeDS turnkey server.(澄清一下,你不用非得使用BlazeDS,只不过本例使用的是BlazeDS)

2. 下载insyncspringas.zip文件并解压缩.

3. 将insyncspringas/java/classes/insync目录拷贝到blazeds/tomcat/webapps/samples/WEB-INF/classes/insync目录

4. 向blazeds/tomcat/webapps/samples/WEB-INF/flex/remoting-config.xml文件添加一下代码:

<destination id=“contacts”>

        <properties>
            <source>insync.dao.ContactDAO</source>
            <scope>application</scope>
        </properties>
</destination>

5. 将insyncspringas/sampledb/insync目录拷贝到blazeds/sampledb/insync目录

6. 编辑blazeds/sampledb的server属性文件:

server.database.0=file:flexdemodb/flexdemodb

server.dbname.0=flexdemodb
server.database.1=file:insync/insync
server.dbname.1=insync
server.port=9002
server.silent=true
server.trace=false

7. 启动数据库(startdb.bat或startdb.sh)

8. 启动BlazeDS

9. 在Flex Builder中创建名为insyncspringas的工程(不用指定Application server type)

10. 将insyncspringas/flex/lib目录下的spring-actionscript.swc和as3reflect.swc拷贝到insyncspringas工程的lib目录下

11. 将insyncspringas/flex/src目录下的文件拷贝到insyncspringas工程的src下

12. 打开applicationContext.xml,确保remoteObject的endpoint属性与server的配置一致

13. 运行程序

自动封装及性能表现的注意事项

基于注释的依赖注入很简洁也很方便,但是我们需要使用describeType来操作每个显示对象,这样就会对性能有影响。也许Flex框架将来会改进这一点。比如我们可以在类实例时为每个Autowired属性派发AutowireEvent 事件,然后把它留给框架去实现,这样框架就只需要监听这些事件而不是对每个显示列表对象都进行内省。(An alternative would be to have a compiler hook to allow annotation-based code injection at compile time.有点不太明白)

同时,你必须确定当前的方案对程序性能的影响是否可以接受,如果否,有些方法可以改进:

1.使用Swiz, Aral Balkan在需要使用自动分配对象的视图中使用autowired属性,代码中,使用describType方法之前先用hasOwnproperty(“autowiring”)方法来来判断对象是否需要自动分配。但该方法在某种程度上还是需要对每个显示对象进行内省分析。

2. Swiz 现在不会对mx 包下对象使用describType方法进行分析。我们可以考虑此方法。

3.还有一种方式是,在类初始化时为需要自动分配对象的视图派发AutowiredEvent事件。这也许比上简单的注释方便,但至少不会产生负面的性能影响,并且此方法能让非显示对象也能使用自动分配的对象。

Part 3 注入service

在第一部分里,我们介绍了怎样利用SPRING ACTIONSCRIPT框架在程序外部设置程序的属性以及分配对象。在第二部份里,我们讨论了怎样对视图的属性自动装配。为了保持简单,我们直接将contact RemoteObject注入到了视图中。但一般在真实的场景下,人们不是想让视图和service的实现过程紧耦合在一起的。视图应该和数据访问策略(RemoteObject,HTTPService, WebService, mock service等)处于独立的关系。

为了满足上述需求, 我们将创建一个IContactService接口,以及2个实现该接口的类。
ContactRemoteObjectService   使用RemoteObject访问数据。
ContactMockService  在没有后台数据时,封装模拟数据用于测试
IContactService 定义如下:

package insync.services
{
import insync.model.Contact;
import mx.rpc.AsyncToken;

public interface IContactService
{
	function getContactsByName(name:String):AsyncToken;

	function save(contact:Contact):AsyncToken;

	function remove(contact:Contact):AsyncToken;
}
}

ContactRemoteObjectService的实现:

package insync.services
{
import insync.model.Contact;

import mx.controls.Alert;
import mx.rpc.AsyncResponder;
import mx.rpc.AsyncToken;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.mxml.RemoteObject;

public class ContactRemoteObjectService implements IContactService
{
	private var remoteObject:RemoteObject;

	public function ContactRemoteObjectService(remoteObject:RemoteObject)
	{
    		this.remoteObject = remoteObject;
	}

	public function save(contact:Contact):AsyncToken
	{
		var token:AsyncToken = remoteObject.save(contact);
		token.contact = contact;
        	token.addResponder(new AsyncResponder(save_result, faultHandler));
        	return token;
	}

	public function remove(contact:Contact):AsyncToken
	{
		var token:AsyncToken = remoteObject.remove(contact);
	        token.addResponder(new AsyncResponder(remove_result, faultHandler));
        	return token;
	}

	public function getContactsByName(name:String):AsyncToken
	{
		var token:AsyncToken = remoteObject.getContactsByName(name);
	        token.addResponder(new AsyncResponder(getContactsByName_result, faultHandler));
        	return token;
	}

	/* Result Handlers ---------------------------------------------------------------*/

	private function save_result(event:ResultEvent, token:AsyncToken=null):void
	{
		// For a create operation, assign the generated primary key to the id property 
		// of the contact object
		event.token.contact.id = event.result.id;

		// Dispatch an event on the async token. This allows the caller of the method to register as
		// a listener for the result event of the specific method call. (See ContactForm.mxml for an example.
		event.token.dispatchEvent(event);
	}		

	private function remove_result(event:ResultEvent, token:AsyncToken=null):void
	{
		event.token.dispatchEvent(event);
	}		

	private function getContactsByName_result(event:ResultEvent, token:AsyncToken=null):void
	{
		event.token.dispatchEvent(event);
    	}		

	private function faultHandler(event:FaultEvent, token:AsyncToken=null):void
    	{
    		Alert.show(event.fault.faultString + "\n" + event.fault.faultDetail, "Error Invoking RemoteObject");
    	}

}
}

Note:ContactRemoteObjectService类除了remoteObject属性是通过Spring AS框架注入的以外,其他代码跟普通的类没什么分别。实现过程和Flex framework特别是rpc API部分紧耦合在一起,我们也可以自己写这部分的实现。Spring AS还提供了抽象API用于引用异步方法,而且不是跟Flex framework耦合的(参考AbstractRemoteObjectService类)。Spring AS的目标是作为AS框架而非Flex框架被开发者使用。

ContactMockService 的实现:

package insync.services
{
import insync.model.Contact;
import mx.collections.ArrayCollection;
import mx.rpc.AsyncResponder;
import mx.rpc.AsyncToken;
import mx.rpc.events.ResultEvent;

public class ContactMockService extends MockService implements IContactService
{
	private var contacts:ArrayCollection = new ArrayCollection();

	private var nextId:int;

	public function ContactMockService()
	{
		var contact:Contact = new Contact();
		contact.id = 1;
		contact.firstName = "Christophe";
		contact.lastName = "Coenraets";
		contacts.addItem(contact);

		contact = new Contact();
		contact.id = 2;
		contact.firstName = "Lisa";
		contact.lastName = "Taylor";
		contacts.addItem(contact);

		contact = new Contact();
		contact.id = 3;
		contact.firstName = "John";
		contact.lastName = "Smith";
		contacts.addItem(contact);

		nextId = 4;
	}

	public function save(contact:Contact):AsyncToken
	{
		if (contact.id == 0) // New contact
		{
			contact.id = nextId++;
			contacts.addItem(contact);
		}
		var token:AsyncToken = createToken(contact);
        	token.addResponder(new AsyncResponder(resultHandler, null));
        	return token;
	}

	public function remove(contact:Contact):AsyncToken
	{
		var result:ArrayCollection = new ArrayCollection();
		for (var i:int=0; i<contacts.length; i++)
		{
			var current:Contact = contacts.getItemAt(i) as Contact;
			if (current.id == contact.id)
			{
				contacts.removeItemAt(i);
				break;
			}
		}
		var token:AsyncToken = createToken(contacts);
	        token.addResponder(new AsyncResponder(resultHandler, null));
        	return token;
	}

	public function getContactsByName(name:String):AsyncToken
	{
		var result:ArrayCollection = new ArrayCollection();
		for (var i:int=0; i<contacts.length; i++)
		{
			var contact:Contact = contacts.getItemAt(i) as Contact;
			if (contact.fullName.indexOf(name)>=0)
			{
				result.addItem(contact);
			}
		}

		var token:AsyncToken = createToken(result);
	        token.addResponder(new AsyncResponder(resultHandler, null));
        	return token;
	}

	private function resultHandler(event:ResultEvent, token:AsyncToken = null):void
	{
		event.token.dispatchEvent(event);
	}

}
}

为了保持视图和service的独立性,我们给视图定义了接口类型的属性(IContactService).依靠Spring AS application context,指定的service实现类会被注入到视图中。如下:
ContactForm的定义

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:controls="insync.controls.*"
	width="100%" height="100%"
	label="{contact.id>0?contact.fullName:'New Contact'}">

	<mx:Script>
	<![CDATA[

	import mx.rpc.events.ResultEvent;
	import insync.events.ContactEvent;
	import insync.services.IContactService;
	import insync.model.Contact;

	[Autowired]			
	public var contactService:IContactService;

	[Bindable] 
	public var contact:Contact;

	private function save():void
	{
		contact.firstName = firstName.text;
		contact.lastName = lastName.text;
		contact.email = email.text;
		contact.phone = phone.text;
		contact.address = address.text;
		contact.city = city.text;
		contact.state = state.text;
		contact.zip = zip.text;
		contact.pic = picture.source;

		contactService.save(contact).addEventListener(ResultEvent.RESULT,
			function(event:ResultEvent):void
			{
				// Display a status message. Added here to provide an example where
				// a specific contact view needs to be notified of the success or failure
				// of a service operation. 
				status.text = "Contact saved successfully";
				setTimeout(function():void{status.text=""}, 1500);						
			});
	}

	private function remove():void
	{
		contactService.remove(contact);
	}

	]]>
	</mx:Script>

	<mx:Form>
		<mx:FormItem label="Id">
			<mx:TextInput text="{contact.id}" enabled="false"/>
		</mx:FormItem>
		<mx:FormItem label="First Name">
			<mx:TextInput id="firstName" text="{contact.firstName}"/>
		</mx:FormItem>
		<mx:FormItem label="Last Name">
			<mx:TextInput id="lastName" text="{contact.lastName}"/>
		</mx:FormItem>
		<mx:FormItem label="Email">
			<mx:TextInput id="email" text="{contact.email}"/>
		</mx:FormItem>
		<mx:FormItem label="Phone">
			<mx:TextInput id="phone" text="{contact.phone}"/>
		</mx:FormItem>
		<mx:FormItem label="Address">
			<mx:TextInput id="address" text="{contact.address}"/>
		</mx:FormItem>
		<mx:FormItem label="City">
			<mx:TextInput id="city" text="{contact.city}"/>
		</mx:FormItem>
		<mx:FormItem label="State">
			<mx:TextInput id="state" text="{contact.state}"/>
		</mx:FormItem>
		<mx:FormItem label="Zip">
			<mx:TextInput id="zip" text="{contact.zip}"/>
		</mx:FormItem>
	</mx:Form>

	<controls:PictureInput id="picture" top="14" left="350" styleName="pictureFrame"
		pictureWidth="160" pictureHeight="160"
		source="{contact.pic}" />

	<mx:Label id="status" left="8" bottom="50"/>
	<mx:HBox left="8" bottom="8">
		<mx:Button label="Save" click="save()"/>
		<mx:Button label="Delete" click="remove()"/>
	</mx:HBox>

</mx:Canvas>

InSync允许人们打开多个视图,所以要让每个视图知道它的某个操作是否成功。在本例中,我们会在save操作成功了显示成功的状态消息。

如果你想使用Mock的service,applicationContext.xml的定义如下:

<?xml version="1.0" encoding="utf-8"?>
<objects>

	<object id="contactService" class="insync.services.ContactMockService" 

</objects>

如果你想使用RemoteObjectService,只需要象下面一样修改applicationContext.xml文件,不用修改程序的任何部分,也不需要重新编译。

<?xml version="1.0" encoding="utf-8"?>
<objects>

	<object id="remoteObject" class="mx.rpc.remoting.mxml.RemoteObject"	abstract="true">
		<property name="endpoint" value="http://localhost:8400/lcds-samples/messagebroker/amf" />
		<property name="showBusyCursor" value="true" />
	</object>

	<object id="contactRemoteObject" parent="remoteObject">
		<property name="destination" value="contacts" />
	</object>

	<object id="contactService" class="insync.services.ContactRemoteObjectService">
	    <constructor-arg>
	        <object id="myContactRemoteObject" parent="remoteObject">
	            <property name="destination" value="contacts" />
	        </object>
	    </constructor-arg>
	</object>

</objects>

在本版程序中,我们达到了一个重要的目的:使视图和Service实现松耦合。Spring AS框架的设计初衷就是要实现Service层与其他层的松耦合。
除此之外,你可以按照自己或团队的需求自由的实现该设计模式。比如你可以设计让你的视图不持有service或controller的引用(即使它们是接口类型)。
使用Mock service的额外好处就是你可以自己配置自己的程序,并让它运行起来,而不用担心数据库的问题(因为根本就没有数据库)。

点击此处参看程序。

安装指南
如果你已经按照第二部份的指导安装了程序,直接跳过1,3,4,5,6步。
1. 安装BlazeDS turnkey server. (http://opensource.adobe.com/blazeds)
2. 下载insyncspringas3.zip并解压缩。(http://coenraets.org/apps/insyncspringas3/srcview/springaspart3.zip)
3. 拷贝insyncspringas3/java/classes/insync目录到blazeds/tomcat/webapps/samples/WEB-INF/classes/insync下
4. 修改blazeds/tomcat/webapps/samples/WEB-INF/flex/remoting-config.xml:

<destination id="contacts">
        <properties>
            <source>insync.dao.ContactDAO</source>
            <scope>application</scope>
        </properties>
</destination>

5. 拷贝insyncspringas3/sampledb/insync目录到blazeds/sampledb/insync下
6. 修改blazeds/sampled目录下server.properties文件:

server.database.0=file:flexdemodb/flexdemodb
server.dbname.0=flexdemodb
server.database.1=file:insync/insync
server.dbname.1=insync
server.port=9002
server.silent=true
server.trace=false

7. 启动数据库
8. 启动BlazeDS
9. 在FB中新建名为insyncspringas3的工程,不必指定Application server type
10. 拷贝spring-actionscript.swc和as3reflect.swc到工程lib目录下
11. 拷贝insyncspringas3/flex/src目录到工程的src目录下
12. 查看applicationContext.xml,确认remoteObject的endpoint与你本机的服务器设置一致
13. 运行程序

翻译Adobe Livedoc之Using Flex Ant Tasks

Using the mxmlc task

你可以使用mxmlc任务来编译Flex的应用程序(Application), 各种模块(modules),以及样式表(CSS).  mxmlc任务支持Flex命令mxmlc的多数编译参数,包括aliases. 参考Using mxmlc, the application compiler获取更多关于使用mxmlc命令的信息。

Required attributes

mxmlc任务需要一个指定了要编译MXMl文件的file属性。在命令行模式下mxmlc命令并没有和mxmlc任务的file属性等效的参数,因为命令行下要编译的的文件是默认参数。(例如:cmd模式,mxmlc c:/myfiles/app.mxml;或是mxmlc -option arg1 arg2 arg3 –target_file.mxml)

Unsupported options

mxmlc任务不支持help和version编译参数:

Example

在下面的例子中mxmlc任务显式地定义了source-path和library-path参数,并且也添加了incremental和keep-generated-actionscript参数。该例还指定了输出目录output。例中定义了main和clean俩个任务,main任务用于将Main.mxml文件编译成swf文件,clean用于删除之前输出目录。

<?xml version="1.0" encoding="utf-8"?>
<!-- myMXMLCBuild.xml -->
<project name="My App Builder" basedir=".">
    <taskdef resource="flexTasks.tasks" classpath="${basedir}/flexTasks/lib/flexTasks.jar" />
    <property name="FLEX_HOME" value="C:/flex/sdk"/>
    <property name="APP_ROOT" value="apps"/>
    <property name="DEPLOY_DIR" value="c:/jrun4/servers/default/default-war"/>
    <target name="main">
        <mxmlc
            file="${APP_ROOT}/Main.mxml"
            output="${DEPLOY_DIR}/Main.swf"
            actionscript-file-encoding="UTF-8"
            keep-generated-actionscript="true"
            incremental="true"
        >
            <!-- Get default compiler options. -->
            <load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/>

            <!-- List of path elements that form the roots of ActionScript
            class hierarchies. -->
            <source-path path-element="${FLEX_HOME}/frameworks"/>

            <!-- List of SWC files or directories that contain SWC files. -->
            <compiler.library-path dir="${FLEX_HOME}/frameworks" append="true">
                <include name="libs" />
                <include name="../bundles/{locale}" />
            </compiler.library-path>

            <!-- Set size of output SWF file. -->
            <default-size width="500" height="600" />
        </mxmlc>
    </target>
    <target name="clean">
        <delete dir="${APP_ROOT}/generated"/>
        <delete>
            <fileset dir="${DEPLOY_DIR}" includes="Main.swf"/>
        </delete>
    </target>
</project>

Using the compc task

我们可以使用compc任务将组件编译成swc文件。compc支持Flex命令compc的多数编译参数,包括aliases. 参考Using compc,the component compiler获取更多关于使用mxmlc命令的信息。

Required attributes

compc任务的唯一一个必要属性就是output属性,output指定了编译生成的swc文件的名称。

Special attributes

include-classes属性可以用一系列的以空格分开的类名作为参数值。例如

<compc include-classes="custom.MyPanel custom.MyButton" ... >
    ...
</compc>

include-resource-bundles属性,我们不能给该属性的某一个入口指定一系列以逗号或空格分开的值作为参数。相反,我们需要为每个所需引入的resource bundle单独嵌套一个include-resource-bundles标签。

<compc output="${swf.output}/compc_rb.swc" locale="en_US">
    <include-resource-bundles bundle="ErrorLog"/>
    <include-resource-bundles bundle="LabelResource"/>
    <sp path-element="locale/{locale}" />
</compc>

Unsupported options

compc任务不支持help和version参数。

Example

下面的例子中compc任务将编译生成swc文件,其中包括2个自定义组件以及一些资源文件。组件是通过include-classes属性来添加的,源文件在components子目录中。资源文件,包括4个图片和一个css文件通过include-file元素添加到swc中。例中定义了main和 clean俩个targets,main用于编译生成MyComps.swc文件, 而clean用于删除main任务所输出的文件。

<?xml version="1.0" encoding="utf-8"?>
<project name="My Component Builder" basedir=".">
    <taskdef resource="flexTasks.tasks" classpath="${basedir}/flexTasks/lib/flexTasks.jar" />
    <property name="FLEX_HOME" value="C:/flex/sdk"/>
    <property name="DEPLOY_DIR" value="c:/jrun4/servers/default/default-war"/>
    <property name="COMPONENT_ROOT" value="components"/>
    <target name="main">
        <compc
            output="${DEPLOY_DIR}/MyComps.swc"
            include-classes="custom.MyButton custom.MyLabel">
            <source-path path-element="${basedir}/components"/>
            <include-file name="f1-1.jpg" path="assets/images/f1-1.jpg"/>
            <include-file name="f1-2.jpg" path="assets/images/f1-2.jpg"/>
            <include-file name="f1-3.jpg" path="assets/images/f1-3.jpg"/>
            <include-file name="f1-4.jpg" path="assets/images/f1-4.jpg"/>
            <include-file name="main.css" path="assets/css/main.css"/>
        </compc>
    </target>
    <target name="clean">
        <delete>
            <fileset dir="${DEPLOY_DIR}" includes="MyComps.swc"/>
        </delete>
    </target>
</project>

Using the html-wrapper task

html-wrapper任务生成我们部署Flex applications所需的文件。HTML wrapper由<object>和<embed>标签组成,<object>和<embed>标签会把swf文件嵌在HTML页面中。

html-wrapper任务生成index.html和AC_OETags.js文件。如果你允许linking support,则html-wrapper任务还会输出deep linking文件, 如historyFrame.html, history.css和history.js等;如果你允许express installation,则html-wrapper任务会生成playerProductInsta.swf文件。

一般来说,我们需要把上述文件和Flex程序一起部署到web服务器上。用户请求的就是嵌入了swf文件的HTML wrapper。我们也可以在Ant编译之后自定义这些支持文件。参考Creating a Wrapper获取更多HTML wrapper的信息。

About the templates

使用html-wrapper任务我们可以生成6种类型的HTML wrapper模板。

1. Client-side detection only — 提供探测客户端player版本的脚本,在版本过低时返回可以更换的内容。

2. Client-side detection with history — 除了Client-side detection之外,还添加了deep linking suppor。

3. Express installation — 提供支持Express Install功能的脚本。

4. Express installation with history — 提供支持Express Install和deep linking的脚本。

5. No player detection — 提供最基本的wrapper。

6. No player detection with history — 提供仅支持deep linking的wrapper

Supported attributes

html-wrapper任务的属性与<object>和<embed>标签的某些属性类似,另外它还支持output和templenate属性,其中output用于指定输出目录,template用于指定wrapper的类型。参考About the object and embed tags, 获取<object>和<embed>标签属性的完整列表。

下表描述了html-wrapper任务所支持的属性

参考 http://livedocs.adobe.com/flex/3/html/help.html?content=anttasks_1.html

Required attributes

html-wrapper任务需要指定swf属性. 另外如果你只指定了swf属性, 默认的wrapper会有以下默认的设置:

height="400"
width="400"
template="express-installation"
bgcolor="white"
history="false"
title="Flex Application"

注意要使用包含扩展名的文件名来给swf属性赋值,html-wrapper会自动在swf属性值的后面添加.swf后缀。例如

swf="Main"

不要使用

swf="Main.swf"

Unsupported options

html-wrapper任务并不能设置<object>和<embed>标签的所有参数,这其中不支持的参数包括quality, allowScriptAccess, classid, pluginspage和type等.

Example

下面的例子包括wrapper和clean俩个targets, wrapper 生成支持deep linking和player detection的HTML wrapper,clean用于删除wrapper生成的所有文件。

<?xml version="1.0" encoding="utf-8"?>
<!-- myWrapperBuild.xml -->
<project name="My Wrapper Builder" basedir=".">
    <taskdef resource="flexTasks.tasks" classpath="${basedir}/lib/flexTasks.jar"/>
    <property name="FLEX_HOME" value="C:/flex3/sdk"/>
    <property name="APP_ROOT" value="apps"/>
    <target name="wrapper">
        <html-wrapper
            title="Welcome to My Flex App"
            file="index.html"
            height="300"
            width="400"
            bgcolor="red"
            application="app"
            swf="Main"
            version-major="9"
            version-minor="0"
            version-revision="0"
            history="true"
            template="express-installation"
            output="${APP_ROOT}"/>
    </target>
    <target name="clean">
        <delete>
            <!-- Deletes playerProductInstall.swf -->
            <fileset dir="${APP_ROOT}"
                includes="playerProductInstall.swf"
                defaultexcludes="false"/>
            <!-- Deletes index.html and historyFrame.html -->
            <fileset dir="${APP_ROOT}" includes="*.html" defaultexcludes="false"/>
            <!-- Deletes history.css -->
            <fileset dir="${APP_ROOT}" includes="*.css" defaultexcludes="false"/>
            <!-- Deletes history.js and AC_OETags.js -->
            <fileset dir="${APP_ROOT}" includes="*.js" defaultexcludes="false"/>
        </delete>
    </target>
</project>


Flex And Java

First Blog

I am coming ,wordpress