Você está na página 1de 26

Exemplo de Aplicao Java Swing com BD Oracle - 1

Hoje vamos iniciar uma srie de artigos que culminaro com uma pequena aplicao exemplo de gesto de biblioteca, feita em Java, para ambiente desktop usando classes Java Swing, e acedendo a uma base de dados (BD) Oracle. Este primeiro artigo trata da criao de uma pequena Base de Dados em Oracle. Foi usado o Oracle Express 10g, o qual pode ser downloaded gratuitamente em http://www.oracle.com/technetwork/database/express-edition/downloads/102xewinsoft090667.html. H j uma verso mais recente do Oracle Express, a 11g release 2, a qual pode ser obtida em http://www.oracle.com/technetwork/database/expressedition/downloads/index.html e com a qual o exemplo tambm dever funcionar. Aps a instalao do Oracle, podemos aceder ferramenta de administrao da base de dados indo ao boto Iniciar --> Todos os Programas --> Oracle Database 10g Express Edition --> Ir para a Home Page de Banco de Dados ou, num browser, ir a http://localhost:8080/apex. Dever, ento, aparecer uma pgina para efectuarmos o login na ferramenta de administrao:

Devemos entrar com o utilizador SYSTEM e a password que definimos para esse utilizador durante o processo de instalao. Aps entrar aparece-nos o ambiente de trabalho:

Neste ponto, devemos, primeiramente, criar um utilizador (Administration --> Database Users --> Create User). Crimos o utilizador libraryuser, o qual ir ser, depois, usado para criar as tabelas da BD e tambm para aceder BD a partir da aplicao Java. necessrio dar-lhe permisso de CREATE TABLE e CREATE SEQUENCE, podendo tambm ser-lhe dada permisso para CREATE VIEW, CREATE PROCEDURE, e CREATE TRIGGER.

O user com que so criadas as tabelas da base de dados ir ficar como prefixo da tabela (schema) e, dependendo dos direitos de acesso, pode ficar restringido a ver apenas as "suas" tabelas.

A referencia a uma coluna de uma tabela, em Oracle, tem a seguinte estrutura:


"schema"."table"."column"

O schema pode ter 30 bytes, o nome da tabela mais 30 bytes, e o nome da coluna mais 30 bytes. O comprimento total mximo de um identificador de coluna , portanto, de 98 bytes (se contarmos os pontos e aspas). No devemos, portanto, usar o user SYSTEM para criar tabelas de utilizador, e muito menos para aceder base de dados a partir de uma aplicao. Claro que para uma aplicao brinquedo isso no importante. O passo seguinte ser, ento, fazer logout de SYSTEM na ferramenta de administrao, e fazer login com o novo user criado (libraryuser).

Agora, podemos criar as tabelas da nossa base de dados, as quais iro ficar com schema libraryuser, pois esse o utilizador que vamos usar na sua criao.

Queremos criar as tabelas conforme o seguinte esquema de BD:

No prximo artigo iremos criar uma classe em Java para aceder base de dados criada. Se tiverem problemas, coloquem as vossas perguntas nos comentrios a este artigo.

Exemplo de Aplicao Java Swing com BD Oracle - 2


No artigo anterior inicimos a construo de uma srie de artigos para a construo de uma pequena aplicao exemplo de gesto de biblioteca, para ambiente desktop usando classes Java Swing, e acedendo a uma base de dados (BD) Oracle. O artigo anterior tratou da criao da Base de Dados em Oracle.Este artigo vai tratar da construo de uma classe Java para acesso Base de Dados. Iremos usar o NetBeans IDE 7.0.1, o qual pode ser downloaded de http://netbeans.org/community/releases/70/. Aps instalar o NetBeans IDE 7.0.1, devemos criar um novo projecto "Java Class Library", ao qual vamos chamar HelperDB, pois ir tratar-se apenas de uma classe de acesso base de dados.

Criamos uma classe Java, a que chamamos DBAccessObj, a qual ficar no ficheiro DBAccessObj.java. necessrio incluir as bibliotecas de classes JAR para acesso por driver ODBC base de dados Oracle:

Estes ficheiros jar devem estar presentes na directoria oraclexe\app\oracle\product\10.2.0\server\jdbc\lib sendo oraclexe a directoria onde foi instalado o Oracle XE.

Vamos criar um package, a que chamamos HelperDB, que ir conter a nossa classe, e vamos importar o package java.sql, o qual contm classes de conexo e envio de statements SQL base de dados:

