Nosso objetivo neste artigo é oferecer um passo-a-passo para desenvolver uma aplicação simples multi-camadas sendo que:
- o servidor de aplicação será implementado com o Delphi 2010 fazendo uso da tecnologia DataSnap 2010/DBExpress e irá atuar como servidor de dados com capacidades para aceitar chamadas HTTP/REST a seus métodos e criar respostas de dados usando o formato de dados JSON, como uma alternativa ao XML;
- como cliente iremos criar uma interface em flex que será capaz de consumir as respostas produzidas pelo nosso servidor de aplicação.
Os requisitos são:
- Delphi 2010;
- Firebird 2.x;
- Adobe Flash Builder 4;
- IBExpert.
Não está no escopo explicar as novidades e conceitos de DataSnap 2010, bem como explicar o formato JSON. Não trataremos da IDE do Adobe Flash Builder 4 nem da linguagem Action Script e sim, apenas demonstrar de forma prática para fins didáticos a quem tiver interesse no assunto, como dar os primeiros passos na integração destas ferramentas.
Faremos pequenos métodos em nosso servidor que irão construir objetos e arrays do tipo JSON.
Para tanto sugerimos que crie na raiz C: uma pasta chamada DelphiFlex e dentro duas pastas: uma delphi e uma flex. Estas serão respectivamente as pastas onde iremos salvar o servidor de aplicação feito em Delphi e o cliente feito em flex.
Criaremos também um banco de dados chamado CONTATOS.FDB. Para isto use o IbExpert Free ou seu front-end preferido.
Para facilitar execute o script a seguir mudando a senha para a senha do SYSDBA do seu Firebird:
SET SQL DIALECT 3;
SET NAMES ISO8859_1;
SET CLIENTLIB 'fbclient.dll';
CREATE DATABASE 'C:\DelphiFlex\Delphi\CONTATOS.fdb'
USER 'SYSDBA' PASSWORD 'A'
PAGE_SIZE 4096
DEFAULT CHARACTER SET ISO8859_1;
CREATE TABLE CONTATOS (
CODIGO INTEGER NOT NULL,
NOME VARCHAR(50)
);
ALTER TABLE CONTATOS ADD CONSTRAINT PK_CONTATOS PRIMARY KEY (CODIGO);
INSERT INTO CONTATOS (CODIGO, NOME) VALUES (1, 'FELIPE DOS SANTOS');
INSERT INTO CONTATOS (CODIGO, NOME) VALUES (2, 'MARCELO FARIA');
INSERT INTO CONTATOS (CODIGO, NOME) VALUES (3, 'PAULO MACHADO');
INSERT INTO CONTATOS (CODIGO, NOME) VALUES (4, 'RODRIGO VIEIRA');
COMMIT WORK;
Crie uma nova aplicação Delphi. Para isso clique em File > New > Other e na janela New Items, na pasta Delphi Projects selecione a sub-pasta DataSnap Server e clique no item DataSnap Server:
Clique em OK e em seguida, na janela New DataSnap Server selecione VCL Forms Applications: marque a caixa HTTP e selecione em Ancestor a opção TPersistent e desmarque a opção Include sample methods:
Clique em OK e assim anova aplicação será criada, onde será adicionada três units: Unit1, ServerMethodsUnit1 e ServerContainerUnit1.
Na unit Unit1:
- Renomeie a propriedade Name para FrmPrincipal;
- Modifique a propriedade caption para Servidor;
- Adicione um componente TMemo localizado na aba Standard e e configure a propriedade Align para alClient e na propriedade Lines apague o conteúdo.
Na unit ServerMethodsUnit1:
- Renomeia o nome da classe para TSMContato.
Na unit ServerContainerUnit1:
- Renomeie a propriedade Name para SCContato;
- Selecione o componente DSServerClass1 e renomeia a propriedade Name para DSServerClassContato.
Pressione (Ctrl + Shift + S) para salvar: salve a unit ServerMethodsUnit1 como uSMContato, salve a unit ServerContainerUnit1 como uSCContato e a unit Unit1 como uFrmPrincipal e o projeto como Servidor.
Para configurar a conexão clique em View > DataExplorer e clique com o botão direito do mouse no item FIREBIRD e no menu suspenso que abrirá clique com o botão esquerdo do mouse em Add New Connection;
Na janela que abrirá, em Connection Name digite, CONTATOS. Clique em OK. Sobre a conexão recém criada de nome CONTATOS clique com o botão direito do mouse e no menu suspenso que abrirá clique com o botão esquerdo do mouse em Modify Connection:
Na Janela Modify Connection, no campo Database Name informe o caminho do banco de dados seguido do nome do banco de dados, nome do usuário e senha. Use a senha do SYSDBA do seu Firebird:
Clique em OK.
Na unit FrmPrincipal:
- Adicione um componente TSQLConnection e um componente TSQLDataSet ambos localizados na aba DBExpres.
Selecione o componente SQLConnection1:
- No object inspector altere a propriedade ConnectionName para CONTATOS;
- A proprieade LoginPrompt para False;
- E configure como True a propriedade Connected.
Selecione o SQLDataSet1:
- Altere a propriedade Name para DstContatos;
- Configure a propriedade SQLConnection para SQLConnection1;
- Digite na propriedade CommandText o seguinte:
SELECT * FROM CONTATOS WHERE NOME LIKE :PNOME
Nesse ponto sua configuração ao banco de dados já estará pronta.
Selecione a Unit uSMContato:
- Adicione no uses a unit DBXJSON;
- Em seguida clique em File > Use Unit e selecione a Unit uFrmPrincipal e clique em OK;
- Crie uma função chamada GetContatos na sessão public;
Abaixo postamos a assinatura e o código completo da função GetContatos:
function GetContatos(pnome: string): TJSONArray;
function TSMContato.GetContatos(pnome: string): TJSONArray;
var
I: Integer;
qtdeCampos: Integer;
ja: TJSONArray;
jo: TJSONObject;
begin
FrmPrincipal.Memo1.Lines.Add('passei no metodo GetContatos INICIO');
FrmPrincipal.DSTContatos.Params.ParamByName('PNOME').AsString := '%' + pnome + '%';
FrmPrincipal.DSTContatos.Open;
FrmPrincipal.DSTContatos.First;
qtdeCampos := FrmPrincipal.DSTContatos.FieldCount - 1;
ja := TJSONArray.Create;
while not FrmPrincipal.DSTContatos.Eof do
begin
jo := TJSONObject.Create;
for I := 0 to qtdeCampos do
jo.AddPair(FrmPrincipal.DSTContatos.Fields[I].FieldName,
TJSONString.Create(FrmPrincipal.DSTContatos.Fields[I].AsString));
ja.AddElement(jo);
FrmPrincipal.DSTContatos.Next;
end;
FrmPrincipal.DSTContatos.Close;
Result := ja;
FrmPrincipal.Memo1.Clear;
FrmPrincipal.Memo1.Lines.Add(Result.ToString);
FrmPrincipal.Memo1.Lines.Add('passei no metodo GetContatos FIM');
end;
Selecione a unit uSCContato:
- Na cláusula uses renomeie ServerMethodsUnit1 para uSMContato;
- Selecione o componente DSServerClassContato e, no object inspector, selecione a aba eventos, clique duplo sobre o evento onGetClass e substitua o código:
PersistentClass := ServerMethodsUnit1.TServerMethods1;
pelo código:
PersistentClass := uSMContato.TSMContato;
Selecione o componente DSHTTPService1 e altere a propriedade HttpPort para 8081. Caso esta porta já esteja sendo usado por outra aplicação, digite outro número de porta.
Pressione (Ctrl + Shift + S) para salvar. Compile a aplicação com F9. Se alguma mensagem para desbloquear a aplicação for apresentada, apenas confirme para desbloquear.
Teste no navegador executando o seguinte comando:
http://localhot:8081/datasnap/rest/TSMContato/GetContatos
ou a mesma sintaxe apenas mudando para a sua porta:
http://localhot:suaPorta/datasnap/rest/TSMContato/GetContatos
Deverá ser apresentado no navegador o seguinte resultado:
Para podermos criar nosso projeto em Flex, é necessario que você tenha o Adobe Flash Builder 4 instalado em sua máquina.
Caso não tenha, você poderá baixar uma versão trial (60 dias de uso) pelo link a seguir: https://www.adobe.com/cfusion/tdrc/index.cfm?product=flash_builder
Após clicar em "Clique para Baixar" você será redirecionado para a página da Adobe. Para efetuar o download, é necessário cadastrar-se.
Após ter concluído o cadastro, na página que abrir, clique em "Download Flash Builder 4 Installer for Windows" no bloco "Flash Builder 4 Standalone Installer.
Com o Flash Builder 4 instalado crie um novo projeto flex usando a opção File > New > Flex Project, conforme a imagem abaixo:
Como sugestão, preencha o campo "Project Name" com "Projeto Flex".No campo "Folder" selecione o caminho "C:\DelphiFlex\Flex" e clique no botão "Finish", conforme sugerido na imagem abaixo:
Selecione a aba "Designer" e clique em Window > Components. Irá aparecer uma guia de componentes e dentro de "Controls" clique e araste 1 "TextInput", 1 "Button" e 1 "DataGrid" para o projeto.
- Selecione o TextInput e na guia "Common" altere seu id para "txt_consulta".
- Selecione o Button e na guia "Common" altere seu Label para "Consultar".
- Seleciona o DataGrid e na guia "Common" altere seu id para "DataGrid" e clique no botão "Configure Columns".
- Selecione o item "Column 1" e altere os campos "Bind to field" e "Header text" do para "CODIGO" e "Width" para "100".
- Selecione o item "Column 2" e altere os campos "Bind to field" e "Header text" do para "NOME" e "Width" para "200".
- Apague o item "Column 3".
O próximo passo é baixar a biblioteca CoreLibAS3 acessando o link "http://code.google.com/p/as3corelib/downloads/list".
Após ter concluído o download descompacte o arquivo baixado. Dentro da pasta descompactada, abra a pasta "src" e copie a pasta "com" para a pasta "C:\DelphiFlex\Flex\src\".
Agora selecione a aba "Source", e adapte o código conforme o exemplo abaixo, onde comentamos a maior parte dos códigos:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" height="212" width="327">
<fx:Script>
<![CDATA[
//AQUI VAI O CÓDIGO ACTION SCRIPT
import com.adobe.serialization.json.JSON;
//biblioteca responsável por converter do formato JSON
//para objetos nativos do Action Script e vice-versa
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
//a função Consultar será responsável por invocar
//a URL e receber os dados da requisição
private function Consultar():void{
var ht:HTTPService = new HTTPService();
//cria o serviço HTTPService sendo que ht é a variável
//de instância que faz referência para o objeto contendo o serviço
ht.showBusyCursor = true;
//para que apareça a ampulheta enquanto aguarda o resultado da requisição
//define no serviço a URL seguido do parâmetro de consulta
ht.url = "http://localhost:8081/datasnap/rest/TSMContato/GetContatos/"
+ txt_consulta.text;
//define no serviço uma função que será responável por
//receber o resultado da requisição feita ao servidor.
//Neste caso criamos ConsultarResultado
//que recebe de ResultEvent.RESULT o resultado da requisição
ht.addEventListener(ResultEvent.RESULT, ConsultarResultado);
ht.send(); //envia a requisição
}
//a função ConsultarResultado é responsável por processar
//as informações recebidas da requisição feita à URL do servidor
private function ConsultarResultado(re:ResultEvent):void{
//neste ponto criamos um objeto em Action Script usando var jo:Object
//Em seguida, de re, acessamos a propriedade result para pegar
//o resultado e usamos o método toString() para garantir que
//nosso resultado seja uma string
//Tendo certeza que nosso resultado agora já é uma JSON string,
//aplicamos a função JSON.decode para transformar nossa JSON string
//em objetos nativos do Action Script
var jo:Object = JSON.decode(re.result.toString());
//Agora que nosso resultado já está contido em objetos
//nativos Action Script criamos um Array usando var arr:Array
//dado nosso resultado
// {"result":[[{"CODIGO":"1","NOME":"FELIPE DOS SANTOS"},
{"CODIGO":"2","NOME":"MARCELO FARIA"},
{"CODIGO":"3","NOME":"PAULO MACHADO"},
{"CODIGO":"4","NOME":"RODRIGO VIEIRA"}]]}
//Em seguida acessamos o objeto jo fazendo uso de jo['result'] para pegar
//o valor da chave result, ou seja, pegamos do par o valor da chave result
//que irá resultar o array abaixo:
//[[{"CODIGO":"1","NOME":"FELIPE DOS SANTOS"},
{"CODIGO":"2","NOME":"MARCELO FARIA"},
{"CODIGO":"3","NOME":"PAULO MACHADO"},
{"CODIGO":"4","NOME":"RODRIGO VIEIRA"}]]
//Como o valor da chave result é um array que tem dentro dele um
//só elemento que também é array
//fazendo uso de [0] estamos dizendo que queremos pegar o
//primeiro elemento de nosso array
//que irá resultar o array abaixo:
//[{"CODIGO":"1","NOME":"FELIPE DOS SANTOS"},
{"CODIGO":"2","NOME":"MARCELO FARIA"},
{"CODIGO":"3","NOME":"PAULO MACHADO"},
{"CODIGO":"4","NOME":"RODRIGO VIEIRA"}]
//pronto, o array acima será então atribuído para arr
var arr:Array = jo['result'][0];
var dp:ArrayCollection = new ArrayCollection(arr);
//Neste ponto transformamos nosso array arr em um ArrayCollection. Motivo:
//os DataGrid do Flex parecem trabalhar melhor com ArrayCollection
DataGrid.dataProvider = dp;
//finalmente passamos os dados para o provedor de dados do DataGrid
//Considerações aqui no flex
//devemos ter em mente que cada elemento do array é uma linha no DataGrid
//e que cada par de um objeto forma uma coluna, ou seja, vários pares
//formam várias colunas, donde podemos concluir
//que um objeto equivale a um registro ou a uma instância de uma
//classe que pode ter 1 ou N Fields (campos)
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:TextInput x="11" y="4" width="184" id="txt_consulta" />
<s:Button x="196" y="5" label="Consultar" width="117" click="Consultar()"/>
<mx:DataGrid x="11" y="34" id="DataGrid" width="302">
<mx:columns>
<mx:DataGridColumn headerText="CODIGO"
dataField="CODIGO" width="100"/>
<mx:DataGridColumn headerText="NOME" dataField="NOME" width="300"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
Salve tudo (Ctrl + Shift + S).
OBS. Deixe executando o servidor
Execute o projeto flex: use o ícone Run ou o menu Run ou pressione (Ctrl + F11)
O resultado deverá ser parecido com o da imagem abaixo:
Abraço e até a próxima