blob: 8bb40e66a618595a2e76a6c1bcb5d00d4bafaf85 [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<!-- -*- xhtml -*- -->
<title>Tutorial do aplicativo NetBeans CRUD para a plataforma NetBeans 6.5</title>
<meta name="AUDIENCE" content="NBUSER">
<meta name="TYPE" content="ARTICLE">
<meta name="EXPIRES" content="N">
<meta name="developer" content="gwielenga@netbeans.org">
<meta name="indexed" content="y">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="description"
content="A guide describing how to create a CRUD application on
NetBeans Platform 6.5.">
<link rel="stylesheet" type="text/css" href="https://netbeans.org/netbeans.css">
<!-- Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. -->
<!-- Use is subject to license terms.-->
</head>
<body>
<h1><a name="top"></a>Tutorial do aplicativo CRUD para a plataforma NetBeans</h1>
<p>Este tutorial mostra como integrar um banco de dados Java DB com um aplicativo da plataforma NetBeans. Come&ccedil;amos por explorar um banco de dados Java DB, do qual criamos uma classe de entidade. No entanto, observe que estas instru&ccedil;&otilde;es n&atilde;o s&atilde;o aplic&aacute;veis somente ao Java DB. Ao inv&eacute;s disso, elas s&atilde;o relevantes para qualquer banco de dados relacional suportado pelo NetBeans IDE. A seguir, colocamos as classes da entidade em um m&oacute;dulo, junto com os m&oacute;dulos dos JPA JARS relacionados.
<p>Uma vez que os m&oacute;dulos acima fizerem parte do nosso aplicativo, criamos um novo m&oacute;dulo que fornece a interface do usu&aacute;rio para o nosso aplicativo. O novo m&oacute;dulo fornece ao usu&aacute;rio uma hierarquia em &aacute;rvore mostrando os dados do banco de dados. N&oacute;s ent&atilde;o criamos outro m&oacute;dulo que permite que o usu&aacute;rio edite os dados exibidos pelo primeiro m&oacute;dulo. Ao separar o visualizador do editor em m&oacute;dulos distintos, permitimos que o usu&aacute;rio instale um editor diferente para o mesmo visualizador, j&aacute; que editores diferentes poderiam ser criados por fornecedores externos, alguns comercialmente e alguns sem custo. &Eacute; esta a flexibilidade que a arquitetura modular da plataforma NetBeans torna poss&iacute;vel.
<p>Uma vez que tivermos um editor, come&ccedil;amos a adicionar a funcionalidade CRUD. Primeiro, o &quot;R&quot; que indica &quot;Read&quot; (ler) &eacute; manipulado pelo visualizador acima descrito. A seguir, &eacute; manipulado o &quot;U&quot; para &quot;Update&quot; (atualizar), seguido pelo &quot;C&quot; para &quot;Create&quot; (criar) e pelo &quot;D&quot; para &quot;Delete&quot; (excluir).
<p>Ao final do tutorial, voc&ecirc; ter&aacute; aprendido sobre a gama de recursos da plataforma NetBeans que lhe ajudam na cria&ccedil;&atilde;o de aplicativos deste tipo. Por exemplo, voc&ecirc; aprendeu sobre o <tt><a href="http://bits.netbeans.org/dev/javadoc/org-openide-awt/org/openide/awt/UndoRedo.Manager.html">UndoRedo.Manager</a></tt> e o <tt><a href="http://bits.netbeans.org/dev/javadoc/org-openide-explorer/org/openide/explorer/ExplorerManager.html">ExplorerManager</a></tt>, assim como sobre os componentes Swing da plataforma NetBeans, tais como <tt><a href="http://bits.netbeans.org/dev/javadoc/org-openide-windows/org/openide/windows/TopComponent.html">TopComponent</a></tt> e <tt><a href="http://bits.netbeans.org/dev/javadoc/org-openide-explorer/org/openide/explorer/view/BeanTreeView.html">BeanTreeView</a></tt>.
<p><b class="notes">Nota:</b> este documento usa a vers&atilde;o NetBeans IDE 6.8. Se voc&ecirc; estiver utilizando uma vers&atilde;o anterior, veja <a href="67/nbm-crud.html">a vers&atilde;o 6.7 deste documento</a>.</p>
<p><b>Conte&uacute;do</b></p>
<p><img src="../images/articles/69/netbeans-stamp8-9.png" class="stamp" width="114" height="114" alt="O conte&uacute;do desta p&aacute;gina se aplica ao NetBeans IDE 6.5, 6.7, 6.8" title="O conte&uacute;do desta p&aacute;gina se aplica ao NetBeans IDE 6.5, 6.7, 6.8" /></p>
<ul class="toc">
<li><a href="#creating-app">Configurando o aplicativo</a></li>
<li><a href="#integrating-database">Integrando o banco de dados</a>
<ul>
<li><a href="#creating-entity">Criando classes de entidade de um banco de dados</a></li>
<li><a href="#wrapping-entity">Colocando a classe da entidade JAR em um m&oacute;dulo</a></li>
<li><a href="#creating-other">Criando outros m&oacute;dulos relacionados</a></li>
<li><a href="#designing-ui">Projetando a interface do usu&aacute;rio</a></li>
<li><a href="#setting-dependencies">Configurando as depend&ecirc;ncias</a></li>
<li><a href="#running-prototype">Executando o prot&oacute;tipo</a></li>
</ul>
<li><a href="#integrating-crud">Integrando a funcionalidade CRUD</a>
<ul>
<li><a href="#read">Ler</a></li>
<li><a href="#update">Atualizar</a></li>
<li><a href="#create">Criar</a></li>
<li><a href="#delete">Excluir</a></li>
</ul>
</li>
</ul>
<p><b>Para seguir este tutorial, os softwares e recursos listados na tabela seguinte s&atilde;o necess&aacute;rios.</b></p>
<table>
<tbody>
<tr>
<th class="tblheader" scope="col">Software ou recurso</th>
<th class="tblheader" scope="col">Vers&atilde;o necess&aacute;ria</th>
</tr>
<tr>
<td class="tbltd1"><a href="https://netbeans.org/downloads/index.html">NetBeans IDE</a></td>
<td class="tbltd1">vers&atilde;o 6.8</td>
</tr>
<tr>
<td class="tbltd1"><a href="http://java.sun.com/javase/downloads/index.jsp">Java Developer Kit (JDK)</a></td>
<td class="tbltd1">Vers&atilde;o 6 ou<br/>vers&atilde;o 5</td>
</tr>
</tbody>
</table>
<p>O aplicativo que voc&ecirc; criar&aacute; neste tutorial ter&aacute; esta apar&ecirc;ncia:</p>
<p><img alt="o estado final do aplicativo" src="http://netbeans.dzone.com/sites/all/files/customer-app-on-nb.png" /> </p>
<p class="tips"> &Eacute; aconselh&aacute;vel assistir &agrave; s&eacute;rie de screencasts <a href="https://platform.netbeans.org/tutorials/nbm-10-top-apis.html">As 10 principais APIs do NetBeans</a> antes de come&ccedil;ar a trabalhar neste tutorial. Muitos dos conceitos tratados neste tutorial s&atilde;o discutidos em maior detalhe dentro da s&eacute;rie de screencasts.
<p>
<!-- ===================================================================================== -->
<br>
<h2 class="tutorial"><a name="creating-app"></a>Configurando o aplicativo</h2>
<p>Vamos come&ccedil;ar criando um novo aplicativo NetBeans.
<ol>
<li>Escolha Arquivo &gt; Novo projeto (Ctrl-Shift-N). Em Categorias, selecione M&oacute;dulos do NetBeans. Em Projetos, selecione Aplicativo da plataforma NetBeans. Clique em Pr&oacute;ximo.</li>
<li>No painel Nome e localiza&ccedil;&atilde;o, digite <tt>DBManager</tt> no campo Nome do projeto. Clique em Terminar.</li>
</ol>
<p>O IDE cria o projeto <tt>DBManager</tt>. O projeto &eacute; um cont&ecirc;iner para todos os outros m&oacute;dulos que voc&ecirc; criar&aacute;.
<p><img alt="Cont&ecirc;iner da plataforma NetBeans" src="../images/tutorials/crud/68dbmanager-1.png" /> </p>
<br>
<!-- ===================================================================================== -->
<br>
<h2><a name="integrating-database"></a>Integrando o banco de dados</h2>
<p>Para poder integrar o banco de dados, &eacute; preciso criar classes de entidades de seu banco de dados e integrar essas classes de entidades, junto com seus JARs relacionados, com os m&oacute;dulos que fazem parte de seu aplicativo da plataforma NetBeans.</p>
<div class="indent">
<h3 class="tutorial"><a name="creating-entity"></a>Criando as classes de entidade</h3>
<p>Nesta se&ccedil;&atilde;o, voc&ecirc; gera classes de entidade de um banco de dados selecionado.
<ol>
<li>Neste exemplo, utilize a janela Servi&ccedil;os para conectar-se ao banco de dados de amostra que est&aacute; inclu&iacute;do no NetBeans IDE:
<p><img alt="janela Servi&ccedil;os" src="../images/tutorials/crud/68dbmanager-2.png" /> </p>
<p class="tips"> Alternativamente, use qualquer banco de dados que desejar e adapte as etapas que se seguem para seu caso particular. No caso do MySQL, consulte <a href="https://netbeans.org/kb/docs/ide/mysql_pt_BR.html">Conectando-se a um banco de dados MySQL</a>.</p>
<p><li>No IDE, escolha Arquivo | Novo projeto, seguido por Java | Biblioteca de classes Java, para criar uma nova biblioteca denominada <tt>CustomerLibrary</tt>.
<p><li>Na janela Projetos, clique com o bot&atilde;o direito do mouse no projeto da biblioteca e escolha Arquivo | Novo arquivo, seguido por Persist&ecirc;ncia | Classes de entidade do banco de dados. No assistente, selecione o banco de dados e as tabelas necess&aacute;rias. Aqui, escolhemos &quot;Customer&quot; e, a seguir, &quot;Discount Code&quot; &eacute; adicionado automaticamente, dado que h&aacute; uma rela&ccedil;&atilde;o entre estas duas tabelas.
<p><img alt="adicionando tabelas" src="../images/tutorials/crud/68dbmanager-3.png" /> </p>
<p><li>Especifique a estrat&eacute;gia de persist&ecirc;ncia, que pode ser qualquer uma das op&ccedil;&otilde;es dispon&iacute;veis. Aqui, visto que precisamos escolher algo, escolheremos EclipseLink:
<p><img alt="escolhendo eclipselink" src="../images/tutorials/crud/68dbmanager-4.png" /> </p>
<p><li>Especifique &quot;demo&quot; como o nome do pacote no qual as classes de entidade ser&atilde;o geradas.
<p><img alt="nome do pacote" src="../images/tutorials/crud/68dbmanager-5.png" /> </p>
<p><li>Clique em Terminar. Ap&oacute;s ter completado esta etapa, examine o c&oacute;digo gerado e observe que, entre outras coisas, voc&ecirc; agora tem um arquivo <tt>persistence.xml</tt> em uma pasta denominada META-INF, assim como as classes de entidade para cada uma de suas tabelas:
<p><img alt="classes de entidade" src="../images/tutorials/crud/68dbmanager-7.png" /> </p>
<p><li>Construa a biblioteca Java e voc&ecirc; ter&aacute; um arquivo JAR na pasta &quot;dist&quot; do projeto da biblioteca, a qual poder&aacute; visualizar na janela Arquivos:
<p><img alt="pasta dist" src="../images/tutorials/crud/68dbmanager-8.png" /> </p>
</li>
</ol>
<h3 class="tutorial"><a name="wrapping-entity"></a>Colocando a classe da entidade JAR em um m&oacute;dulo</h3>
<p>Nesta se&ccedil;&atilde;o, voc&ecirc; adiciona seu primeiro m&oacute;dulo ao aplicativo! O novo m&oacute;dulo NetBeans conter&aacute; o arquivo JAR que voc&ecirc; criou na se&ccedil;&atilde;o anterior.
<ol>
<li>Clique com o bot&atilde;o direito do mouse no n&oacute; do m&oacute;dulo <tt>DBManager</tt> na janela Projetos e escolha Adicionar nova biblioteca.
<p><li>Selecione o JAR criado na subse&ccedil;&atilde;o anterior e complete o assistente, especificando quaisquer valores que desejar. Vamos supor que o aplicativo destina-se a tratar com clientes no shop.org, em cujo caso um identificador &uacute;nico &quot;org.shop.model&quot; &eacute; apropriado para o nome de base do c&oacute;digo:
<p><img alt="id &uacute;nico do m&oacute;dulo" src="../images/tutorials/crud/68dbmanager-9.png" /> </p>
</ol>
<p>Voc&ecirc; agora tem seu primeiro m&oacute;dulo personalizado no novo aplicativo, contendo o JAR que cont&eacute;m as classes de entidade e o arquivo persistence.xml:</p>
<p><img alt="persistence.xml" src="../images/tutorials/crud/68dbmanager-91.png" /> </p>
<h3 class="tutorial"><a name="creating-other"></a>Criando outros m&oacute;dulos relacionados</h3>
<p>Nesta se&ccedil;&atilde;o, voc&ecirc; cria dois novos m&oacute;dulos, colocando o EclipseLinks JARs, assim como o JAR do conector do banco de dados.
<ol>
<li>Fa&ccedil;a o mesmo que fez ao criar o wrapper de bibliotecas para a classe de entidade JAR, mas desta vez para os JARs de EclipseLink, que est&atilde;o na biblioteca Java &quot;CustomerLibrary&quot; criada anteriormente:
<p><img alt="empacotando um biblioteca" src="../images/tutorials/crud/68dbmanager-94.png" /></p>
<p class="tips"> No assistente para m&oacute;dulo de wrapper de bibliotecas, voc&ecirc; pode usar Ctrl-clique para selecionar v&aacute;rios JARs.</p>
<p><li>A seguir, crie outro m&oacute;dulo de wrapper de bibliotecas, desta vez para o JAR cliente do banco de dados Java DB, que est&aacute; dispon&iacute;vel na sua distribui&ccedil;&atilde;o do JDK em <tt>db/lib/derbyclient.jar</tt>.
</ol>
<h3 class="tutorial"><a name="designing-ui"></a>Projetando a interface do usu&aacute;rio</h3>
<p>Nesta se&ccedil;&atilde;o, voc&ecirc; cria um prot&oacute;tipo simples de interface do usu&aacute;rio, fornecendo uma janela que usa uma <tt>JTextArea</tt> para exibir os dados recuperados do banco de dados.
<ol>
<li>Clique com o bot&atilde;o direito do mouse no n&oacute; do m&oacute;dulo <tt>DBManager</tt> na janela Projetos e escolha Adicionar novo. Crie um novo m&oacute;dulo denominado <tt>CustomerViewer</tt>, com o nome de base de c&oacute;digo <tt>org.shop.ui</tt>.
<p><li>Na janela Projetos, clique com o bot&atilde;o direito do mouse no novo m&oacute;dulo e escolha Novo | Componente de janela. Especifique que ele deve ser criado na posi&ccedil;&atilde;o do <tt>editor</tt> e que deve ser aberto quando o aplicativo for iniciado. Defina <tt>Customer</tt> como o prefixo do nome da classe da janela.
<p><li>Utilize a paleta (Ctrl-Shift-8) para arrastar e soltar uma <tt>JTextArea</tt> na nova janela:
<p><img alt="JTextArea selecionado" src="../images/tutorials/crud/68dbmanager-93.png" /></p>
<p><li>Adicione isso no fim do construtor TopComponent:
<pre class="examplecode">EntityManager entityManager = Persistence.createEntityManagerFactory(&quot;CustomerLibraryPU&quot;).createEntityManager();
Query query = entityManager.createQuery(&quot;SELECT c FROM Customer c&quot;);
List&lt;Customer&gt; resultList = query.getResultList();
for (Customer c : resultList) {
jTextArea1.append(c.getName() + &quot; (&quot; + c.getCity() + &quot;)&quot; + &quot;\n&quot;);
}</pre>
<p class="tips"> Como voc&ecirc; n&atilde;o definiu depend&ecirc;ncias no m&oacute;dulo que fornece o objeto Customer e as JARS de persist&ecirc;ncia, as declara&ccedil;&otilde;es acima ser&atilde;o marcadas com linhas sublinhadas em vermelho indicando o erro. Esses ser&atilde;o corrigidos na se&ccedil;&atilde;o que segue.</p>
<p>Acima, &eacute; poss&iacute;vel ver as refer&ecirc;ncias &agrave; unidade de persist&ecirc;ncia denominada &quot;CustomerLibraryPU&quot;, que &eacute; o mesmo nome definido no arquivo <tt>persistence.xml</tt>. Al&eacute;m disso, h&aacute; uma refer&ecirc;ncia a uma das classes de entidade, denominada <tt>Customer</tt>, que est&aacute; no m&oacute;dulo de classes de entidade. Adapte estas partes &agrave;s suas necessidades caso sejam diferentes das de cima.
</ol>
<h3 class="tutorial"><a name="setting-dependencies"></a>Configurando as depend&ecirc;ncias</h3>
<p>Nesta se&ccedil;&atilde;o, voc&ecirc; habilita alguns dos m&oacute;dulos para utilizar o c&oacute;digo de alguns dos outros m&oacute;dulos. Voc&ecirc; faz isso de forma bem expl&iacute;cita ao definir contratos intencionais entre m&oacute;dulos relacionados, ou seja, o oposto &agrave; reutiliza&ccedil;&atilde;o acidental e ca&oacute;tica do c&oacute;digo, que tende a acontecer quando n&atilde;o h&aacute; uma arquitetura modular estrita, como a fornecida pela plataforma NetBeans.
<ol>
<li>O m&oacute;dulo de classes de entidade precisa ter depend&ecirc;ncias no m&oacute;dulo Derby Client, assim como no m&oacute;dulo EclipseLink. Clique com o bot&atilde;o direito do mouse no m&oacute;dulo <tt>CustomerLibrary</tt>, escolha Propriedades e utilize a aba Bibliotecas para definir as depend&ecirc;ncias nos dois m&oacute;dulos que o m&oacute;dulo <tt>CustomerLibrary</tt> necessita.
<p><li>O m&oacute;dulo <tt>CustomerViewer</tt> precisa de uma depend&ecirc;ncia no m&oacute;dulo EclipseLink, assim como no m&oacute;dulo de classes de entidade. Clique com o bot&atilde;o direito do mouse no m&oacute;dulo <tt>CustomerViewer</tt>, escolha Propriedades e utilize a aba Bibliotecas para definir as depend&ecirc;ncias nos dois m&oacute;dulos que o m&oacute;dulo <tt>CustomerViewer</tt> necessita.
<p><li>Abra o <tt>CustomerTopComponent</tt> na visualiza&ccedil;&atilde;o C&oacute;digo-fonte, clique com o bot&atilde;o direito do mouse no editor e escolha &quot;Corrigir importa&ccedil;&otilde;es&quot;. O IDE agora &eacute; capaz de adicionar as declara&ccedil;&otilde;es importadas, porque os m&oacute;dulos que fornecem as classes necess&aacute;rias agora est&atilde;o dispon&iacute;veis no <tt>CustomerTopComponent</tt>.
</ol>
<p>Voc&ecirc; agora definiu os contratos entre os m&oacute;dulos em seu aplicativo, fornecendo-lhe o controle sobre as depend&ecirc;ncias entre as distintas partes do c&oacute;digo.
<h3 class="tutorial"><a name="running-prototype"></a>Executando o prot&oacute;tipo</h3>
<p>Nesta se&ccedil;&atilde;o, voc&ecirc; executa o aplicativo para que possa ver se est&aacute; acessando corretamente seu banco de dados.
<ol>
<li>Inicie seu servidor de banco de dados.
<p><li>Execute o aplicativo. O seguinte dever&aacute; ser exibido:
<p><img alt="executando o prot&oacute;tipo" src="../images/tutorials/crud/68dbmanager-92.png" /></p>
</ol>
<p>Voc&ecirc; agora tem um prot&oacute;tipo simples que compreende um aplicativo da plataforma NetBeans que exibe os dados do seu banco de dados, o qual ser&aacute; ampliado na pr&oacute;xima se&ccedil;&atilde;o.
</div>
<br>
<h2><a name="integrating-crud"></a>Integrando a funcionalidade CRUD</h2>
<p>Para poder criar a funcionalidade CRUD que se integra com suavidade &agrave; plataforma NetBeans, alguns padr&otilde;es bem espec&iacute;ficos de codifica&ccedil;&atilde;o da plataforma NetBeans precisam ser implementados. A se&ccedil;&atilde;o que segue descreve esses padr&otilde;es em detalhes.</p>
<div class="indent">
<h3 class="tutorial"><a name="read"></a>Ler</h3>
<p>Nesta se&ccedil;&atilde;o, voc&ecirc; altera a <tt>JTextArea</tt>, apresentada na se&ccedil;&atilde;o anterior, para uma visualiza&ccedil;&atilde;o do explorador da plataforma NetBeans. As visualiza&ccedil;&otilde;es do explorador da plataforma NetBeans s&atilde;o componentes Swing que se integram melhor com a plataforma NetBeans do que os componentes padr&atilde;o do Swing. Entre outras coisas, elas oferecem suporte &agrave; no&ccedil;&atilde;o de um contexto, o que permite que elas detectem o contexto.
<p>Ao representar seus dados, voc&ecirc; ter&aacute; um modelo hier&aacute;rquico gen&eacute;rico fornecido por uma classe <tt>Node</tt> da plataforma NetBeans, que pode ser exibido por quaisquer das visualiza&ccedil;&otilde;es do explorador da plataforma NetBeans. Esta se&ccedil;&atilde;o termina com uma explica&ccedil;&atilde;o de como sincronizar as visualiza&ccedil;&otilde;es do explorador com a janela Propriedades da plataforma NetBeans.
<ol>
<li>Em seu <tt>TopComponent</tt>, exclua a <tt>JTextArea</tt> na visualiza&ccedil;&atilde;o Desenho e comente seu c&oacute;digo relacionado na visualiza&ccedil;&atilde;o C&oacute;digo-fonte:
<pre class="examplecode">EntityManager entityManager = Persistence.createEntityManagerFactory(&quot;CustomerLibraryPU&quot;).createEntityManager();
Query query = entityManager.createQuery(&quot;SELECT c FROM Customer c&quot;);
List&lt;Customer&gt; resultList = query.getResultList();
//for (Customer c : resultList) {
// jTextArea1.append(c.getName() + &quot; (&quot; + c.getCity() + &quot;)&quot; + &quot;\n&quot;);
//}</pre>
<p><li>Clique com o bot&atilde;o direito do mouse no m&oacute;dulo <tt>CustomerViewer</tt>, escolha Propriedades e use a aba Bibliotecas para definir as depend&ecirc;ncias nos n&oacute;s da API e a API do explorador e da folha de propriedades.
<p><li>A seguir, altere a assinatura da classe para implementar o <tt>ExplorerManager.Provider</tt>:
<pre class="examplecode">final class CustomerTopComponent extends TopComponent implements ExplorerManager.Provider</pre>
<p>Ser&aacute; necess&aacute;rio sobrepor o <tt>getExplorerManager()</tt>
<pre class="examplecode">@Override
public ExplorerManager getExplorerManager() {
return em;
}</pre>
<p>Acima da classe, declare e inicialize o <tt>ExplorerManager</tt>:
<pre class="examplecode">private static ExplorerManager em = new ExplorerManager();</pre>
<p class="tips"> Assista <a href="https://platform.netbeans.org/tutorials/nbm-10-top-apis.html">As 10 principais APIs do NetBeans</a> para obter os detalhes para o c&oacute;digo acima, especialmente o screencast que trata dos n&oacute;s da API e da API do explorador e da folha de propriedades.
<p><li>Alterne para a visualiza&ccedil;&atilde;o Desenho do <tt>TopComponent</tt> , clique com o bot&atilde;o direito do mouse na paleta, escolha Gerenciador de paleta | Adicionar do JAR. A seguir, v&aacute; a <tt>org-openide-explorer.jar</tt>, que est&aacute; na pasta <tt>platform11/modules</tt>, dentro do diret&oacute;rio de instala&ccedil;&atilde;o do NetBeans IDE. Feche a BeanTreeView e complete o assistente. Agora voc&ecirc; deveria ver a <tt>BeanTreeView</tt> na paleta. Arraste-a da paleta e solte-a na janela.
<p><li>Crie uma classe de f&aacute;brica que criar&aacute; um novo <a href="http://bits.netbeans.org/dev/javadoc/org-netbeans-modules-db/org/netbeans/api/db/explorer/node/BaseNode.html">BeanNode</a> para cada cliente do seu banco de dados:
<pre class="examplecode">import demo.Customer;
import java.beans.IntrospectionException;
import java.util.List;
import org.openide.nodes.BeanNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.openide.util.Exceptions;
public class CustomerChildFactory extends ChildFactory&lt;Customer&gt; {
private List&lt;Customer&gt; resultList;
public CustomerChildFactory(List&lt;Customer&gt; resultList) {
this.resultList = resultList;
}
@Override
protected boolean createKeys(List&lt;Customer&gt; list) {
for (Customer Customer : resultList) {
list.add(Customer);
}
return true;
}
@Override
protected Node createNodeForKey(Customer c) {
try {
return new BeanNode(c);
} catch (IntrospectionException ex) {
Exceptions.printStackTrace(ex);
return null;
}
}
}</pre>
<p><li>De volta ao <tt>CustomerTopComponent</tt>, utilize o <tt>ExplorerManager</tt> para passar a lista de resultados da consulta JPA para <tt>Node</tt>:
<pre class="examplecode">EntityManager entityManager = Persistence.createEntityManagerFactory(&quot;CustomerLibraryPU&quot;).createEntityManager();
Query query = entityManager.createQuery(&quot;SELECT c FROM Customer c&quot;);
List&lt;Customer&gt; resultList = query.getResultList();
<b>em.setRootContext(new AbstractNode(Children.create(new CustomerChildFactory(resultList), true)));</b>
//for (Customer c : resultList) {
// jTextArea1.append(c.getName() + &quot; (&quot; + c.getCity() + &quot;)&quot; + &quot;\n&quot;);
//}</pre>
<p><li>Execute o aplicativo. Quando o aplicativo estiver sendo executado abra a janela Propriedades. Observe que embora os dados estejam dispon&iacute;veis, exibidos em uma <tt>BeanTreeView</tt>, a <tt>BeanTreeView</tt> n&atilde;o est&aacute; sincronizada com a janela Propriedades, que est&aacute; dispon&iacute;vel atrav&eacute;s de Janela | Propriedades. Em outras palavras, nada &eacute; exibido na janela Propriedades quando voc&ecirc; move acima e abaixo na hierarquia da &aacute;rvore.
<p><li>Sincronize a janela Propriedades com <tt>BeanTreeView</tt> ao adicionar o seguinte construtor no <tt>TopComponent</tt>:
<pre class="examplecode">associateLookup(ExplorerUtils.createLookup(em, getActionMap()));</pre>
<p>Aqui adicionamos, do <tt>TopComponent</tt>, o <tt>ActionMap</tt> e o <tt>ExplorerManager</tt> ao <tt>Lookup</tt> do <tt>TopComponent</tt>. Uma consequ&ecirc;ncia disso, &eacute; que a janela Propriedades come&ccedil;a a exibir o nome e o texto da dica de ferramenta do <tt>Node</tt> selecionado.
<p><li>Execute novamente o aplicativo e observe que a janela Propriedades agora est&aacute; sincronizada com a visualiza&ccedil;&atilde;o do explorador:
<p><img alt="sincroniza&ccedil;&atilde;o" src="../images/tutorials/crud/68dbmanager-95.png" />
</ol>
<p>Agora voc&ecirc; pode visualizar seus dados na hierarquia da &aacute;rvore, assim como deveria ser capaz de fazer com um <tt>JTree</tt>. No entanto, tamb&eacute;m &eacute; poss&iacute;vel alternar entre diferentes visualiza&ccedil;&otilde;es do explorador sem a necessidade de alterar nada no modelo porque o <tt>ExplorerManager</tt> faz a media&ccedil;&atilde;o entre o modelo e a visualiza&ccedil;&atilde;o. Finalmente, agora tamb&eacute;m &eacute; poss&iacute;vel sincronizar a visualiza&ccedil;&atilde;o com a janela Propriedades.
<h3 class="tutorial"><a name="update"></a>Atualizar</h3>
<p>Nesta se&ccedil;&atilde;o, primeiramente &eacute; criado um editor. O editor ser&aacute; fornecido por um novo m&oacute;dulo do NetBeans. Portanto, primeiramente &eacute; criado um novo m&oacute;dulo. A seguir, dentro daquele novo m&oacute;dulo, criar&aacute; um novo <tt>TopComponent</tt>, contendo dois <tt>JTextFields</tt>, em cada uma das colunas que deseja permitir que sejam editadas pelo usu&aacute;rio. Ser&aacute; necess&aacute;rio deixar que o m&oacute;dulo do visualizador se comunique com o m&oacute;dulo do editor. Sempre que um novo <tt>Node</tt> for selecionado no m&oacute;dulo do visualizador, voc&ecirc; adicionar&aacute; o objeto <tt>Customer</tt> atual ao <tt>Lookup</tt>. No m&oacute;dulo do editor, voc&ecirc; ouvir&aacute; o <tt>Lookup</tt> para a apresenta&ccedil;&atilde;o dos objetos <tt>Customer</tt>. Sempre que um novo objeto <tt>Customer</tt> for introduzido no <tt>Lookup</tt>, voc&ecirc; atualizar&aacute; o <tt>JTextFields</tt> no editor.
<p>A seguir, voc&ecirc; sincronizar&aacute; seu <tt>JTextFields</tt> com a funcionalidade de Desfazer, Refazer e Salvar da plataforma NetBeans. Em outras palavras, quando o usu&aacute;rio faz altera&ccedil;&otilde;es em um <tt>JTextField</tt>, voc&ecirc; deseja que a funcionalidade existente da plataforma NetBeans se torne dispon&iacute;vel para que, em vez de ter que criar uma nova funcionalidade, voc&ecirc; tenha somente que utilizar o suporte da plataforma NetBeans. Para esse fim, ser&aacute; necess&aacute;rio usar o <tt>UndoRedoManager</tt> junto com o <tt>SaveCookie</tt>.
<ol>
<li>Crie um novo m&oacute;dulo denominado <tt>CustomerEditor</tt> com o <tt>org.shop.editor</tt> como o nome de base do c&oacute;digo.
<p><li>Clique com o bot&atilde;o direito do mouse no m&oacute;dulo <tt>CustomerEditor</tt> e escolha Novo | Componente de janela. Certifique-se de especificar que a janela deve aparecer na posi&ccedil;&atilde;o do <tt>editor</tt> e que deve abrir quando o aplicativo for iniciado. No painel final do assistente, defina &quot;Editor&quot; como o prefixo do nome da classe.
<p><li>Utilize a paleta (Ctrl-Shift-8) para adicionar dois <tt>JLabels</tt> e dois <tt>JTextFields</tt> na nova janela. Defina os textos dos r&oacute;tulos como &quot;Nome&quot; e &quot;Cidade&quot; e defina os nomes das vari&aacute;veis dos dois <tt>JTextFields</tt> como <tt>jTextField1</tt> e <tt>jTextField2</tt>.
<p>No construtor de GUI, a janela agora deve se parecer com a figura seguinte:</p>
<p><img alt="projetando a interface do usu&aacute;rio" src="../images/tutorials/crud/68dbmanager-96.png" /></p>
<p><li>Volte para o m&oacute;dulo <tt>CustomerViewer</tt> e altere o arquivo <tt>layer.xml</tt> para que especifique que a janela <tt>CustomerTopComponent</tt> aparecer&aacute; no modo <tt>explorer</tt>.
<p class="tips"> Clique com o bot&atilde;o direito do mouse no projeto do aplicativo e escolha &quot;Limpar&quot;, ap&oacute;s alterar o arquivo <tt>layer.xml</tt>. Por que? Porque sempre que voc&ecirc; executa o aplicativo e o fecha, as posi&ccedil;&otilde;es da janela s&atilde;o armazenadas no diret&oacute;rio do usu&aacute;rio. Portanto, se o <tt>CustomerViewer</tt> foi inicialmente exibido no modo <tt>editor</tt>, ele permanecer&aacute; no modo <tt>editor</tt> at&eacute; que voc&ecirc; fa&ccedil;a &quot;Limpar&quot;, redefinindo, assim, o diret&oacute;rio do usu&aacute;rio (ou seja, <i>excluindo</i> o diret&oacute;rio do usu&aacute;rio) e permitindo que o <tt>CustomerViewer</tt> seja exibido na posi&ccedil;&atilde;o definida atualmente no arquivo <tt>layer.xml</tt>.</p>
<p>Verifique tamb&eacute;m se <tt>BeanTreeView</tt> no <tt>CustomerViewer</tt> ser&aacute; ampliada na horizontal e na vertical quando o usu&aacute;rio redimensionar o aplicativo. Verifique isso abrindo a janela, selecionando <tt>BeanTreeView</tt> e clicando nos bot&otilde;es de seta na barra de ferramentas do construtor da GUI.
<li>Execute o aplicativo e certifique-se de ver o seguinte quando o aplicativo se iniciar:
<p><img alt="executando a nova UI" src="../images/tutorials/crud/68dbmanager-97.png" /></p>
<li>Agora podemos come&ccedil;ar a adicionar alguns c&oacute;digos. Primeiramente, precisamos mostrar no editor o objeto Customer atualmente selecionado:
<ul>
<li>Inicie por adaptar o m&oacute;dulo <tt>CustomerViewer</tt> para que o objeto <tt>Customer</tt> atual seja adicionado ao <tt>Lookup</tt> da janela do visualizador sempre que um novo <tt>Node</tt> for selecionado. Para isso, crie um <tt>AbstractNode</tt>, em vez de um <tt>BeanNode</tt>, na classe <tt>CustomerChildFactory</tt>. Isso permite adicionar o objeto <tt>Customer</tt> atual ao <tt>Lookup</tt> do Node, conforme ilustrado a seguir (observe a parte em negrito):
<pre class="examplecode">@Override
protected Node createNodeForKey(Customer c) {
Node node = new AbstractNode(Children.LEAF, Lookups.singleton(c));
node.setDisplayName(c.getName());
node.setShortDescription(c.getCity());
return node;
// try {
// return new BeanNode(c);
// } catch (IntrospectionException ex) {
// Exceptions.printStackTrace(ex);
// return null;
// }
}</pre>
<p>Agora, sempre que um novo <tt>Node</tt> for criado, o que acontece sempre que o usu&aacute;rio seleciona um novo estado no visualizador, um novo objeto <tt>Customer</tt> &eacute; adicionado ao <tt>Lookup</tt> do <tt>Node</tt>.
<p><li>Agora vamos alterar o m&oacute;dulo do editor de tal forma que sua janela detecte os objetos <tt>Customer</tt> que s&atilde;o adicionados ao <tt>Lookup</tt>. Primeiro, defina uma depend&ecirc;ncia no m&oacute;dulo do editor que fornece a classe da entidade, bem como o m&oacute;dulo que fornece os JARS de persist&ecirc;ncia.
<p><li>A seguir, altere a assinatura da classe <tt>EditorTopComponente</tt> para implementar o <tt>LookupListener</tt>:
<pre class="examplecode">public final class EditorTopComponent extends TopComponent implements LookupListener</pre>
<p><li>Substitua o <tt>resultChanged</tt> para que os <tt>JTextFields</tt> sejam atualizados sempre que um novo objeto <tt>Customer</tt> for introduzido no <tt>Lookup</tt>:
<pre class="examplecode">@Override
public void resultChanged(LookupEvent lookupEvent) {
Lookup.Result r = (Lookup.Result) lookupEvent.getSource();
Collection&lt;Customer&gt; coll = r.allInstances();
if (!coll.isEmpty()) {
for (Customer cust : coll) {
jTextField1.setText(cust.getName());
jTextField2.setText(cust.getCity());
}
} else {
jTextField1.setText(&quot;[no name]&quot;);
jTextField2.setText(&quot;[no city]&quot;);
}
}</pre>
<p><li>Agora que o <tt>LookupListener</tt> est&aacute; definido, precisamos adicion&aacute;-lo a algo. Aqui, n&oacute;s o adicionamos ao <tt>Lookup.Result</tt> obtido do contexto global. Os proxies do contexto global do contexto do <tt>Node</tt> selecionado. Por exemplo, se &quot;Ford Motor Co&quot; for selecionado na hierarquia da &aacute;rvore, o objeto <tt>Customer</tt> de &quot;Ford Motor Co&quot; &eacute; adicionado ao <tt>Lookup</tt> do <tt>Node</tt> que, por ser o <tt>Node</tt> atualmente selecionado, significa que o objeto <tt>Customer</tt> de &quot;Ford Motor Co&quot; agora est&aacute; dispon&iacute;vel no contexto global. Isso &eacute;, ent&atilde;o, passado para o <tt>resultChanged</tt>, fazendo com que os campos de texto sejam preenchidos.
<p>Todo o acima come&ccedil;a a acontecer, ou seja, o <tt>LookupListener</tt> se torna ativo sempre que a janela do editor for aberta, como pode ser visto abaixo:</p>
<pre class="examplecode">@Override
public void componentOpened() {
result = Utilities.actionsGlobalContext().lookupResult(Customer.class);
result.addLookupListener(this);
resultChanged(new LookupEvent(result));
}
@Override
public void componentClosed() {
result.removeLookupListener(this);
result = null;
}</pre>
<p>Como a janela do editor &eacute; aberta quando o aplicativo &eacute; iniciado, o <tt>LookupListener</tt> est&aacute; dispon&iacute;vel no momento da inicializa&ccedil;&atilde;o do aplicativo.
<p><li>Finalmente, declare a vari&aacute;vel do resultado acima da classe, como segue:
<pre class="examplecode">private Lookup.Result result = null;</pre>
<p><li>Execute novamente o aplicativo e observe que a janela do editor &eacute; atualizada sempre que voc&ecirc; seleciona um novo <tt>Node</tt>:
<p><img alt="janela do editor atualizada" src="../images/tutorials/crud/68dbmanager-98.png" /></p>
<p>No entanto, observe o que acontece quando voc&ecirc; alterna o foco para a janela do editor:</p>
<p><img alt="alternar foco" src="../images/tutorials/crud/68dbmanager-99.png" /></p>
<p>Como o <tt>Node</tt> n&atilde;o &eacute; mais o atual, o objeto <tt>Customer</tt> n&atilde;o est&aacute; mais no contexto global. Isto se deve, conforme mostrado acima, aos proxies do contexto global do <tt>Lookup</tt> do <tt>Node</tt> atual. Portanto, nesse caso, n&atilde;o podemos usar o contexto global. Em vez disso, usaremos o <tt>Lookup</tt> local fornecido pela janela Clientes.</p>
<p>Reescreva esta linha:
<pre class="examplecode">result = Utilities.actionsGlobalContext().lookupResult(Customer.class);</pre>
<p>Para:
<pre class="examplecode">result = WindowManager.getDefault().findTopComponent(&quot;CustomerTopComponent&quot;).getLookup().lookupResult(Customer.class);</pre>
<p>A string &quot;CustomerTopComponent&quot; &eacute; a ID do <tt>CustomerTopComponent</tt>, que &eacute; uma constante da string que voc&ecirc; pode encontrar no c&oacute;digo-fonte do <tt>CustomerTopComponent</tt>. Uma desvantagem da abordagem acima &eacute; a de que seu novo <tt>EditorTopComponent</tt> funciona somente se ele puder encontrar um <tt>TopComponent</tt> com a ID &quot;CustomerTopComponent&quot;. Isto precisa ser explicitamente documentado para que os desenvolvedores de editores alternativos possam saber que precisam identificar o visualizador <tt>TopComponent</tt> desta forma, ou &eacute; necess&aacute;rio reescrever o modelo de sele&ccedil;&atilde;o, <a href="http://weblogs.java.net/blog/timboudreau/archive/2007/01/how_to_replace.html">conforme descrito aqui</a> por Tim Boudreau.
<p>Se utilizar uma das abordagens acima, verificar&aacute; que o contexto n&atilde;o se perde ao alternar o foco para o <tt>EditorTopComponent</tt>, conforme ilustrado abaixo:</p>
<p><img alt="o contexto n&atilde;o se perde" src="../images/tutorials/crud/68dbmanager-991.png" /></p>
<p class="tips"> Visto que agora voc&ecirc; est&aacute; utilizando <tt>AbstractNode</tt>, em vez de <tt>BeanNode</tt>, nenhuma propriedade &eacute; mostrada na janela Propriedades. Voc&ecirc; mesmo precisa fornec&ecirc;-las, conforme descrito no <a href="https://platform.netbeans.org/tutorials/nbm-nodesapi2.html">Tutorial da API de n&oacute;s</a>.
</ul>
<li>Em segundo lugar, vamos trabalhar na funcionalidade Desfazer/Refazer. O que gostar&iacute;amos que acontecesse &eacute; que sempre que o usu&aacute;rio fizer uma altera&ccedil;&atilde;o em um dos <tt>JTextFields</tt>, o bot&atilde;o &quot;Desfazer&quot; e o bot&atilde;o &quot;Refazer&quot;, assim como os itens de menu relacionados no meu Editar, se tornassem habilitados. Para este fim, a plataforma NetBeans torna o <a href="http://bits.netbeans.org/dev/javadoc/org-openide-awt/org/openide/awt/UndoRedo.Manager.html">UndoRedo.Manager</a> dispon&iacute;vel.
<ul>
<li>Declare e crie uma inst&acirc;ncia de um novo UndoRedoManager acima do <tt>EditorTopComponent</tt>:
<pre class="examplecode">private UndoRedo.Manager manager = new UndoRedo.Manager();</pre>
<p><li>A seguir, sobreponha o m&eacute;todo <tt>getUndoRedo()</tt> no <tt>EditorTopComponent</tt>:
<pre class="examplecode">@Override
public UndoRedo getUndoRedo() {
return manager;
}</pre>
<p><li>No construtor do <tt>EditorTopComponent</tt>, adicione um <tt>KeyListener</tt> ao <tt>JTextFields</tt> e, dentro dos m&eacute;todos relacionados que voc&ecirc; precisa implementar, adicione o <tt>UndoRedoListeners</tt>:
<pre class="examplecode">jTextField1.getDocument().addUndoableEditListener(manager);
jTextField2.getDocument().addUndoableEditListener(manager);
</pre>
<p><li>Execute o aplicativo e mostre a funcionalidade Desfazer e Refazer em a&ccedil;&atilde;o, os bot&otilde;es e tamb&eacute;m os itens de menu. A funcionalidade funciona exatamente como esperado. Voc&ecirc; pode desejar alterar o <tt>KeyListener</tt> para que nem TODAS as teclas causem a habilita&ccedil;&atilde;o da funcionalidade Desfazer/Refazer. Por exemplo, quando Enter &eacute; pressionado, voc&ecirc; provavelmente n&atilde;o deseja que a funcionalidade Desfazer/Refazer se torne dispon&iacute;vel. Portanto, adapte o c&oacute;digo acima para se adequar &agrave;s suas necessidades administrativas.
</ul>
<li>Em terceiro lugar, precisamos integrar com a funcionalidade Salvar do NetBeans:
<ul>
<li>como padr&atilde;o, o bot&atilde;o &quot;Salvar todos&quot; est&aacute; dispon&iacute;vel na barra de ferramentas da plataforma NetBeans. Em nosso cen&aacute;rio atual, n&atilde;o desejamos salvar &quot;todos&quot;, porque &quot;todos&quot; se refere a v&aacute;rios documentos. Em nosso caso, temos somente um &quot;documento&quot;, que &eacute; o editor que estamos reutilizando para todos os n&oacute;s na hierarquia da &aacute;rvore. Remova o bot&atilde;o &quot;Salvar todos&quot; e adicione &quot;Salvar&quot; em seu lugar, adicionando o seguinte arquivo de camada do m&oacute;dulo <tt>CustomerEditor</tt>:
<pre class="examplecode">&lt;folder name=&quot;Toolbars&quot;&gt;
&lt;folder name=&quot;File&quot;&gt;
&lt;file name=&quot;org-openide-actions-SaveAction.shadow&quot;&gt;
&lt;attr name=&quot;originalFile&quot; stringvalue=&quot;Actions/System/org-openide-actions-SaveAction.instance&quot;/&gt;
&lt;attr name=&quot;position&quot; intvalue=&quot;444&quot;/&gt;
&lt;/file&gt;
&lt;file name=&quot;org-openide-actions-SaveAllAction.shadow_hidden&quot;/&gt;
&lt;/folder&gt;
&lt;/folder&gt;</pre>
<p>Agora, quando voc&ecirc; executar o aplicativo, ver&aacute; um &iacute;cone diferente na barra de ferramentas. Em vez do bot&atilde;o &quot;Salvar todos&quot;, agora o bot&atilde;o &quot;Salvar&quot; est&aacute; dispon&iacute;vel.
<p><li>Defina as depend&ecirc;ncias na API das caixas de di&aacute;logo e na API dos n&oacute;s.
<p><li>No construtor <tt>EditorTopCompontn</tt>, adicione uma chamada para disparar um m&eacute;todo (que ser&aacute; definido na etapa seguinte) sempre que uma altera&ccedil;&atilde;o for detectada:
<pre class="examplecode">public EditorTopComponent() {
...
...
...
jTextField1.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent arg0) {
fire(true);
}
public void removeUpdate(DocumentEvent arg0) {
fire(true);
}
public void changedUpdate(DocumentEvent arg0) {
fire(true);
}
});
jTextField2.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent arg0) {
fire(true);
}
public void removeUpdate(DocumentEvent arg0) {
fire(true);
}
public void changedUpdate(DocumentEvent arg0) {
fire(true);
}
});
//Create a new instance of our SaveCookie implementation:
impl = new SaveCookieImpl();
//Create a new instance of our dynamic object:
content = new InstanceContent();
//Add the dynamic object to the TopComponent Lookup:
associateLookup(new AbstractLookup(content));
}
...
...
...
</pre>
<p><li>Aqui est&atilde;o os dois m&eacute;todos mencionados acima. Primeiro, o m&eacute;todo que &eacute; disparado sempre que uma altera&ccedil;&atilde;o for detectada. Uma implementa&ccedil;&atilde;o do <tt>SaveCookie</tt> da API de n&oacute;s &eacute; adicionada ao <tt>InstanceContent</tt> sempre que uma altera&ccedil;&atilde;o for detectada:
<pre class="examplecode"> public void fire(boolean modified) {
if (modified) {
//If the text is modified,
//we add SaveCookie impl to Lookup:
content.add(impl);
} else {
//Otherwise, we remove the SaveCookie impl from the lookup:
content.remove(impl);
}
}
private class SaveCookieImpl implements SaveCookie {
@Override
public void save() throws IOException {
Confirmation message = new NotifyDescriptor.Confirmation(&quot;Do you want to save \&quot;&quot;
+ jTextField1.getText() + &quot; (&quot; + jTextField2.getText() + &quot;)\&quot;?&quot;,
NotifyDescriptor.OK_CANCEL_OPTION,
NotifyDescriptor.QUESTION_MESSAGE);
Object result = DialogDisplayer.getDefault().notify(message);
//When user clicks &quot;Yes&quot;, indicating they really want to save,
//we need to disable the Save action,
//so that it will only be usable when the next change is made
//to the JTextArea:
if (NotifyDescriptor.YES_OPTION.equals(result)) {
fire(false);
//Implement your save functionality here.
}
}
}
</pre>
<p><li>Execute o aplicativo e observe a habilita&ccedil;&atilde;o/desabilita&ccedil;&atilde;o do bot&atilde;o Salvar:
<p><img alt="bot&atilde;o salvar ativado" src="../images/tutorials/crud/68dbmanager-992.png" /></p>
<p class="tips"> No momento, nada acontece quando voc&ecirc; clica em OK na caixa de di&aacute;logo acima. Na pr&oacute;xima etapa, adicionamos alguns c&oacute;digos JPA para manipular a persist&ecirc;ncias de nossas altera&ccedil;&otilde;es.
<p><li>A seguir, adicionamos o c&oacute;digo JPA para manter nossa altera&ccedil;&atilde;o. Fa&ccedil;a isso substituindo o coment&aacute;rio &quot;//Implement your save functionality here.&quot; (Implemente sua funcionalidade salva aqui). O coment&aacute;rio deveria ser substitu&iacute;do pelo c&oacute;digo a seguir:
<pre class="examplecode">EntityManager entityManager = Persistence.createEntityManagerFactory(&quot;CustomerLibraryPU&quot;).createEntityManager();
entityManager.getTransaction().begin();
Customer c = entityManager.find(Customer.class, customer.getCustomerId());
c.setName(jTextField1.getText());
c.setCity(jTextField2.getText());
entityManager.getTransaction().commit();</pre>
<p class="tips"> O &quot;customer&quot; de <tt>customer.getCustomerId()()</tt> n&atilde;o est&aacute; definido no momento. Adicione a linha em negrito ao <tt>resultChanged</tt> abaixo, ap&oacute;s declarar <tt>Customer customer;</tt> acima da classe, de modo que o objeto <tt>Customer</tt> atual defina o <tt>customer</tt>, o qual &eacute; ent&atilde;o usado no c&oacute;digo de persist&ecirc;ncia acima para obter a ID do objeto <tt>Customer</tt> atual.
<pre class="examplecode">@Override
public void resultChanged(LookupEvent lookupEvent) {
Lookup.Result r = (Lookup.Result) lookupEvent.getSource();
Collection&lt;Customer&gt; c = r.allInstances();
if (!c.isEmpty()) {
for (Customer customer : c) {
<b>customer = cust;</b>
jTextField1.setText(customer.getName());
jTextField2.setText(customer.getCity());
}
} else {
jTextField1.setText(&quot;[no name]&quot;);
jTextField2.setText(&quot;[no city]&quot;);
}
}</pre>
<p><li>Execute o aplicativo e altere alguns dados. No momento, n&atilde;o temos a funcionalidade &quot;Atualizar&quot; (que ser&aacute; adicionada na etapa seguinte), portanto, para ver os dados alterados, reinicie o aplicativo. Aqui, por exemplo, a hierarquia da &aacute;rvore mostra o nome do cliente persistente &quot;Toyota Motor Co&quot;:
<p><img alt="banco de dados alterado" src="../images/tutorials/crud/68dbmanager-993.png" /></p>
</ul>
<li>Em quarto lugar, precisamos adicionar a funcionalidade de atualiza&ccedil;&atilde;o para o visualizador Customer. Voc&ecirc; pode desejar adicionar um <tt>Temporizador</tt> que periodicamente atualiza o visualizador. No entanto, neste exemplo, n&oacute;s adicionaremos um item de menu &quot;Atualizar&quot; no n&oacute; Raiz, para que o usu&aacute;rio seja capaz de atualizar manualmente o visualizador.
<ul>
<li>No pacote principal do m&oacute;dulo <tt>CustomerViewer</tt>, crie um novo <tt>Node</tt>, que substituir&aacute; o <tt>AbstractNode</tt> que estamos utilizando atualmente como a raiz dos filhos do visualizador. Observe que tamb&eacute;m vinculamos uma a&ccedil;&atilde;o &quot;Atualizar&quot; com nosso novo n&oacute; raiz.
<pre class="examplecode">public class CustomerRootNode extends AbstractNode {
public CustomerRootNode(Children kids) {
super(kids);
setDisplayName(&quot;Root&quot;);
}
@Override
public Action[] getActions(boolean context) {
Action[] result = new Action[]{
new RefreshAction()};
return result;
}
private final class RefreshAction extends AbstractAction {
public RefreshAction() {
putValue(Action.NAME, &quot;Refresh&quot;);
}
public void actionPerformed(ActionEvent e) {
CustomerTopComponent.refreshNode();
}
}
}</pre>
<p><li>Adicione este m&eacute;todo ao <tt>CustomerTopComponent</tt> para atualizar a visualiza&ccedil;&atilde;o:
<pre class="examplecode">public static void refreshNode() {
EntityManager entityManager = Persistence.createEntityManagerFactory(&quot;CustomerLibraryPU&quot;).createEntityManager();
Query query = entityManager.createQuery(&quot;SELECT c FROM Customer c&quot;);
List&lt;Customer&gt; resultList = query.getResultList();
em.setRootContext(new <b>CustomerRootNode</b>(Children.create(new CustomerChildFactory(resultList), true)));
} </pre>
<p>Agora, substitua o c&oacute;digo acima no construtor do <tt>CustomerTopComponent</tt> por uma chamada para c&oacute;digo acima. Como voc&ecirc; pode ver na parte real&ccedil;ada acima, agora estamos utilizando nosso <tt>CustomerRootNode</tt> ao inv&eacute;s do <tt>AbstractNode</tt>. O <tt>CustomerRootNode</tt> inclui a a&ccedil;&atilde;o &quot;Atualizar&quot;, que chama o c&oacute;digo acima.
<p><li>Na sua funcionalidade de salvar, adicione a chamada ao m&eacute;todo acima para que, sempre que os dados forem salvos, ocorra uma atualiza&ccedil;&atilde;o autom&aacute;tica. &Eacute; poss&iacute;vel utilizar diferentes abordagens ao implementar esta extens&atilde;o &agrave; funcionalidade de salvar. Por exemplo, voc&ecirc; pode criar um novo m&oacute;dulo que cont&eacute;m a a&ccedil;&atilde;o de atualiza&ccedil;&atilde;o. Tal m&oacute;dulo &eacute;, ent&atilde;o, compartilhado entre o m&oacute;dulo do visualizador e o m&oacute;dulo do editor, proporcionando a funcionalidade que &eacute; comum a ambos.
<p><li>Execute novamente o aplicativo e observe que voc&ecirc; tem um novo n&oacute; raiz com uma a&ccedil;&atilde;o &quot;Atualizar&quot;:
<p><img alt="novo n&oacute; raiz" src="../images/tutorials/crud/68dbmanager-994.png" /></p>
<p><li>Altere alguns dados, salve-os, chame a a&ccedil;&atilde;o Atualizar e observe que o visualizador est&aacute; atualizado.
</ul>
</ol>
<p>Voc&ecirc; agora aprendeu como a plataforma NetBeans tem a permiss&atilde;o de manipular as altera&ccedil;&otilde;es no <tt>JTextFields</tt>. Sempre que o texto muda, os bot&otilde;es Desfazer e Refazer da plataforma NetBeans s&atilde;o habilitados ou desabilitados. O bot&atilde;o Salvar tamb&eacute;m &eacute; corretamente habilitado ou desabilitado, permitindo que o usu&aacute;rio salve os dados alterados no banco de dados.
<h3 class="tutorial"><a name="create"></a>Criar</h3>
<p>Nesta se&ccedil;&atilde;o, voc&ecirc; permite que o usu&aacute;rio crie uma nova entrada no banco de dados.
<ol>
<li>Clique com o bot&atilde;o direito do mouse no m&oacute;dulo <tt>CustomerEditor</tt> e escolha &quot;Nova a&ccedil;&atilde;o&quot;. Utilize o assistente Nova a&ccedil;&atilde;o para criar uma nova a&ccedil;&atilde;o &quot;Sempre habilitado&quot;. A nova a&ccedil;&atilde;o deve ser exibida na barra de ferramentas ou na barra de menus. Na pr&oacute;xima etapa do assistente, chame a a&ccedil;&atilde;o <tt>NewAction</tt>.
<p class="tips">Certifique-se de ter dispon&iacute;vel um &iacute;cone 16x16, que o assistente for&ccedil;a que seja selecionado, se for indicado que deseja que a a&ccedil;&atilde;o seja chamada da barra de ferramentas.</p>
<P><li>Na nova a&ccedil;&atilde;o, deixe que o <tt>TopComponent</tt> seja aberto com <tt>JTextFields</tt> vazios:
<pre class="examplecode">import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public final class NewAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
EditorTopComponent tc = EditorTopComponent.getDefault();
tc.resetFields();
tc.open();
tc.requestActive();
}
}</pre>
<p class="tips">A a&ccedil;&atilde;o implementa a classe <tt>ActionListener</tt> que est&aacute; vinculada ao aplicativo atrav&eacute;s de entradas no arquivo de camadas, colocado pelo assistente Nova a&ccedil;&atilde;o. Imagine que f&aacute;cil ser&aacute; quando transferir seu aplicativo Swing existente para a plataforma NetBeans, j&aacute; que voc&ecirc; simplesmente poder&aacute; utilizar as mesmas classes <tt>Action</tt> utilizadas em seu aplicativo original, sem a necessidade de reescrev&ecirc;-las para estarem em conformidade com as classes <tt>Action</tt> fornecidas pela plataforma NetBeans!</p>
<p>No <tt>EditorTopComponent</tt>, adicione o seguinte m&eacute;todo para redefinir o <tt>JTextFields</tt> e para criar um novo objeto <tt>Customer</tt>:
<pre class="examplecode">public void resetFields() {
customer = new Customer();
jTextField1.setText(&quot;&quot;);
jTextField2.setText(&quot;&quot;);
}</pre>
<p><li>No <tt>SaveCookie</tt>, assegure que um retorno de <tt>null</tt> indique que a nova entrada est&aacute; salva, em vez de uma entrada existente ser atualizada:
<pre>public void save() throws IOException {
Confirmation message = new NotifyDescriptor.Confirmation(&quot;Do you want to save \&quot;&quot;
+ jTextField1.getText() + &quot; (&quot; + jTextField2.getText() + &quot;)\&quot;?&quot;,
NotifyDescriptor.OK_CANCEL_OPTION,
NotifyDescriptor.QUESTION_MESSAGE);
Object result = DialogDisplayer.getDefault().notify(msg);
//When user clicks &quot;Yes&quot;, indicating they really want to save,
//we need to disable the Save button and Save menu item,
//so that it will only be usable when the next change is made
//to the text field:
if (NotifyDescriptor.YES_OPTION.equals(result)) {
fire(false);
EntityManager entityManager = Persistence.createEntityManagerFactory(&quot;CustomerLibraryPU&quot;).createEntityManager();
entityManager.getTransaction().begin();
<b>if (customer.getCustomerId() != null)</b> {
Customer c = entityManager.find(Customer.class, cude.getCustomerId());
c.setName(jTextField1.getText());
c.setCity(jTextField2.getText());
entityManager.getTransaction().commit();
} else {
<b>Query query = entityManager.createQuery(&quot;SELECT c FROM Customer c&quot;);
List&lt;Customer&gt; resultList = query.getResultList();
customer.setCustomerId(resultList.size()+1);
customer.setName(jTextField1.getText());
customer.setCity(jTextField2.getText());
//add more fields that will populate all the other columns in the table!
entityManager.persist(customer);
entityManager.getTransaction().commit();</b>
}
}
}</pre>
<p><li>Execute novamente o aplicativo e adicione um novo cliente no banco de dados.
</ol>
<h3 class="tutorial"><a name="delete"></a>Excluir</h3>
<p>Nesta se&ccedil;&atilde;o, voc&ecirc; permite que o usu&aacute;rio exclua uma entrada selecionada no banco de dados. Utilizando os conceitos e c&oacute;digos acima descritos, implemente voc&ecirc; mesmo a a&ccedil;&atilde;o Excluir.
<ol>
<li>Crie uma nova a&ccedil;&atilde;o, <tt>DeleteAction</tt>. Decida se deseja vincul&aacute;-la a um n&oacute; Customer ou se deseja vincul&aacute;-la &agrave; barra de ferramentas, &agrave; barra de menus, ao atalho do teclado ou a uma combina&ccedil;&atilde;o destes. Dependendo de onde deseja vincul&aacute;-la, ser&aacute; necess&aacute;rio utilizar uma abordagem em seu c&oacute;digo. Leia novamente o tutorial para obter ajuda, especialmente ao examinar como a a&ccedil;&atilde;o &quot;Novo&quot; foi criada ao compar&aacute;-la com a a&ccedil;&atilde;o &quot;Atualizar&quot; no n&oacute; raiz.
<p><li>Obtenha o objeto <tt>Customer</tt> atual e retorne uma caixa de di&aacute;logo 'Tem certeza?'. e, em seguida, exclua a entrada. Para obter ajuda neste ponto, leia novamente o tutorial, focando na parte onde a funcionalidade &quot;Salvar&quot; &eacute; implementada. Ao inv&eacute;s de salvar, voc&ecirc; agora deseja excluir uma entrada do banco de dados.
</ol>
</div>
<!-- ======================================================================================== -->
<h2><a name="nextsteps"></a>Consulte tamb&eacute;m</h2>
<p>Isto conclui o tutorial CRUD da plataforma NetBeans. Este documento descreveu como criar um novo aplicativo na plataforma NetBeans com a funcionalidade CRUD para um determinado banco de dados. Para obter mais informa&ccedil;&otilde;es sobre a cria&ccedil;&atilde;o e o desenvolvimento de aplicativos, consulte os seguintes recursos:
<ul>
<li><a href="https://netbeans.org/kb/trails/platform_pt_BR.html">Trilha do aprendizado da plataforma NetBeans</a></li>
<li><a href="http://bits.netbeans.org/dev/javadoc/">Javadoc da API da NetBeans</a></li>
</ul>
<!-- ======================================================================================== -->
</body>
</html>