Raible's Wiki

Raible Designs
Wiki Home
News
Recent Changes

AppFuse

Homepage
  - Korean
  - Chinese
  - Italian
  - Japanese

QuickStart Guide
  - Chinese
  - French
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish
  - Japanese

User Guide
  - Korean
  - Chinese

Tutorials
  - Chinese
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish

FAQ
  - Korean

Latest Downloads

Other Applications

Struts Resume
Security Example
Struts Menu

Set your name in
UserPreferences


Referenced by
Articles
Articles_pt
CreateManager_pt
LeftMenu




JSPWiki v2.2.33

[RSS]


Hide Menu

CreateDAO_pt


Difference between version 36 and version 12:

At line 11 added 9 lines.
%%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 50 changed 1 line.
No fragmento de código acima, nós estamos extendendo [BaseObject|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/model/BaseObject.java.html] porque ela contem os seguintes métodos úteis: toString(), equals(), hashCode() - os dois últimos são requeridos pelo 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 61 added 2 lines.
;:''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 87 changed 1 line.
[schemaexport] id BIGINT NOT NULL AUTO_INCREMENT,
[schemaexport] id bigint not null,
At line 92 changed 1 line.
Se você quiser procurar o arquivo Pessoa.hbm.xml que Hibernate gera para você, procure no diretório build/dao/gen/**/hibernate. Aqui está o conteúdo do Pessoa.hbm.xml (até aqui):
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 157 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 167 changed 1 line.
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 teste desenvolvimento dirigido por teste agora é porque descobri que ele rapidamente aumenta a velocidade do processo de desenvolvimento de software.
%%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 169 changed 1 line.
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], 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 automaticamente 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”.
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 171 changed 1 line.
;:%%(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.''%%
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 177 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 181 removed 1 line.
At line 184 removed 3 lines.
//~ Instance fields ========================================================
At line 190 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 195 removed 8 lines.
protected void tearDown() {
dao = null;
}
public static void main(String[] args) {
junit.textui.TestRunner.run(PersonDaoTest.class);
}
At line 206 changed 1 line.
O código que você vê acima é o que precisamos para um teste JUnit básico, que inicializa e destrói nosso PessoaDAO. O objeto “ctx” é uma referência ao ApplicationContext do Spring, o qual é inicializado em um bloco estático da classe [BaseDaoTestCase's|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/dao/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 225 added 1 line.
At line 235 changed 1 line.
assertTrue(person.getLastName().equals("Last Name Updated"));
assertEquals(person.getLastName(), "Last Name Updated");
At line 249 added 1 line.
At line 253 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 257 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 274 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 276 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 282 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 290 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 292 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/**/dao 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 301 removed 2 lines.
import java.util.List;
At line 304 removed 3 lines.
public List getPeople(Person person);
At line 308 changed 3 lines.
public void savePerson(Object person);
public void savePerson(Person person);
At line 315 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 317 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 319 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/**/dao/hibernate and name it PersonDAOHibernate.java. It should extend [BaseDaoHibernate|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/dao/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 325 removed 3 lines.
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
At line 328 added 1 line.
import org.springframework.orm.ObjectRetrievalFailureException;
At line 331 removed 2 lines.
import java.util.List;
At line 335 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 337 changed 3 lines.
public List getPeople(Person person) {
return getHibernateTemplate().find("from Person");
}
if (person == null) {
throw new ObjectRetrievalFailureException(Person.class, id);
}
At line 341 changed 2 lines.
public Person getPerson(Long id) {
return (Person) getHibernateTemplate().get(Person.class, id);
return person;
At line 345 changed 1 line.
public void savePerson(Object person) {
public void savePerson(Person person) {
At line 350 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 357 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 359 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 363 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/**/dao/hibernate/applicationContext-hibernate.xml and add {{Person.hbm.xml}} to the following code block.
[{Java2HtmlPlugin
At line 390 removed 2 lines.
<value>org/appfuse/model/UserCookie.hbm.xml</value>
<value>org/appfuse/model/UserRole.hbm.xml</value>
At line 396 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 406 changed 1 line.
;:''You could also use __autowire="byName"__ to the &lt;bean&gt; 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 &lt;bean&gt; e se livrar da propriedade “sessionFactory”. Pessoalmente, gosto de ter as dependências de meus objetos documentadas (em XML).''
At line 408 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 417 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).

Back to CreateDAO_pt, or to the Page History.