Integrando Flex com Java usando BlazeDS – primeiros passos

O Adobe Flex tem se tornado tendência quando o assunto é camada de visão entre os desenvolvedores, analistas, gerentes e principalmente os usuários, podendo se integrar praticamente com qualquer linguagem de programação. Na camada de negocios temos uma disputa boa entre Java e .NET(ok ok Java leva vantagem).
Para que o Flex consiga se integrar perfeitamente com Java, é necessário ter um gateway (dispositivo que atua em qualquer camada do modelo ISO/OSI para vencer “diferenças” entres redes, manipulando e convertendo dados) que possa converter os tipos de dados nativos do Flex para os tipos de dados nativos do Java e vice-versa utlizando o protocolo AMF.
No seguinte link temos os tipos de dados do Flex e seu correspondente em Java:
http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html
O AMF(Action Message Format) é um protocolo de especificação aberta, compacta e trafega em formato binário, sendo que na versão 3 do ActionScript, será usado o AMF3 com suporte aos tipos de dados especificos do AS3.
Hoje temos varias implementações que suportam o AMF3, utlizaremos o BlazeDS como gateway para comunicação em o ActionScript 3 e o Java.
O banco de dados de nome “contatos” usado sera o MySQL tendo a seguinte estrutura:
[SQL]
CREATE TABLE `tabela` (
`id` int(11) NOT NULL,
`nome` varchar(30) default NULL,
`email` varchar(100) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
[/SQL]
Como servidor de aplicação utlizaremos o JBoss Application Server e utilizaremos o Eclipse e o Flex Builder respectivamente para codificação( nada empede de se usar o Eclipse para codificar em Flex e Java numa mesma IDE)
O BlazeDS vem por padrão com o Tomcat, mas ele é somente um container de sevlet. Com o JBoss poderemos usar mais tarde ejb3, JPA, Hibernate etc.
Baixe a ultima versão do BlazeDS neste link
Tendo tudo pronto e devidamente configurado, vamos a codificação:

  • Crie um novo projeto do tipo “Dynamic Web Project” e nomeie como “Contatos”.
  • Selecione o “Target Runtime” como JBoss e em “Configurations” deixe “Default Configuration for JBoss v4.2.
  • Em “Projects Facets” não precisa mudar nada, basta clicar em next.
  • Em “Web Module” também não precisa mudar nada, clique em Finish.

Pronto, feito isso já podemos começar nossa codificação, mas antes vamos inserir no projeto as bibliotecas do BlazeDS, se você baixou o bin do BlazeDS, basta descompactar o “blazeds.war” com algum winrar da vida, e copiemos o diretorio “WEB-INF\lib” para dentro de nosso projeto em “WebContent\WEB-INF\lib”, logo em seguida, façamos a mesma coisa com o diretorio “WEB-INF\flex” e com o arquivo “WEB-INF\web.xml”.
Configure o JBoss para ser iniciado pelo eclipse e adicione o projeto “Contatos” para ser publicado automaticamente no JBoss e inicie o JBoss(caso não tenha configurado ainda, siga os passos desse link).
Agora vamos testar se nosso BlazeDS está devidamente configurado, basta abrir o navegador e entrar com o seguinte endereço:

http://localhost:8080/Contatos/messagebroker/amf

Se aparecer uma página em branco, significa que o BlazeDS esta pronto para ser usado 😀

Comecemos pelo nosso VO, crie um package chamado “br.com.leonardofranca.vo” e crie uma classe chamada “ContatosVO”, seu codigo é o seguinte:
[JAVA]
package br.com.leonardofranca.vo;

public class ContatosVO
{
private int id;
private String nome;
private String email;

public int getId()
{
return id;
}

public void setId(int id)
{
this.id = id;
}

public String getNome()
{
return nome;
}

public void setNome(String nome)
{
this.nome = nome;
}

public String getEmail()
{
return email;
}

public void setEmail(String email)
{
this.email = email;
}
}
[/JAVA]

Até aqui, nenhum misterio, temos um simples objeto tipado para ser usando no Java. Vamos a nossa classe Main que fara todo o trabalho.
[JAVA]
package br.com.leonardofranca;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import br.com.leonardofranca.vo.ContatosVO;

public class Contatos
{
Connection conn;
Statement stm;
ResultSet rs;

public Contatos()
{
try
{
Class.forName(“com.mysql.jdbc.Driver”);
conn = DriverManager.getConnection(“jdbc:mysql://localhost:3306/meubanco”,”root”,”minhasenha”);
stm = conn.createStatement();
}
catch (Exception e)
{
e.printStackTrace();
}
}

public List< ContatosVO > getData()
{
List< ContatosVO > list = new ArrayList< ContatosVO >();
try
{
rs = stm.executeQuery(“SELECT id, nome, email FROM tabela”);
while (rs.next())
{
ContatosVO contatosVO = new ContatosVO();
contatosVO.setId(rs.getInt(“id”));
contatosVO.setNome(rs.getString(“nome”));
contatosVO.setEmail(rs.getString(“email”));
list.add(contatosVO);
}
}
catch (SQLException e)
{
e.printStackTrace();
}
return list;
}

public Boolean insertData(ContatosVO contatosVO)
{
try
{
String sql = “INSERT INTO tabela (nome, email) VALUES(‘”+contatosVO.getNome()+”‘,'”+contatosVO.getEmail()+”‘)”;
if(stm.execute(sql))
{
return true;
}
}
catch (SQLException e)
{
e.printStackTrace();
}
return false;
}

public Boolean deleteData(ContatosVO contatosVO)
{
try
{
stm = conn.createStatement();
String sql = “DELETE FROM tabela WHERE id = ‘”+contatosVO.getId()+”‘”;
if(stm.execute(sql))
{
return true;
}
}
catch (SQLException e)
{
e.printStackTrace();
}
return false;
}

public Boolean updateData(ContatosVO contatosVO)
{
try
{
stm = conn.createStatement();
String sql = “UPDATE tabela SET nome = ‘”+contatosVO.getNome()+”‘, email = ‘”+contatosVO.getEmail()+”‘ WHERE id = ‘”+contatosVO.getId()+”‘”;
if(stm.execute(sql))
{
return true;
}
}
catch (SQLException e)
{
e.printStackTrace();
}
return false;
}
}
[/JAVA]

No construtor instancio a classe do banco de dados, o método seguinte é para listar os dados do banco, retornando uma List do Java que alimentara minha DataGrid no Flex, o restante dos métodos(para inserir, atualizar e deletar) deixei apenas para me retornar um Boolean.

Agora vamos a parte em Flex.
Começamos pelo VO da parte do Flex, note que não é necessário colocar os métodos get’s e set’s, no entanto, é necessário colocar o “RemoteClass”:
[ACTIONSCRIPT3]
package br.com.leonardofranca.vo
{
[Bindable]
[RemoteClass(alias=”br.com.leonardofranca.vo.ContatosVO”)]
public class ContatosVO
{
public var id:uint;
public var nome:String;
public var email:String;

public function ContatosVO()
{
}

}
}
[/ACTIONSCRIPT3]
Vamos implementar agora a nossa camada de apresentação, precisaremos de um formulario com dois campos de nome e email, e uma datagrid para listar os emails do banco de dados, necessitamos ainda de três botões, um para cadastro, uma para atualizar e outro para excluir os registros do banco de dados. O Esqueleto da aplicação ficaria da seguinte forma:
[MXML]
< ?xml version="1.0" encoding="utf-8"?>
< mx :Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" >
< mx : HBox x="0" y="0" width="100%" height="100%">
< mx : Panel width="338" height="389" layout="absolute">
< mx : Form x="0" y="0" width="100%" height="100%">
< mx : FormItem label="Nome:">
< mx : TextInput id="input_nome"/>
< / mx : FormItem>
< mx : FormItem label="Email:">
< mx : TextInput id="input_email"/>
< / mx : FormItem>
< mx : FormItem>
< mx : Button id="btnCadastrar" label="Cadastrar" />
< / mx : FormItem>
< mx : FormItem>
< mx : Button label="Excluir"/>
< / mx : FormItem>
< mx : FormItem>
< mx : Button label="Atualizar" />
< / mx : FormItem>
< / mx : Form>
< / mx : Panel>
< mx : DataGrid height="390" id="dg">
< mx : columns>
< mx : DataGridColumn headerText="id" dataField="id"/>
< mx : DataGridColumn headerText="Nome" dataField="nome"/>
< mx : DataGridColumn headerText="Email" dataField="email"/>
< / mx : columns>
< / mx : DataGrid>
< / mx : HBox>
< / mx : Application>
[/MXML]
Geralmente agora precisariamos configurar o arquivo services-config.xml para que o swf saiba onde buscar o serviço. Mas farei diferente, vou configurar direto no endpoint do RemoteObject:
[MXML]
< mx : RemoteObject id="ro" destination="blazeds" source="br.com.leonardofranca.Contatos" endpoint="http://localhost:8080/Contatos/messagebroker/amf">
< mx : method name="getData" result="onResult(event);" fault="onFault(event);"/>
< mx : method name="insertData" result="onResultData(event);" fault="onFault(event);"/>
< mx : method name="deleteData" result="onResultData(event);" fault="onFault(event);"/>
< mx : method name="updateData" result="onResultData(event);" fault="onFault(event);"/>
< / mx : RemoteObject>
[/MXML]
E na tag method, deixo configurado para chamar os métodos da minha classe Java. Agora basta escrever as funções que receberão os retornos de sucesso ou falha, note que deixei o mesmo método em caso de falha.
[ACTIONSCRIPT3]
import mx.controls.Alert;
import mx.events.ListEvent;
import br.com.leonardofranca.vo.ContatosVO;
import mx.collections.ArrayCollection;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;

public function init():void
{
dg.addEventListener(ListEvent.CHANGE,selectedItems);
}

public function onResult(re:ResultEvent):void
{
var data:Object = re.message.body;
dg.dataProvider = data;
}

public function onFault(fault:FaultEvent):void
{
trace(“Code: “+fault.fault.faultCode);
trace(“Detail: “+fault.fault.faultDetail);
trace(“String: “+fault.fault.faultString);
}

public function insertData():void
{
var contatosVO:ContatosVO = new ContatosVO();
contatosVO.nome = input_nome.text;
contatosVO.email = input_email.text;
ro.insertData(contatosVO);
}

public function onResultData(re:ResultEvent):void
{
ro.getData();
}

public function deleteData():void
{
if(dg.selectedItem != null)
{
var contatosVO:ContatosVO = new ContatosVO();
contatosVO.id = dg.selectedItem.id;
ro.deleteData(contatosVO);
}
else
{
Alert.show(“Selecione um item da tabela!!!”);
}
}

public function selectedItems(evt:ListEvent):void
{
input_nome.text = dg.selectedItem.nome;
input_email.text = dg.selectedItem.email;
}

public function updateData():void
{
if(dg.selectedItem != null)
{
var contatosVO:ContatosVO = new ContatosVO();
contatosVO.id = dg.selectedItem.id;
contatosVO.nome = input_nome.text;
contatosVO.email = input_email.text;
ro.updateData(contatosVO);
}
else
{
Alert.show(“Selecione um item da tabela!!!”);
}
}
[/ACTIONSCRIPT3]
Segue o código completo:
[MXML]
< ?xml version="1.0" encoding="utf-8"?>
< mx : Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="ro.getData();init();">
< mx : Script>
< ![CDATA[ import mx.controls.Alert; import mx.events.ListEvent; import br.com.leonardofranca.vo.ContatosVO; import mx.collections.ArrayCollection; import mx.rpc.events.FaultEvent; import mx.utils.ObjectUtil; import mx.rpc.events.ResultEvent; public function init():void { dg.addEventListener(ListEvent.CHANGE,selectedItems); } public function onResult(re:ResultEvent):void { var data:Object = re.message.body; dg.dataProvider = data; } public function onFault(fault:FaultEvent):void { trace("Code: "+fault.fault.faultCode); trace("Detail: "+fault.fault.faultDetail); trace("String: "+fault.fault.faultString); } public function insertData():void { var contatosVO:ContatosVO = new ContatosVO(); contatosVO.nome = input_nome.text; contatosVO.email = input_email.text; ro.insertData(contatosVO); } public function onResultData(re:ResultEvent):void { ro.getData(); } public function deleteData():void { if(dg.selectedItem != null) { var contatosVO:ContatosVO = new ContatosVO(); contatosVO.id = dg.selectedItem.id; ro.deleteData(contatosVO); } else { Alert.show("Selecione um item da tabela!!!"); } } public function selectedItems(evt:ListEvent):void { input_nome.text = dg.selectedItem.nome; input_email.text = dg.selectedItem.email; } public function updateData():void { if(dg.selectedItem != null) { var contatosVO:ContatosVO = new ContatosVO(); contatosVO.id = dg.selectedItem.id; contatosVO.nome = input_nome.text; contatosVO.email = input_email.text; ro.updateData(contatosVO); } else { Alert.show("Selecione um item da tabela!!!"); } } ]]>
< / mx : Script>
< mx : RemoteObject id="ro" destination="blazeds" source="br.com.leonardofranca.Contatos" endpoint="http://localhost:8080/Contatos/messagebroker/amf">
< mx : method name="getData" result="onResult(event);" fault="onFault(event);"/>
< mx : method name="insertData" result="onResultData(event);" fault="onFault(event);"/>
< mx : method name="deleteData" result="onResultData(event);" fault="onFault(event);"/>
< mx : method name="updateData" result="onResultData(event);" fault="onFault(event);"/>
< / mx : RemoteObject>
< mx : HBox x="0" y="0" width="100%" height="100%">
< mx : Panel width="338" height="389" layout="absolute">
< mx : Form x="0" y="0" width="100%" height="100%">
< mx : FormItem label="Nome:">
< mx : TextInput id="input_nome"/>
< / mx : FormItem>
< mx : FormItem label="Email:">
< mx : TextInput id="input_email"/>
< / mx : FormItem>
< mx : FormItem>
< mx : Button id="btnCadastrar" label="Cadastrar" click="insertData();"/>
< / mx : FormItem>
< mx : FormItem>
< mx : Button label="Excluir" click="deleteData();"/>
< / mx : FormItem>
< mx : FormItem>
< mx : Button label="Atualizar" click="updateData();"/>
< / mx : FormItem>
< / mx : Form>
< / mx : Panel>
< mx : DataGrid height="390" id="dg">
< mx : columns>
< mx : DataGridColumn headerText="id" dataField="id"/>
< mx : DataGridColumn headerText="Nome" dataField="nome"/>
< mx : DataGridColumn headerText="Email" dataField="email"/>
< / mx : columns>
< / mx : DataGrid>
< / mx : HBox>
< / mx : Application>
[/MXML]
Se você chegou ate aqui ok! tudo certo e funcionando, mas pode esquecer, logo mostrarei uma maneira melhor e mais eficiente de fazer a integração do Flex com Java 😉

[UPDATE]
Acabei esquecendo de mencionar que é necessario um diretorio do projeto no eclispe, chamado WebContent/WEB-INF/flex que devem constar os arquivos: services-config.xml, remoting-config.xml, proxy-config.xml, messaging-config.xml. No caso do projeto só é necessario mesmo o remoting-config.xml, cujo o conteúdo deve ser como o código abaixo:
[XML]





br.com.leonardofranca.Contatos
session


[/XML]

Livros recomendados:
Flex 3 em Ação
Adobe Flex 3 Treinamento Direto da Fonte

Translations:
English Version

BlazeDS, Flex, Java, MySQL , , ,

38 comments


  1. Paulo Larini

    Fala ai! Qual seria essa forma melhorada ?

  2. esta saindo do forno, so sobrar mais tempo e publicarei o mais breve possivel 😉

  3. Inocêncio

    Só uma ressalta.

    Seu tutorial ficou muito bom. Mas você falou que deve-se usar o JBoss ao invés do TomCat para usar JPA e Hibernate, mas tanto o JPA quanto o Hibernate podem rodar sem problemas em um container web, e não somente em um servidor de aplicações. Inclusive fiz aplicações completas hibernate + jpa usando apenas TomCat.

  4. LEANDRO

    Leonardo, estou começando tanto com Java como com Flex. Seria muito grato se vc publicasse essa maneira mais facil. To meio confuso com essa integração. abraço.

  5. Só estou dependando de um amigo terminar a parte dele para publicar o artigo ;o)

  6. Jeff

    Este artigo está me ajudando bastante, a minha dúvida é examente esta integração.
    Sobre o outro método é data service?
    Estou no aguardo da segunda parte, muito bom o artigo, parabéns.

  7. o outro método é com Hibernate e JPA, vou acabar escrevendo eu mesmo, o amigo que ficou de me ajudar anda muito ocupado, mas tenho que estudar um pouco mais pra nao falar bobagem 😉

  8. claud

    quando faz a requisicao ao AMF recebo a seguinte mensagem

    Failed to load source for: http://localhost:8080/Contatos/messagebroker/amf

    o que fiz de errado, será que pode me ajuddar

  9. claud

    faltou mapear o servico no remote-config.xml, coloque uma observação no post para outros usuários caso tenha o mesmo problema.

  10. post atualizado, obrigado pelo aviso 😉

  11. ae agora sim, tudo funfando.
    A e a mesma configuração serve para o tomcat também.

  12. mt bom post! parabens!

  13. Elane

    Oi Leonardo,
    estou com um problema, quando eu entro na urlhttp://localhost:8080/Contatos/messagebroker/amf, aparece a seguinte mensagem de erro:
    The requested resource (/Contatos/messagebroker/amf) is not available.

    eu mapiei o remoting-config.xml conforme você mostrou.
    O que pode estar acontecendo?

  14. Ola Elane, verifique se as bibliotecas do BlazeDS estão no local correto e se o eclipse esta jogando no local correto no tomcat ;o)

  15. Elane

    Blz Leonardo,
    já consegui resolver esse problema. Era isso mesmo 😀
    Agora o BlazeDS tá bacana, tabela criada e banco startado, o servidor (JBoss) tá startado com a aplicação rodando; porém os botões não estão realizando nenhuma ação, nem trazem os dados do banco que inseri manualmente no dataGrid.
    E agora, o que pode ser?

  16. Leonardo,
    debugando aqui vi que dá erro de null pointer na na classe Contato.java, na instrução:

    Class.forName(“com.mysql.jdbc.Driver”);

    eu baixei um drive do msql (mysql-connector-java-5.0.8-bin.jar) e apontei no properties do projeto.

    tem alguma outra mandinga dessas pra fazer?

  17. opa,resolvi xD
    eu não tinha colocado o .jar do mysql connector na lib do projeto, apenas tinha adicionado no properties xP

    muito bom o exemplo e blog,
    parabéns!

  18. Oi Leonardo,
    esqueci de perguntar qual o retorno do trecho:
    var data:Object = re.message.body;
    Qual o tipo de retorno do message.body?

    Outra dúvida,
    tenho que recuperar um objeto do tipo Projeto, que é retornado do Java, e mostrar na aplicação Flex.
    Como eu recupero esse objeto no flex?
    tente usar esse message.body e, depois, o re.result, mas não tive sucesso com nenhum.

    Você podia me indicar um exemplo desse tipo de situação?

    t+

  19. o ResultEvent é um objeto
    Projeto é o seu vo? você consegue da um trace(ObjectUtil.toString(re.message.body));

  20. Olá Leonardo, beleza?
    Você disse que precisa dos arquivos:
    services-config.xml, remoting-config.xml, proxy-config.xml, messaging-config.xm

    Mas basta utilizarmos o remoting-config.xml…
    Pra que servem os outros?

    Obrigado. Abraço.

  21. Claudinho Ramires

    Olá amigo. Tenho uma aplicação Flex-BlazeDs-Java totalmente funcional no meu computador local. O meu problema é quando publico em meu host. Ele me retorna “Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Status 404: url: ‘http://www.meusite.com/MeuSite/messagebroker/amf’
    Você sabe o que pode ser?

  22. o proxy-config.xml não sei ainda para que é usado, o messaging-config.xml é para usar com Data Push.

  23. verifique se vc mandou todas as bibliotecas do BlazeDS para o server tb 😉

  24. estou com dúvida apenas onde crio os arquivos do flex… eu instalei o plugin corretamente no meu eclipse, se tanto que consigo criar novos projetos tranquilo….

    Porém quando clico pra criar um as ou mxml ele manda eu criar um projeto flex antes, e no tutotial ele manda criar um Web Dynamic.

    Eu tentei colocar o ContatosVO.as junto com o ContatosVO.java e mxml no src e no web-inf, e quando rodo ele não gera nada… o que estou fazendo de errado?

    eu sou acostumado de usar o flex com php usando o flexbuilder apenas… alguém poderia me ajudar?

    Obrigado

  25. basta clicar com o botão direito no projeto, em seguida Flex Project Nature->Add Flex Project Nature
    sera criado um diretorio chamado flex_src onde você deve salvar seus arquivos .mxml e .as

  26. Wagner

    O artigo é muito bom, passo a passo,porém quando a parte Flex começa a explicação deixa um pouco a desejar, tornando difícil a implementação para um iniciante. Abs

  27. Paulo Ricardo

    Bom dia, eu estava com o mesmo problema do Rodrigo acima, eu consegui criar os AS com o “Flex Project Nature”, porém não entendi como compilo esses mxml pra rodar no meu servidor…

    Essas foram as únicas duas dificuldades encontradas para elaborar e testar esse exemplo.

    Abraços

  28. Por default, quando vc converte para um projeto Flex, é criado também um diretorio “WebContent” ou “bin-debug”, você pode configurar nas propriedades do projeto onde serão criados os html’s e swf’s.
    caso vc esteja com a opção “Project->Build Automatically” marcada, cada vez que vc salva um arquivo, ele gera os swf’s

  29. BN

    Muito bom o blog e o post…
    Estou aguardando ansioso outro post (o mais simples citado neste)..

    +D

    Att.
    BN

  30. Eduardo

    Por acaso vc teria algum tutorial de configuração do JBoss com BlazeDS ??

    Obrigado.

  31. Vinícios

    Leonardo, muito bom o artigo.
    Eu utilizo o Flash Builder 4 separado do Eclipse. Devo criar o projeto em qual dessas ferramentas?

  32. o java no eclipse e o flex no Flash Builder, o projeto do Flash Builder apontará para o projeto java

  33. Ricardo Jr.

    Olá Leonardo.
    Eu uso o NetBeans, tenho um projeto, feito no padrão MVC, tudo certinho, com a view em JSP/HTML. E eu gostaria de passar essa view pra Flex. Teria como eu fazer isso usando meu Netbeans? O que eu tenho que fazer?
    Obrigado.

  34. Não sei como é no Netbeans, mas em teoria, se vc conseguir gerar o jar so com a parte do negocio e apontar o view pra ela. 🙂

  35. Eu adorei o artigo. parabéns

  36. Vinícios

    Bom dia, Leonardo.
    Embora não esteja nesse contexto, estou com um pouco de dificuldade para entender quando devo usar eventos do tipo FlexEvent. Se você puder me ajudar…
    Obrigado.

  37. Pingback: Leonardo França » Adobe Flex com PHP usando ZendAMF – primeiros passos

  38. Olá, Leonardo. Tudo blz ?
    Eu segui todo o tutorial, porém usei eclipse + plugin e Tomcat. Na hora de que faço o Run on Server, ele executa e mostra o conteudo do diretorio bin-debug http://localhost:8400/Contac
    Tentei trocar o nome de contato.mxml para index.. Também não funcionou.
    FlexBuildPath(
    outputFolder:bin-debug ,
    MainSourceFolder:flex_src ,
    OutputFolderURL:(EM BRANCO)).
    Tive sucesso com o ZEND mas não consegui fazer funcionar com o java, me ajuda pro favor.. obrigado !!!

Leave a Reply