Programação Comercial Sumário



Documentos relacionados
Manipulação de Banco de Dados com Java 1. Objetivos

JDBC. Siga as instruções para instalar o banco de dados H2 e criar a tabela Alunos.

Listando itens em ComboBox e gravando os dados no Banco de Dados MySQL.

JDBC. Prof. Márcio Bueno

Leonardo Gresta Paulino Murta

Padrões de Projeto e Persistência com DAO

Java na WEB Banco de Dados

Código-Fonte da Prática 02

Persistência de Objetos no SGBD PostgreSQL, Utilizando as APIs: JDBC, JDK, Swing e Design Patteners DAO.

Persistência de Classes em Tabelas de Banco de Dados

Manipulação de Banco de Dados com Java. Ms. Bruno Crestani Calegaro Maio/ 2015

JDBC Java Database Connectivity

JAVA COM BANCO DE DADOS PROFESSORA DANIELA PIRES

Acesso a banco de dados

Desenvolvimento Web TCC Turma A-1

Programação Orientada a Objetos JDBC Java Database Connectivity

JDBC (Java Database Connectivity) Padrão de Projeto DAO (Data Access Object) Roteiro para instalação do banco de dados e do driver JDBC

Procedimentos para Reinstalação do Sisloc

Escritório Virtual Administrativo

CRIANDO BANCOS DE DADOS NO SQL SERVER 2008 R2 COM O SQL SERVER MANAGEMENT STUDIO

Integrando Java com Banco de Dados

Fernando Freitas Costa. Pós-Graduando em Gestão e Docência Universitária. blog.fimes.edu.br/fernando nando@fimes.edu.br

Trabalhando com conexão ao banco de dados MySQL no Lazarus. Prof. Vitor H. Migoto de Gouvêa Colégio IDESA 2011

Java com Banco de Dados Posgree

Drive MySql de conexão para Eclipse

Criando uma agenda simples com NetBeans 6.5

Aula 1 Acesso a Banco de Dados

SISTEMA EXPERIMENTALL 15/11/2009. Olá! A partir de agora vamos conhecer a IDE NetBeans efetuando um micro projeto swing.

Criando Banco de Dados, Tabelas e Campos através do HeidiSQL. Prof. Vitor H. Migoto de Gouvêa Colégio IDESA 2011

Sistema de Recursos Humanos

Modo Estrutura é o ambiente de definição e estruturação dos campos, tipos de dados, descrição e propriedades do campo.

INTRODUÇÃO 12. DOCUMENTAÇÃO INTRODUÇÃO INTRODUÇÃO

Figura 1. A Classe Java

AULA 8 CRIANDO UMA CLASSE EM PHP INTERAGINDO COM BANCO DE DADOS - COM RELACIONAMENTO ENTRE TABELAS

JAVA JDBC COMO FUNCIONA. Programação Orientada a Objetos Flávio de Oliveira Silva 315. Programação Orientada a Objetos Flávio de Oliveira Silva 316

PostgreSQL Exemplo MDI

Curso: Desenvolvimento Java

NOVIDADES DO JAVA PARA PROGRAMADORES C

Java JDBC - I. Ex. 2: para o SQLServer da Microsoft, o driver JDBC pode ser obtido em

Acessando um Banco de Dados

Programação de Computadores - I. Profª Beatriz Profº Israel

Revisão: Introdução. - Integração com o AutoManager; 1 Atualização de versão do banco de dados PostgreSQL

MANUAL COTAÇAO WEB MANUAL MANUAL AVANÇO INFORMÁTICA AVANÇO INFORMÁTICA. [Digite seu endereço] [Digite seu telefone] [Digite seu endereço de ]

Especificação do 3º Trabalho

Desenvolvendo Aplicações Web com NetBeans

Módulo SAC Atendimento ao Cliente

Autenticação e Autorização

1. Escritório Virtual Atualização do sistema Instalação e ativação do sistema de Conexão...5

MANUAL DE UTILIZAÇÃO SISTEMA DE CADASTRO INTRANET

INSTALAÇÃO DO SISTEMA CONTROLGÁS

ROTEIRO NOTA FISCAL ELETRONICA A partir de Agosto/2012

Linguagem de Programação JAVA. Técnico em Informática Professora Michelle Nery

APOSTILA BANCO DE DADOS INTRODUÇÃO A LINGUAGEM SQL

ArpPrintServer. Sistema de Gerenciamento de Impressão By Netsource Rev: 02

MANUAL DO ANIMAIL Terti Software

Driver Mysql para Banco de Dados. Conexão com um Banco de Dados

Treinamento. Módulo. Escritório Virtual. Sistema Office. Instruções para configuração e utilização do módulo Escritório Virtual do sistema Office

1. Instalação do Remessa Q Prof Trabalhando com o Remessa Q Prof Botão Opções e suas Funcionalidades Aba Título...

8. Outros tipos de Transação (Modo de Transação de Autoconfirmação e Modo Implícito)

Manual de Utilização Portal de Serviços do Inmetro nos Estados - PSIE

GUIA PRÁTICO DE INSTALAÇÃO

UNIVERSIDADE FEDERAL DO RIO GRANDE DO NORTE ESCOLA AGRÍCOLA DE JUNDIAÍ EAJ - PRONATEC / REDE etec MÓDULO III DESENVOLVIMENTO PROFESSOR ADDSON COSTA

Laboratório de Banco de Dados Aula 1 Acesso a Banco de Dados. Prof. Josenildo Silva jcsilva@ifma.edu.br

Lição 1 - Criação de campos calculados em consultas

Procedimentos para Instalação do Sisloc

Instalando software MÉDICO Online no servidor

Java & Bancos de Dados Adaptado de Slides da Universidade Salgado de Oliveira Goiânia

Unidade 9: Middleware JDBC para Criação de Beans

Programação WEB (JSP + Banco Dados) Eng. Computação Prof. Rodrigo Rocha

Microsoft Office Outlook Web Access ABYARAIMOVEIS.COM.BR

PHP INTEGRAÇÃO COM MYSQL PARTE 1

SISTEMA DE PRODUTOS E SERVIÇOS CERTIFICADOS. MÓDULO DO CERTIFICADOR MANUAL DE OPERAÇÃO Versão 2.4.6

Manual de operação. BS Ponto Versão 5.1

Fox Gerenciador de Sistemas

e-ouv Passo-a-passo Sistema de Ouvidorias do Poder Executivo Federal Junho, 2015 Controladoria-Geral da União

Cadastro Avaliação 2013 Manual de Instruções

MANUAL PORTAL CLIENTE AVANÇO

AULA 2 INTERAÇÃO COM O BANCO DE DADOS

Sistema Click Principais Comandos

Manual Instalação Pedido Eletrônico

Guia Site Empresarial

Prática em Laboratório N.02 Criando um serviço Web via NetBeans

GUIA INTEGRA SERVICES E STATUS MONITOR

ROTEIRO DE INSTALAÇÃO

Banco de Dados. Sérgio Luiz Ruivace Cerqueira

EXEMPLO DE COMO FAZER UMA MALA DIRETA

Código-Fonte da Prática 04

WF Processos. Manual de Instruções

Programação Orientada a Objetos II

02 - Usando o SiteMaster - Informações importantes

Iniciando o MySQL Query Brower

Para desenvolver a atividade a atividade desta aula utilizaremos o ambiente de desenvolvimento integrado NetBeans.

Tutorial de Computação Introdução a Programação Gráfica em Java para MEC1100 v

Aplicativo da Manifestação do Destinatário. Manual

JAVA 14 ODBC / JDBC Aceder a Bases de Dados através da Internet. Vitor Vaz da Silva

Manual das funcionalidades Webmail AASP

2. INSTALAÇÃO E CONFIGURAÇÃO

Transcrição:

Programação Comercial Para a fixação do conhecimento, uma sequência de práticas detalhas a seguir deve ser executada. Nesta sequência de práticas, uma pequena aplicação para o cadastro e manutenção de dados de clientes, fornecedores e pedidos será criada. Para a realização das práticas é necessário que o banco de dados MySQL esteja instalado e iniciado. As práticas serão realizadas no IDE Netbeans. Sumário Prática 1: Banco de Dados...3 1.1 Modelo do banco de dados da aplicação Pedido...3 1.2 Acessando o servidor MySQL através do Netbeans... 3 1.3 Criando o banco de dados e as tabelas... 3 1.4 Exercícios...5 Prática 2: Definindo os Value Objects para as tabelas... 6 2.1 Criando um novo projeto...6 2.2 Criando enum TipoLogradouro e TipoUnidadeFederada... 6 2.2.1 Enum TipoLogradouro... 6 2.2.2 Enum TipoUnidadeFederada...7 2.2.3 Exercícios... 8 2.3 O Value Object Cliente... 8 2.4 Exercícios...8 Prática 3: Acessando o banco de dados... 10 3.1 Classe utilitária para a conexão com o banco de dados... 10 3.1.1 Implementação da classe ConexaoBD... 10 3.2.2 Driver JDBC para a conexão com o banco de dados...12 3.2.3 Teste de Unidade da classe ConexaoBD... 12 3.2.4 Utilizando um arquivo de configuração (propriedades)... 14 3.2.5 Exercícios... 15 Prática 4: Padrão de Projeto Data Access Object (DAO)...16 4.1 Manipulando registros de clientes...16 4.1.1 DAO para a tabela cliente...16 4.1.2 Testando a tabela cliente...17 4.1.3 Exercícios... 18 4.2 Manipulando registros de produtos... 20 4.2.1 DAO para a tabela produto...20 4.2.2 Testando a tabela produto...23 4.2.3 Exercícios... 26 4.3 Manipulando registros de pedidos...27 4.3.1 DAO para a tabela pedido... 27 4.3.2 Testando a tabela pedido...32 4.3.3 Exercícios... 34 Prática 5: Denvolvimento da interface gráfica da aplicação...35 5.1 Tela principal da aplicação... 35 5.1.1 Menu principal da aplicação...35 5.1.2 Aplicação Multi Document Interface (MDI)...35 5.1.3 Exercícios... 36 5.2 Tela do cadastro de clientes... 36 5.2.1 Criação da janela filha de cadastro de clientes...36 5.2.2 Criação do painel com guias (JTabbedPane)...36 5.2.3 Design da aba Cadastro... 37 5.2.4 Design da aba Registros... 40 5.2.5 Exercícios... 43 5.3 Consulta de Pedidos por Cliente...43 5.3.1 Criando a tela de consulta...43 5.3.2 Exercícios... 46 Prática 6: Cadastro de Pedidos... 47 6.1 Classe utilitária para a formatação de dados... 47 6.1.1 Implementação da classe utilitária... 47 1

6.1.2 Exercício...47 6.2 Ajustes nos value objects...48 6.2.1 Alterando as JavaBeans... 48 6.2.2 Exercício...48 6.3 Formulário de cadastro de pedidos...48 6.3.1 O formulário de entrada de dados... 49 2

