Escolar Documentos
Profissional Documentos
Cultura Documentos
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.
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.
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.
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); }
- 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.
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.
public Book() {
} } }
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 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 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; }
} 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.
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.
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:
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:
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.