IntroduçãoDesde de a chegada do ColdFusion MX 7, venho publicando exemplos que utilizam Flash Remoting, mas aqui vamos detalhar a utilização desta tecnologia em aplicações construídas com a TAG CFFORM com o farmato flash, e o desenvolvimento do ActionScript nesta aplicação.. Pré-requisito- ColdFusion MX 7.0.2 ConceitosO conceito de Flash Remoting é muito confundido ao conceito de RIA, com uma simples diferença o Flash Remoting, é um mensageiro, é um dos elementos que permitem as aplicações RIA realizarem comunicações/requests sem reload de pagina, assim como wsdl, ajax e similares. ConteúdoComponente Remoto Usuario.cfc <cfcomponent name="Usuario" alias="labs.remoting.Usuario">
<cffunction name="validate" access="private" output="false" returntype="struct">
<cfargument name="dados" type="struct" required="true" />
<cfargument name="type" type="string" required="true" />
<cfset var user = StructNew() />
<cfset var colunas = ListToArray("nome,email,username") />
<cfset var isRequerida = ListToArray("false,true,true") />
<cfset var i = 0 />
<cfset user.destino = ArrayNew(1) />
<cfset user.value = ArrayNew(1) />
<cfset user.valid = false />
<cfloop from="1" to="#ArrayLen(colunas)#" index="i">
<cfif StructKeyExists(arguments.dados,colunas[i]) and Len(Trim(arguments.dados[colunas[i]])) >
<cfif arguments.type eq "update">
<cfset ArrayAppend(user.value,"#colunas[i]# = '#Trim(arguments.dados[colunas[i]])#'") />
<cfelse>
<cfset ArrayAppend(user.destino,colunas[i]) />
<cfset ArrayAppend(user.value,"'#Trim(arguments.dados[colunas[i]])#'") />
</cfif>
<cfset user.valid = true />
<cfelseif isRequerida[i] >
<cfset user.valid = false />
<cfreturn user />
</cfif>
</cfloop>
<cfreturn user />
</cffunction>
<cffunction name="append" access="remote" output="false" returntype="numeric">
<cfargument name="dados" type="struct" required="true" />
<cfset var user = validate(arguments.dados,"add") />
<cfset var query = "" />
<cfif user.valid >
<cfset query = search(arguments.dados.username) />
<cfif query.recordcount>
<cfreturn 0 />
</cfif>
<cfquery datasource="mxstudio_mysql">
insert into usuarios (#ArrayToList(user.destino)#) values (#ArrayToList(user.value)#)
</cfquery>
<cfset query = search(arguments.dados.username) />
<cfif query.recordcount>
<cfreturn query.userid />
</cfif>
</cfif>
<cfreturn -1 />
</cffunction>
<cffunction name="update" access="remote" output="false" returntype="numeric">
<cfargument name="dados" type="struct" required="true" />
<cfargument name="id" type="numeric" required="true" />
<cfset var user = validate(arguments.dados,"update") />
<cfset var query = "" />
<cfif user.valid >
<cfquery name="query" datasource="mxstudio_mysql">
select * from usuarios
where userid <> #arguments.id#
and username = '#arguments.dados.username#'
</cfquery>
<cfif query.recordcount>
<cfreturn 0 />
</cfif>
<cfquery datasource="mxstudio_mysql">
update usuarios set
#ArrayToList(user.value)#
where userid = #arguments.id#
</cfquery>
<cfreturn 1 />
</cfif>
<cfreturn -1 />
</cffunction>
<cffunction name="remove" access="remote" output="false" returntype="boolean">
<cfargument name="id" type="string" required="true" />
<cfset var soma = 0 />
<cftry>
<cfset soma = ArraySum(ListToArray(arguments.id)) />
<cfcatch type="expression">
<cfreturn false/>
</cfcatch>
</cftry>
<cfquery datasource="mxstudio_mysql">
delete from usuarios
where userid in (#arguments.id#)
</cfquery>
<cfreturn true/>
</cffunction>
<cffunction name="get" access="remote" output="false" returntype="query">
<cfset var query = "" />
<cfquery name="query" datasource="mxstudio_mysql">
select userid as data, nome as label, usuarios.* from usuarios
</cfquery>
<cfreturn query />
</cffunction>
<cffunction name="search" access="remote" output="false" returntype="query">
<cfargument name="str" type="any" required="true" />
<cfset var query = "" />
<cfquery name="query" datasource="mxstudio_mysql">
select userid as data, nome as label, usuarios.* from usuarios
where
<cfif IsNumeric(arguments.str)>
userid = #arguments.str#
<cfelse>
username like '%#arguments.str#%'
or nome like '%#arguments.str#%'
or email like '%#arguments.str#%'
</cfif>
</cfquery>
<cfreturn query />
</cffunction>
</cfcomponent>
Banco de dados Usuario.sql create table usuarios (
userid int(10) unsigned NOT NULL auto_increment,
username varchar(100) default NULL,
nome varchar(255) default NULL,
email varchar(255) default NULL,
primary key (userid)
) engine=InnoDB default charset=utf8;
insert into usuarios values ('','zezinho','Jose','zezinho@mail.com');
insert into usuarios values ('','cabeça','Andre','andre@mail.com');
insert into usuarios values ('','cachaça','Walter','cachaca@mail.com');
A parte CFML já está a disposição para acesso por Flash Remoting, dependendo da construção do proxy ActionScript na aplicação flash cliente. Para construir o proxy no Flash é preciso fazer o include de uma classe, isso na primeira versão de Flash MX, e nas verões posteriores através de import, como pode ser encontrado com facilidade em qualquer buscador. Essa mesma construção em uma aplicação CFFORM Flash muda completamente, pois a época do desenvolvimento do ColdFusion MX 7, o ActionScript no qual foi baseado sofria grandes alterações, e também devido as restrições que este ActionScript recebeu quando inserido como features no ColdFusion, assunto que já foi visto http://www.mxstudio.com.br/views.tutorial.php?act=view&cid=7&aid=733. O include ActionScript é permitido no CFFORM, porém desnecessário na construção de um proxy Flash Remoting nele, já que podemos realizar chamadas diretas as classes que estão no servidor. Os exemplos foram construídos sem qualquer elemento cfform, a não ser o proprio cfform, que carrega proxy e executa o serviço. 1.cfm
<!--- o no evento onload do cfform invoco a inicialização do Remoting --->
<cfform name="basic" format="flash" onload="initRemoting();">
<cfformitem type="script">
function initRemoting(){
/*
A classe mx.remoting.NetServices através do método
createGatewayConnection construímos o a ligação
cliente/servidor
*/
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection("http://localhost/cfusion/flashservices/gateway/");
// objeto receberá ações para o serviço
var serviceEvent:Object = {};
// toda ação de um invoke ok, estaré em onResult
serviceEvent.onResult = function(result):Void{
alert('Resposta do servidor','result');
};
// caminho para o componente
var servicePath:String = "labs.remoting.Usuario";
// conecta o cliente ao serviço
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
// invoca serviço
service.get();
}
</cfformitem>
</cfform>
Quando disse que o objeto receberá “ações” para o serviço, não está errado, isto porque o serviço pode responder a dois eventos, que são onResult e onStatus, este segundo só será executado caso ocorra uma anomalia na conexão com o serviço ou na execução dele. Separei alguns exemplos disto para observarmos. Nesta primeira observação um exemplo sem erros, apenas para verificar quais as propriedades do evento receberemos do servidor, reparem na função onStatus. 2_1.cfm
<cfform name="basic" format="flash" onload="initRemoting();">
<cfformitem type="script">
function initRemoting(){
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection("http://localhost/cfusion/flashservices/gateway/");
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
alert('Resposta do servidor','result');
};
serviceEvent.onStatus = function(info:Object):Void{
/*
info.code - corrente SERVER.PROCESSING
info.type - nome da classe envolvida no erro
info.details - informa onde ocorreu o erro
info.level - tipo do status, no remoting sempre erro
info.description - mensagem de erro do servidor
*/
alert(info.description,info.level);
};
var servicePath:String = "labs.remoting.Usuario";
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
service.get();
}
</cfformitem>
</cfform>
Agora sim, a série de erros provocados, neste tentarei conectar o cliente a um serviço que não existe. 2_2.cfm
<cfform name="basic" format="flash" onload="initRemoting();">
<cfformitem type="script">
function initRemoting(){
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection("http://localhost/cfusion/flashservices/gateway/");
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
alert('Resposta do servidor','result');
};
serviceEvent.onStatus = function(info:Object):Void{
alert(info.description,info.level);
};
// aqui o erro provocado
var servicePath:String = "labs.remoting.ERRO";
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
service.get();
}
</cfformitem>
</cfform>
Uma tentativa de conexão, onde o caminho do serviço não é um componente, neste exemplo em particular o caminho informado é uma pasta, e o serviço não pede um cfc e sim um cfm, não me pergunte porque, mas o caminho deve ser um componente. 2_3.cfm
<cfform name="basic" format="flash" onload="initRemoting();">
<cfformitem type="script">
function initRemoting(){
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection("http://localhost/cfusion/flashservices/gateway/");
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
alert('Resposta do servidor','result');
};
serviceEvent.onStatus = function(info:Object):Void{
alert(info.description,info.level);
};
// aqui o erro provocado
var servicePath:String = "labs.remoting";
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
service.get();
}
</cfformitem>
</cfform>
Uma conexão sem caminho. 2_4.cfm
<cfform name="basic" format="flash" onload="initRemoting();">
<cfformitem type="script">
function initRemoting(){
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection("http://localhost/cfusion/flashservices/gateway/");
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
alert('Resposta do servidor','result');
};
serviceEvent.onStatus = function(info:Object):Void{
alert(info.description,info.level);
};
// aqui o erro provocado
var servicePath:String = "";
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
service.get();
}
</cfformitem>
</cfform>
A tentiva de execução de um serviço que não existe. 2_5.cfm
<cfform name="basic" format="flash" onload="initRemoting();">
<cfformitem type="script">
function initRemoting(){
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection("http://localhost/cfusion/flashservices/gateway/");
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
alert('Resposta do servidor','result');
};
serviceEvent.onStatus = function(info:Object):Void{
alert(info.description,info.level);
};
var servicePath:String = "labs.remoting.Usuario";
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
// aqui o erro provocado
service.ERRO();
}
</cfformitem>
</cfform>
A chamada de um serviço que necessita de parâmetro, mas não foi informado. 2_6.cfm
<cfform name="basic" format="flash" onload="initRemoting();">
<cfformitem type="script">
function initRemoting(){
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection("http://localhost/cfusion/flashservices/gateway/");
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
alert('Resposta do servidor','result');
};
serviceEvent.onStatus = function(info:Object):Void{
alert(info.description,info.level);
};
var servicePath:String = "labs.remoting.Usuario";
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
// aqui o erro provocado
service.search();
}
</cfformitem>
</cfform>
A execução de um serviço onde o parâmetro passado é diferente do requerido. 2_7.cfm
<cfform name="basic" format="flash" onload="initRemoting();">
<cfformitem type="script">
function initRemoting(){
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection("http://localhost/cfusion/flashservices/gateway/");
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
alert('Resposta do servidor','result');
};
serviceEvent.onStatus = function(info:Object):Void{
alert(info.description,info.level);
};
var servicePath:String = "labs.remoting.Usuario";
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
var param:Object = {};
// aqui o erro provocado
param.dados="";
service.append(param);
}
</cfformitem>
</cfform>
Prosseguindo, veremos agora a passagem de parâmetros ao serviço. O mais correto é informar os parâmetros dentro de um objeto. 3.cfm
<cfform name="basic" format="flash" onload="initRemoting();">
<cfformitem type="script">
function initRemoting(){
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection('');
connection.connect("http://localhost/cfusion/flashservices/gateway/");
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
alert('Resposta do servidor','result');
};
serviceEvent.onStatus = function(info:Object):Void{
alert(info.description,info.level);
};
var servicePath:String = "labs.remoting.Usuario";
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
//cria o objeto que receberá os parâmetros
var params:Object = {};
/*
adiciona o nome do parâmetro exatamente como está no serviço,
no atributo name da tag cfargument,
<cfargument name="str" ...>
*/
params.str = 'W';
service.search(params);
}
</cfformitem>
</cfform>
E por fim o tratamento do tipo de dado retornado pelo serviço na execução do onResult. Os tipos de dados comuns entre linguagens serão manipulados normalmente como estivesse na linguagem de origem, porém você deve estar atento ao case-sensitive do ActionScript, e por vezes alguns servidores passam ao cliente estruturas de dados (structs) e o ActionScript recebe este como Object, natural, mas em alguns casos suas keys estarão em caixa alta, e o tratamento deste objeto no cliente estaria esperando uma key em caixa baixa, atenção com isto ? já vi casos de desenvolvedor ficar um dia inteiro procurando o erro. 4.cfm
<cfform name="basic" format="flash" onload="initRemoting();">
<cfformitem type="script">
function initRemoting(){
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection('');
connection.connect("http://localhost/cfusion/flashservices/gateway/");
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
// _items é a propriedade onde estará a query retornada
var query:Array = result._items;
// identifico o recordcount da query retornada
var recordCount:Number = query.length;
var columnlist:String ="";
// cria um lista com os keys do primeiro registro
for(var i in query[0]){
columnlist+=i+",";
}
alert('RecordCount = '+recordCount,'result');
alert('ColumnList = '+columnlist,'result');
};
serviceEvent.onStatus = function(info:Object):Void{
alert(info.description,info.level);
};
var servicePath:String = "labs.remoting.Usuario";
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
service.get();
}
</cfformitem>
</cfform>
ConclusãoSeu conhecimento vai definir a variedade de operações index.cfm
<cfform name="form1" format="flash">
<cfformgroup type="panel" width="420">
<cfformgroup type="horizontal">
<cfinput type="text" name="qry" id="qry" >
<cfinput type="button" name="search" id="search" value="Pesquisar"
onclick="
var params:Object = {};
params.str = _root.qry.text;
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection('http://localhost/cfusion/flashservices/gateway/');
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
_root.listUsuarios.dataProvider = result._items;
_root.id.text = '';
_root.username.text = '';
_root.email.text = '';
_root.nome.text = '';
CFFormValidators.resetInValidFields();
};
var servicePath:String = 'labs.remoting.Usuario';
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
service.search(params);
"
>
</cfformgroup>
</cfformgroup>
<cfformgroup type="panel" width="420">
<cfgrid name="listUsuarios" width="400" rowheaders="false">
<cfgridcolumn name="nome" >
<cfgridcolumn name="username" >
<cfgridcolumn name="email" >
</cfgrid>
<cfformgroup type="horizontal">
<cfinput name="RefreshUsuarios" id="RefreshUsuarios" type="button" value="Refresh"
onclick="
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection('http://localhost/cfusion/flashservices/gateway/');
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
_root.listUsuarios.dataProvider = result._items;
_root.id.text = '';
_root.username.text = '';
_root.email.text = '';
_root.nome.text = '';
CFFormValidators.resetInValidFields();
};
var servicePath:String = 'labs.remoting.Usuario';
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
service.get();
"
>
<cfinput name="RemoveUsuarios" id="RemoveUsuarios" type="button" value="Remove"
onclick="
if(_root.listUsuarios.selectedItem != null){
var params:Object = {};
params.id = _root.listUsuarios.selectedItem.userid;
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection('http://localhost/cfusion/flashservices/gateway/');
var servicePath:String = 'labs.remoting.Usuario';
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
if(result){
var dt:Array = [];
for(var i =0; i < _root.listUsuarios.dataProvider.length;i++ ){
if(_root.listUsuarios.dataProvider[i].userid != params.id){
dt.push(_root.listUsuarios.dataProvider[i]);
}
}
_root.listUsuarios.dataProvider = dt;
_root.id.text = '';
_root.username.text = '';
_root.email.text = '';
_root.nome.text = '';
CFFormValidators.resetInValidFields();
alert('Ok','result');
}else{
alert('Erro','result');
}
};
serviceEvent.onStatus = function(info:Object):Void{
alert(info.description,info.level);
};
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
service.remove(params);
}else{
alert('Selecione um usuario','Erro');
}
"
>
</cfformgroup>
</cfformgroup>
<cfformgroup type="panel" width="420">
<cfinput type="text" id="id" name="id" label="ID" bind="{listUsuarios.selectedItem.userid}" enabled="false" validate="integer">
<cfinput type="text" id="username" name="username" label="username" bind="{listUsuarios.selectedItem.username}" validate="noblanks" required="true">
<cfinput type="text" id="nome" name="nome" label="nome" bind="{(listUsuarios.selectedItem.nome != null)?listUsuarios.selectedItem.nome:''}" validate="noblanks" required="false">
<cfinput type="text" id="email" name="email" label="email" bind="{listUsuarios.selectedItem.email}" validate="email" required="true" >
<cfinput name="saveUsuarios" id="saveUsuarios" type="button" value="Salvar"
onclick="
_root.enableAllValidators();
CFFormValidators.resetInValidFields();
if(mx.validators.Validator.isStructureValid(this, 'form1')){
var params:Object = {};
params.dados = {};
params.dados.username = _root.username.text;
params.dados.email = _root.email.text ;
params.dados.nome = _root.nome.text ;
var serviceName = 'append';
if(_root.id.text != ''){
serviceName = 'update';
params.id = _root.id.text ;
}
var connection:mx.remoting.Connection = mx.remoting.NetServices.createGatewayConnection('http://localhost/cfusion/flashservices/gateway/');
var servicePath:String = 'labs.remoting.Usuario';
var serviceEvent:Object = {};
serviceEvent.onResult = function(result):Void{
_root.id.text = '';
_root.username.text = '';
_root.email.text = '';
_root.nome.text = '';
CFFormValidators.resetInValidFields();
alert(result,'result');
};
serviceEvent.onStatus = function(info:Object):Void{
alert(info.description,info.level);
};
var service:mx.remoting.NetServiceProxy = connection.getService(servicePath,serviceEvent);
service[serviceName](params);
}else{
_root.userOnError();
}
"
>
</cfformgroup>
</cfform>
|
FormatCF(new Array(\’/labs/remoting/Usuario.cfc\’,\’1.cfm\’,\’2_1.cfm\’,\’2_2.cfm\’,\’2_3.cfm\’,\’2_4.cfm\’,\’2_5.cfm\’,\’2_6.cfm\’,\’2_7.cfm\’,\’3.cfm\’,\’4.cfm\’,\’index.cfm\’)); FormatSQL(new Array(\’Usuario.sql\’));















ShareThis