blob: d5820e525fda12f96300c6af7e1a7523046f9fce [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= Web Service Passando Dados Binários, parte 5: Criando o Cliente Swing
:jbake-type: tutorial
:jbake-tags: tutorials
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: Web Service Passando Dados Binários, parte 5: Criando o Cliente Swing - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, Web Service Passando Dados Binários, parte 5: Criando o Cliente Swing
O objetivo deste exercício é criar um cliente para o Web service criado e implantado anteriormente e, em seguida, adicionar uma interface de GUI a esse cliente. A interface exibe as imagens que o Web service passa como dados binários.
É possível fazer download de uma versão completa do cliente a partir do link:https://netbeans.org/projects/samples/downloads/download/Samples%252FWeb%2520Services%252FWeb%2520Service%2520Passing%2520Binary%2520Data%2520--%2520EE6%252FFlowerClient.zip[+Catálogo de Amostras do NetBeans+].
*Lições Deste Tutorial*
image::images/netbeans-stamp-74-73-72.png[title="O conteúdo desta página se aplica ao NetBeans IDE 7.2, 7.3 e 7.4"]
1. link:./flower_overview.html[+Visão Geral+]
2. link:./flower_ws.html[+Criando o Web Service+]
3. link:./flower-code-ws.html[+Codificando e Testando o Web Service+]
4. link:./flower_wsdl_schema.html[+ Modificando o Esquema e os Arquivos WSDL para Passar Dados Binários+]
5. => Criando o Cliente Swing
[start=1]
1. <<create-client-app,Criando a Aplicação Cliente>>
[start=2]
. <<design-jframe,Projetando o JFrame>>
[start=3]
.
<<bind-jframe,Vinculando os Componentes do JFrame>>
[start=4]
. <<code-main-class,Codificando a Classe Principal>>
== Criando a Aplicação Cliente
Nesta seção, você criará uma aplicação Web. Nessa aplicação, você criará um cliente que consumirá o Web service criado e modificado em tutoriais anteriores.
*Para criar a aplicação cliente:*
1. Selecione Arquivo > Novo Projeto (Ctrl-Shift-N no Linux/Windows, ⌘-Shift-N no MacOS). O Assistente de Novo Projeto será exibido.
2. Selecione Aplicação Java na categoria Java. Clique em Próximo. O assistente de Nova Aplicação Java será exibido. Digite ``FlowerClient`` em Nome do Projeto. Selecione uma localização para o projeto e clique em Finalizar. O IDE criará um novo projeto de aplicação Java.
3. Clique com o botão direito do mouse no nó do projeto ``FlowerClient`` e selecione Novo > Cliente de Web Service no menu de contexto. O assistente de Novo Cliente de Web Service será aberto.
4. Selecione o botão de opção URL WSDL e cole o URL do arquivo WSDL nesse campo. (Por default, o URL é ``http://localhost:8080/FlowerAlbumService/FlowerServiceService?wsdl`` . Localize o URL no browser testando o Web service e substituindo ``?Tester`` por ``?wsdl`` no final do URL.) Aceite todos os outros valores default, incluindo um nome de pacote em branco.
image::images/ws-client-wiz.png[]
[start=5]
. Clique em Finalizar. O IDE faz download do arquivo WSDL, adiciona stubs de cliente para interagir com o Web service e adiciona nós à janela Projetos no projeto de aplicação Java.
image::images/client-generated-sources.png[title="Visualização Projetos mostrando o novo cliente do Web Service"]
[[design-jframe]]
== Projetando o Form JFrame
Nesta seção, você adicionará um ``JFrame`` à aplicação Web e projetará uma interface de GUI dentro dele utilizando componentes Swing. Finalmente, você vinculará os componentes Swing ao código do cliente de Web service.
Se não desejar projetar o form JFrame você mesmo, você poderá fazer download de um arquivo Java do JFrame pré-projetado link:https://netbeans.org/projects/www/downloads/download/webservices%252FFlowerFrame.java[+aqui+].
1. Clique com o botão direito do mouse no nó ``FlowerClient`` e selecione Novo > Form JFrame. Chame o quadro de ``FlowerFrame`` . Coloque-o no pacote ``flowerclient`` .
2. ``FlowerFrame`` será aberto no editor. Abra a Paleta, se ainda não estiver aberta. Estenda o limite inferior do quadro em aproximadamente um terço.
image::images/opened-flowerform.png[]
[start=3]
. Arraste um JPanel da seção Contêineres Swing da Paleta para o ``FlowerFrame`` . Expanda-o para preencher o ``FlowerFrame`` inteiro.
image::images/add-panel.png[]
[start=4]
. Clique com o botão direito do mouse no Painel na View do Design. Selecione Alterar Nome da Variável... no menu de contexto. Defina o nome do painel como ``gardenFlowersPanel`` .
[start=5]
. Arraste um JLabel da Paleta para o início do `` gardenFlowersPanel`` . Clique com o botão direito do mouse no label e altere seu nome de variável para ``titleLabel`` . Clique com o botão direito do mouse novamente em ``titleLabel`` e selecione Editar Texto. Altere o texto para Flores do Jardim. Talvez você queira explorar as propriedades do ``titleLabel`` e dar a ele uma fonte de maior expressão.
[start=6]
. Arraste um Grupo de Botões para a view de design. Aceite o nome da variável default do grupo de botões, ``buttonGroup1`` .
[start=7]
. Arraste quatro Botões de Opções para uma linha horizontal abaixo do ``titleLabel`` . Nas propriedades de cada botão, defina-o como um membro de ``buttonGroup1`` . As outras propriedades dos botões são:
|===
|Botões de Opção em ButtonGroup1
|Nome da Variável |Selecionado |Texto
|asterRadioButton |verdadeiro ster
|honeysuckleRadioButton |falso |Madressilva
|roseRadioButton |falso |Rosa
|sunflowerRadioButton |falso |Girassol
|===
[start=8]
. Arraste um Painel de Rolagem para baixo dos botões de opções. Expanda-o para preencher todo o espaço horizontal e cerca de dois terços do espaço vertical livre. Altere o nome da variável do painel de rolagem para ``mainScrollPane`` .
[start=9]
. Arraste um Painel para o ``mainScrollPane`` . Altere o nome da variável do Painel para ``mainPanel`` .
[start=10]
. Na view Design, clique com o botão direito do mouse no ``mainPanel`` e selecione Definir layout > Layout da Borda.
[start=11]
. Arraste um Botão para o ``mainPanel`` . Como o ``mainPanel`` tem layout de borda, o botão automaticamente preenche todo o painel. Altere o nome da variável do botão para ``mainPictureButton`` e mude o texto do botão para "Aguardando imagem..."
[start=12]
. Arraste outro Painel de Rolagem para o espaço abaixo do ``mainScrollPane`` . Expanda o novo painel de rolagem para preencher todo o espaço livre remanescente. Altere o nome da variável do novo painel de rolagem para ``thumbnailScrollPane`` .
[start=13]
. Arraste um Painel para o ``thumbnailScrollPane`` . Altere o nome da variável do Painel para ``thumbnailPanel`` . Defina o layout do ``thumbnailPanel`` para Layout de Grade.
[start=14]
. Arraste quatro Botões para o ``thumbnailPanel`` Como o ``thumbnailPanel`` tem Layout de Grade, os botões são automaticamente de mesmo tamanho e preenchem o painel completamente. As propriedades dos botões são: Botões no thumbnailPanel
|===
|Nome da Variável |Texto
|asterButton |Aguardando...
|honeysuckleButton |Aguardando...
|roseButton |Aguardando
|sunflowerButton |Aguardando...
|===
O Form JFrame agora está totalmente projetado. Nesse ponto, o ``FlowerFrame`` deverá ter a seguinte aparência.
image::images/designed-form.png[title="Quadro de Flores Concluído mostrando os textos do botão em vez de imagens"]
== Vinculando os Componentes do JFrame
Nesta seção, você inicializará os componentes no construtor e vinculará os componentes aos listeners. Os listeners chamam o código que mostra as imagens das flores.
=== [[Inicializando os Componentes]]
[[Nesta seção, você preencherá o construtor ``FlowerFrame``
]]
1. Alterne para a view de Código-fonte do editor. Localize o início do corpo da classe ``FlowerFrame`` e o construtor ``FlowerFrame`` .
image::images/ff-empty-constructor.png[]
. Na parte superior do corpo da classe do ``FlowerFrame`` , antes do construtor, crie um array de strings dos nomes de cada flor.
[source,java]
----
protected static final String[] FLOWERS = {"aster", "honeysuckle", "rose", "sunflower"};
----
. Entre o array da string FLOWERS e o construtor, adicione uma linha que inicialize um ``link:http://download.oracle.com/javase/6/docs/api/java/util/Map.html[+java.util.Map+]`` denominado ``flores`` . O mapa utiliza uma ``String`` e a mapeia para uma ``Image`` .
[source,java]
----
private Map<String, Image> flowers;
----
. Adicione instruções de importação para ``java.util.Map`` e ``java.awt.Image`` .
. Adicione código ao construtor ``FlowerFrame`` para associar uma ``Image`` específica a uma ``String`` específica de uma instância específica do mapa ``flowers``
[source,java]
----
public FlowerFrame(Map<String, Image> flowers) {
this.flowers = flowers;
for (String flower:FLOWERS) {
flowers.put(flower,null);
}
initComponents();
}
----
[start=3]
. Inicialize ``ItemListener`` s para os botões de opções e ``ActionListener`` s para os quatro botões de flores e defina o título default.
[source,java]
----
public FlowerFrame(Map<String, Image> flowers) {
this.flowers = flowers;
for (String flower:FLOWERS) {
flowers.put(flower,null);
}
initComponents();
setTitle("Garden Flowers [waiting for picture]");
ItemListener rbListener = new RBListener();
asterRadioButton.addItemListener(rbListener);
honeysuckleRadioButton.addItemListener(rbListener);
roseRadioButton.addItemListener(rbListener);
sunflowerRadioButton.addItemListener(rbListener);
ActionListener bListener = new ButtonListener();
asterButton.addActionListener(bListener);
honeysuckleButton.addActionListener(bListener);
roseButton.addActionListener(bListener);
sunflowerButton.addActionListener(bListener);
}
----
[start=4]
. Adicione instruções de importação para ``link:http://download.oracle.com/javase/6/docs/api/java/awt/event/ItemListener.html[+java.awt.event.ItemListener+]`` e ``link:http://download.oracle.com/javase/6/docs/api/java/awt/event/ActionListener.html[+java.awt.event.ActionListener+]`` .
Agora, o construtor está completo. Você receberá advertências de erros de compilação no código porque ele não contém as classes ``RBListener`` e ``ButtonListener`` . Essas duas classes são implementações personalizadas do ``ItemListener`` e ``ActionListener`` , respectivamente. Você escreverá essas duas classes na próxima seção.
=== [[Mostrando as Flores]]
[[Nesta seção, você escreverá listeners personalizados para os botões de opções e os botões de flores. Você também escreverá um método que determinará qual flor será selecionada pelos botões e obterá uma ``Image`` daquela flor a partir do mapa ``flowers`` . Finalmente, você escreverá um método que é chamado pela classe ``Main`` e que obterá uma ``Image`` para cada miniatura.
]]
1. Encontre o método ``public static void main(String args[])`` no corpo da classe ``FlowerFrame`` . Delete esse método e sua documentação. (A aplicação utilizará a classe ``Main`` .)
. No lugar do método ``main`` , escreva um ``ItemListener`` personalizado para os botões de opções. Esse listener mostrará uma nova imagem de flor quando um botão de opção for selecionado.
[source,java]
----
private class RBListener implements ItemListener {
public void itemStateChanged(ItemEvent e) {
showFlower();
}
}
----
. Adicione uma instrução de importação para ``link:http://download.oracle.com/javase/6/docs/api/java/awt/event/ItemEvent.html[+java.awt.event.ItemEvent+]`` .
. Abaixo do ``ItemListener`` personalizado, escreva um ``ActionListener`` personalizado para os quatro botões de flores. Quando um botão for clicado, o listener selecionará o botão de opção relacionado:
[source,java]
----
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == asterButton) asterRadioButton.setSelected(true);
else if (e.getSource() == honeysuckleButton) honeysuckleRadioButton.setSelected(true);
else if (e.getSource() == roseButton) roseRadioButton.setSelected(true);
else if (e.getSource() == sunflowerButton) sunflowerRadioButton.setSelected(true);
}
}
----
[start=2]
. Adicione uma instrução de importação para ``link:http://download.oracle.com/javase/6/docs/api/java/awt/event/ActionEvent.html[+java.awt.event.ActionEvent+]`` .
[start=3]
. Abaixo do ``ActionListener`` personalizado, escreva o método ``showFlower`` . Esse método determina o botão de opção selecionado e obtém uma ``Image`` da flor correspondente a partir do mapa ``flowers`` .
[source,java]
----
void showFlower() {
Image img = null;
if (asterRadioButton.isSelected()) {
img = flowers.get("aster");
if (img != null) {
mainPictureButton.setIcon(new ImageIcon(img));
setTitle("Garden Flowers [Aster]");
}
} else if (honeysuckleRadioButton.isSelected()) {
img = flowers.get("honeysuckle");
if (img != null) {
mainPictureButton.setIcon(new ImageIcon(img));
setTitle("Garden Flowers [Honeysuckle]");
}
} else if (roseRadioButton.isSelected()) {
img = flowers.get("rose");
if (img != null) {
mainPictureButton.setIcon(new ImageIcon(img));
setTitle("Garden Flowers [Rose]");
}
} else if (sunflowerRadioButton.isSelected()) {
img = flowers.get("sunflower");
if (img != null) {
mainPictureButton.setIcon(new ImageIcon(img));
setTitle("Garden Flowers [Sunflower]");
}
}
if (img == null) {
mainPictureButton.setIcon(null);
setTitle("Garden Flowers [waiting for picture]");
} else mainPictureButton.setText("");
}
----
[start=4]
. Adicione uma instrução de importação para ``link:http://download.oracle.com/javase/6/docs/api/javax/swing/ImageIcon.html[+javax.swing.ImageIcon+]`` .
[start=5]
. Escreva o método ``setThumbnails`` . Esse método obtém uma imagem para cada miniatura do mapa ``flowers`` . A classe ``Main`` chama esse método.
[source,java]
----
void setThumbnails(Map<String, Image> thumbs) {
Image img = thumbs.get("aster");
if (img != null) {
asterButton.setIcon(new ImageIcon(img));
asterButton.setText("");
}
img = thumbs.get("honeysuckle");
if (img != null) {
honeysuckleButton.setIcon(new ImageIcon(img));
honeysuckleButton.setText("");
}
img = thumbs.get("rose");
if (img != null) {
roseButton.setIcon(new ImageIcon(img));
roseButton.setText("");
}
img = thumbs.get("sunflower");
if (img != null) {
sunflowerButton.setIcon(new ImageIcon(img));
sunflowerButton.setText("");
}
}
----
[start=6]
. Corrija as importações em ``FlowerFrame`` , caso elas não tenham sido corrigidas quando foram coladas no código. É possível corrigir todas de uma vez clicando com o botão direito do mouse no editor e selecionando Corrigir Importações, no menu de contexto. O conjunto completo de instruções de importação é:
[source,java]
----
import java.awt.Image;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.ItemEvent;import java.awt.event.ItemListener;import java.util.Map;import javax.swing.ImageIcon;
----
O ``FlowerFrame`` agora está completo.
== [[Codificando a Classe Principal]]
[[Nesta seção, você completará a classe ``Main`` para que mostre o ``FlowerFrame`` , estabelecerá uma conexão com o Web service e chamará as operações do Web service.
1. Abra a classe ``Main.java`` no editor.
image::images/main-empty.png[]
[start=2]
. No corpo da classe, antes do método ``principal`` , inicialize uma variável ``int`` para a quantidade de imagens obtidas por download.
[source,java]
----
private static int downloadedPictures;
----
[start=3]
. No corpo do método ``main`` , crie um ``HashMap`` de quatro flores e outro ``HashMap`` de quatro miniaturas.
[source,java]
----
final Map<String,Image> flowers = new HashMap<String,Image>(4);
final Map<String,Image> thumbs = new HashMap<String,Image>(4);
----
[start=4]
. Adicione instruções de importação para ``java.awt.Image`` , ``java.util.Map`` e ``java.util.HashMap`` .
[start=5]
. No corpo do método ``main`` , adicione código para mostrar o ``FlowerFrame`` .*// Show the FlowerFrame.*
[source,java]
----
final FlowerFrame frame = new FlowerFrame(flowers);
frame.setVisible(true);
----
[start=6]
. No corpo do método ``main`` , adicione o código para conectar o cliente ao serviço.*// The client connects to the service with this code.*
[source,java]
----
FlowerServiceService service = new FlowerServiceService();
final FlowerService port = service.getFlowerServicePort();
----
[start=7]
. Adicione instruções de importação para ``org.flower.service.FlowerService`` e ``org.flower.service.FlowerServiceService`` .
[start=8]
. No corpo do método ``main`` , adicione o código que cria um array de quatro threads ``Runnable`` e chama a operação ``getFlower`` do Web service uma vez em cada thread.*// The web service getFlower operation
// is called 4 times, each in a separate thread.
// When the operation finishes the picture is shown in
// a specific button.*
[source,java]
----
Runnable[] tasks = new Runnable[4];
for (int i=0; i<4;i++) {
final int index = i;
tasks[i] = new Runnable() {
public void run() {
try {
*// Call the getFlower operation
// on the web service:*
Image img = port.getFlower(FlowerFrame.FLOWERS[index]);
System.out.println("picture downloaded: "+FlowerFrame.FLOWERS[index]);
*// Add strings to the hashmap:*
flowers.put(FlowerFrame.FLOWERS[index],img);
*// Call the showFlower operation
// on the FlowerFrame:*
frame.showFlower();
} catch (IOException_Exception ex) {
ex.printStackTrace();
}
downloadedPictures++;
}
};
new Thread(tasks[i]).start();
}
----
[start=9]
. Adicione uma instrução de importação para ``org.flower.service.IOException_Exception`` .
[start=10]
. No corpo do método ``principal`` , adicione o código que chama a operação ``getThumbnails`` do Web service em um thread separado.*// The web service getThumbnails operation is called
// in a separate thread, just after the previous four threads finish.
// When the images are downloaded, the thumbnails are shown at
// the bottom of the frame.*
[source,java]
----
Runnable thumbsTask = new Runnable() {
public void run() {
try {
while (downloadedPictures < 4) {
try {Thread.sleep(100);} catch (InterruptedException ex) {}
}
*// Call the getThumbnails operation
// on the web service:*
List<Image> images = port.getThumbnails();
System.out.println("thumbs downloaded");
if (images != null &amp;&amp; images.size() == 4) {
for (int i=0;i<4;i++) {
thumbs.put(FlowerFrame.FLOWERS[i],images.get(i));
}
frame.setThumbnails(thumbs);
}
} catch (IOException_Exception ex) {
ex.printStackTrace();
}
}
};
new Thread(thumbsTask).start();
----
[start=11]
. Corrija as importações em ``Main.java`` , caso elas não tenham sido corrigidas quando foram coladas no código. É possível corrigir todas de uma vez clicando com o botão direito do mouse no editor e selecionando Corrigir Importações, no menu de contexto. Você verá uma Lista de classes para importação; selecione ``java.util.List`` . O conjunto completo de instruções de importação é:
[source,java]
----
import flower.album.FlowerService;import flower.album.FlowerService_Service;import flower.album.IOException_Exception;import java.awt.Image;import java.util.HashMap;import java.util.List;import java.util.Map;
----
A classe ``Main`` agora está completa.
[source,java]
----
public class Main {
private static int downloadedPictures;
public static void main(String[] args) {
final Map<String,Image> flowers = new HashMap<String,Image>(4);
final Map<String,Image> thumbs = new HashMap<String,Image>(4);
*// Show the FlowerFrame.*
final FlowerFrame frame = new FlowerFrame(flowers);
frame.setVisible(true);
* // The client connects to the service with this code.*
FlowerService_Service service = new FlowerService_Service();
final FlowerService port = service.getFlowerServicePort();
Runnable[] tasks = new Runnable[4];
*// The web service getFlower operation
// is called 4 times, each in a separate thread.
// When the operation finishes the picture is shown in
// a specific button.*
for (int i=0; i<4;i++) {
final int index = i;
tasks[i] = new Runnable() {
public void run() {
try {
*// Call the getFlower operation
// on the web service:*
Image img = port.getFlower(FlowerFrame.FLOWERS[index]);
System.out.println("picture downloaded: "+FlowerFrame.FLOWERS[index]);
*// Add strings to the hashmap:*
flowers.put(FlowerFrame.FLOWERS[index],img);
*// Call the showFlower operation
// on the FlowerFrame:*
frame.showFlower();
} catch (IOException_Exception ex) {
ex.printStackTrace();
}
downloadedPictures++;
}
};
new Thread(tasks[i]).start();
}
*// The web service getThumbnails operation is called
// in a separate thread, just after the previous four threads finish.
// When the images are downloaded, the thumbnails are shown at
// the bottom of the frame.*
Runnable thumbsTask = new Runnable() {
public void run() {
try {
while (downloadedPictures < 4) {
try {Thread.sleep(100);} catch (InterruptedException ex) {}
}
*// Call the getThumbnails operation
// on the web service:*
List<Image> images = port.getThumbnails();
System.out.println("thumbs downloaded");
if (images != null &amp;&amp; images.size() == 4) {
for (int i=0;i<4;i++) {
thumbs.put(FlowerFrame.FLOWERS[i],images.get(i));
}
frame.setThumbnails(thumbs);
}
} catch (IOException_Exception ex) {
ex.printStackTrace();
}
}
};
new Thread(thumbsTask).start();
}
}
----
A aplicação cliente agora está completa, com o código que interage com o Web service que é delegado ao módulo EJB para a exposição de suas imagens. Clique com o botão direito do mouse no cliente e selecione Executar. A aplicação Swing é iniciada e, depois de um tempo, é preenchida com as imagens recebidas do Web service. Se as imagens não aparecerem, limpe e construa o projeto FlowerService e execute-o novamente. Observe que é possível alterar a imagem exibida no quadro principal selecionando um botão de opção ou clicando em uma miniatura.
]]
link:/about/contact_form.html?to=3&subject=Feedback:%20Flower%20Swing%20Client%20EE6[+Enviar Feedback neste Tutorial+]
Para enviar comentários e sugestões, obter suporte e se manter informado sobre os mais recentes desenvolvimentos das funcionalidades de desenvolvimento Java EE do NetBeans IDE, link:../../../community/lists/top.html[+inscreva-se na lista de notícias nbj2ee@netbeans.org+].