Prática 1: Banco de Dados Nesta prática, criaremos o banco de dados e também a estrutura de tabelas para trabalharmos em nosso projeto. 1.1 Modelo do banco de dados da aplicação Pedido Na Figura 1, ilustrada abaixo, está representado o diagrama do modelo de dados que iremos utilizar em nosso projeto. Figura 1: Modelo de dados da aplicação 1.2 Acessando o servidor MySQL através do Netbeans 1. Com o Netbeans aberto, acione o comando de menu Janela > Serviços (Ctrl + 5); 2. Clique no item Banco de Dados, com o botão direito do mouse, acionando o comando Nova Conexão...; 3. Selecione o Driver MySQL (Connector/J driver) e clique no botão Próximo; 4. Limpe o conteúdo do campo Banco de dados (caso tenha definido uma senha, esta deve ser informada) e clique em Testar Conexão; 5. Clique no botão Próximo; 6. Clique no botão Próximo novamente; 7. Altere o nome da conexão para MySQL e clique no botão Finalizar para fechar a janela; 8. Clique com o botão direito do mousesobre a nova conexão que acabamos de criar (MySQL) e acione o comando Conectar; 9. Na janela de diálogo que solicita o usuário e a senha, deixe os valores em branco (a não ser que você tenha definido uma senha) e clique em OK; 10. Clique com o botão direito do mouse novamente sobre a conexão anterior (MySQL) e acione o comando Executar Comando..., onde será aberta uma nova janela para inserção de comandos SQL; 11. Execute o comando abaixo para listar os bancos de dados existentes e verificar que a conexão está funcionando adequadamente: show databases 1.3 Criando o banco de dados e as tabelas 1. Crie o banco de dados, executando o comando SQL abaixo: create database pedido 2. Note que a lista de banco de dados foi automaticamente atualizada, contendo também o banco de dados recém-criado; 3. Selecione o banco de dados pedido, utilizando o comando SQL abaixo (se não fizer isso, as instruções SQL 3

para a criação de tabelas necessitarão do nome completo de cada uma das tabelas criadas e suas referências): use pedido 4. Agora, precisamos criar as tabelas e, para isso, devemos executar as instruções SQL abaixo (digite os comandos em vezde apenas copiar e colar): CREATE TABLE `cliente` ( `clicod` int(11) NOT NULL AUTO_INCREMENT, `clinome` varchar(100) NOT NULL, `clicpf` varchar(14) NOT NULL, `clitelefone` varchar(20) NOT NULL, `cliemail` varchar(100) NOT NULL, `cliendcep` varchar(10) NOT NULL, `cliendtiplogradouro` int(2) NOT NULL, `cliendlogradouro` varchar(40) NOT NULL, `cliendnumero` varchar(10) NOT NULL, `cliendcomplemento` varchar(40) NOT NULL, `cliendbairro` varchar(40) NOT NULL, `cliendmunicipio` varchar(40) NOT NULL, `clienduf` char(2) NOT NULL, PRIMARY KEY (`clicod`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE `fornecedor` ( `forcod` int(11) NOT NULL AUTO_INCREMENT, `fornome` varchar(100) NOT NULL, `forcnpj` varchar(18) NOT NULL, `fortelefone` varchar(20) NOT NULL, `forfax` varchar(20) NOT NULL, `foremail` varchar(100) NOT NULL, `forwebsite` varchar(100) NOT NULL, PRIMARY KEY (`forcod`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1; CREATE TABLE `produto` ( `procod` int(11) NOT NULL AUTO_INCREMENT, `forcod` int(11) NOT NULL, `pronome` varchar(100) NOT NULL, `prodescricao` text NOT NULL, `prounimedida` int(2) NOT NULL, `provalunitario` decimal(20,2) NOT NULL, PRIMARY KEY (`procod`), KEY `forcod` (`forcod`), CONSTRAINT `fornecedor_produto_fk` FOREIGN KEY (`forcod`) REFERENCES `fornecedor` (`forcod`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE `pedido` ( `pedcod` int(11) NOT NULL AUTO_INCREMENT, `clicod` int(11) NOT NULL, `peddata` date NOT NULL, PRIMARY KEY (`pedcod`), KEY `clicod` (`clicod`), CONSTRAINT `cliente_pedido_fk` FOREIGN KEY (`clicod`) REFERENCES `cliente` (`clicod`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE `pedido_item` ( `pedcod` int(11) NOT NULL, `procod` int(11) NOT NULL, `pedproquantidade` decimal(15,3) NOT NULL, PRIMARY KEY (`pedcod`,`procod`), 4

KEY `procod` (`procod`), CONSTRAINT `pedido_item_fk` FOREIGN KEY (`pedcod`) REFERENCES `pedido` (`pedcod`), CONSTRAINT `produto_pedido_item_fk` FOREIGN KEY (`procod`) REFERENCES `produto` (`procod`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 5. Veja que a lista de tabelas foi atualizada, com as cinco tabelas do modelo de dados (Figura 1); 6. A janela de execução de comandos SQL é uma importante janela que você pode utilizar para executar qualquer comando SQL para qualquer banco de dados para o qual tenha criado uma conexão; 7. Portanto, busque estudar mais sobre banco de dados, incluindo comandos SQL e sobre o banco de dados em que estiver trabalhando. 1.4 Exercícios 1. Crie o banco de dados pedido no MySQL. 2. Crie as tabelas desta prática no banco de dados MySQL. 3. Insira alguns registros em cada uma das tabelas, usando o assistente visual de consulta do Netbeans: cliente, fornecedor, produto, pedido, pedido_item. 4. Insira alguns registros nas tabelas do exercício acima usando comandos SQL. 5. Faça consultas ao banco dedados usando instruções SQL. 5

Prática 2: Definindo os Value Objects para as tabelas Nesta prática começaremos a implementar o sistema. Para tanto, será necessário criarmos algumas implementações de suporte para que possamos utilizar no na nossa aplicação. Para entendermos melhor como funciona a comunicação com o banco de dados, a implementação será manual, somente com as classes mais básicas, sem uso de frameworks e APIs, pois para utilizarmos seria necessário primeiro dominar o código mais básico antes de se pensar em ter produtividade com o uso deles, pois mesmo que os frameworks como JPA e CDI possam tornar o processo de desenvolvimento mais produtivo, caso ocorra algum problema, poderemos perder mais tempo do que se estivermos implementando sem eles. 2.1 Criando um novo projeto 1. No Netbeans, acione o comando de menu Janela > Projetos (Ctrl + 1); 2. Acione o comando Arquivo > Novo Projeto...; 3. Na janela Novo Projeto, selecione a categoria Java e o tipo de projeto Aplicação Java; 4. Clique no botão Próximo; 5. Informe sisped como o nome do projeto; 6. Informe um local para iniciar o projeto; 7. Marque a opção Usar Pasta Dedicada para Armazenar Bibliotecas; 8. Desmarque a opção Criar Classe Principal; 9. Clique no botão Finalizar. 2.2 Criando enum TipoLogradouro e TipoUnidadeFederada Observe que no modelo de dados (Figura 1) a tabela cliente possui o campo para tipo de logradouro definido como int(2), armazenando somente o código, e o campo para a unidade federada como char(2), armazenando somente a sigla. Esse tipo de implementação em banco de dados é comum, evitando que sejam criadas tabelas para listas que sejam alteradas com uma frequência muito baixa. Nesta situação, é necessário existir uma documentação que liste tanto os códigos como as descrições, para que não ocorram problemas de uso incorreto de código. Para facilitar a implementação deste cenário, o Java fornece um tipo especial denominado enum, em que podemos definir uma lista de constantes e, se necessário, incluir atributos e construtores para a definição mais detalhada da implementação. 2.2.1 Enum TipoLogradouro 1. Crie um pacote chamado br.edu.univag.sisped.tipo, para armazenarmos os tipos da nossa aplicação; 2. No pacote criado acima, crie um enum clicando com o botão direito do mouse sobre o pacote e acionando comando Novo > Outros; 3. Selecione a categoria Java, o tipo de arquivo Enum Java e clique no botão Próximo; 4. Informe o nome da classe TipoLogradouro e clique no botão Finalizar; 5. Inclua no início do enum TipoLogradouro as seguintes constantes: AVENIDA, RUA, OUTROS; 6. Note que não foi necessário definir a visibilidade e nem o tipo de cada literal; 7. Isso acontece porque as literais dentro de um enum Java já são public e final e possuem o mesmo tipo do enum onde se encontram; 8. Como os enum Java não geram um código interno próṕrio, é interessante criarmos atributos para que possamos armazenar os dados no formato que precisamos para a nossa aplicação; 9. Crie os atributos para o armazenamento do código e da descrição de cada tipo de logradouro: private final int codigo; private final String descricao; 9. O compilador irá reclamar que esses dois atributos não foram inicializados pelo construtor, portanto, crie um construtor usando as teclas de atalho <Ctrl> + <Espaço>, selecionando o construtor que recebe os parâmetros para popular os dois atributos: private TipoLogradouro(int codigo, String descricao) { this.codigo = codigo; this.descricao = descricao; 6

10. Agora, o compilador irá reclamar que os valores constantes do enum não podem ser aplicados aos contrutores disponíveis, então precisamos alterar esses valores, passando tanto o código como a descrição de cada constante que definimos antes: AVENIDA(1, "Avenida"), RUA(2, "Rua"), OUTROS(99, "Outros"); 11. Como os atributos precisam ser acessados pelas classes do projeto, crie os acessores (somente os getters) para os atributos codigo e descricao que possuem a visibilidade private, acionando o atalho de teclado <Alt> + <Insert>. 12. Para finalizar, crie um método de classe (static) para permitir que um tipo de logradouro seja recuperado através de seu código: public static TipoLogradouro get(int codigo) { TipoLogradouro resposta = null; for (TipoLogradouro t : values()) { if (t.getcodigo() == codigo) { resposta = t; return resposta; 2.2.2 Enum TipoUnidadeFederada Em muitas situações as Unidades Federadas são implementadas no código-fonte em vez de se criarem tabelas no banco de dados para o armazenamento delas. Isto ocorre porque as unidades federadas não são criadas ou alteradas com frequência. E, quando são criadas novas Unidades Federadas ou algum nome é alterado, é necessário aguardar um prazo para que a lei possa entrar em vigor, dando tempo suficiente para alterar as definições dos códigos-fonte existentes nas aplicações implementadas. Sendo assim, iremos implementar as Unidades Federadas também no código-fonte: 1. Crie um novo enum Java chamado TipoUnidadeFederada no pacote br.edu.univag.sisped.tipo; 2. Inclua as siglas e nomes de alguns estados brasileiros: AC("AC", "Acre"), AM("AM", "Amazonas"), MT("MT", "Mato Grosso"), RJ("RJ", "Rio de Janeiro"), SP("SP", "São Paulo"); 3. Crie os atributos para o armazenamento das siglas e nomes dos estados brasileiros; private final String sigla; private final String nome; 4. Crie um construtor parametrizado para inicializar as siglas e nomes de cada valor do enum: private TipoUnidadeFederada(String sigla, String nome) { this.sigla = sigla; this.nome = nome; 5. Crie os métodos acessores para que os valores dos atributos possam ser utilizados por outras classes: public String getsigla() { return sigla; public String getnome() { return nome; 6. Note que desta vez usamos um atributo do tipo String para a identificação (sigla) em vez do tipo int; 7. Finalmente, crie um método estático para obter uma unidade federada através de sua sigla: public static TipoUnidadeFederada get(string sigla) { TipoUnidadeFederada resposta = null; for (TipoUnidadeFederada t : values()) { 7

if (t.getsigla().equals(sigla)) { resposta = t; return resposta; 2.2.3 Exercícios 1. Pesquise e responda: por que os construtores dos enum Java possuem a visibilidade private? 2. Pesquise sobre os métodos equals e hashcode, implementados na classe Object e que devem ser sobrescritos em certas subclasses para atender à certas necessidades. Quando eles são necessários? 3. Complete a lista de tipos de logradouro, incluindo os tipos que faltam (se alterar o código, deverá ajustar o valor do campo associado para manter a integridade dos dados): aeroporto, alameda, área, campo, chácara, colônia, condomínio, conjunto, distrito, esplanada, estação, estrada, favela, fazenda, feira, jardim, ladeira, lago, lagoa, largo, loteamento, morro, núcleo, parque, passarela, pátio, praça, quadra, recanto, residencial, rodovia, setor, sítio, travessa, trecho, trevo, vale, vereda, via, viaduto, viela, vila. 4. Remova o tipo de logradouro OUTROS. 5. Complete a relação de Unidades Federadas: AL, AP, BA, CE, DF, ES, GO, MA, MG, MS, PA, PB, PE, PI, PR, RN, RO, RR, RS, SC, SE, TO. 2.3 O Value Object Cliente Precisamos criar um JavaBean, também conhecido como Value Object ou Data Transfer Object, para armazenar os dados do cliente. Essa JavaBean será uma representação dos dados da tabela cliente, do nosso modelo. 1. Crie o pacote br.edu.univag.sisped.vo no projeto sisped; 2. Crie uma classe chamada Cliente Java no pacote acima; 3. Crie os atributos para fazer o mapeamento com os campos da tabela: private int cod; private String nome; private String cpf; private String telefone; private String email; private String cep; private TipoLogradouro tipologradouro; private String logradouro; private String numero; private String complemento; private String bairro; private String municipio; private TipoUnidadeFederada uf; 4. Adicione as importações necessárias (enum TipoLogradouro e TipoUnidadeFederada), usando o atalho de teclado <Ctrl> + <Shift> + i; 5. Acrescente os métodos acessores (getters e setters) para cada atributo, com a combinação de teclado <Alt> + <Insert>; 6. Pronto, os registros da tabela cliente agora podem ser utilizados na nossa aplicação. 2.4 Exercícios 1. Implemente o value object para a tabela fornecedor, criando uma classe chamada Fornecedor, no pacote br.edu.univag.sisped.vo, com os seguintes nomes de atributos: cod (int), nome (String), cnpj (String), telefone (String), fax (String), email (String) e website (String). 2. Implemente um novo enum Java, chamado TipoUnidadeMedida, no pacote br.edu.univag.sisped.tipo, para ser usado como atributo da classe Produto. Pesquise quais são as unidades legais de medida (símbolo e nome) e implemente algumas. Para criar, siga os passos descritos na seção para criar TipoLogradouro e TipoUnidadeFederada. 3. Implemente o value object para a tabela produto, criando uma classe chamada Produto, no pacote br.edu.univag.sisped.vo, com os seguintes nomes de atributos: cod (int), fornecedor (Fornecedor), nome (String), descricao (String), unidademedida (TipoUnidadeMedida) e valorunitario (double). Observação: Em vez de ter 8

um atributo com o código do fornecedor, deve-se inserir uma referência para a classe Fornecedor, criada no primeiro exercício. 4. Implemente o value object para a tabela de itens de pedido, pedido_item, criando uma classe chamada PedidoItem, no pacote br.edu.univag.sisped.vo, com os seguintes nomes de atributos: produto (Produto) e quantidade (double). 5. Implemente um método chamado gettotal() na classe PedidoItem, calculando o total do item de pedido. 6. Implemente o value object para a tabela de pedido, criando uma classe chamada Pedido, no pacote br.edu.univag.sisped.vo, com os seguintes nomes de atributos: cod (int), cliente (Cliente), data (java.util.date) e itens (List<PedidoItem>). 9

Prática 3: Acessando o banco de dados Nesta prática conectaremos nossa aplicação com o banco de dados, onde serão inseridos, consultados, aterados e excluídos um conjunto de registros através de uma conexão usando driver JDBC para o banco de dados MySQL. 3.1 Classe utilitária para a conexão com o banco de dados Para centralizar a conexão com o banco de dados, se faz necessário criar uma classe utilitária para gerenciar a conexão com o banco de dados. Para um reaproveitamento melhor das implementações, recomenda-se criar um projeto específico para as classes utilitárias que podem ser reutilizadas e reaproveitadas em outros projetos. Na sequêcia de práticas a serem executadas, todos os arquivos serão mantidos em um único projeto. 3.1.1 Implementação da classe ConexaoBD A seguir vamos implementar uma classe de conexão com o banco de dados e também começaremos a criar as classes de teste unitário para verificarmos se a implementação está funcionando de fato. 1. Crie um novo pacote chamado br.edu.univag.util.sql, para as implementações que devem ficar em outros projetos, provendo a reutilização; 2. No pacote acima crie uma nova classe chamada ConexaoBD; 3. Para conectarmos com um banco de dados, precisamos saber qual é o driver de conexão a ser usado, a URL com o endereço do banco de dados, o usuário de banco de dados e a senha para efetuar o login, então acrescente os atributos necessários para armazenar estes dados: private final String driver; private final String url; private final String usuario; private final String senha; 4. Precisamos também de um atributo para referenciarmos a conexão criada e outro para o situação (conectado ou não): private Connection con; private boolean conectado; 5. Acrescente a importação da classe java.sql.connection, utilizando o atalho de teclado <CtrL>+<Shift>+<i>; 6. Crie um construtor, utilizando o atalho de teclado <Ctrl> + <Espaço>, de forma que os atributos driver, url, usuario e senha possam ser preenchidos. No caso, o Netbeans oferece auxílio apenas para o construtor default ou para para o construtor contendo todos os atributos, então selecione o segundo e remova o código que esteja sobrando: public ConexaoBD(String driver, String url, String usuario, String senha) { this.driver = driver; this.url = url; this.usuario = usuario; this.senha = senha; 7. Inclua, através do atalho de teclado <Ctrl>+<Espaço>, o método acessor get para o atributo conectado (note que não é oferecido o método getconectado e sim isconectado, essa é uma característica específica para os atributos do tipo boolean, pois possui uma semântica melhor em inglês); 8. Agora será necessário criar os métodos para se conectar e desconectar ao banco de dados: public void conectar() { Class.forName(this.driver); this.con = DriverManager.getConnection(url, usuario, senha); this.con.setautocommit(false); this.conectado = true; catch (ClassNotFoundException SQLException ex) { Logger.getLogger(ConexaoBD.class.getName()).log(Level.SEVERE, ex); this.conectado = false; public void desconectar() { null, 10

if (isconectado()) { this.con.rollback(); this.con.close(); this.conectado = false; catch (SQLException ex) { Logger.getLogger(ConexaoBD.class.getName()).log(Level.SEVERE, null, ex); 9. Adicione as importações necessárias (<Ctrl>+<Shift>+<i>); 10. Para podermos executar comandos SQL no banco de dados, precisamos criar objetos do tipo java.sql.preparedstatement. Adicionalmente, como as chaves primárias das nossas tabelas são geradas automaticamente, será necessário informar quando iremos ou não precisar obter as chaves geradas pelo banco de dados. Então, teremos dois métodos para executarmos os comandos SQL e um terceiro para obter o valor da chave gerada pelo banco de dados: public PreparedStatement prepararsql(string sql) throws SQLException { return prepararsql(sql, false); public PreparedStatement prepararsql(string sql, boolean gerarchaves) throws SQLException { if (isconectado()) { if (gerarchaves) { return con.preparestatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); else { return con.preparestatement(sql, PreparedStatement.NO_GENERATED_KEYS); else { throw new SQLException("Não conectado ao banco de dados!"); public long getchave(preparedstatement ps) throws SQLException { long resposta = 0; try (ResultSet rs = ps.getgeneratedkeys()) { if (rs.next()) { resposta = rs.getlong(1); return resposta; 11. Adicione as importações necessárias (<Ctrl>+<Shift>+<i>); 12. No código-fonte acima, obtemos o valor da chave gerada através do método getgeneratedkeys(), da classe java.sql.preparedstatement e, adicionalmente precisamos da interface java.sql.resultset para tratarmos a resposta deste método; 13. Para finalizarmos, precisamos de um método para formatar o resultado de maneira que possa ser visualizada em uma tabela, quando construirmos a interface visual de uma consulta ao banco de dados: public DefaultTableModel gettabela(resultset rs) { DefaultTableModel tabela = new DefaultTableModel(); //Obtém os meta dados ResultSetMetaData rsmd = rs.getmetadata(); //Pega o número de colunas 11

int numcolunas = rsmd.getcolumncount(); //Cria um vetor para guardar o título das colunas String[] nomesdascolunas = new String[numColunas]; //Alimenta o vetor com os títulos das colunas for (int i = 0; i < numcolunas; i++) { nomesdascolunas[i] = rsmd.getcolumnlabel(i + 1); //Ajusta os títulos das colunas da tabela em função dos //dados do vetor tabela.setcolumnidentifiers(nomesdascolunas); while (rs.next()) { Object[] linha = new Object[numColunas]; for (int i = 0; i < numcolunas; i++) { linha[i] = rs.getobject(i + 1); tabela.addrow(linha); catch (SQLException ex) { Logger.getLogger(ConexaoBD.class.getName()).log(Level.SEVERE, ex); null, return tabela; 14. Adicione as importações necessárias (<Ctrl>+<Shift>+<i>); 15. Pronto, agora temos uma classe utilitária para banco de dados. 3.2.2 Driver JDBC para a conexão com o banco de dados Para se conectar com o banco de dados MySQL, será necessário incluir a biblioteca de conexão conhecida como MySQL Connector/J: 1. Clique com o botão direito em Bibliotecas, do seu projeto sisped, no Netbeans, acionando o comando Adicionar JAR/Pasta...; 2. Selecione o arquivo C:\mysql-connector-java-5.1.36\mysql-connector-java-5.1.36-bin.jar; 3. Marque a opção Copiar para a Pasta de Bibliotecas; 4. Clique no botão OK. 3.2.3 Teste de Unidade da classe ConexaoBD Bom, até agora não testamos as classes que criamos. É sempre uma boa prática testarmos os códigos que criamos para termos a certeza de que estão funcionando, com o objetivo de aumentar a qualidade dos softwares desenvolvidos: 1. Acione o comando de menu Arquivo > Novo Arquivo...; 2. Na janela Novo Arquivo, vá para o campo Filtro, digitando teste; 3. Selecione o tipo de arquivo Teste para a Classe Existente; 4. Clique no botão Próximo; 5. Selecione a classe br.edu.univag.util.sql.conexaobd no campo Classe a Testar; 6. Clique no botão Finalizar; 7. Se for perguntado a versão do JUnit a ser utilizado, selecione a opção JUnit 4.x e confirme; 8. Note que agora o seu projeto possui mais dois elementos: Pacotes de Teste e Bibliotecas de Testes; 9. A classe de teste possui três seções: o construtor, as configurações para serem executadas antes e depois tanto da classe como de cada método, os testes para cada um dos métodos a ser avaliado; 10. Execute o teste (<Ctrl>+<F6>); 11. Note que ocorreram erros (diferente de falhar) nos testes, pois ainda precisam ser implementados para testarem cada um dos cenários adequadamente; 12. Primeiramente, crie um atributo estático para referenciar um objeto de ConexaoBD: private static ConexaoBD conbd; 12

13. O método setupclass é chamado apenas uma vez durante o tempo de vida da classe de teste, então é o local ideal para criarmos uma referência a um objeto estático: @BeforeClass public static void setupclass() { System.out.println("setUpClass"); String driver = "com.mysql.jdbc.driver"; String url = "jdbc:mysql://localhost/pedido"; String usuario = "root"; String senha = ""; conbd = new ConexaoBD(driver, url, usuario, senha); 14. Agora, podemos implementar o primeiro método de teste: @Test public void testisconectado() { System.out.println("isConectado"); ConexaoBD instance = ConexaoBDTest.conBD; boolean expresult1 = false; boolean result1 = instance.isconectado(); assertequals(expresult1, result1); instance.conectar(); boolean expresult2 = true; boolean result2 = instance.isconectado(); assertequals(expresult2, result2); instance.desconectar(); boolean expresult3 = false; boolean result3 = instance.isconectado(); assertequals(expresult3, result3); 15. Execute a classe de teste novamente e confira na janela Resultados do Teste que existe um teste aprovado; 16. Faça o mesmo o método para conectar: @Test public void testconectar() { System.out.println("conectar"); ConexaoBD instance = ConexaoBDTest.conBD; instance.conectar(); boolean expresult = true; boolean result = instance.isconectado(); assertequals(expresult, result); 17. Faça o teste a cada implementação e contunue até o restante da classe de teste: @Test public void testdesconectar() { System.out.println("desconectar"); ConexaoBD instance = ConexaoBDTest.conBD; instance.desconectar(); boolean expresult = false; boolean result = instance.isconectado(); assertequals(expresult, result); @Test public void testprepararsql_string() throws Exception { System.out.println("prepararSQL"); String sql = "show tables"; 13

ConexaoBD instance = conbd; instance.conectar(); try (PreparedStatement result = instance.prepararsql(sql)) { assertnotnull(result); instance.desconectar(); @Test public void testprepararsql_string_boolean() throws Exception { System.out.println("prepararSQL"); String sql = "show tables"; boolean gerarchaves = false; ConexaoBD instance = conbd; instance.conectar(); try (PreparedStatement result = instance.prepararsql(sql, gerarchaves)) { assertnotnull(result); instance.desconectar(); @Test public void testgetchave() throws Exception { System.out.println("getChave"); String sql = "show tables"; boolean gerarchaves = true; ConexaoBD instance = conbd; instance.conectar(); try (PreparedStatement ps = instance.prepararsql(sql, gerarchaves)) { long expresult = 0L; long result = instance.getchave(ps); assertequals(expresult, result); instance.desconectar(); @Test public void testgettabela() throws SQLException { System.out.println("getTabela"); String sql = "show tables"; ConexaoBD instance = conbd; instance.conectar(); try (PreparedStatement ps = instance.prepararsql(sql); ResultSet rs = ps.executequery()) { DefaultTableModel result = instance.gettabela(rs); assertnotnull(result); instance.desconectar(); 18. É lógico que alguns desses testes acima precisa melhorar em razão de não refletirem exatamente os cenários reais e não testarem adequadamente as situações que possam ocorrer. 3.2.4 Utilizando um arquivo de configuração (propriedades) Em vez de incluirmos os dados para o acesso ao banco de dados no código-fonte, mesmo que em uma classe utilitária única, é melhor incluir esses detalhes em uma configuração externa. Assim, é possível que utlizemos um banco de dados enquanto estamos desenvolvendo a aplicação e utilizemos outro banco de dados, com diferentes dados para ser acessado. E, além disso, não precisamos ficar recompilando toda vez que muda algum detalhe, como o driver, URL, usuário ou senha do banco de dados. 1. Acione o comando de menu Arquivo > Novo Arquivo...; 2. Na janela Novo Arquivo, selecione a categoria Outros e o tipo de arquivo Arquivo de Propriedades; 14

3. Clique no botão Próximo; 4. Informe conexao como o nome do arquivo; 5. Selecione a pasta src (um arquivo nomeado conexao.properties será criado no pacote default do projeto NetBeans); 6. Clique no Botão Finalizar; 7. Um arquivo de propriedades possui sempre um par contendo um identificador (chave) e um valor associado, portanto inclua os dados necessários no seu conteúdo: jdbc.driver = com.mysql.jdbc.driver jdbc.url = jdbc:mysql://localhost/pedido jdbc.usuario = root jdbc.senha = 8. Agora, precisamos ler o conteúdo do arquivo acima. Para isso crie uma classe utilitária chamada PropriedadesBD no pacote br.edu.univag.util.sql, removendo o modificador public, para que somente classes do mesmo pacote tenham acesso à esta classe; 9. Adicione os seguintes atributos constantes: public static final String DRIVER; public static final String URL; public static final String USUARIO; public static final String SENHA; 10. Note que os atributos não foram inicializados. É uma boa prática carregarmos apenas uma vez as propriedades sobre os dados da conexão, para evitarmos leituras demasiadas em um arquivo que quase não se altera. Caso o arquivo de propriedades seja alterado, podemos simplesmente reiniciar a aplicação. 11. Na classe PropriedadesBD, adicione um bloco de código estático, após os atributos estáticos, para podermos carregar as constantes apenas uma única vez quando a classe for carregada: static { Properties props = new Properties(); props.load(properties.class.getresourceasstream("/conexao.properties")); catch (IOException ex) { Logger.getLogger(PropriedadesBD.class.getName()).log(Level.SEVERE, null, ex); DRIVER = props.getproperty("jdbc.driver"); URL = props.getproperty("jdbc.url"); USUARIO = props.getproperty("jdbc.usuario"); SENHA = props.getproperty("jdbc.senha"); 12. Adicione as importações necessárias (<Ctrl>+<Shift>+<i>); 13. Altere a classe ConexaoBD, inserindo um novo construtor sem parâmetros (default) e carregando os dados através da classe PropriedadesBD: public ConexaoBD() { this.driver = PropriedadesBD.DRIVER; this.url = PropriedadesBD.URL; this.usuario = PropriedadesBD.USUARIO; this.senha = PropriedadesBD.SENHA; 14. Desta forma, temos uma maneira mais fácil de manter e atualizar os dados de conexão com o nosso banco de dados. 3.2.5 Exercícios 1. Por que os atributos driver, url, usuario e senha da classe ConexaoBD foram marcados com o modificador final? 2. Qual a finalidade da instrução this.con.setautocommit(false), encontrada no método conectar()? 3. Qual a finalidade da instrução this.con.rollback(), encontrada no método desconectar()? 4. Implemente o método commit() na classe ConexaoBD. 5. Pesquise sobre como efetuar testes usando o JUnit. Existem muitos artigos e tutoriais nas mais renomadas fontes. Uma rápida pesquisa no Google permite um bom aprofundamento, seguindos os exemplos encontrados. 6. Altere a classe ConexaoBDTest para que utilize o construtor default, utilizando o arquivo de propriedades. 15

Prática 4: Padrão de Projeto Data Access Object (DAO) Nesta prática construiremos a camada de persistência da aplicação. Para isso, usaremos o mapeamento obbjeto relacional através do padrão de projeto DAO. Para padronizar o comportamento das classes DAO, iremos criar uma classe abstrata, contendo a implementação de atributos e assinaturas dos métodos que devem ser implementados nas classes filhas. 1. Crie uma nova classe Java, chamada DAO, no pacote br.edu.univag.util.sql; 2. Adicione o modificador abstract entre as palavras-reservadas public e class; 3. Crie um atributo para manter uma referência a um objeto ConexaoBD: protected final ConexaoBD conbd; 4. Note que o atributo possui a visibilidade protected para que possa ser acessado pelas classes filhas; 5. Observe também que o atributo possui o modificador final, para que a referência não seja atualizada após ter sido inicializada e, por este motivo, é necessário que seja implementado um construtor inicializando este atributo; 6. Implemente o construtor inicializando o atributo: public DAO(ConexaoBD condb) { this.conbd = condb; 7. Agora, podemos criar as implementações das classes para fazer o mapeamento objeto-relacional. 4.1 Manipulando registros de clientes Para manipular os registros de cliente, precisamos montar as intruções SQL e enviá-las para o servidor. Para tanto, 4.1.1 DAO para a tabela cliente 1. Para começarmos, crie um novo pacote, chamado br.edu.univag.sisped.dao; 2. No pacote acima, crie uma nova classe chamada ClienteDAO; 3. Acrescente extends DAO, na linha de declaração da classe para informar que estamos especializando a classe abstrata DAO; 4. Importe a classe DAO (<Ctrl>+<Shift>+<i>); 5. O compilador irá reclamar que está faltando o construtor definido na classe DAO, use o atalho de teclado <Alt>+<Enter> na linha da declaração da classe e selecione a opção Adicionar Construtor - ClienteDAO(ConexaoBD); 6. Note que a classe ConexaoBD foi importada automaticamente, veja como ficou a classe ClienteDAO: package br.edu.univag.sisped.dao; import br.edu.univag.util.sql.conexaobd; import br.edu.univag.util.sql.dao; public class ClienteDAO extends DAO { public ClienteDAO(ConexaoBD condb) { super(condb); 7. A nossa classe está pronta para começar a ser implementada; 8. Implemente o primeiro método, insert, conforme o código-fonte abaixo: public int insert(cliente cliente) throws SQLException { String sql = "insert into " + "cliente(clinome, clicpf, clitelefone, cliemail, cliendcep, " + "cliendtiplogradouro, cliendlogradouro, cliendnumero, " + "cliendcomplemento, cliendbairro, cliendmunicipio, clienduf) " + "values (?,?,?,?,?,?,?,?,?,?,?,?)"; PreparedStatement ps = null; ResultSet rs = null; ps = conbd.prepararsql(sql, true); 16

ps.setstring(1, cliente.getnome()); ps.setstring(2, cliente.getcpf()); ps.setstring(3, cliente.gettelefone()); ps.setstring(4, cliente.getemail()); ps.setstring(5, cliente.getcep()); ps.setint(6, cliente.gettipologradouro().getcodigo()); ps.setstring(7, cliente.getlogradouro()); ps.setstring(8, cliente.getnumero()); ps.setstring(9, cliente.getcomplemento()); ps.setstring(10, cliente.getbairro()); ps.setstring(11, cliente.getmunicipio()); ps.setstring(12, cliente.getuf().getsigla()); int resposta = ps.executeupdate(); if (resposta == 1) { int cod = (int)conbd.getchave(ps); cliente.setcod(cod); return resposta; finally { if (rs!= null) { rs.close(); if (ps!= null) { ps.close(); 9. Adicione as importações necessárias (<Ctrl>+<Shift>+<i>); 10. A instrução SQL deve ser construída manualmente, mas o Netbeans pode auxiliar na construção das instruções SQL através da janela de Serviços, conforme visto em laboratório; 11. Continue a implementação com os métodos para alterar, excluir, consultar um cliente pelo código e obtenha uma listagem de todos os clientes. 4.1.2 Testando a tabela cliente Como visto anteriormente, é bom testarmos o código-fonte que construímos. Então, vamos testar o método para inserir registro de cliente no banco de dados: 1. Crie um novo teste a classe existente; 2. Selecione a classe br.edu.univag.sisped.dao.clientedao; 3. Clique no botão Finalizar; 4. Como iremos testar apenas a instrução insert, altere o nome da classe clicando com o botão direito do mouse e acionando o comando Refatorar > Renomear...; 5. Informe o novo nome como ClienteDAOInsertTest e clique em Refatorar; 6. Implemente o método testinsert(), conforme o código abaixo: @Test public void testinsert() throws Exception { System.out.println("insert"); ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); Cliente cliente = new Cliente(); cliente.setnome("pato Donald"); cliente.setcpf("123.456.789-12"); cliente.settelefone("(65) 1234-5678"); cliente.setemail("pato.donald@apatada.com.br"); cliente.setcep("21.345-987"); cliente.settipologradouro(tipologradouro.rua); 17

cliente.setlogradouro("das Margaridas"); cliente.setnumero("1313"); cliente.setcomplemento("quadra 13"); cliente.setbairro("lagoa dos Patos"); cliente.setmunicipio("patópolis"); cliente.setuf(tipounidadefederada.mt); ClienteDAO instance = new ClienteDAO(conBD); int expresult = 1; int result = instance.insert(cliente); assertequals(expresult, result); conbd.commit(); conbd.desconectar(); 7. Adicione as importações necessárias (<Ctrl>+<Shift>+<i>); 8. Execute a classe de teste (<Ctrl>+<F6>); 9. Confira na janela de Serviços a inserção do registro; 10. É importante continuar e desenvolver os testes para as demais operações para manter os registros de clientes, copiando a classe e gerando novas classes, uma para cada método a ser testado. 4.1.3 Exercícios 1. Efetue outros testes de inserção de registros, trocando os dados armazenados pela classe de teste. 2. Implemente os métodos para alterar, excluir, consultar, na classe ClienteDAO, conforme as assinaturas abaixo: public int update(cliente cliente) throws SQLException public int delete(int clicod) throws SQLException public Cliente select(int clicod) throws SQLException public List<Cliente> select() throws SQLException 3. Para cada um dos métodos acima, crie uma classe de teste (copie a classe ClienteDAOInsertTest e faça as devidas adequações), com os nomes que correspondam ao nome de classe e método testado: ClienteDAOUpdateTest, ClienteDAODeleteTest, ClienteDAOSelectTest, ClienteDAOSelectAllTest. 4. Os métodos da classe ClienteDAO estão listados abaixo: public int update(cliente cliente) throws SQLException { String sql = "update cliente set " + "clinome =?, clicpf =?, clitelefone =?, cliemail =?, " + "cliendcep =?, cliendtiplogradouro =?, cliendlogradouro =?, " + "cliendnumero =?, cliendcomplemento =?, cliendbairro =?, cliendmunicipio =?, clienduf =? " + "where clicod =?"; PreparedStatement ps = null; ps = conbd.prepararsql(sql); ps.setstring(1, cliente.getnome()); ps.setstring(2, cliente.getcpf()); ps.setstring(3, cliente.gettelefone()); ps.setstring(4, cliente.getemail()); ps.setstring(5, cliente.getcep()); ps.setint(6, cliente.gettipologradouro().getcodigo()); ps.setstring(7, cliente.getlogradouro()); ps.setstring(8, cliente.getnumero()); ps.setstring(9, cliente.getcomplemento()); ps.setstring(10, cliente.getbairro()); ps.setstring(11, cliente.getmunicipio()); ps.setstring(12, cliente.getuf().getsigla()); ps.setint(13, cliente.getcod()); return ps.executeupdate(); finally { 18

if (ps!= null) { ps.close(); public int delete(int clicod) throws SQLException { String sql = "delete from cliente " + "where clicod =?"; PreparedStatement ps = null; ps = conbd.prepararsql(sql); ps.setint(1, clicod); return ps.executeupdate(); finally { if (ps!= null) { ps.close(); private Cliente getcliente(resultset rs) throws SQLException { Cliente resposta = new Cliente(); int indcampo = 0; resposta.setcod(rs.getint(++indcampo)); resposta.setnome(rs.getstring(++indcampo)); resposta.setcpf(rs.getstring(++indcampo)); resposta.settelefone(rs.getstring(++indcampo)); resposta.setemail(rs.getstring(++indcampo)); resposta.setcep(rs.getstring(++indcampo)); resposta.settipologradouro(tipologradouro.get(rs.getint(++indcampo))); resposta.setlogradouro(rs.getstring(++indcampo)); resposta.setnumero(rs.getstring(++indcampo)); resposta.setcomplemento(rs.getstring(++indcampo)); resposta.setbairro(rs.getstring(++indcampo)); resposta.setmunicipio(rs.getstring(++indcampo)); resposta.setuf(tipounidadefederada.get(rs.getstring(++indcampo))); return resposta; public Cliente select(int clicod) throws SQLException { String sql = "select " + "clicod, clinome, clicpf, clitelefone, cliemail, cliendcep, " + "cliendtiplogradouro, cliendlogradouro, cliendnumero, " + "cliendcomplemento, cliendbairro, cliendmunicipio, clienduf " + "from cliente " + "where clicod =?"; PreparedStatement ps = null; ResultSet rs = null; ps = conbd.prepararsql(sql); ps.setint(1, clicod); rs = ps.executequery(); Cliente resposta = null; if (rs.next()) { 19

resposta = getcliente(rs); return resposta; finally { if (rs!= null) { rs.close(); if (ps!= null) { ps.close(); public List<Cliente> select() throws SQLException { String sql = "select " + "clicod, clinome, clicpf, clitelefone, cliemail, cliendcep, " + "cliendtiplogradouro, cliendlogradouro, cliendnumero, " + "cliendcomplemento, cliendbairro, cliendmunicipio, clienduf " + "from cliente " + "order by clinome"; PreparedStatement ps = null; ResultSet rs = null; ps = conbd.prepararsql(sql); rs = ps.executequery(); ArrayList<Cliente> resposta = new ArrayList<>(); while (rs.next()) { resposta.add(getcliente(rs)); return resposta; finally { if (rs!= null) { rs.close(); if (ps!= null) { ps.close(); 5. Ao inserir o código acima, adicione as importações necessárias (<Ctrl>+<Shift>+<i>). 6. O método auxiliar getcliente foi criado para ser reutilizado, evitando a que tenham códigos duplicados. 7. Crie uma classe para o mapeamento objeto-relacional para a tabela fornecedor, chamada de FornecedorDAO. Crie também as classes de teste para verificar o funcionamento dos métodos da classe. 4.2 Manipulando registros de produtos Após criar a classe FornecedorDAO, podemos criar uma classe específica para a manipulação de produtos. 4.2.1 DAO para a tabela produto 1. Crie uma nova classe, chamada ProdutoDAO, no pacote br.edu.univag.sisped.dao; 2. Seguindo os passos para a criação das classes ClienteDAO e FornecedorDAO, implemente a classe ProdutoDAO: package br.edu.univag.sisped.dao; 20

import br.edu.univag.sisped.tipo.tipounidademedida; import br.edu.univag.sisped.vo.fornecedor; import br.edu.univag.sisped.vo.produto; import br.edu.univag.util.sql.conexaobd; import br.edu.univag.util.sql.dao; import java.sql.preparedstatement; import java.sql.resultset; import java.sql.sqlexception; import java.util.arraylist; import java.util.list; public class ProdutoDAO extends DAO { public ProdutoDAO(ConexaoBD condb) { super(condb); public int insert(produto produto) throws SQLException { String sql = "insert into " + "produto(forcod, pronome, prodescricao, prounimedida, " + "provalunitario) " + "values (?,?,?,?,?)"; PreparedStatement ps = null; ResultSet rs = null; ps = conbd.prepararsql(sql, true); ps.setint(1, produto.getfornecedor().getcod()); ps.setstring(2, produto.getnome()); ps.setstring(3, produto.getdescricao()); ps.setint(4, produto.getunidademedida().getcodigo()); ps.setdouble(5, produto.getvalorunitario()); int resposta = ps.executeupdate(); if (resposta == 1) { int cod = (int) conbd.getchave(ps); produto.setcod(cod); return resposta; finally { if (rs!= null) { rs.close(); if (ps!= null) { ps.close(); " public int update(produto produto) throws SQLException { String sql = "update produto set " + "forcod =?, pronome =?, prodescricao =?, prounimedida =?, + "provalunitario =? " + "where procod =?"; try (PreparedStatement ps = conbd.prepararsql(sql)) { ps.setint(1, produto.getfornecedor().getcod()); ps.setstring(2, produto.getnome()); 21

ps.setstring(3, produto.getdescricao()); ps.setint(4, produto.getunidademedida().getcodigo()); ps.setdouble(5, produto.getvalorunitario()); ps.setint(6, produto.getcod()); return ps.executeupdate(); public int delete(int procod) throws SQLException { String sql = "delete from produto " + "where procod =?"; try (PreparedStatement ps = conbd.prepararsql(sql)) { ps.setint(1, procod); return ps.executeupdate(); private Produto getproduto(resultset rs) throws SQLException { Produto resposta = new Produto(); int indcampo = 0; resposta.setcod(rs.getint(++indcampo)); int forcod = rs.getint(++indcampo); resposta.setnome(rs.getstring(++indcampo)); resposta.setdescricao(rs.getstring(++indcampo)); resposta.setunidademedida(tipounidademedida.get(rs.getint(++indcampo))); resposta.setvalorunitario(rs.getdouble(++indcampo)); FornecedorDAO fornecedordao = new FornecedorDAO(conBD); Fornecedor fornecedor = fornecedordao.select(forcod); resposta.setfornecedor(fornecedor); return resposta; public Produto select(int procod) throws SQLException { String sql = "select " + "procod, forcod, pronome, prodescricao, prounimedida, " + "provalunitario " + "from produto " + "where procod =?"; PreparedStatement ps = null; ResultSet rs = null; ps = conbd.prepararsql(sql); ps.setint(1, procod); rs = ps.executequery(); Produto resposta = null; if (rs.next()) { resposta = getproduto(rs); return resposta; finally { if (rs!= null) { 22

rs.close(); if (ps!= null) { ps.close(); public List<Produto> select() throws SQLException { String sql = "select " + "procod, forcod, pronome, prodescricao, prounimedida, " + "provalunitario " + "from produto " + "order by pronome"; PreparedStatement ps = null; ResultSet rs = null; ps = conbd.prepararsql(sql); rs = ps.executequery(); ArrayList<Produto> resposta = new ArrayList<>(); while (rs.next()) { resposta.add(getproduto(rs)); return resposta; finally { if (rs!= null) { rs.close(); if (ps!= null) { ps.close(); 3. Note que como os dados do fornecedor são referenciados em vez de se guardar o código do fornecedor, o método para recuperar os dados de um registro acaba fazendo uma consulta para obter os dados do fornecedor usando a classe FornecedorDAO. Caso haja necessidade de alta performance, esse tipo de consulta deve ser evitado. 4.2.2 Testando a tabela produto Crie uma classe de teste para testar todo o fluxo de manutenção de um registro de banco de dados: 1. Crie um novo Teste para a Classe Existente; 2. Selecione a classe br.edu.univag.sisped.dao.produtodao para testar; 3. Clique no botão Finalizar; 4. Para exercitarmos o fluxo completo, primeiramente precisamos armazenar o registro inserido no banco de dados, criando um atributo de classe: private static Produto produto; 5. Adicione as importações necessárias (<Ctrl>+<Shift>+<i>); 6. Adicionalmente, para evitarmos os trechos repetitivos de preparação de conexão, transação e mapeamento objeto-relacional, precisamos de mais dois atributos, um para tratar das conexões com o banco de dados (ConexaoBD) e outro para a integração com a camada de persistência: private ConexaoBD conbd; private ProdutoDAO produtodao; 7. Adicione as importações necessárias (<Ctrl>+<Shift>+<i>); 23

8. O método setup é chamado antes de cada método de teste, enquanto o método teardown é chamado após cada método de teste: @Before public void setup() { System.out.println("setUp"); conbd = new ConexaoBD(); conbd.conectar(); produtodao = new ProdutoDAO(conBD); @After public void teardown() { System.out.println("tearDown"); conbd.commit(); conbd.desconectar(); 9. Agora, devemos implementar os métodos de teste em uma ordem em que possamos testar a implementação: package br.edu.univag.sisped.dao; import br.edu.univag.sisped.tipo.tipounidademedida; import br.edu.univag.sisped.vo.fornecedor; import br.edu.univag.sisped.vo.produto; import br.edu.univag.util.sql.conexaobd; import java.util.list; import org.junit.after; import org.junit.afterclass; import org.junit.before; import org.junit.beforeclass; import org.junit.test; import static org.junit.assert.*; public class ProdutoDAOTest { private static Produto produto; private ConexaoBD conbd; private ProdutoDAO produtodao; public ProdutoDAOTest() { @BeforeClass public static void setupclass() { @AfterClass public static void teardownclass() { @Before public void setup() { System.out.println("setUp"); conbd = new ConexaoBD(); conbd.conectar(); produtodao = new ProdutoDAO(conBD); 24

@After public void teardown() { System.out.println("tearDown"); conbd.commit(); conbd.desconectar(); @Test public void testinsert() throws Exception { System.out.println("insert"); FornecedorDAO fornecedordao = new FornecedorDAO(conBD); Fornecedor fornecedor = fornecedordao.select(1); produto = new Produto(); produto.setfornecedor(fornecedor); produto.setnome("arroz Tio Sam"); produto.setdescricao("arroz tipo agulhinha, descascado"); produto.setunidademedida(tipounidademedida.metro); produto.setvalorunitario(2.34); int expresult = 1; int result = produtodao.insert(produto); assertequals(expresult, result); @Test public void testupdate() throws Exception { System.out.println("update"); produto.setnome("arroz Tio João"); produto.setdescricao("arroz tipo 1, agulhinha"); produto.setunidademedida(tipounidademedida.quilograma); produto.setvalorunitario(2.82); int expresult = 1; int result = produtodao.update(produto); assertequals(expresult, result); @Test public void testselect_int() throws Exception { System.out.println("select por código"); int procod = produto.getcod(); Produto expresult = produto; Produto result = produtodao.select(procod); assertequals(expresult, result); @Test public void testselect_0args() throws Exception { System.out.println("select todos"); List<Produto> result = produtodao.select(); 25

asserttrue(result.size() > 0); @Test public void testdelete() throws Exception { System.out.println("delete"); int procod = produto.getcod(); int expresult = 1; int result = produtodao.delete(procod); assertequals(expresult, result); 10. Utilize o assistente do Netbeans para criar os métodos equals e hashcode, selecionando todos os atributos, para cada um dos Value Objects ou JavaBeans (Cliente, Fornecedor, Produto, Pedido e PedidoItem), permitindo uma comparação do conteúdo dos objetos; 4.2.3 Exercícios 1. Implemente a classe ProdutoDAO (será necessário implementar a classe FornecedorDAO antes), fazendo um teste a cada método criado. 2. Implemente a classe de testes a cada método (insert, update, delete, select) implementado na classe ProdutoDAO, incrementando aos poucos. 3. O enum Java TipoUnidadeMedida possui a seguinte implementação: package br.edu.univag.sisped.tipo; public enum TipoUnidadeMedida { LITRO(1, "l", "Litro"), METRO(2, "m", "Metro"), QUILOGRAMA(3, "kg", "Quilograma"), TONELADA(4, "t", "Tonelada"), UNIDADE(5, "un", "Unidade"); private final int codigo; private final String simbolo; private final String nome; private TipoUnidadeMedida(int codigo, String simbolo, String nome) { this.codigo = codigo; this.simbolo = simbolo; this.nome = nome; public int getcodigo() { return codigo; public String getsimbolo() { return simbolo; public String getnome() { return nome; public static TipoUnidadeMedida get(int codigo) { TipoUnidadeMedida resposta = null; 26

for (TipoUnidadeMedida t : values()) { if (t.getcodigo() == codigo) { resposta = t; return resposta; 4. Note que em um enum Java podemos colocar quantos atributos forem necessários no nosso projeto. No caso do TipoUnidadeMedida foram utilizados três atributos: codigo (a ser armazenado no banco de dados), simbolo e nome. 4.3 Manipulando registros de pedidos A entidade de armazenamento de pedidos é diferente das três anteriores, pois ela agrega os itens de pedidos, que não sentido se existirem sozinhas. Portanto, teremos somente um único DAO para as duas tabelas. Teremos também uma consulta de todos os pedidos de um cliente, um cenário muito comum em aplicações comerciais. 4.3.1 DAO para a tabela pedido 1. Crie uma nova classe Java, chamada PedidoDAO, no pacote br.edu.univag.sisped.dao; 2. Estenda a classe br.edu.univag.util.sql.dao; 3. Implemente o construtor recebendo uma referência de ConexaoBD como parâmetro; 4. Implemente o restante de acordo com a seguinte listagem: package br.edu.univag.sisped.dao; import br.edu.univag.sisped.tipo.tipounidademedida; import br.edu.univag.sisped.vo.cliente; import br.edu.univag.sisped.vo.pedido; import br.edu.univag.sisped.vo.pedidoitem; import br.edu.univag.sisped.vo.produto; import br.edu.univag.util.sql.conexaobd; import br.edu.univag.util.sql.dao; import java.sql.date; import java.sql.preparedstatement; import java.sql.resultset; import java.sql.sqlexception; import java.util.arraylist; import java.util.list; public class PedidoDAO extends DAO { public PedidoDAO(ConexaoBD condb) { super(condb); public int insert(pedido pedido) throws SQLException { String sql = "insert into " + "pedido(clicod, peddata) " + "values (?,?)"; PreparedStatement ps = null; ResultSet rs = null; ps = conbd.prepararsql(sql, true); ps.setint(1, pedido.getcliente().getcod()); ps.setdate(2, new Date(pedido.getData().getTime())); int resposta = ps.executeupdate(); 27

if (resposta == 1) { int cod = (int) conbd.getchave(ps); pedido.setcod(cod); resposta += insert(cod, pedido.getitens()); return resposta; finally { if (rs!= null) { rs.close(); if (ps!= null) { ps.close(); { private int insert(int pedcod, List<PedidoItem> itens) throws SQLException String sql = "insert into " + "pedido_item(pedcod, procod, pedproquantidade) " + "values (?,?,?)"; try (PreparedStatement ps = conbd.prepararsql(sql)) { ps.setint(1, pedcod); for (PedidoItem item : itens) { ps.setint(2, item.getproduto().getcod()); ps.setdouble(3, item.getquantidade()); ps.addbatch(); int resposta = 0; int[] qtdregistros = ps.executebatch(); for (int qtdregistro : qtdregistros) { resposta += qtdregistro; return resposta; private int deleteitem(int pedcod) throws SQLException { String sql = "delete from pedido_item " + "where pedcod =?"; try (PreparedStatement ps = conbd.prepararsql(sql)) { ps.setint(1, pedcod); return ps.executeupdate(); public int update(pedido pedido) throws SQLException { String sql = "update pedido set " + "clicod =?, peddata =? " + "where pedcod =?"; PreparedStatement ps = null; 28

ResultSet rs = null; ps = conbd.prepararsql(sql); ps.setint(1, pedido.getcliente().getcod()); ps.setdate(2, new Date(pedido.getData().getTime())); ps.setint(3, pedido.getcod()); int resposta = ps.executeupdate(); resposta += deleteitem(pedido.getcod()); resposta += insert(pedido.getcod(), pedido.getitens()); return resposta; finally { if (rs!= null) { rs.close(); if (ps!= null) { ps.close(); public int delete(int pedcod) throws SQLException { String sql = "delete from pedido " + "where pedcod =?"; try (PreparedStatement ps = conbd.prepararsql(sql)) { ps.setint(1, pedcod); int resposta = deleteitem(pedcod); resposta += ps.executeupdate(); return resposta; private PedidoItem geitem(resultset rs) throws SQLException { Produto produto = new Produto(); produto.setcod(rs.getint("procod")); produto.setnome(rs.getstring("pronome")); produto.setunidademedida(tipounidademedida.get(rs.getint("prounimedida"))); produto.setvalorunitario(rs.getdouble("provalunitario")); PedidoItem resposta = new PedidoItem(); resposta.setproduto(produto); resposta.setquantidade(rs.getdouble("pedproquantidade")); return resposta; private List<PedidoItem> selectitem(int pedcod) throws SQLException { String sql = "select " + "i.procod, i.pedproquantidade, " + "pronome, prounimedida, provalunitario " + "from pedido_item i " + "inner join produto p on (p.procod = i.procod) " + "where i.pedcod =? " + "order by pronome"; PreparedStatement ps = null; 29

ResultSet rs = null; ps = conbd.prepararsql(sql); ps.setint(1, pedcod); rs = ps.executequery(); ArrayList<PedidoItem> resposta = new ArrayList<>(); while (rs.next()) { resposta.add(geitem(rs)); return resposta; finally { if (rs!= null) { rs.close(); if (ps!= null) { ps.close(); private Pedido getpedido(resultset rs) throws SQLException { Pedido resposta = new Pedido(); int indcampo = 0; resposta.setcod(rs.getint(++indcampo)); int clicod = rs.getint(++indcampo); resposta.setdata(rs.getdate(++indcampo)); ClienteDAO clientedao = new ClienteDAO(conBD); Cliente cliente = clientedao.select(clicod); resposta.setcliente(cliente); resposta.setitens(selectitem(resposta.getcod())); return resposta; public Pedido select(int pedcod) throws SQLException { String sql = "select " + "pedcod, clicod, peddata " + "from pedido " + "where pedcod =?"; PreparedStatement ps = null; ResultSet rs = null; ps = conbd.prepararsql(sql); ps.setint(1, pedcod); rs = ps.executequery(); Pedido resposta = null; if (rs.next()) { resposta = getpedido(rs); return resposta; finally { if (rs!= null) { 30

rs.close(); if (ps!= null) { ps.close(); public List<Pedido> select() throws SQLException { String sql = "select " + "pedcod, clicod, peddata " + "from pedido " + "order by pedcod"; PreparedStatement ps = null; ResultSet rs = null; ps = conbd.prepararsql(sql); rs = ps.executequery(); ArrayList<Pedido> resposta = new ArrayList<>(); while (rs.next()) { resposta.add(getpedido(rs)); return resposta; finally { if (rs!= null) { rs.close(); if (ps!= null) { ps.close(); public List<Object[]> selectbycliente(int clicod) throws SQLException { String sql = "select " + "p.pedcod, p.clicod, " + "date_format(p.peddata, '%d/%m/%y') data, " + "format(sum(pi.pedproquantidade), 3, 'de_de') quantidade, " + "format(sum(pi.pedproquantidade * prod.provalunitario), 2, 'de_de') valor_total " + "from pedido p " + "inner join pedido_item pi on (pi.pedcod = p.pedcod) " + "inner join produto prod on (prod.procod = pi.procod) " + "where p.clicod =? " + "group by p.pedcod, p.clicod, p.peddata " + "order by p.pedcod"; PreparedStatement ps = null; ResultSet rs = null; ps = conbd.prepararsql(sql); ps.setint(1, clicod); rs = ps.executequery(); ArrayList<Object[]> resposta = new ArrayList<>(); 31

while (rs.next()) { Object[] linha = new Object[]{ rs.getint(1), rs.getstring(3), rs.getstring(4), rs.getstring(5) ; resposta.add(linha); return resposta; finally { if (rs!= null) { rs.close(); if (ps!= null) { ps.close(); 5. Note que o código ficou maior em razão da responsabilidade da classe. 4.3.2 Testando a tabela pedido 1. Para testar, será necessário obter os dados necessários para a gravação, recuperação, alteração e exclusão dos dados que, neste caso devem ser dados contidos em uma transação; 2. Crie uma classe de teste, denominado PedidoDAOTest, para a classe PedidoDAO, seguindo os passos para a criação de teste da classe ProdutoDAO. 3. O código-fonte deve ficar parecido com o apresentado a seguir: package br.edu.univag.sisped.dao; import br.edu.univag.sisped.vo.cliente; import br.edu.univag.sisped.vo.pedido; import br.edu.univag.sisped.vo.pedidoitem; import br.edu.univag.sisped.vo.produto; import br.edu.univag.util.sql.conexaobd; import java.util.arraylist; import java.util.calendar; import java.util.date; import java.util.list; import org.junit.after; import org.junit.afterclass; import org.junit.before; import org.junit.beforeclass; import org.junit.test; import static org.junit.assert.*; public class PedidoDAOTest { private static Pedido pedido; private ConexaoBD conbd; private PedidoDAO pedidodao; public PedidoDAOTest() { @BeforeClass public static void setupclass() { @AfterClass 32

public static void teardownclass() { @Before public void setup() { System.out.println("setUp"); conbd = new ConexaoBD(); conbd.conectar(); pedidodao = new PedidoDAO(conBD); @After public void teardown() { System.out.println("tearDown"); conbd.commit(); conbd.desconectar(); @Test public void testinsert() throws Exception { System.out.println("insert"); Cliente cliente = new Cliente(); cliente.setcod(1); Produto produto = new Produto(); produto.setcod(1); PedidoItem item = new PedidoItem(); item.setproduto(produto); item.setquantidade(15.123); List<PedidoItem> itens = new ArrayList<>(); itens.add(item); pedido = new Pedido(); pedido.setcliente(cliente); pedido.setdata(new Date()); pedido.setitens(itens); int result = pedidodao.insert(pedido); asserttrue(result > 1); @Test public void testupdate() throws Exception { System.out.println("update"); Calendar calendar = Calendar.getInstance(); calendar.set(calendar.hour, 0); calendar.set(calendar.minute, 0); calendar.set(calendar.second, 0); calendar.set(calendar.millisecond, 0); pedido.setdata(calendar.gettime()); int result = pedidodao.update(pedido); asserttrue(result > 1); 33

@Test public void testselect_int() throws Exception { System.out.println("select"); int pedcod = pedido.getcod(); Pedido result = pedidodao.select(pedcod); assertnotnull(result); @Test public void testselect_0args() throws Exception { System.out.println("select"); List<Pedido> result = pedidodao.select(); assertfalse(result.isempty()); @Test public void testselectbycliente() throws Exception { System.out.println("selectByCliente"); int clicod = 1; List<Pedido> result = pedidodao.selectbycliente(clicod); assertfalse(result.isempty()); @Test public void testdelete() throws Exception { System.out.println("delete"); int pedcod = pedido.getcod(); int result = pedidodao.delete(pedcod); asserttrue(result > 0); 4. Ajuste os valores de acordo com os registros armazenados em seu banco de dados. 4.3.3 Exercícios 1. Implemente as classes DAO apresentados neste capítulo. 2. Implemente também as classes de teste unitário para avaliar o funcionamento das classes implementadas. Implemente aos poucos, para poder testar com mais precisão. 34

Prática 5: Denvolvimento da interface gráfica da aplicação Vamos agora criar as telas da nossa aplicação. Começaremos com uma tela principal, contendo o menu principal e depois as telas para manter os dados da aplicação. 1. Crie um novo pacote de código-fonte, chamado br.edu.univag.sisped.view; 2. No pacote acima iremos criar as nossas telas. 5.1 Tela principal da aplicação 1. No pacote br.edu.univag.sisped.view, crie um novo Form JFrame; 2. No campo nome da classe, informe FrmPrincipal; 3. Clique no botão Finalizar; 4. Na janela de Propriedades, altere o título (title) para Sistema de Pedido; 5. Na janela de Propriedades, altere o tamanho preferido (preferredsize) para [640, 480]; 6. Mude para a visão de código-fonte e localize o construtor, inserindo o código abaixo no final para maximizar o formulário principal: setextendedstate(jframe.maximized_both); 7. Entre nas propriedades da aplicação, usando o botão direito do mouse sobre o projeto sisped; 8. Na categoria Executar, selecione br.edu.univag.sisped.view.frmprincipal como a classe principal; 9. Clique no botão OK para confirmar; 10. Execute a aplicação (<F6>). 5.1.1 Menu principal da aplicação 1. Mude para a visão de projeto; 2. Clique com o botão direito do mouse sobre a área de desenho do formulário e selecione o comando Adicionar da Paleta > Menus Swing > Barra de Menu; 3. Altere os textos (text) dos menus iniciais e acrescente mais um menu, itens de menu e separadores usando o botão direito do mouse e selecionando o comando Adicionar da Paleta, para que o menu fique na seguinte configuração: 4. Os menus Consulta e Relatório não possuem conteúdo e foram colocados apenas como exemplos; 5. Implemente a ação para o comando Sair: dispatchevent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); 6. Execute a aplicação (<F6>). 5.1.2 Aplicação Multi Document Interface (MDI) Aplicações que possuam interface de múltiplos documentos ou multi document interface (MDI) é muito comum. Por exemplo, os editores de texto possuem esse tipo de interface, onde cada uma das janelas filhas é aberta em área específica dentro da janela principal. 1. Retorne para a visão de Projeto; 2. Clique com o botão direito do mouse sobre a janela principal da aplicação, acionando o comando Adicionar da Paleta > Contêineres Swing > Painel da Área de Trabalho; 3. Redimensione o novo painel (jdesktoppane1) para ocupar toda a área cliente da janela principal; 4. Execute a aplicação (<F6>), confira como deve ficar a janela: 35

5.1.3 Exercícios 1. Por que na implementação do comando Sair não foi usado o comando System.exit(0);? 2. Descreva o que são aplicações MDI? 3. Qual a vantagem em se implementar aplicação com formulários MDI? 5.2 Tela do cadastro de clientes Nesta seção criaremos uma janela filha (JInternalFrame) para representar os dados do cliente, a ser aberta como subjanela da janela principal da aplicação. 5.2.1 Criação da janela filha de cadastro de clientes 1. Crie um novo JInternalFrame, no pacote br.edu.univag.pedido.view; 2. Informe FrmCadCliente, como o nome da classe; 3. Clique no botão Finalizar; 4. Na janela de Propriedades, altere o título (title) para Cadastro de Cliente; 5. Na janela de Propriedades, marque a opção closable; 6. Na janela de Propriedades, marque a opção maximizable; 7. Na janela de Propriedades, marque a opção resizable; 8. Volte para o formulário principal e adicione a seguinte implementação para o item de menu Cadastro > Cliente, para abrir o formulário de cadastro de clientes criados acima: JInternalFrame frame = null; for (JInternalFrame f : jdesktoppane1.getallframes()) { if (f.gettitle().equals("cadastro de Cliente")) frame = f; if (frame == null) { frame = new FrmCadCliente(); jdesktoppane1.add(frame); frame.setvisible(true); //Trate exceção nas duas linhas abaixo frame.setselected(true); frame.setmaximum(true); 9. Execute a aplicação (<F6>). 5.2.2 Criação do painel com guias (JTabbedPane) 1. Volte ao formulário de cadastro de cliente; 2. Adicione um Painel com Guias (Contâineres Swing) no formuário; 3. Redimensione o painel com guias (jtabbedpane1) para que ocupe toda a área cliente da janela do cadastro de cliente; 4. No painel com guias (jtabbedpane1), adicione três painéis (Contâineres Swing > Painel) com as seguintes 36

propriedades: Painel Propriedade Valor jpane1 Título da Tab Cadastro jpane2 Título da Tab Registros 5. Veja como ficou a janela com os painéis: 6. Execute a aplicação, executando a classe (<F6>). 5.2.3 Design da aba Cadastro 1. Na aba Cadastro, inclua os seguintes componentes, com as propriedades abaixo especificados: Componente Propriedade Valor Label (Controles Swing) text Código JTextField (Controles Swing) text Apague o conteúdo horizontalalignment RIGHT enabled Desmarque a opção preferredsize [72, 27] nome (janela Navegador) codigo Label (Controles Swing) text Nome JTextField (Controles Swing) text Apague o conteúdo preferredsize [508, 27] nome (janela Navegador) nome Label (Controles Swing) text CPF JFormattedTextField (Controles text Apague o conteúdo Swing) formatterfactory Máscara personalizada ###.###.###-## preferredsize [120, 27] nome (janela Navegador) cpf Label (Controles Swing) text Telefone JFormattedTextField (Controles text Apague o conteúdo Swing) formatterfactory Máscara personalizada (##) *####-#### preferredsize [140, 27] nome (janela Navegador) telefone Label (Controles Swing) text e-mail JTextField (Controles Swing) text Apague o conteúdo preferredsize [300, 27] nome (janela Navegador) email Label (Controles Swing) text CEP JFormattedTextField (Controles text Apague o conteúdo Swing) formatterfactory Máscara personalizada ##.###-### preferredsize [100, 27] nome (janela Navegador) cep 37

Label (Controles Swing) text Tipo JComboBox model Código personalizado new DefaultComboBoxModel(Tip ologradouro.values()) preferredsize [100, 27] nome (janela Navegador) tipologradouro Label (Controles Swing) text Logradouro JTextField (Controles Swing) text Apague o conteúdo preferredsize [350, 27] nome (janela Navegador) logradouro Label (Controles Swing) text Número JTextField (Controles Swing) text Apague o conteúdo preferredsize [80, 27] nome (janela Navegador) numero Label (Controles Swing) text Complemento JTextField (Controles Swing) text Apague o conteúdo preferredsize [90, 27] nome (janela Navegador) complemento Label (Controles Swing) text Bairro JTextField (Controles Swing) text Apague o conteúdo preferredsize [150, 27] nome (janela Navegador) bairro Label (Controles Swing) text Município JTextField (Controles Swing) text Apague o conteúdo preferredsize [150, 27] nome (janela Navegador) municipio Label (Controles Swing) text UF JComboBox model Código personalizado new DefaultComboBoxModel(Tip ounidadefederada.values( )) preferredsize [55, 27] nome (janela Navegador) uf JButton (Controles Swing) label Salvar Registro nome (janela Navegador) btnsalvar JButton (Controles Swing) label Limpar Formulário nome (janela Navegador) btnlimpar 2. Alterne para a visão de código-fonte e corrija as importações (<Ctrl>+<Shift>+<i>); 3. Implemente o método tostring em TipoLogradouro, para que seja exibido o conteúdo do atributo descricao no campo Tipo (de logradouro): @Override public String tostring() { return getdescricao(); 4. Veja como ficou o resultado final: 38

5. Implemente a ação para o botão Salvar Registro: //Preenche os dados a serem armazenados Cliente cliente = new Cliente(); if (!"".equals(codigo.gettext())) { cliente.setcod(integer.parseint(codigo.gettext())); cliente.setnome(nome.gettext().trim()); cliente.setcpf(cpf.gettext().trim()); cliente.settelefone(telefone.gettext().trim()); cliente.setemail(email.gettext().trim()); cliente.setcep(cep.gettext().trim()); cliente.settipologradouro((tipologradouro) tipologradouro.getselecteditem()); cliente.setlogradouro(logradouro.gettext().trim()); cliente.setnumero(numero.gettext().trim()); cliente.setcomplemento(complemento.gettext().trim()); cliente.setbairro(bairro.gettext().trim()); cliente.setmunicipio(municipio.gettext().trim()); cliente.setuf((tipounidadefederada)uf.getselecteditem()); //Grava o registro no banco de dados ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); ClienteDAO clientedao = new ClienteDAO(conBD); if ("".equals(codigo.gettext())) { String mensagem = String.format("Confirma a inclusão do cliente '%s'?", nome.gettext()); if (JOptionPane.showConfirmDialog(this, mensagem, "Incluir Registro", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { clientedao.insert(cliente); codigo.settext(string.valueof(cliente.getcod())); JOptionPane.showMessageDialog(this, "Inclusão realizada com sucesso.", "Informação", JOptionPane.INFORMATION_MESSAGE); else { JOptionPane.showMessageDialog(this, "Inclusão cancelada.", "Informação", JOptionPane.INFORMATION_MESSAGE); else { 39

String mensagem = String.format("Confirma a alteração do cliente '%s'?", nome.gettext()); if (JOptionPane.showConfirmDialog(this, mensagem, "Alterar Registro", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { clientedao.update(cliente); JOptionPane.showMessageDialog(this, "Alteração realizada com sucesso.", "Informação", JOptionPane.INFORMATION_MESSAGE); else { JOptionPane.showMessageDialog(this, "Alteração cancelada.", "Informação", JOptionPane.INFORMATION_MESSAGE); catch (SQLException e) { JOptionPane.showMessageDialog(this, e.getmessage(), "Erro", JOptionPane.ERROR_MESSAGE); conbd.commit(); conbd.desconectar(); 6. Corrija as importações (<Ctrl>+<Shift>+<i>); 7. Implemente a ação para o botão Limpar Formulário: codigo.settext(""); nome.settext(""); cpf.settext(""); telefone.settext(""); email.settext(""); cep.settext(""); tipologradouro.setselectedindex(0); logradouro.settext(""); numero.settext(""); complemento.settext(""); bairro.settext(""); municipio.settext(""); uf.setselectedindex(0); 8. Execute a aplicação (<F6>). 5.2.4 Design da aba Registros Nesta aba teremos a lista de todos os clientes cadastrados no sistema. Iremos utilizar ela para listar, alterar ou excluir clientes. 1. Adicione um JPanel (Contêineres Swing) alinhado à parte superior, para incluirmos os botões de ação; 2. Inclua no painel do passo 1 três botões, com as seguintes propriedades: Componente Propriedade Valor JButton (Controles Swing) text Listar Registros preferredsize [150, 27] nome (janela Navegador) btnlistarregistros JButton (Controles Swing) text Alterar Registro preferredsize [150, 27] nome (janela Navegador) btnalterarregistro JButton (Controles Swing) text ExcluirRegistro preferredsize [150, 27] nome (janela Navegador) btnexcluirregistro 3. Ajuste a altura do painel criado no passo 1; 4. Insira um JTabble (Controles Swing) e redimensione-o para ocupar o restante da janela, com as seguintes configurações: Propriedade autocreaterowsorter autoresizemode selectionmodel Marque esta opção OFF Seleção Única Valor 40

model Código personalizado: new javax.swing.table.defaulttablemodel( new Object [][] {, new String [] { "Código", "Nome", "Telefone", "e-mail" ) { public boolean iscelleditable(int row, int column) { return false; nome (janela Navegador) registros 5. Adicione as seguintes instruções no construtor, para alinhar o código à direita: //Alinha os números da tabela à direita DefaultTableCellRenderer rightrenderer = new DefaultTableCellRenderer(); rightrenderer.sethorizontalalignment(defaulttablecellrenderer.right); registros.getcolumn("código").setcellrenderer(rightrenderer); //Redimensiona as colunas da tabela TableColumnModel colunas = registros.getcolumnmodel(); colunas.getcolumn(0).setpreferredwidth(60); colunas.getcolumn(1).setpreferredwidth(160); colunas.getcolumn(2).setpreferredwidth(120); colunas.getcolumn(3).setpreferredwidth(250); 6. Implemente a ação para o botão Listar Registros: //Limpa a tabela de registros DefaultTableModel tabela = (DefaultTableModel) registros.getmodel(); tabela.setrowcount(0); ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); ClienteDAO clientedao = new ClienteDAO(conBD); List<Cliente> clientes = clientedao.select(); for (Cliente cliente : clientes) { Object[] linha = new Object[]{ cliente.getcod(), cliente.getnome(), cliente.gettelefone(), cliente.getemail() ; tabela.addrow(linha); catch (SQLException ex) { JOptionPane.showMessageDialog(this, ex.getmessage(), "Erro", JOptionPane.ERROR_MESSAGE); Logger.getLogger(FrmCadCliente.class.getName()).log(Level.SEVERE, ex); conbd.desconectar(); 7. Implemente a ação para o botão Alterar Registro: //Obtém o identificador do cliente DefaultTableModel tabela = (DefaultTableModel) registros.getmodel(); Object codigoobj = tabela.getvalueat(registros.getselectedrow(), 0); int clicod = (Integer) codigoobj; null, //Muda para a primeira aba jtabbedpane1.setselectedindex(0); 41

//Recupera o registro ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); ClienteDAO clientedao = new ClienteDAO(conBD); Cliente cliente = clientedao.select(clicod); codigo.settext(string.valueof(cliente.getcod())); nome.settext(cliente.getnome()); cpf.settext(cliente.getcpf()); telefone.settext(cliente.gettelefone()); email.settext(cliente.getemail()); cep.settext(cliente.getcep()); tipologradouro.setselecteditem(cliente.gettipologradouro()); logradouro.settext(cliente.getlogradouro()); numero.settext(cliente.getnumero()); complemento.settext(cliente.getcomplemento()); bairro.settext(cliente.getbairro()); municipio.settext(cliente.getmunicipio()); uf.setselecteditem(cliente.getuf()); catch (SQLException ex) { JOptionPane.showMessageDialog(this, ex.getmessage(), "Erro", JOptionPane.ERROR_MESSAGE); Logger.getLogger(FrmCadCliente.class.getName()).log(Level.SEVERE, ex); conbd.desconectar(); 8. Implemente a ação para o botão Excluir Registro: //Obtém o identificador do cliente DefaultTableModel tabela = (DefaultTableModel) registros.getmodel(); Object clicodobj = tabela.getvalueat(registros.getselectedrow(), 0); Object clinomeobj = tabela.getvalueat(registros.getselectedrow(), 1); int clicod = (Integer) clicodobj; String clinome = (String) clinomeobj; null, //Exclui o registro ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); ClienteDAO clientedao = new ClienteDAO(conBD); String mensagem = String.format("Confirma a exclusão do cliente '%s'?", clinome); if (JOptionPane.showConfirmDialog(this, mensagem, "Excluir Registro", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { clientedao.delete(clicod); JOptionPane.showMessageDialog(this, "Exclusão realizada com sucesso.", "Informação", JOptionPane.INFORMATION_MESSAGE); btnlistarregistrosactionperformed(evt); else { JOptionPane.showMessageDialog(this, "Exclusão cancelada.", "Informação", JOptionPane.INFORMATION_MESSAGE); catch (SQLException ex) { JOptionPane.showMessageDialog(this, ex.getmessage(), "Erro", JOptionPane.ERROR_MESSAGE); Logger.getLogger(FrmCadCliente.class.getName()).log(Level.SEVERE, null, ex); conbd.commit(); conbd.desconectar(); 42

9. A aba de registros tem a seguinte interface: 10. Corrija as importações necessárias (<Ctrl>+<Shift>+<i>); 11. Execute a aplicação (<F6>). 5.2.5 Exercícios 1. Crie um novo JInternalFrame (chamado FrmCadFornecedor) e, usando os componentes visuais apresentados até o momento, implemente uma tela com dois painéis, um para entrada de dados e outro para listar os registros, para manter os registros da tabela fornecedor. É necessário executar todo o fluxo apresentado: incluir, alterar, listar, consultar e excluir os fornecedores. Não esqueça de incluir uma ação no menu do formulário principal para chamar este novo formulário interno. 2. Como as larguras das colunas da tabela de registros foi definida? 3. Como a tabela foi configurada para se comportar como somente leitura? 4. O uso de somente um formulário para incluir, alterar, listar, consultar e excluir registros facilita a operação da aplicação do ponto de vista do usuário final? Existe alguma forma melhor e mais amigável possível de ser implementado? 5.3 Consulta de Pedidos por Cliente Nesta seção iremos implementar a consulta de pedidos por cliente. 5.3.1 Criando a tela de consulta 1. Crie um novo Form JInternalFrame, chamado br.edu.univag.sisped.viewfrmconclipedido, alterando as seguintes propriedades: a) closable: marque esta propriedade; b) maximizable: marque esta propriedade; c) resizable: marque esta propriedade; d) title: Consulta de Pedidos por Cliente; e) preferredsize: [640, 480]. 2. Insira um JPanel (Contêineres Swing) alinhado na parte superior, contendo os seguintes componentes e propriedades: Componente Propriedade Valor JLabel Text Cliente: JComboBox Model Código personalizado: new DefaultComboBoxModel(get Clientes()) preferredsize [450, 27] nome (janela Navegador) cliente JButton Text Consultar preferredsize [100, 27] 43

nome (janela Navegador) btnconsultar 3. Ajuste a altura do JPanel criado acima para que os componentes fiquem distribuídos visualmente; 4. Crie o método getclientes( ), utilizado para popular a caixa de combinação contendo a lista de clientes: private Object[] getclientes() { ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); ClienteDAO clientedao = new ClienteDAO(conBD); List<Cliente> clientes = clientedao.select(); return clientes.toarray(); catch (SQLException e) { JOptionPane.showMessageDialog(this, e.getmessage(), "Erro", JOptionPane.ERROR_MESSAGE); return new Object[0]; finally { conbd.desconectar(); 5. Sobrescreva o método tostring da classe Object, na classe Cliente (br.edu.univag.sisped.vo), para que sejam exibidos somente os nomes dos clientes na combobox contendo os clientes: @Override public String tostring() { return getnome(); 6. Insira um JTabble (Controles Swing) e redimensione-o para ocupar o restante da janela, com as seguintes configurações: Propriedade Valor autocreaterowsorter Marque esta opção autoresizemode OFF selectionmodel model nome (janela Navegador) pedidos 7. Veja como ficou o leiaute do formulário: Seleção Única Código personalizado: new javax.swing.table.defaulttablemodel( new Object [][] {, new String [] { "Código", "Data", "Quantidade", "Valor Total" ) { public boolean iscelleditable(int row, int column) { return false; 44

8. Adicione o código para um ajuste mais fino no construtor da janela: //Alinha os números da tabela à direita DefaultTableCellRenderer rightrenderer = new DefaultTableCellRenderer(); rightrenderer.sethorizontalalignment(defaulttablecellrenderer.right); pedidos.getcolumn("código").setcellrenderer(rightrenderer); pedidos.getcolumn("quantidade").setcellrenderer(rightrenderer); pedidos.getcolumn("valor Total").setCellRenderer(rightRenderer); //Alinha a data da tabela no centro DefaultTableCellRenderer centerrenderer = new DefaultTableCellRenderer(); centerrenderer.sethorizontalalignment(defaulttablecellrenderer.center); pedidos.getcolumn("data").setcellrenderer(centerrenderer); //Redimensiona as colunas da tabela TableColumnModel colunas = pedidos.getcolumnmodel(); colunas.getcolumn(0).setpreferredwidth(80); colunas.getcolumn(1).setpreferredwidth(160); colunas.getcolumn(2).setpreferredwidth(160); colunas.getcolumn(3).setpreferredwidth(200); 9. Implementa a ação para o botão Consultar: //Limpa a tabela de registros DefaultTableModel tabela = (DefaultTableModel) pedidos.getmodel(); tabela.setrowcount(0); ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); PedidoDAO pedidodao = new PedidoDAO(conBD); Cliente cli = (Cliente)cliente.getSelectedItem(); List<Object[]> linhas = pedidodao.selectbycliente(cli.getcod()); for (Object[] linha : linhas) { tabela.addrow(linha); catch (SQLException ex) { JOptionPane.showMessageDialog(this, ex.getmessage(), "Erro", JOptionPane.ERROR_MESSAGE); Logger.getLogger(FrmCadCliente.class.getName()).log(Level.SEVERE, ex); null, 45

conbd.desconectar(); 10. Não se esqueça de criar um novo item de menu (Pedido por Cliente), no menu Consulta, do formulário principal (FrmPrincipal) e de incluir o código para a abrir o formulário de consulta de pedidos por cliente no item de menu: JInternalFrame frame = null; for (JInternalFrame f : jdesktoppane1.getallframes()) { if (f.gettitle().equals("consulta de Pedidos por Cliente")) frame = f; if (frame == null) { frame = new FrmConCliPedido(); jdesktoppane1.add(frame); frame.setvisible(true); //Trate exceção nas duas linhas abaixo frame.setselected(true); frame.setmaximum(true); catch (PropertyVetoException ex) { Logger.getLogger(FrmPrincipal.class.getName()).log(Level.SEVERE, ex); 11. Execute a aplicação (<F6>). null, 5.3.2 Exercícios 1. Crie um formulário para a consulta de produtos por fornecedor (FrmConForProdutos, com o título Consulta de Produtos por Fornecedor), com uma interface similar ao de consulta de pedidos por cliente. 2. Não se esqueça de criar um item no menu Consulta para acessar esse novo formulário. 3. Adicione os componentes e códigos-fonte necessários para a execução correta da aplicação. 46

Prática 6: Cadastro de Pedidos Nesta prática continuaremos a implementação da nossa aplicação, agora com o cadastro de produtos. Para isso, utilizaremos mais alguns recursos dos componentes visuais e também recursos do Java, como suas classes utilitárias. 6.1 Classe utilitária para a formatação de dados A linguagem Java fornece nativamente diversas classes utilitárias e, entre elas, podemos encontrar as classes utilitárias responsáveis pela formatação de dados. 6.1.1 Implementação da classe utilitária Criaremos uma classe responsável pela formatação de dados na tela, para isso, siga os passos abaixo: 1. Crie uma classe chamada Formatador, no pacote br.edu.univag.util; 2. Implemente os métodos estáticos de formatação que iremos utilizar mais à frente: public static String formatadata(date data) { SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); return sdf.format(data); public static String formataquantidade(double quantidade) { NumberFormat nf = NumberFormat.getNumberInstance(); nf.setgroupingused(true); nf.setmaximumfractiondigits(3); nf.setminimumfractiondigits(3); return nf.format(quantidade); public static String formatavalor(double valor) { NumberFormat nf = NumberFormat.getNumberInstance(); nf.setgroupingused(true); nf.setmaximumfractiondigits(2); nf.setminimumfractiondigits(2); return nf.format(valor); public static Date parsedate(string data) { SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); return sdf.parse(data); catch (ParseException ex) { Logger.getLogger(Formatador.class.getName()).log(Level.SEVERE, null, ex); return null; public static double parsedouble(string numero) { NumberFormat nf = NumberFormat.getNumberInstance(); Number number = nf.parse(numero); return number.doublevalue(); catch (ParseException ex) { Logger.getLogger(Formatador.class.getName()).log(Level.SEVERE, null, ex); return 0.0; 3. Não esqueça de efetuar as importações necessárias (<Ctrl><Shift><i>). 6.1.2 Exercício Implemente uma classe de teste para testar os métodos da classe Formatador. 47

6.2 Ajustes nos value objects As classes JavaBeans precisam ser ajustadas para podermos ter um melhor aproveitamento. 6.2.1 Alterando as JavaBeans 1. Implemente o método para obter o total na classe Pedido (br.edu.univag.sisped.vo): public double gettotal() { double total = 0.0; for (PedidoItem item : getitens()) { total += item.gettotal(); return total; 2. Implemente o método tostring, na classe Produto (br.edu.univag.sisped.vo) para que somente o nome seja exibido nas caixas de combinação e nas tabelas: @Override public String tostring() { return getnome(); 6.2.2 Exercício Implemente uma classe de teste para cada classe (Pedido e Produto) e teste os novos métodos implementados. 6.3 Formulário de cadastro de pedidos Nesta seção iremos criar um formulário de cadastro de pedidos, conforme as figuras abaixo: 48

6.3.1 O formulário de entrada de dados 1. Crie um novo JInternalFrame, chamado FrmCadPedido no pacote br.edu.univag.sisped.view; 2. Insira os elementos visuais, posicionando-os para obter uma interface similar às figuras acima: Componente Propriedade Valor JTabbedPane nome (janela Navegador) abas JPanel Título da Tab Cadastro JPanel Título da Tab Registros 3. Componentes da aba Cadastro: Componente Propriedade Valor JLabel text Código JTextField horizontalalignment RIGHT enabled Desmarque esta propriedade nome (janela Navegador) codigo JLabel text Cliente JComboBox model Código personalizado: new DefaultComboBoxModel(getClientes()) nome (janela Navegador) cliente JLabel text Data JFormattedTextField formatterfactory Data > Personalizado > dd/mm/yyyy nome (janela Navegador) data JButton text Incluir Item nome (janela Navegador) btnincluiritem JButton text Excluir Item nome (janela Navegador) btnexcluiritem JTable model Código personalizado: new javax.swing.table.defaulttablemodel( new Object [][] {, new String [] { "Produto", "Unid Medida", "Val Unitário", "Quantidade", "Total" 49

) { public boolean iscelleditable(int row, int column) { return (column == 0) (column == 3); autoresizemode OFF columnselectedallowed Marque esta opção nome (janela Navegador) itens JButton text Salvar Registro nome (janela Navegador) btnsalvar JButton text Limpar Formulárop nome (janela Navegador) btnlimpar 4. Componentes da aba Registros: Componente Propriedade Valor JToolBar floatable Desmarque esta propriedade JButton text Listar Registros nome (janela Navegador) btnlistar JButton text Alterar Registro nome (janela Navegador) btnalterar JButton text Excluir Registro nome (janela Navegador) btnexcluir JTable autocreaterowsorter Marque esta propriedade model Código personalizado: new javax.swing.table.defaulttablemodel( new Object [][] {, new String [] { "Código", "Data", "Cliente", "Total" ) { public boolean iscelleditable(int row, int column) { return false; autoresizemode OFF nome (janela Navegador) registros 5. Mude para o modo de visualização de código-fonte; 6. Acrescente o código abaixo no construtor, para melhorar a apresentação da tela: //Inclui a seleção de produto na tabela de itens itens.getcolumnmodel().getcolumn(0).setcelleditor(getcelleditorprodutos()); //Cria um campo para informar a quantidade, que calcula o total itens.getcolumnmodel().getcolumn(3).setcelleditor(getcelleditorquantidade()); //Alinha os números da tabela à direita DefaultTableCellRenderer rightrenderer = new DefaultTableCellRenderer(); rightrenderer.sethorizontalalignment(defaulttablecellrenderer.right); itens.getcolumn("val Unitário").setCellRenderer(rightRenderer); itens.getcolumn("quantidade").setcellrenderer(rightrenderer); itens.getcolumn("total").setcellrenderer(rightrenderer); registros.getcolumn("código").setcellrenderer(rightrenderer); registros.getcolumn("total").setcellrenderer(rightrenderer); //Redimensiona as colunas da tabela TableColumnModel colunas = itens.getcolumnmodel(); colunas.getcolumn(0).setpreferredwidth(250); colunas.getcolumn(1).setpreferredwidth(90); 50

colunas.getcolumn(2).setpreferredwidth(90); colunas.getcolumn(3).setpreferredwidth(90); colunas.getcolumn(4).setpreferredwidth(110); colunas = registros.getcolumnmodel(); colunas.getcolumn(0).setpreferredwidth(60); colunas.getcolumn(1).setpreferredwidth(100); colunas.getcolumn(2).setpreferredwidth(320); colunas.getcolumn(3).setpreferredwidth(120); 7. Implemente os métodos que são necessários para a o código-fonte apresentado acima: private Object[] getclientes() { ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); ClienteDAO clientedao = new ClienteDAO(conBD); List<Cliente> clientes = clientedao.select(); return clientes.toarray(); catch (SQLException e) { JOptionPane.showMessageDialog(this, e.getmessage(), "Erro", JOptionPane.ERROR_MESSAGE); return new Object[0]; finally { conbd.desconectar(); private DefaultCellEditor getcelleditorprodutos() { ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); ProdutoDAO produtodao = new ProdutoDAO(conBD); List<Produto> produtos = produtodao.select(); JComboBox cb = new JComboBox(produtos.toArray()); cb.additemlistener((itemevent e) -> { Produto produto = (Produto) e.getitem(); int linhaatual = itens.getselectedrow(); if (linhaatual >= 0) { DefaultTableModel tabela = (DefaultTableModel) itens.getmodel(); tabela.setvalueat(produto.getunidademedida(), linhaatual, 1); String valor = Formatador.formataValor(produto.getValorUnitario()); tabela.setvalueat(valor, linhaatual, 2); ); return new DefaultCellEditor(cb); catch (SQLException e) { JOptionPane.showMessageDialog(this, e.getmessage(), "Erro", JOptionPane.ERROR_MESSAGE); return null; finally { conbd.desconectar(); private DefaultCellEditor getcelleditorquantidade() { JTextField tf = new JTextField(); tf.addactionlistener((actionevent e) -> { DefaultTableModel tabela = (DefaultTableModel) itens.getmodel(); int linhaatual = itens.getselectedrow(); if (linhaatual >= 0) { String valunitariostr = (String) tabela.getvalueat(linhaatual, 2); 51

double valunitario = Formatador.parseDouble(valUnitarioStr); String quantidadestr = (String) tabela.getvalueat(linhaatual, 3); double quantidade = Formatador.parseDouble(quantidadeStr); double valtotal = quantidade * valunitario; quantidadestr = Formatador.formataQuantidade(quantidade); tabela.setvalueat(quantidadestr, linhaatual, 3); String valtotalstr = Formatador.formataValor(valTotal); tabela.setvalueat(valtotalstr, linhaatual, 4); ); return new DefaultCellEditor(tf); 8. Acesse a classe FrmPrincipal e alterne para o modo de visão de código fonte; 9. Implemente a ação para o item de menu Cadastro > Pedido: JInternalFrame frame = null; for (JInternalFrame f : jdesktoppane1.getallframes()) { if (f.gettitle().equals("cadastro de Pedido")) frame = f; if (frame == null) { frame = new FrmCadPedido(); jdesktoppane1.add(frame); frame.setvisible(true); //Trate exceção nas duas linhas abaixo frame.setselected(true); frame.setmaximum(true); catch (PropertyVetoException ex) { Logger.getLogger(FrmPrincipal.class.getName()).log(Level.SEVERE, null, ex); 10. Volte ao formulário de cadastro de pedido; 11. Implemente a ação do botão para incluir item no pedido: DefaultTableModel tabela = (DefaultTableModel) itens.getmodel(); tabela.addrow(new Object[]{null, null, null, null, null); 12. Implemente a ação do botão para excluir item do pedido: int linha = itens.getselectedrow(); if (linha < 0 linha >= itens.getrowcount()) { JOptionPane.showMessageDialog(this, "Nenhum item de pedido selecionado.", "Erro", JOptionPane.ERROR_MESSAGE); else { DefaultTableModel tabela = (DefaultTableModel) itens.getmodel(); tabela.removerow(linha); 13. Implemente a ação para o botão de salvar o registro de pedido: //Preenche os dados a serem armazenados Pedido pedido = new Pedido(); if (!"".equals(codigo.gettext())) { pedido.setcod(integer.parseint(codigo.gettext())); pedido.setcliente((cliente) cliente.getselecteditem()); pedido.setdata(formatador.parsedate(data.gettext().trim())); List<PedidoItem> itens = new ArrayList<>(); DefaultTableModel tabela = (DefaultTableModel) this.itens.getmodel(); for (int linha = 0; linha < tabela.getrowcount(); linha++) { PedidoItem item = new PedidoItem(); item.setproduto((produto) tabela.getvalueat(linha, 0)); 52

String quantidadestr = (String) tabela.getvalueat(linha, 3); double quantidade = Formatador.parseDouble(quantidadeStr); item.setquantidade(quantidade); itens.add(item); pedido.setitens(itens); //Grava o registro no banco de dados ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); PedidoDAO pedidodao = new PedidoDAO(conBD); if ("".equals(codigo.gettext())) { String mensagem = String.format("Confirma a inclusão do pedido do cliente '%s'?", cliente.getselecteditem()); if (JOptionPane.showConfirmDialog(this, mensagem, "Incluir Registro", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { pedidodao.insert(pedido); codigo.settext(string.valueof(pedido.getcod())); JOptionPane.showMessageDialog(this, "Inclusão realizada com sucesso.", "Informação", JOptionPane.INFORMATION_MESSAGE); else { JOptionPane.showMessageDialog(this, "Inclusão cancelada.", "Informação", JOptionPane.INFORMATION_MESSAGE); else { String mensagem = String.format("Confirma a alteração do pedido do cliente '%s'?", cliente.getselecteditem()); if (JOptionPane.showConfirmDialog(this, mensagem, "Alterar Registro", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { pedidodao.update(pedido); JOptionPane.showMessageDialog(this, "Alteração realizada com sucesso.", "Informação", JOptionPane.INFORMATION_MESSAGE); else { JOptionPane.showMessageDialog(this, "Alteração cancelada.", "Informação", JOptionPane.INFORMATION_MESSAGE); catch (SQLException e) { JOptionPane.showMessageDialog(this, e.getmessage(), "Erro", JOptionPane.ERROR_MESSAGE); conbd.commit(); conbd.desconectar(); 14. Implemente a ação para o botão para limpar o formulário: codigo.settext(""); cliente.setselectedindex(-1); data.settext(formatador.formatadata(new Date())); DefaultTableModel tabela = (DefaultTableModel) itens.getmodel(); tabela.setrowcount(0); 15. Na aba Registros, implemente a ação para listar os registros: //Limpa a tabela de registros DefaultTableModel tabela = (DefaultTableModel) registros.getmodel(); tabela.setrowcount(0); ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); PedidoDAO pedidodao = new PedidoDAO(conBD); 53

List<Pedido> pedidos = pedidodao.select(); for (Pedido pedido : pedidos) { Object[] linha = new Object[]{ pedido.getcod(), Formatador.formataData(pedido.getData()), pedido.getcliente(), Formatador.formataValor(pedido.getTotal()) ; tabela.addrow(linha); catch (SQLException ex) { JOptionPane.showMessageDialog(this, ex.getmessage(), "Erro", JOptionPane.ERROR_MESSAGE); Logger.getLogger(FrmCadCliente.class.getName()).log(Level.SEVERE, null, ex); conbd.desconectar(); 16. Implemente a ação do botão para alterar o registro selecionado: //Obtém o identificador do pedido DefaultTableModel tabela = (DefaultTableModel) registros.getmodel(); Object codigoobj = tabela.getvalueat(registros.getselectedrow(), 0); int pedcod = (Integer) codigoobj; //Muda para a primeira aba abas.setselectedindex(0); //Recupera o registro ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); PedidoDAO pedidodao = new PedidoDAO(conBD); Pedido pedido = pedidodao.select(pedcod); codigo.settext(string.valueof(pedido.getcod())); cliente.setselecteditem(pedido.getcliente()); data.settext(formatador.formatadata(pedido.getdata())); DefaultTableModel tabitens = (DefaultTableModel) itens.getmodel(); tabitens.setrowcount(0); for (PedidoItem item : pedido.getitens()) { Object[] linha = new Object[]{ item.getproduto(), item.getproduto().getunidademedida(), Formatador.formataValor(item.getProduto().getValorUnitario()), Formatador.formataQuantidade(item.getQuantidade()), Formatador.formataValor(item.getTotal()) ; tabitens.addrow(linha); catch (SQLException ex) { JOptionPane.showMessageDialog(this, ex.getmessage(), "Erro", JOptionPane.ERROR_MESSAGE); Logger.getLogger(FrmCadCliente.class.getName()).log(Level.SEVERE, null, ex); conbd.desconectar(); 17. Implemente a ação do botão para excluir o registro selecionado: //Obtém o identificador do pedido DefaultTableModel tabela = (DefaultTableModel) registros.getmodel(); Object pedcodobj = tabela.getvalueat(registros.getselectedrow(), 0); int pedcod = (Integer) pedcodobj; //Exclui o registro ConexaoBD conbd = new ConexaoBD(); conbd.conectar(); PedidoDAO pedidodao = new PedidoDAO(conBD); 54

String mensagem = String.format("Confirma a exclusão do pedido '%d'?", pedcod); if (JOptionPane.showConfirmDialog(this, mensagem, "Excluir Registro", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) { pedidodao.delete(pedcod); JOptionPane.showMessageDialog(this, "Exclusão realizada com sucesso.", "Informação", JOptionPane.INFORMATION_MESSAGE); else { JOptionPane.showMessageDialog(this, "Exclusão cancelada.", "Informação", JOptionPane.INFORMATION_MESSAGE); catch (SQLException ex) { JOptionPane.showMessageDialog(this, ex.getmessage(), "Erro", JOptionPane.ERROR_MESSAGE); Logger.getLogger(FrmCadCliente.class.getName()).log(Level.SEVERE, null, ex); conbd.commit(); conbd.desconectar(); btnlistaractionperformed(evt); 18. Note que diversos eventos além do actionperformed foram tratados na implementação acima; 19. Podemos responder a qualquer evento que possa ocorrer em qualquer componente, bastando para isso implementarmos o tratamento para cada evento específico que deva ser tratado pela aplicação. 6.3.2 Exercícios 1. Implemente o formulário de cadastro de pedidos apresentado nesta seção 2. Com as técnicas e recursos aprendidos até este momento, crie um formulário para tratar do cadastro de produtos (FrmCadProduto), contendo o leiaute dos formulários apresentados. 3. Pesquise como podemos separar a responsabilidade de validação de campos e acesso ao banco de dados das classes de formulário que ciamos, diminuindo o acoplamento e aumentando a coesão. 55