package HelperDB; import java.sql.*; public class DBAccessObj{ private Connection conn; public DBAccessObj() {

} }

Como nica varivel de instncia da nossa classe, criamos conn do "tipo" java.sql.Connection. Na verdade, Connection uma interface que poder conter um objecto de qualquer tipo que implemente essa interface. Assim, conn poder conter uma instncia de uma conexo de qualquer tipo. O tipo ser dado pelo DriverManager de acordo com o driver que for utilizado. O construtor da classe ser ento modificado para criar uma conexo base de dados:

public DBAccessObj() { this.createDBConnection(); } private void createDBConnection() { try { Class.forName("oracle.jdbc.driver.OracleDriver"); } catch(ClassNotFoundException e) { System.out.println("Oops! Can't find class oracle.jdbc.driver.OracleDriver"); System.exit(1); } try{ conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE", "libraryuser","libraryuser"); } catch(Exception e){ System.out.println("ERRO " + e.getMessage()); } }

O driver a usar o "oracle.jdbc.driver.OracleDriver" e a string de ligao base de dados : "jdbc:oracle:thin:@localhost:1521:XE" sendo "libraryuser","libraryuser", respectivamente o user e password do utilizador que queremos usar no acesso base de dados (ver artigo anterior).

Neste ponto, se fizermos uma pequena classe de teste (TestClass.java) para criar uma instncia da nossa classe, j ser possvel ver se a conexo possvel: import HelperDB.DBAccessObj; public class TestClass { public static void main(String[] args) { DBAccessObj conexao = new DBAccessObj(); } } Se no for possvel, aparecer uma das mensagens de erro que damos num dos catchs acima. Depois de criar a conexo base de dados queremos enviar statements SQL para inserir dados numa tabela (INSERT), alterar dados (UPDATE), apagar dados (DELETE) ou consultar dados (SELECT). Para isso temos que ter uma instncia de uma classe que implemente a interface java.sql.Statement:

public Statement createStatement() { Statement st=null; if (this.conn==null) this.createDBConnection(); try{ st = this.conn.createStatement(); } catch(Exception e){ System.out.println("ERRO " + e.getMessage()); } return st; } Para executar um comando SQL usando a instncia de Statement, vamos criar mais uns mtodos na nossa classe: - Para executar um comando SQL que no devolve resultado (INSERT, UPDATE ou DELETE): public void executeSQL(String SqlComm) { Statement st = this.createStatement(); try{ st.execute(SqlComm); }

catch(Exception e){ System.out.println("ERRO " + e.getMessage()); } }

- Para executar um comando SQL que devolve um resultado (SELECT): public ResultSet executeQuery(String SqlComm) { Statement st = this.createStatement(); ResultSet rs=null; try{ rs = st.executeQuery(SqlComm); } catch(Exception e){ System.out.println("ERRO " + e.getMessage()); } return rs; }

Por fim, vamos escrever mtodos para criar uma conexo e eliminar uma conexo:

public Connection openConnection() { if(this.conn==null) this.createDBConnection(); return this.conn; } public void closeConnection() { if(this.conn!=null) { try{ this.conn.close(); } catch(Exception e){ System.out.println("ERRO " + e.getMessage()); } } }

Isto termina a nossa classe. Para a testar, podemos agora melhorar a nossa classe de teste: import HelperDB.DBAccessObj; import java.sql.*; public class TestClass { public static void main(String[] args) { DBAccessObj conexao = new DBAccessObj(); conexao.executeSQL("Insert into Author columns (Name, SURNAME) VALUES ('XICO', 'MENDES')"); ResultSet rs = conexao.executeQuery("SELECT * FROM AUTHOR"); try{ while(rs.next()){ String aName = ((String)rs.getString("Name")); String aSurname = ((String)rs.getString("Surname")); // System.out.println(aName + " " + aSurname); } } catch(Exception e){ System.out.println("ERRO " + e.getMessage()); } } } Se tudo estiver bem, o resultado do teste ser a insero do autor com nome XICO MENDES na tabela AUTHOR e a posterior listagem do contedo da mesma tabela. No foram testados os mtodos de criar e fechar a conexo, mas veremos a sua utilidade noutro artigo.

Exemplo de Aplicao Java Swing com BD Oracle 3


Hoje, vamos desenvolver uma biblioteca de classes que mapeia os conceitos do domnio do problema, e faz a ponte entre a interface com o utilizador, cujo desenvolvimento trataremos no prximo artigo, e a camada de persistncia de dados, tratada no primeiro artigo desta srie. Esta camada com conceitos e operaes do domnio do problema comummente chamada de camada intermdia ou camada de lgica do negcio. Podemos considerar que o nosso pequeno sistema aplicacional ter, ento, uma arquitectura de software em 3-camadas (abordaremos o tema da arquitectura de software num artigo futuro).

H vrias maneiras de desenvolver esta camada intermdia, a qual pode ela prpria conter uma ou mais camadas. Ns iremos desenvolver uma classe para cada conceito do domnio, o que corresponde, mais ou menos, neste pequeno exemplo, a desenvolver uma classe para cada tabela da base de dados. H vrias maneiras de fazer isso. Em particular, vamos ver duas possveis maneiras, cada uma com o seu grupo de defensores, e com as suas prprias vantagens e desvantagens.

1 H autores que defendem o desenvolvimento de uma camada de classes apenas


com atributos, getters e setters (ex.: classe Book abaixo), separadamente de uma camada de classes com operaes com significado para o negcio (ex.: classe BookBLL abaixo).

1.1 classe Book:


public class Book { private int idBook; private String title; private String editor; private java.sql.Date date; private String ISBN; private String edition; // private List<Author> authors = new ArrayList<Author>();

public Book() {

} } }

public int getID() { return this.idBook;

public void setTitle(String title) { this.title = title; public String getTitle() { return title; }

public void setEditor(String editor) { this.editor = editor; public String getEditor() { return editor; }

public void setDate(java.sql.Date date) { this.date = date; public java.sql.Date getDate() { return date; } }

public void setISBN(String ISBN) { this.ISBN = ISBN; public String getISBN() { return ISBN; }

public void setEdition(String edition) { this.edition = edition; public String getEdition() { return edition; }

public List<Author> getAuthors() { return this.authors; }

1.2 classe BookBLL:


public class BookBLL { private DBAccessObj dbo; public BookBLL() { this.dbo = new DBAccessObj(); this.dbo.openConnection(); } public BookBLL(DBAccessObj dbo) { this.dbo = dbo; this.dbo.openConnection(); } public void create(Book b) throws SQLException{ String sqlCommand = "INSERT INTO Book (ISBN, Title, Edition, Editor) VALUES('" + b.getISBN() + "', '" + b.getTitle() + "', '" + b. getEdition() + "', '" + b.getEditor() + "')"; this.dbo.executeSQL(sqlCommand); } // restantes operaes } Esta primeira abordagem no explora o encapsulamento de dados e operaes sobre os dados (conceito fundamental do paradigma de programao orientado a objetos).

2 Outra maneira, desenvolver:


uma camada de classes com atributos, getters e setters, mais as operaes CRUD (Create, Retrieve, Update, Delete) (ex.: class BookDAL abaixo); separadamente de, uma camada de classes com operaes com significado para o negcio, e que no dependem directamente da base de dados e podem ser obtidas por composio das operaes CRUD primitivas (ex.: class BookBLL abaixo).

2.1 classe BookDAL:


public class BookDAL { private int idBook; private String title; private String editor; private java.sql.Date date; private String ISBN; private String edition; // private List<Author> authors = new ArrayList<Author>(); private DBAccessObj dbo; public BookDAL() { this.dbo = new DBAccessObj(); this.dbo.openConnection(); } public BookDAL(DBAccessObj dbo) { this.dbo = dbo; this.dbo.openConnection(); }

public int getID() { return this.idBook;

} }

public void setTitle(String title) { this.title = title; public String getTitle() { return title; }

public void setEditor(String editor) { this.editor = editor; public String getEditor() { return editor; }

public void setDate(java.sql.Date date) { this.date = date; public java.sql.Date getDate() { return date; } }

public void setISBN(String ISBN) { this.ISBN = ISBN; public String getISBN() { return ISBN; }

public void setEdition(String edition) { this.edition = edition; public String getEdition() { return edition; } }

public List<Author> getAuthors() { return this.authors;

public void create() throws SQLException{ String sqlCommand = "INSERT INTO Book (ISBN, Title, Edition, Editor) VALUES('" + this.ISBN + "', '" + this.title + "', '" + this.edition + "', '" + this.editor + "')"; this.dbo.executeSQL(sqlCommand); } public void retrieve(int id) throws SQLException{ String sqlCommand = "SELECT ISBN, Title, DateEdition, Edition, Editor FROM Book WHERE ID = '" + id + "'"; ResultSet book; book = this.dbo.executeQuery(sqlCommand); if (book.next()){ this.idBook = id; this.ISBN = book.getString("ISBN"); this.title = book.getString("Title"); this.date = book.getDate("DateEdition"); this.edition = book.getString("Edition"); this.editor = book.getString("Editor"); } }

public void retrieveByISBN(String isbn) throws SQLException{ String sqlCommand = "SELECT ID, Title, DateEdition, Edition, Editor FROM Book WHERE ISBN = '" + isbn + "'"; ResultSet book; book = this.dbo.executeQuery(sqlCommand); if (book.next()){ this.idBook = book.getInt("ID"); this.title = book.getString("Title"); this.date = book.getDate("DateEdition"); this.edition = book.getString("Edition"); this.editor = book.getString("Editor"); this.ISBN = isbn; } } public void update() { String sqlCommand = "UPDATE Book SET ISBN = '" + this.ISBN + "', Title = '" + this.title + "', Edition = '" + this.edition + "', Editor = '" + this.editor + "' WHERE ID = '" + this.idBook + "'"; this.dbo.executeSQL(sqlCommand); } public void delete() { String sqlCommand = "DELETE FROM Book WHERE ID = '" + this.idBook + "'"; this.dbo.executeSQL(sqlCommand); }

public ResultSet retrieveThisBookAuthors(DBAccessObj dbo) throws SQLException{ String sqlCommand = "SELECT B.ID, B.ISBN, B.Title, A.ID, A.Name, A.Surname FROM BookAuthor BA, Author A, Book B WHERE BA.BookID = B.ID AND BA.AuthorID = A.ID AND B.ID = " + this.getID() + " ORDER BY 3, 2"; ResultSet books; dbo.openConnection(); books = dbo.executeQuery(sqlCommand); return books; }

public void fillThisBookAuthors() throws SQLException{ String sqlCommand = "SELECT A.ID, A.Name, A.Surname FROM BookAuthor BA, Author A, Book B WHERE BA.BookID = B.ID AND BA.AuthorID = A.ID AND B.ID = " + this.getID() + " ORDER BY 3, 2"; ResultSet booksA; this.dbo.openConnection(); booksA = this.dbo.executeQuery(sqlCommand); while (booksA.next()){ Author au = new Author(); au.setName(booksA.getString("Name")); au.setSurname(booksA.getString("Surname")); this.authors.add(au); } } public static ResultSet retrieveAllBooks(DBAccessObj dbo) throws SQLException{ String sqlCommand = "SELECT ISBN, Title, DateEdition, Edition, Editor FROM Book"; ResultSet books; dbo.openConnection(); books = dbo.executeQuery(sqlCommand); return books; } public static ResultSet retrieveAllBooksAuthors(DBAccessObj dbo) throws SQLException{ String sqlCommand = "SELECT B.ID, B.ISBN, B.Title, A.ID, A.Name, A.Surname FROM BookAuthor BA, Author A, Book B WHERE BA.BookID = B.ID AND BA.AuthorID = A.ID ORDER BY 1, 6, 5"; ResultSet books; dbo.openConnection(); books = dbo.executeQuery(sqlCommand); return books; }

2.2 classe ManageBooksBLL:


public class ManageBooksBLL { public ManageBooksBLL () { } public int requisitarBook (Book book, Borrower leitor) throws ManageBookException {

} public int requisitarBook (int bookID, int leitorID) throws ManageBookException { } public int devolverBook (Book book) throws ManageBookException{ } public int devolverBook (int bookID) throws ManageBookException { } }

Nesta abordagem, o encapsulamento de dados e operaes aparece, orientado s entidades do domnio do problema (classes Entidade ou persistentes), na camada DAL. A camada BLL (Business Logic Layer) contm operaes orientadas aos casos de uso a implementar na aplicao, podendo portanto ser vista como uma camada de fornecimento de servios para a camada acima, de Interface com o utilizador (UI, User Interface).

Em termos prticos, dependendo da quantidade de operaes complexas num programa (diferentes de CRUD), podemos ainda misturar a DAL e BLL da 2 abordagem, passando isso por acrescentar nas classes DAL os poucos mtodos BLL que tivssemos, eliminando as classes BLL.

De notar, em ambas as abordagens, a utilizao da classe DBAccessObj, cujo desenvolvimento foi tratado no artigo anterior, para acesso base de dados. O zip com o resultado final pode, como de costume, ser solicitado nos comentrios a este artigo.

Exemplo de Aplicao Java Swing com BD Oracle 4


Neste artigo vamos desenvolver a camada de apresentao, ou de Interface com o utilizador, para a aplicao que vem sendo desenvolvida h algum tempo. No artigo Exemplo de Aplicao Java Swing com BD Oracle - 1, o 1 desta srie, tratmos da criao da Base de Dados em Oracle. No 2 artigo, foi criada um package para acesso base de dados, HelperDB. O 3 artigo tratou da criao de uma biblioteca de classes ao nvel da lgica de negcio e acesso a dados. Este artigo vai tratar da criao do projecto de Interface com o utilizador (GUI Graphical User Interface) usando classes Swing. Para isso, vamos criar um novo projecto no Net Beans, chamado LibrarySystem:

Este projecto deve ser um Java Desktop Application. Este tipo de projecto fornece um template com a infraestrutura bsica de uma aplicao desktop, tal como uma janela principal com uma barra de menu e uma barra de estado. Depois, vamos seleccionar Basic Application (o outro tipo, Database Application, iremos abordar numa outra srie de artigos).

Este tipo de projecto cria de antemo 3 classes: - LibrarySystemApp.java - a classe principal da aplicao. A main ir lanar a janela principal. A partir da, toda a aplicao ser guiada por eventos.

- LibrarySystemView.java - a janela principal:

- LibrarySystemAboutBox.java - uma janela About (Acerca de...).

Na janela com a vista de projectos podemos ver o novo projecto, assim como os que crimos anteriormente. Para mantr uma lgica nos nomes dos projectos, altermos o nome deste projecto para libraryProjectGUI:

1. Construo da interface (GUI)


A partir da Pallete (onde esto os Swing containers, Swing controls, Swing Windows, etc.), arrastamos os objectos de interface que pretendemos ver nas janelas da interface.

Aqui, vamos fazer toda a aplicao na mesma janela. Vamos comear por acrescentar menus (JMenu) e itens de menu (JMenuItem) na barra de menus que j temos inicialmente.

Criamos um item de menu, Initial Panel, no menu File, que nos permitir voltar ao ecr inicial:

E criamos um novo menu, Books, com um item de menu, Manage Books, o qual nos levar lista e manuteno de livros da biblioteca:

Chegou, ento o momento de criar novos painis (JPanel) que substituiro o painel inicial na janela da aplicao. Criamos um novo painel para criao e edio de um livro:

E, criamos um painel para listar os livros existentes:

2. Criao de mtodos para tratamento de eventos despoletados na GUI


Vamos agora fazer trocar o painel visvel, quando selecionada a opo de menu Manage Books do menu Books. Quando ocorre um evento "selecionar o item de menu" queremos correr um mtodo para fazer a troca de painis. Temos duas maneiras de o fazer:

2.1 Com o boto do lado direito sobre o item de menu Manage Books, selecionamos
Events --> Action --> actionPerformed:

Isto provoca a gerao de cdigo na classe LibrarySystemView.java, associando um novo mtodo ao evento de seleo do item de menu, e criando um template para esse novo mtodo: private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: }

2.2 Com o boto do lado direito sobre o item de menu Manage Books,
selecionamosSet Action. Isto conduz-nos a uma janela para entrada de detalhes sobre o cdigo que ir ser gerado:

Em Action, selecionamos Create New Action, e em Action's Method, escrevemos listBooks. O mtodo listBooks() ser criado de novo, e ser associado ao evento de seleo do item de menu. @Action public void listBooks() { }

No mtodo listBooks(), ou no jMenuItem1ActionPerformed() se optarmos pelo primeiro mtodo, vamos colocar o cdigo para troca de painis.

@Action public void listBooks() { ListBooksJPanel listbooksP = new ListBooksJPanel(this, this.dbo); this.visiblePanel.setVisible(false); this.visiblePanel = listbooksP; listbooksP.setVisible(true); this.getFrame().setContentPane(listbooksP); this.getFrame().repaint(); // } Antes, tivmos que criar as variveis de instncia seguintes na classe LibrarySystemView: private HelperDB.DBAccessObj dbo; private JPanel visiblePanel = null;

tambm necessrio criar cdigo para ler os livros da base de dados e preencher a tabela no painel ListBooksJPanel. Para isso devem ser usadas as classes da biblioteca de classes criada no artigo anterior. Se tiverem dificuldades com o cdigo ou quiserem as sources do exemplo, coloquem comentrios a este post.