At line 1 changed 1 line. |
__Part I:__ [Creating new DAOs and Objects in AppFuse|CreateDAO] - A HowTo for creating Java Objects (that represent tables) and creating Java classes to persist those objects in the database. |
__Parte I:__ [Criando novos DAOs e Objetos no AppFuse|CreateDAO] - Um HowTo para criar Objetos Java (que representam tabelas) e criar classes Java para persistir estes objetos no banco de dados. |
At line 3 changed 2 lines. |
!!About this Tutorial |
This tutorial will show you how to create a new table in the database, and how to create Java code to access this table. |
!!Sobre este Tutorial |
Este tutorial mostrara a você como criar uma nova tabela no banco de dados, e como criar código java para acessar esta tabela. |
At line 6 changed 1 line. |
We will create an object and then some more classes to persist (save/retrieve/delete) that object from the database. In Java speak, we call the object a Plain Old Java Object (a.k.a. a [POJO|http://forum.java.sun.com/thread.jsp?forum=92&thread=425300&tstart=0&trange=15]). This object basically represents a database table. The ''other classes'' will be: |
Nós criaremos um objeto e então mais algumas classes para persistir (save/retrieve/delete) aquele objeto do banco de dados. Em termos java, chamaremos o objeto de Plain Old Java Object (a.k.a. a [POJO|http://forum.java.sun.com/thread.jsp?forum=92&thread=425300&tstart=0&trange=15]). Este objeto basicamente representa uma tabela do banco de dados. As ''outras classes'' serão: |
At line 8 changed 2 lines. |
* A Data Access Object (a.k.a. a [DAO|http://java.sun.com/blueprints/patterns/DAO.html]), an [Interface|http://java.sun.com/docs/books/tutorial/java/concepts/interface.html] and a Hibernate Implementation |
* A [JUnit|http://www.junit.org] class to test our DAO is working |
* Um Objeto de Acesso a Dados (a.k.a. a [DAO|http://java.sun.com/blueprints/patterns/DAO.html]), uma [Interface|http://java.sun.com/docs/books/tutorial/java/concepts/interface.html] e uma implementação Hibernate |
* Uma classe [JUnit|http://www.junit.org] para testar se nosso DAO está funcionado |
At line 11 changed 1 line. |
AppFuse uses [Hibernate|http://www.hibernate.org] for it's persistence layer. Hibernate is an Object/Relational (O/R) Framework that allows you to relate your Java Objects to database tables. It allows you to very easily perform CRUD (Create, Retrieve, Update, Delete) on your objects. |
%%note __NOTA:__ Se você está usando MySQL e quer usar transações (provavelmente usará) você tem de usar tabelas InnoDB. Para fazê-lo, adicione o seguinte ao seu arquivo mysql de configurações (/etc/my.cnf ou c:\Windows\my.ini). O segundo ajuste (para um character set UTF-8) é necessário para a versão 4.1.7+. |
{{{ |
[mysqld] |
default-table-type=innodb |
default-character-set=utf8 |
}}} |
Se você está usando PostgreSQL e obtém erros confusos sobre processamento batch, tente desabilitá-lo adicionando {{<prop key="hibernate.jdbc.batch_size">0</prop>}} ao seu arquivo src/dao/**/hibernate/applicationContext-hibernate.xml. |
%% |
At line 13 changed 1 line. |
;:''You can also use [iBATIS|http://ibatis.com] as a persistence framework option. To install iBATIS in AppFuse, view the README.txt in {{extras/ibatis}}. If you're using iBATIS over Hibernate, I expect you have your reasons and are familiar with the framework. I also expect that you can figure out how to adapt this tutorial to work with iBATIS. ;-)'' |
AppFuse usa [Hibernate|http://www.hibernate.org] para sua camada de persistência. Hibernate é um framework Objeto/Relacional (OR) que nos permite relacionar objetos Java à tabelas no banco de dados. Permitindo muito facilmente efetuar CRUD (Create, Retrieve, Update, Delete) em nossos objetos. |
At line 22 added 2 lines. |
;:''Você também pode usar [iBATIS|http://ibatis.com] como opção de framework de persistência. Para instalar iBATIS no AppFuse, veja o arquivo README.TXT em {{extras/ibatis}}. Se você estiver usando iBATIS, espero que tenha suas razões e que conheça este framework. Espero também que você descubra como adaptar este tutorial para que funcione com iBATIS. ;-)'' |
|
At line 17 changed 1 line. |
Let's get started on creating a new Object, DAO and Test in AppFuse's architecture. |
Vamos começar criando um novo Objeto, DAO, Test na arquitetura AppFuse. |
At line 19 changed 7 lines. |
!Table of Contents |
* [1] Create a new Object and add [XDoclet|http://xdoclet.sf.net] tags |
* [2] Create a new database table from the object using Ant |
* [3] Create a new DaoTest to run JUnit tests on the DAO |
* [4] Create a new DAO to perform CRUD on the object |
* [5] Configure Spring for the Person object and PersonDao |
* [6] Run the DaoTest |
!Tabela de Conteúdo |
* [1] Criar um novo Objeto e adicionar tags [XDoclet|http://xdoclet.sf.net] |
* [2] Criar uma nova tabela no banco de dados a partir do objeto, usando Ant |
* [3] Criar uma nova classe DaoTest para executar testes JUnit no DAO |
* [4] Criar uma nova classe DAO para efetuar CRUD no objeto |
* [5] Configurar o framework Spring para o objeto Pessoa e PessoaDAO |
* [6] Executar o DaoTest |
At line 27 changed 1 line. |
!!Create a new Object and add XDoclet tags [#1] |
!!Criar um novo Objeto e Adicionar tags XDoclet [#1] |
At line 29 changed 1 line. |
The first thing we need to do is create an object to persist. Let's create a simple "Person" object (in the src/dao/**/model directory) that has an id, a firstName and a lastName (as properties). |
A primeira coisa que precisamos fazer é criar um objeto a persistir. Vamos criar um simples objeto Pessoa (no diretório src/dao/**model) que tem um id, primeiroNome e ultimoNome (como propriedades). |
At line 48 changed 1 line. |
;:%%(color: blue)''I usually open an existing object (i.e. User.java or Resume.java) and save it as a new file. Then I delete all the methods and properties. This gives me the basic JavaDoc header. I'm sure I could edit Eclipse templates to do this, but since I develop on 3 different machines, this is just easier.''%% |
;:%%(color: blue)''Usualmente abro um objeto existente (ex.: User.java ou Resume.java) e o salvo como um novo arquivo. Então deleto todos os métodos e propriedades. Isto me dá um básico cabeçalho JavaDoc. Estou certo que poderia editar os Templates Eclipse para fazer isto, mas eu desenvolvo em 3 diferentes máquinas, e isso é justamente mais fácil.''%% |
At line 50 changed 2 lines. |
In the code snippet above, we're extending [BaseObject|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/model/BaseObject.java.html] because it has the following useful methods: toString(), equals(), hashCode() - the latter two |
are required by Hibernate. |
Esta classe deve extender [BaseObject|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/model/BaseObject.java.html], a qual tem 3 métodos abstratos: (equals(), hashCode() and toString()) que você precisará implementar na classe Pessoa. Os dois primeiros são requeridos pelo Hibernate. A maneira mais simples de fazer isto é usando [Commonclipse|http://commonclipse.sf.net]. Mais informações em usar esta ferramenta pode ser encontrada em [Lee Grey's site|http://www.leegrey.com/hmm/2004/09/29/1096491256000.html]. Outro Eclipse Plugin que você pode usar é [Commons4E|http://commons4e.berlios.de/]. Eu não o usei, assim eu não posso comentar sua funcionalidade. |
At line 53 changed 1 line. |
Now that we have this POJO created, we need to add XDoclet tags to generate the Hibernate mapping file. This mapping file is used by Hibernate to map objects → tables and properties (variables) → columns. |
;:''Se você está usando [IntelliJ IDEA|http://www.jetbrains.com/idea], você pode gerar equals() and hashCode(), mas não toString(). Há um [ToStringPlugin|http://www.intellij.org/twiki/bin/view/Main/ToStringPlugin], mas não o testei pessoalmente.'' |
At line 55 changed 1 line. |
First of all, we add a [@hibernate.class|http://xdoclet.sourceforge.net/tags/hibernate-tags.html#@hibernate.class%20(0..1)] tag that tells Hibernate what table this object relates to: |
Agora que temos este POJO criado, nós precisamos adicionar tags XDoclet para gerar o arquivo de mapeamento Hibernate. Este arquivo de mapeamento é usado pelo Hibernate para mapear objetos => tabelas e propriedades => colunas. |
At line 65 added 2 lines. |
Primeiro de tudo, nós adicionaremos uma tag [@hibernate.class|http://xdoclet.sourceforge.net/tags/hibernate-tags.html#@hibernate.class%20(0..1)] que diz ao Hibernate que tabela este objeto se relaciona: |
|
At line 65 changed 1 line. |
We also have to add a primary key mapping or XDoclet will puke when generating the mapping file. Note that all @hibernate.* tags should be placed in the __getters'__ Javadocs of your POJOs. |
Nós também precisamos adicionar um mapeamento de chave primária ou XDoclet irá vomitar quando gerar o arquivo de mapeamento. Note que todos os tags @hibernate.* deverão ser colocados no JavaDocs dos métodos get de seus POJOs. |
At line 79 added 1 line. |
|
At line 80 changed 1 line. |
;:%%(color: blue)''I'm using {{generator-class="increment"}} instead of {{generate-class="native"}} because I [found some issues|AppFuseOnDB2] when using "native" on other databases. If you only plan on using MySQL, I recommend you use the "native" value.''%% |
;:%%(color: blue)''Estou usando {{generator-class="increment"}} ao invés de {{generate-class="native"}} porque [encontrei alguns problemas|AppFuseOnDB2] ao usar native em outros bancos de dados. Se você somente planeja usar o MySql, eu recomendo que você use o valor native.''%% |
At line 82 changed 2 lines. |
!!Create a new database table from the object using Ant [#2] |
At this point, you can actually create the person table by running "ant setup-db". This task creates the Person.hbm.xml file and creates a database table called "person." From the ant console, you can see the table schema the Hibernate creates for your: |
!!Criar uma nova tabela no banco de dados a partir do objeto, usando Ant [#2] |
|
Neste ponto, você pode atualmente criar a tabela pessoa executando ant setup-db. Esta tarefa cria o arquivo Pessoa.hbm.xml e cria uma tabela no banco de dados chamada pessoa. A partir do console ant, você pode ver o schema da tabela que Hibernate cria para você: |
At line 86 changed 1 line. |
[schemaexport] id BIGINT NOT NULL AUTO_INCREMENT, |
[schemaexport] id bigint not null, |
At line 91 changed 1 line. |
If you want to look at the Person.hbm.xml file that Hibernate generates for you, look in the build/dao/gen/**/hibernate directory. Here's the contents of Person.hbm.xml (so far): |
Se você quiser procurar o arquivo Pessoa.hbm.xml que Hibernate gera para você, procure no diretório build/dao/gen/**/model. Aqui está o conteúdo do Pessoa.hbm.xml (até aqui): |
At line 130 changed 1 line. |
Now we'll add additional [@hibernate.property|http://xdoclet.sourceforge.net/tags/hibernate-tags.html#@hibernate.property%20(0..1)] tags for our other columns (first_name, last_name): |
Agora nós iremos adicionar tags [@hibernate.property|http://xdoclet.sourceforge.net/tags/hibernate-tags.html#@hibernate.property%20(0..1)] para nossas colunas (primeiroNome, ultimoNome): |
At line 151 changed 1 line. |
In this example, the only reason for adding the ''column'' attribute is because the column name is different from our property name. If they're the same, you don't need to specify the ''column'' attribute. See the [@hibernate.property|http://xdoclet.sourceforge.net/tags/hibernate-tags.html#@hibernate.property%20(0..1)] reference for other attributes you can specify for this tag. |
Neste exemplo, a única razão de adicionar o atributo column é porque o nome da coluna é diferente do nome da propriedade. Se elas forem iguais, você não necessita especificar o atributo column. Veja a referência [@hibernate.property|http://xdoclet.sourceforge.net/tags/hibernate-tags.html#@hibernate.property%20(0..1)] para outros atributos que você pode especificar para este tag. |
At line 153 changed 1 line. |
Run "ant setup-db" again to get the additional columns added to your table. |
Execute ant setup-db outra vez para ter as colunas adicionais adicionadas à sua tabela. |
At line 156 changed 3 lines. |
[schemaexport] id BIGINT NOT NULL, |
[schemaexport] first_name VARCHAR(255), |
[schemaexport] last_name VARCHAR(255), |
[schemaexport] id bingint NOT NULL, |
[schemaexport] first_name varchar(255), |
[schemaexport] last_name varchar(255), |
At line 162 changed 1 line. |
If you want to change the size of your columns, specify a length=''size'' attribute in your @hibernate.property tag. If you want to make it a required field (NOT NULL), add not-null="true". |
Se você quiser alterar o tamanho de suas colunas, especifique um atributo length=tamanho no tag @hibernate.property. Se quiser que ele se torne um campo requerido (NOT NULL), adicione not-null=true. |
At line 164 changed 1 line. |
!!Create a new DaoTest to run JUnit tests on your DAO [#3] |
!!Criar uma nova classe DaoTest para executar testes JUnit no DAO [#3] |
At line 166 changed 1 line. |
Now we'll create a DaoTest to test our DAO works. "Wait a minute," you say, "we haven't created a DAO!" You are correct. However, I've found that [Test-Driven Development|http://www.artima.com/intv/testdriven.html] breeds higher quality software. For years, I thought __write your test before your class__ was hogwash. It just seemed stupid. Then I tried it and I found that it works great. The only reason I do all this test-driven stuff now is because I've found it rapidly speeds up the process of software development. |
%%note <a name="appgen"></a>__NOTE:__ AppFuse versions 1.6.1+ contain include an [AppGen] tool that can be used to generate all the classes for the rest of these tutorials. However, it's best that you go through these tutorials before using this tool - then you'll know what code it's generating.%% |
At line 168 changed 1 line. |
To start, create a PersonDaoTest.java class in the test/dao/**/persistence directory. This class should extend [BaseDaoTestCase|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/persistence/BaseDaoTestCase.java.html], which already exists in this package. This parent class is used to load [Spring's|http://www.springframework.org] ApplicationContext (since Spring binds the layers together), and for automatically loading a .properties file (ResourceBundle) that has the same name as your *Test.class. In this example, if you put a PersonDaoTest.properties file in the same directory as PersonDaoTest.java, this file's properties will be available via an "rb" variable. |
Agora iremos criar uma classe DaoTest para testar se nosso DAO funciona. Espere um minuto você diz, nós não criamos um DAO! Você está correto. No entanto, eu descobri que [Desenvolvimento dirigido por Testes|http://www.artima.com/intv/testdriven.html] produz softwares de alta qualidade. Por anos, pensei que __escrever seu teste antes de sua classe__ era tolice. Simplesmente parecia estúpido. Então eu tentei e descobri que funciona notavelmente. A única razão de fazer todo este desenvolvimento dirigido por teste agora é porque descobri que ele rapidamente aumenta a velocidade do processo de desenvolvimento de software. |
At line 170 changed 1 line. |
;:%%(color: blue)''I usually copy (open → save as) an existing test (i.e. UserDaoTest.java) and find/replace [[Uu]ser with [[Pp]erson, or whatever the name of my object is.''%% |
Para começar, crie uma classe PessoaDaoTest.java no diretório test/dao/**/dao. Esta classe deve estender [BaseDaoTestCase|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/dao/BaseDAOTestCase.java.html], sub-classe da classe [AbstractDependencyInjectionSpringContextTests|http://www.springframework.org/docs/api/org/springframework/test/AbstractDependencyInjectionSpringContextTests.html] do Spring que já existe neste pacote. Esta classe pai é usada para carregar ApplicationContext do [Spring's|http://www.springframework.org] (Spring une todas as camadas), e para (opcionalmente) carregar um arquivo .properties (ResourceBundle) que tem o mesmo nome que sua classe *Test.class. Neste exemplo, se você colocar um arquivo PessoaDAOTest.properties no mesmo diretório que PessoaDAOTest.java, este arquivo de propriedades estará disponível via uma variável rb. |
At line 184 added 2 lines. |
;:%%(color: blue)''Usualmente copio (abrir salvar como) um teste existente (ex.: UserDaoTest.java) e procurar/substituir [[Uu]ser com [[Pp]essoa, ou qualquer que seja o nome do meu objeto.''%% |
|
At line 174 changed 1 line. |
package org.appfuse.persistence; |
package org.appfuse.dao; |
At line 176 removed 2 lines. |
import org.apache.commons.logging.Log; |
import org.apache.commons.logging.LogFactory; |
At line 191 added 1 line. |
import org.springframework.dao.DataAccessException; |
At line 180 removed 1 line. |
|
At line 183 removed 1 line. |
//~ Instance fields ======================================================== |
At line 187 changed 4 lines. |
//~ Methods ================================================================ |
protected void setUp() { |
log = LogFactory.getLog(PersonDaoTest.class); |
dao = (PersonDao) ctx.getBean("personDao"); |
public void setPersonDao(PersonDao dao) { |
this.dao = dao; |
At line 192 removed 8 lines. |
|
protected void tearDown() { |
dao = null; |
} |
|
public static void main(String[] args) { |
junit.textui.TestRunner.run(PersonDaoTest.class); |
} |
At line 203 changed 1 line. |
The code you see above is what we need for a basic JUnit test that initializes and destroys our PersonDao. The "ctx" object is a reference to Spring's ApplicationContext, which is initialized in a static block of the [BaseDaoTestCase's|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/persistence/BaseDaoTestCase.java.html] class. |
O código que você vê acima é o que precisamos para um teste de integração Spring básico que inicializa e destrói nosso PessoaDAO. Spring irá usar autowiring (auto-ligamento) por tipo para chamar o método ''setPersonDao()'' e atribuir o bean "personDao" como uma dependência desta classe. |
At line 205 changed 1 line. |
Now we need to actually test that the CRUD (create, retrieve, update, delete) methods work in our DAO. To do this we created methods that begin with "test" (all lower case). As long as these methods are public, have a void return type and take no arguments, they will be called by our <junit> task in our Ant build.xml file. Here's some simple tests for testing CRUD. An important thing to remember is that each method (also known as a test), should be autonomous. Add the following methods to your PersonDaoTest.java file: |
Agora precisamos realmente testar que os métodos CRUD (Create, Retrieve, Update, Delete) funcionem em nosso DAO. Para fazê-lo, criamos métodos que começam com test (tudo letra minúscula). Contanto que estes métodos sejam públicos, tenham o tipo void como retorno e não receba argumentos, eles serão chamados por nossa tarefa <junit> em nosso arquivo build.xml. Aqui esta alguns testes simples para testar CRUD. Uma coisa importante a lembrar é que cada método (também conhecido como test) deve ser autônomo. Adicione os seguintes métodos para seu arquivo PessoaDaoTest.java: |
At line 225 added 1 line. |
|
At line 232 changed 1 line. |
assertTrue(person.getLastName().equals("Last Name Updated")); |
assertEquals(person.getLastName(), "Last Name Updated"); |
At line 249 added 1 line. |
|
At line 250 changed 1 line. |
assertNull(dao.getPerson(person.getId())); |
|
try { |
person = dao.getPerson(person.getId()); |
fail("Person found in database"); |
} catch (DataAccessException dae) { |
log.debug("Expected exception: " + dae.getMessage()); |
assertNotNull(dae); |
} |
At line 254 changed 1 line. |
;:%%(color: blue)''In the testGetPerson method, we're creating a person and then calling a get. I usually enter a record in the database that I can always rely on. Since [DBUnit|http://www.dbunit.org] is used to populate our database with test data before our tests are run, you can simply add the new table/record to the metadata/sql/sample-data.xml file:''%% |
;:%%(color: blue)''No método testGetPessoa, estamos criando uma pessoa e então chamado um get. Costumo inserir um registro no banco de dados que possa sempre confiar. Como [DBUnit|http://www.dbunit.org] é usado para popular nosso banco de dados com dados de teste antes da execução, você pode simplesmente adicionar uma nova table/record ao arquivo metadata/sql/sample-data.xml:''%% |
At line 271 changed 1 line. |
;:%%(color: blue)''This way, you can eliminate the "create new" functionality in the testGetPerson method. If you'd rather add this record directly into the database (via SQL or a GUI), you can rebuild your sample-data.xml file using "ant db-export" and then "cp db-export.xml metadata/sql/sample-data.xml".''%% |
;:%%(color: blue)''Desta forma, você pode eliminar a funcionalidade criar um novo no método testGetPessoa. Se você preferir adicionar este registro diretamente no banco de dados (via SQL ou GUI), você pode reconstruir seu arquivo sample-data.xml usando ant db-export e então cp db-export metadata/sql/sample-data.xml.''%% |
At line 273 changed 2 lines. |
In the above example, you can see that we're calling person.set*(value) to populate our object before saving it. This is easy in this example, but it could get quite cumbersome if we're persisting an object with 10 required fields (not-null="true"). This is why I created the ResourceBundle in the BaseDaoTestCase. Simply create a PersonDaoTest.properties file in the same directory as the PersonDaoTest.java file and define your property values inside it: |
;:''I tend to just hard-code test values into Java code - but the .properties file is an option.'' |
No exemplo acima, você pode vê que estamos chamando pessoa.set*(valor) para popular nosso objeto antes de salvá-lo. Isto é fácil neste exemplo, mas poderia se tornar bastante incômodo se estivermos persistindo um objeto com 10 campos requeridos (not-null=true). Dai o porque da criação do ResourceBundle na classe BaseDaoTestCase. Simplesmente crie um arquivo PessoaDaoTest.properties no mesmo diretório que o arquivo PessoaDAOTest.java e defina o valor das propriedades dentro dele: |
;:''Tendo simplesmente a codificar valores de testes no código java mas o arquivo .properties é uma opção.'' |
At line 279 changed 1 line. |
Then, rather than calling person.set* to populate your objects, you can use the BaseDaoTestCase.populate(java.lang.Object) method: |
Então, ao invés de chamar pessoa.set* para popular seus objetos, você pode usar o método BaseDaoTestCase.populate(java.lang.Object): |
At line 287 changed 1 line. |
At this point, the PersonDaoTest class won't compile yet because there is no PersonDao.class in our classpath, we need to create it. PersonDAO.java is an interface, and PersonDAOHibernate.java is the Hibernate implementation of that interface. Let's go ahead and create those. |
Neste ponto, a classe PessoaDaoTest não irá compilar ainda porque não há PessoaDAO.class em nosso classpath, nós precisamos criá-la. PessoaDAO.java é uma Interface, e PessoaDAOHibernate é uma implementação Hibernate desta interface. Vamos seguir adiante e criar todas elas. |
At line 289 changed 2 lines. |
!!Create a new DAO to perform CRUD on the object [#4] |
First off, create a PersonDao.java interface in the src/dao/**/persistence directory and specify the basic CRUD methods for any implementation classes. ''I've eliminated the JavaDocs in the class below for display purposes.'' |
!!Criar uma nova classe DAO para efetuar CRUD no objeto [#4] |
At line 301 added 2 lines. |
Primeiro, crie a interface PessoaDAO.java no diretório src/dao/**/dao e especifique os métodos CRUD básicos para qualquer classe de implementação. Eliminei as partes JavaDocs na classe abaixo apenas por propósito de visualização. |
|
At line 294 changed 1 line. |
package org.appfuse.persistence; |
package org.appfuse.dao; |
At line 298 removed 2 lines. |
import java.util.List; |
|
At line 301 removed 3 lines. |
|
public List getPeople(Person person); |
|
At line 305 changed 3 lines. |
|
public void savePerson(Object person); |
|
public void savePerson(Person person); |
At line 312 changed 1 line. |
Notice in the class above there are no exceptions on the method signatures. This is due to the power of [Spring|http://www.springframework.org] and how it wraps Exceptions with RuntimeExceptions. At this point, you should be able to compile all the source in src/dao and test/dao using "ant compile-dao". However, if you try to run "ant test-dao -Dtestcase=PersonDao", you will get an error: <span style="color: red">No bean named 'personDao' is defined</span>. This is an error message from Spring - indicating that we need to specify a bean named ''personDAO'' in applicationContext-hibernate.xml. Before we do that, we need to create the PersonDao implementation class. |
Note na classe acima que não há exceções nas assinaturas dos métodos. Isto devido à força do [Spring|http://www.springframework.org] e como ele encapsula Exceptions com RuntimeExceptions. Neste ponto, você deve ser capaz de compilar todo fonte em src/dao e test/dao usando ant compile-dao. No entanto, se você tentar executar ant -Dtestcase=PessoaDAO, você receberá um erro: <span style="color: red">No bean named 'pessoaDAO' is defined</span>. Esta é uma mensagem de erro do Spring indicando que nós precisamos especificar um bean nomeado pessoaDAO no arquivo ApplicationContex-hibernate.xml. Antes de fazê-lo, precisamos criar a classe que implementa a interface PessoaDAO. |
At line 314 changed 1 line. |
;:''The ant task for running dao tests is called "test-dao". If you pass in a testcase parameter (using -Dtestcase=name), it will look for **/*${testcase}* - allowing us to pass in Person, PersonDao, or PersonDaoTest - all of which will execute the PersonDaoTest class.'' |
;:''A tarefa Ant para executar os testes dao é chamada test-dao. Se você passar um parâmetro testcase (usando -Dtestcase=nome), a tarefa irá procurar por **/*${testcase}* - nos permitindo passar Pessoa, PessoaDAO ou PessoaDaoTest todos o qual executará a classe PessoaDAOTest.'' |
At line 316 changed 1 line. |
Let's start by creating a PersonDaoHibernate class that implements the methods in PersonDao and uses Hibernate to get/save/delete the Person object. To do this, create a new class in src/dao/**/persistence/hibernate and name it PersonDAOHibernate.java. It should extend [BaseDaoHibernate|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/persistence/BaseDAOHibernate.java.html] and implement PersonDAO. ''Javadocs eliminated for brevity.'' |
Vamos começar, criando uma classe PessoaDAOHibernate que implementa os métodos em PessoaDAO e usa Hibernate para get/save/delete o objeto Pessoa. Para fazê-lo, crie uma nova classe em src/dao/**/dao/hibernate e a nomeie PessoaDAOHibernate.java. Ela deverá estender [BaseDaoHibernate|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/dao/BaseDAOHibernate.java.html] e implementar PessoaDAO. ''JavaDocs eliminados por brevidade.'' |
At line 320 changed 1 line. |
package org.appfuse.persistence.hibernate; |
package org.appfuse.dao.hibernate; |
At line 322 removed 3 lines. |
import org.apache.commons.logging.Log; |
import org.apache.commons.logging.LogFactory; |
|
At line 326 changed 1 line. |
import org.appfuse.persistence.PersonDao; |
import org.appfuse.dao.PersonDao; |
import org.springframework.orm.ObjectRetrievalFailureException; |
At line 328 removed 2 lines. |
import java.util.List; |
|
At line 332 changed 1 line. |
private Log log = LogFactory.getLog(PersonDaoHibernate.class); |
public Person getPerson(Long id) { |
Person person = (Person) getHibernateTemplate().get(Person.class, id); |
At line 334 changed 3 lines. |
public List getPeople(Person person) { |
return getHibernateTemplate().find("from Person"); |
} |
if (person == null) { |
throw new ObjectRetrievalFailureException(Person.class, id); |
} |
At line 338 changed 2 lines. |
public Person getPerson(Long id) { |
return (Person) getHibernateTemplate().get(Person.class, id); |
return person; |
At line 342 changed 1 line. |
public void savePerson(Object person) { |
public void savePerson(Person person) { |
At line 347 changed 2 lines. |
Object person = getHibernateTemplate().load(Person.class, id); |
getHibernateTemplate().delete(person); |
// object must be loaded before it can be deleted |
getHibernateTemplate().delete(getPerson(id)); |
At line 353 added 1 line. |
Agora, se você tentar executar ant test-dao -Dtestcase=PessoaDAO, você obterá o mesmo erro. Precisamos configurar Spring de forma que ele saiba que PessoaDAOHibernate é a implementação de PessoaDAO, e precisamos também informá-lo sobre o objeto Pessoa. |
At line 354 changed 1 line. |
You'll notice here that we're doing nothing with the ''person'' parameter. This is just a placeholder for now - in the future you may want to filter on it's properties using [Hibernate's Query Language|http://www.hibernate.org/hib_docs/reference/en/html/queryhql.html] (HQL) or using [Criteria Queries|http://www.hibernate.org/hib_docs/reference/en/html/querycriteria.html]. |
!!Configurar o framework Spring para o objeto Pessoa e PessoaDAO [#5] |
At line 356 changed 1 line. |
''An example using a Criteria Query:'' |
Primeiro, necessitamos dizer ao Spring onde o arquivo de mapeamento do Hibernate está localizado. Para isso, abra src/dao/**/dao/hibernate/ApplicationContext.xml e adicione {{Pessoa.hbm.xml}} ao seguinte bloco de código. |
At line 360 removed 22 lines. |
Example example = Example.create(person) |
.excludeZeroes() //exclude zero valued properties |
.ignoreCase(); //perform case insensitive string comparisons |
try { |
return getSession().createCriteria(Person.class) |
.add(example) |
.list(); |
} catch (Exception e) { |
throw new DAOException(e); |
} |
return new ArrayList(); |
|
}] |
|
Now, if you try to run "ant test-dao -Dtestcase=PersonDao", you will get the same error. We need to configure Spring so it knows that PersonDaoHibernate is the implementation of PersonDAO, and we also need to tell it about the Person object. |
|
!!Configure Spring for the Person object and PersonDao [#5] |
|
First, we need to tell Spring where the Hibernate mapping file is located. To do this, open src/dao/**/persistence/hibernate/applicationContext-hibernate.xml and add {{Person.hbm.xml}} to the following code block. |
|
[{Java2HtmlPlugin |
|
At line 387 removed 2 lines. |
<value>org/appfuse/model/UserCookie.hbm.xml</value> |
<value>org/appfuse/model/UserRole.hbm.xml</value> |
At line 393 changed 1 line. |
Now we need to add some XML to this file to bind PersonDaoHibernate to PersonDao. To do this, add the following at the bottom of the file: |
Agora precisamos adicionar algum XML a este arquivo para ligar PessoaDAOHibernate à PessoaDAO. Para fazê-lo, adicione o seguinte na parte inferior do arquivo: |
At line 398 changed 1 line. |
<bean id="personDao" class="org.appfuse.persistence.hibernate.PersonDaoHibernate"> |
<bean id="personDao" class="org.appfuse.dao.hibernate.PersonDaoHibernate"> |
At line 403 changed 1 line. |
;:''You could also use __autowire="byName"__ to the <bean> and get rid of the "sessionFactory" property. Personally, I like having the dependencies of my objects documented (in XML).'' |
;:''Você poderia também usar __autowire="byName"__ ao <bean> e se livrar da propriedade sessionFactory. Pessoalmente, gosto de ter as dependências de meus objetos documentadas (em XML).'' |
At line 405 changed 2 lines. |
!!Run the DaoTest [#6] |
Save all your edited files and try running "ant test-dao -Dtestcase=PersonDao" one more time. |
!!Executar o DaoTest [#6] |
At line 384 added 2 lines. |
Salve todos os arquivos editados e tente executar ant test-dao -Dtestcase=PessoaDAO uma vez mais. |
|
At line 390 added 2 lines. |
Nota: |
Antes que você envie críticas, peço que compreenda que estou apenas contribuindo com o projeto e que não sou um profundo conhecedor da idioma Inglês. Sinta-se no direito de corrigir os erros de tradução ou mesmo os erros ortográficos não sou perfeito!;-) |
At line 414 changed 1 line. |
''Next Up:'' __Part II:__ [Creating new Managers|CreateManager] - A HowTo for creating [Business Delegates|http://java.sun.com/blueprints/corej2eepatterns/Patterns/BusinessDelegate.html] that talk to the database tier (DAOs) and the web tier (Struts Actions). |
''Próxima:'' __Parte II:__ [Criando novos Managers|CreateManager_pt] - Um "HowTo" para criar [Business Delegates|http://java.sun.com/blueprints/corej2eepatterns/Patterns/BusinessDelegate.html] que comunicam-se com a camada de banco de dados (DAOs) e web (Spring Controllers). |