Pré-requisitos
Conhecer o método de trabalho do Flash, comunicando-se com uma base de dados através do AMF (Action Message Format) no ActionScript 3.0.
Programação Orientada a Objetos no Flash: Artigo de nível básico.
Objetivos
Executar ações como ler, gravar, alterar e excluir dados de um Banco de Dados.
Conteúdo
Primeiramente necessitamos de um banco de dados para teste (ACCESS, MySQL, SQLServer…), uma linguagem de servidor que trabalhe com o sistema AMF (ColdFusion, Java, .Net, PHP…), e claro, do próprio Flash utilizando ActionScript 3.0.
Lembrando que o assunto do artigo está voltado ao ActionScript 3, usando o AMF, assuntos como SQL e ColdFusion – os quais usarei neste artigo – não serão discutidos, mas o código também estará incluso no documento abaixo.
SQL para a criação da Tabela com seus respectivos campos:
CREATE TABLE GUESTBOOK(
ID INT NOT NULL AUTO_INCREMENT,
NOME VARCHAR(200) NOT NULL,
EMAIL VARCHAR(50) NOT NULL,
MENSAGEM TEXT,
PRIMARY KEY(ID)
) ENGINE=MYISAM
ColdFusion para acesso ao Banco de Dados:
<cfcomponent>
<!-- RETORNA TODAS AS MENSAGENS -->
<cffunction name="getMensagens" access="remote" returntype="query">
<cfquery name="results" datasource="amf" dbtype="odbc">
SELECT * FROM GUESTBOOK
ORDER BY ID ASC</cfquery>
<cfreturn results>
</cffunction>
<!-- ADICIONA UMA MENSAGEM -->
<cffunction name="setMensagem" access="remote" returntype="string" hint="Incluído com sucesso!">
<cfargument name="nome" type="string" required="true">
<cfargument name="email" type="string" required="true">
<cfargument name="mensagem" type="string" required="true">
<cfquery datasource="amf" dbtype="odbc">
insert into GUESTBOOK(NOME,EMAIL,MENSAGEM)
values('#nome#','#email#','#mensagem#')
</cfquery>
<cfset results="Incluído com sucesso!">
<cfreturn results>
</cffunction>
<!-- ALTERA UMA MENSAGEM -->
<cffunction name="updateMensagem" access="remote" returntype="string">
<cfargument name="nome" type="string" required="true">
<cfargument name="email" type="string" required="true">
<cfargument name="mensagem" type="string" required="true">
<cfargument name="id" type="numeric" required="true">
<cfquery datasource="amf" dbtype="odbc">
UPDATE GUESTBOOK
SET NOME='#nome#', EMAIL='#email#', MENSAGEM='#mensagem#'
WHERE ID=#id#
</cfquery>
<cfreturn "Alterada com sucesso">
</cffunction>
<!-- EXCLUI UMA MENSAGEM -->
<cffunction name="deleteMensagem" access="remote" returntype="string">
<cfargument name="id" type="numeric" required="true">
<cfquery datasource="amf" dbtype="odbc">
DELETE
FROM GUESTBOOK
WHERE ID=#id#
</cfquery>
<cfreturn "Excluída com sucesso">
</cffunction>
</cfcomponent>
Com os dados acima, basicamente manipularemos uma tabela de nome GUESTBOOK, que contém os campos ID, NOME, EMAIL e MENSAGEM.
Um arquivo feito em ASP seguirá em anexo, juntamente ao ColdFusion.
Ambos os arquivos acima estão na pasta wwwroot do servidor ColdFusion, dentro de uma pasta chamada amf, que eu criei.
O arquivo ColdFusion se chama serviços.cfc (componente ColdFusion).
Vamos agora ao Flash, nosso target neste artigo.
Primeiramente, o AMF pode retornar duas coisas quando fazemos um chamado. Um Erro ou um Resultado. Para isso criarei duas classes de eventos como vimos no artigo (https://imasters.com.br/artigo/8397/actionscript/disparando_um_evento_customizado/), uma delas será responsável pela informação do erro, caso ocorra, e outra pelos resultados do ColdFusion, como a query vinda do banco de dados ou uma informação simples, como, por exemplo, se o cadastro de um item foi feito com sucesso.
Classe responsável pelo status (erro, antiga onFault no ActionScript 2):
package {
import flash.events.Event;
public class StatusEvent extends Event {
public static const STATUS = "status";
public var status:Object;
public function StatusEvent(type:String, bubbles = false, cancelable = false, status:Object = null):void {
super(type, bubbles, cancelable);
this.status = status;
}
public override function clone():Event {
return new ResultEvent(type, false, false, status);
}
public override function toString():String {
return formatToString("StatusEvent", "type", "bubbles", "cancelable", "eventPhase", "status");
}
}
}
Classe responsável pelo resultado (retorno do arquivo ColdFusion neste exemplo, antigo onResult no ActionScript 2):
package {
import flash.events.Event;
public class ResultEvent extends Event {
public static const RESULT = "result";
public var result:*;
public function ResultEvent(type:String, bubbles = false, cancelable = false, result:* = null):void {
super(type, bubbles, cancelable);
this.result = result;
}
/**
* Creates and returns a copy of the current instance.
* @return A copy of the current instance.
*/
public override function clone():Event {
return new ResultEvent(type, false, false, result);
}
/**
* Returns a String containing all the properties of the current
* instance.
* @return A string representation of the current instance.
*/
public override function toString():String {
return formatToString("ResultEvent", "type", "bubbles", "cancelable", "eventPhase", "result");
}
}
}
Classe Responsável pela conexão:
package {
import flash.net.NetConnection;
import flash.net.ObjectEncoding;
import flash.net.Responder;
import flash.events.EventDispatcher;
import flash.events.Event;
public class RemoteConnector extends EventDispatcher{
//responsável pela conexão com o banco
private var conn:NetConnection;
//responsável pelo resultado ou informação do erro ocorrido
private var responder:Responder;
//definimos um padrão de leitura para teste local
public function RemoteConnector(uri:String = "http://localhost:8500/flashservices/gateway"):void {
conn = new NetConnection();
conn.objectEncoding = ObjectEncoding.AMF0;
conn.connect(uri);
}
public function call(command:String, ... args):void {
//chama a função onResult caso ocorra tudo bem ou onStatus caso ocorra um erro, o nome das funções é indiferente, desde que as mesmas sejam renomeadas abaixo
responder = new Responder(onResult, onStatus);
//chama um método co ColdFusion, seguindo pasta, arquivo e nome do método, exemplo: call("amf.servicos.getMensagens");
conn.call(command, responder, args);
}
//dispara um ResultEvent para que possa ser reutilizado fora desta classe, já com a propriedade result com as informações do Banco de Dados
private function onResult(result:*):void {
dispatchEvent(new ResultEvent(ResultEvent.RESULT, false, false, result));
}
//dispara um StatucEvent para que possa ser reutilizado fora desta classe, já com a propriedade statuc com as informações do erro
private function onStatus(status:Object):void {
dispatchEvent(new StatusEvent(StatusEvent.STATUS, false, false, status));
}
public function get uri():String {
return conn.uri;
}
}
}
Para testar o arquivo acima, usarei um .fla de teste, que contém o seguinte código no frame 1:
import com.leandroamano.remoting.RemoteConnector;
import com.leandroamano.events.ResultEvent;
import com.leandroamano.events.StatusEvent;
//RemoteConnector
var rc:RemoteConnector = new RemoteConnector();
rc.addEventListener(ResultEvent.RESULT, onResult);
rc.addEventListener(com.leandroamano.events.StatusEvent.STATUS, onStatus);
rc.call("amf.servicos.getMensagens");
trace(rc);
function onResult(e:ResultEvent):void {
trace(e.result);
for(var i in e.result.serverInfo){
trace(i, ":", e.result.serverInfo[i]);
}
trace("\t", e);
}
function onStatus(e:com.leandroamano.events.StatusEvent):void {
trace(e.status.description);
trace("\t", e);
}
Também criei um .fla com o código no frame 1, sem utilizar as classes citadas acima (somente as do próprio Adobe Flash CS3) com alguns elementos visuais no palco [object MainTimeline], que podem ser observados nos arquivos que acompanham este artigo. O código segue abaixo:
import flash.net.NetConnection;
import flash.net.Responder;
import flash.net.ObjectEncoding;
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFieldAutoSize;
import flash.geom.ColorTransform;
import flash.utils.setInterval;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.events.EventPhase;
import fl.data.DataProvider;
import fl.controls.DataGrid;
var selecionado:uint;
var intervalID:uint;
var count:uint;
var gridObj:DataGrid = getChildByName("grid") as DataGrid;
var nome_txt:TextField = getChildByName("nome") as TextField;
var email_txt:TextField = getChildByName("email") as TextField;
var mensagem_txt:TextField = getChildByName("mensagem") as TextField;
var resposta_txt:TextField = getChildByName("resposta") as TextField;
var insert_mc:MovieClip = getChildByName("inserir") as MovieClip;
var update_mc:MovieClip = getChildByName("alterar") as MovieClip;
var delete_mc:MovieClip = getChildByName("excluir") as MovieClip;
var conn:NetConnection = new NetConnection();
var responder:Responder = new Responder(onResult, onFault);
var responderUpdates:Responder = new Responder(onResultUpdates, onFault);
gridObj.addEventListener(Event.CHANGE, onChange);
resposta_txt.mouseEnabled = false;
resposta_txt.wordWrap = true;
resposta_txt.autoSize = TextFieldAutoSize.LEFT;
var initTexto:String = "Para alterar os valores, clique duas vezes sobre o campo de texto desejado";
intervalID = setInterval(displayMessage, 40, initTexto.toUpperCase(), resposta_txt);
for(var i:uint, t:TextField; i<numChildren; i++){
if(getChildAt(i) is TextField && getChildAt(i) != resposta_txt){
t = getChildAt(i) as TextField;
t.doubleClickEnabled = true;
t.restrict = "A-Z0-9\\@\\ \\-\\?\\.";
t.maxChars = 50;
t.autoSize = TextFieldAutoSize.LEFT;
t.addEventListener(MouseEvent.DOUBLE_CLICK, onDoubleClick);
}
}
conn.objectEncoding = ObjectEncoding.AMF0;
conn.connect("http://localhost:8500/flashservices/gateway");
conn.call("amf.servicos.getMensagens", responder);
setColor(0x009900, insert_mc);
insert_mc.buttonMode = true;
insert_mc.addEventListener(MouseEvent.CLICK, insertAMF);
setColor(0xFF6600, update_mc);
update_mc.buttonMode = true;
update_mc.addEventListener(MouseEvent.CLICK, updateAMF);
delete_mc.buttonMode = true;
delete_mc.addEventListener(MouseEvent.CLICK, deleteAMF);
stage.addEventListener(MouseEvent.CLICK, deselect);
function onResult(re:Object):void {
var dados:Array = new Array();
for(var l:uint; l<re.serverInfo.initialData.length; l++){
dados.push({id:re.serverInfo.initialData[l][0],
nome:re.serverInfo.initialData[l][1],
email:re.serverInfo.initialData[l][2],
mensagem:re.serverInfo.initialData[l][3]});
}
gridObj.dataProvider = new DataProvider(dados.sortOn("id", Array.DESCENDING));
gridObj.columns = ["id", "nome", "email", "mensagem"];
var colunas:Array = new Array("ID", "Nome", "E-mail", "Mensagem");
for(var i:uint; i<re.serverInfo.columnNames.length; i++){
gridObj.getColumnAt(i).headerText = colunas[i];
}
gridObj.selectedIndex = selecionado;
gridObj.dispatchEvent(new Event(Event.CHANGE));
}
function onFault(fe:Object):void {
intervalID = setInterval(displayMessage, 50, fe.description.toUpperCase(), resposta_txt);
}
function onResultUpdates(re:String):void {
intervalID = setInterval(displayMessage, 50, re.toUpperCase(), resposta_txt);
conn.call("amf.servicos.getMensagens", responder);
}
function onChange(e:Event):void {
var grid:DataGrid = e.currentTarget as DataGrid;
selecionado = grid.selectedIndex;
nome_txt.text = grid.selectedItem.nome.toUpperCase();
email_txt.text = grid.selectedItem.email.toUpperCase();
mensagem_txt.text = grid.selectedItem.mensagem.toUpperCase();
}
function onDoubleClick(e:MouseEvent):void {
deselect(new MouseEvent(MouseEvent.CLICK));
var texto:TextField = e.currentTarget as TextField;
texto.type = TextFieldType.INPUT;
texto.border = true;
texto.background = true;
texto.backgroundColor = 0x000000;
texto.textColor = 0xFFFFFF;
texto.selectable = true;
}
function deselect(e:MouseEvent):void {
if(e.eventPhase == EventPhase.AT_TARGET){
for(var i:uint, t:TextField; i<numChildren; i++){
if(getChildAt(i) is TextField && getChildAt(i) != resposta_txt){
t = getChildAt(i) as TextField;
t.border = false;
t.selectable = false;
t.background = false;
t.backgroundColor = 0xFFFFFF;
t.textColor = 0x000000;
}
}
}
}
function insertAMF(e:MouseEvent):void {
deselect(new MouseEvent(MouseEvent.CLICK));
var params:Object = new Object();
params.nome = nome_txt.text;
params.email = email_txt.text;
params.mensagem = mensagem_txt.text;
conn.call("amf.servicos.setMensagem", responderUpdates, params);
}
function updateAMF(e:MouseEvent):void {
deselect(new MouseEvent(MouseEvent.CLICK));
var params:Object = new Object();
params.nome = nome_txt.text;
params.email = email_txt.text;
params.mensagem = mensagem_txt.text;
params.id = gridObj.selectedItem.id;
conn.call("amf.servicos.updateMensagem", responderUpdates, params);
}
function deleteAMF(e:MouseEvent):void {
deselect(new MouseEvent(MouseEvent.CLICK));
var params:Object = new Object();
params.id = gridObj.selectedItem.id;
conn.call("amf.servicos.deleteMensagem", responderUpdates, params);
selecionado = 0;
}
function setColor(color:uint, object:DisplayObject):void {
var cor:ColorTransform = new ColorTransform();
cor.color = color;
object.transform.colorTransform = cor;
}
function displayMessage(value:String, t:TextField):void {
count = count == 0 ? count = 0 : count;
if(count <= value.length){
t.text = value.substr(0, count);
count++;
}else {
count = 0;
clearInterval(intervalID);
}
}
Espero que esse artigo ajude quando o assunto for Flash com Banco de Dados, com grande volume de troca de dados.
Obrigado e até a próxima!
Download dos arquivos.