Terminou de ler?
Eu espero.
Pronto mesmo? Adiante então!
Para os trabalhos de hoje vamos precisar do seguinte material:
- Todo o material já utilizado na parte 1
- Hibernate 4.2
- H2 Database
Vamos aos downloads:
E agora o Banco de dados:
Prefira o .zip
Resolvidos os downloads, vamos Trabalhar!
No episódio de hoje vamos fazer uma... Agenda! Rá!
Vamos começar descompactando o banco H2:
Em seguida, copie-o pra dentro do projeto que fizemos no primeiro artigo:
E não esqueça, de adicioná-lo ao build path:
Feito isso, vamos configurar um DataSource, :-)
O Spring tem uma implementação pronta, precisamos apenas configurá-la. Modifique o applicationContext.xml para que ele fique assim:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <context:annotation-config/> <context:component-scan base-package="hellospring.beans"/> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.h2.Driver" /> <property name="url" value="jdbc:h2:~/agenda" /> <property name="username" value="sa" /> <property name="password" value="sa" /> </bean> </beans>
Perfeito né não? Se nosso assunto fosse só JDBC, estaríamos resolvidos aqui. Mas prossigamos.
Uma vez criado o datasource, vamos proceder com a adição do suporte a JPA no projeto. Descompacte o hibernate que baixamos:
Dentro da pasta descompactada você encontrará uma pasta chamada lib. Dentro dela, uma pasta chamada required, e outra chamada jpa. As outras pastas não nos interessam. Copie o conteúdo destas duas pastas para o projeto:
Não esqueça de colocar as bibliotecas no buildpath.
Agora vamos criar umas entidades persistentes aqui, ;-) crie a seguinte classe:
package hellospring.entity;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Entity;
@Entity
public class Contato {
@Id
@GeneratedValue
private int id;
@Column
private String nome;
@Column
private String endereco;
@Column
private String telefone;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getEndereco() {
return endereco;
}
public void setEndereco(String endereco) {
this.endereco = endereco;
}
public String getTelefone() {
return telefone;
}
public void setTelefone(String telefone) {
this.telefone = telefone;
}
}
Representa nossa tabela de contatos, da nossa agenda. Crie agora a seguinte classe:
package hellospring.beans;
import hellospring.entity.Contato;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Component;
@Component
public class Agenda {
@PersistenceContext
private EntityManager em;
public void salvar(Contato c) {
em.getTransaction().begin();
em.persist(c);
em.getTransaction().commit();
}
public void excluir(int id) {
em.getTransaction().begin();
em.createQuery("delete from contato c where c.id = :id")//
.setParameter("id", id).executeUpdate();
em.getTransaction().commit();
}
public List<contato> listar() {
return em.createQuery("select c from contato c", Contato.class)
.getResultList();
}
}
Agora devemos retornar à configuração do xml do spring; pois para termos um EntityManager, vamos precisar de um entityManagerFactory. Deixe o applicationContext.xml deste jeito:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<context:component-scan base-package="hellospring.beans"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:~/agenda" />
<property name="username" value="sa" />
<property name="password" value="sa" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true"/>
</bean>
</property>
</bean>
</beans>
Agora um último detalhe: como estamos lidando com JPA, precisamos definir um persistence.xml e nele declarar as classes mapeadas. crie a pasta META-INF dentro do seu src e nela crie o perssitence.xml:
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="hello-spring-pu" transaction-type="RESOURCE_LOCAL"> <class>hellospring.entity.Contato</class> </persistence-unit> </persistence>Tudo limpo até aqui? abaixo um exemplo de saída caso tudo tenha corrido bem (até o momento):
Mar 18, 2013 9:06:12 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7ea269e2: startup date [Mon Mar 18 21:06:12 GMT-03:00 2013]; root of context hierarchy Mar 18, 2013 9:06:12 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [applicationContext.xml] Mar 18, 2013 9:06:13 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName INFO: Loaded JDBC driver: org.h2.Driver Mar 18, 2013 9:06:13 PM org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean createNativeEntityManagerFactory INFO: Building JPA container EntityManagerFactory for persistence unit 'hello-spring-pu' Mar 18, 2013 9:06:13 PM org.hibernate.annotations.common.VersionINFO: HCANN000001: Hibernate Commons Annotations {4.0.1.Final} Mar 18, 2013 9:06:13 PM org.hibernate.Version logVersion INFO: HHH000412: Hibernate Core {4.2.0.Final} Mar 18, 2013 9:06:13 PM org.hibernate.cfg.Environment INFO: HHH000206: hibernate.properties not found Mar 18, 2013 9:06:13 PM org.hibernate.cfg.Environment buildBytecodeProvider INFO: HHH000021: Bytecode provider name : javassist Mar 18, 2013 9:06:13 PM org.hibernate.ejb.Ejb3Configuration configure INFO: HHH000204: Processing PersistenceUnitInfo [ name: hello-spring-pu ...] Mar 18, 2013 9:06:13 PM org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator instantiateExplicitConnectionProvider INFO: HHH000130: Instantiating explicit connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider Mar 18, 2013 9:06:14 PM org.hibernate.dialect.Dialect INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect Mar 18, 2013 9:06:14 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService INFO: HHH000268: Transaction strategy: org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory Mar 18, 2013 9:06:14 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory INFO: HHH000397: Using ASTQueryTranslatorFactory Mar 18, 2013 9:06:15 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute INFO: HHH000228: Running hbm2ddl schema update Mar 18, 2013 9:06:15 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute INFO: HHH000102: Fetching database metadata Mar 18, 2013 9:06:15 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute INFO: HHH000396: Updating schema Mar 18, 2013 9:06:15 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute INFO: HHH000232: Schema update complete Mar 18, 2013 9:06:15 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2e4fda99: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,agenda,sampleBean1,sampleBean2,dataSource,entityManagerFactory,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy Hello!
Você pode modificar a classe Main para executar um pequeno teste:
package hellospring;
import hellospring.beans.Agenda;
import hellospring.beans.SampleBean2;
import hellospring.entity.Contato;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = //
new ClassPathXmlApplicationContext("applicationContext.xml");
Agenda agenda = ctx.getBean(Agenda.class);
Contato c = new Contato();
c.setNome("Fulano");
c.setEndereco("Rua tal");
c.setTelefone("12345678");
agenda.salvar(c); System.out.println(agenda.listar());
}
}
Perfeito né? ocorre que se você executar esta classe, um erro curioso e não muito óbvio vai ocorrer:
INFO: HHH000232: Schema update complete
Mar 19, 2013 10:48:50 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2df0d2a3: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,agenda,sampleBean1,sampleBean2,dataSource,entityManagerFactory,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
Hibernate: select contato0_.id as id1_0_, contato0_.endereco as endereco2_0_, contato0_.nome as nome3_0_, contato0_.telefone as telefone4_0_ from Contato contato0_
[]
Percebeu? No código de testes mandamos primeiro salvar, depois listar. Mas ao listar temos um resultado vazio.
Isto ocorre porque o modo transacional não está funcionando. Sim... se não comitou, não salvou, ainda estamos no mundo relacional, ;-)
Para ativar o modo relacional, primeiro modifique seu applicationContext.xml para adicionar o suporte a transações:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:annotation-config/>
<context:component-scan base-package="hellospring.beans"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:~/agenda" />
<property name="username" value="sa" />
<property name="password" value="sa" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!-- <property name="generateDdl" value="true"/> -->
<property name="showSql" value="true" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
Mas isto não é tudo, um novo erro ocorrerá:
Mar 19, 2013 11:30:49 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@397dea61: startup date [Tue Mar 19 23:30:49 GMT-03:00 2013]; root of context hierarchy Mar 19, 2013 11:30:49 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [applicationContext.xml] Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class path resource [applicationContext.xml]; nested exception is java.lang.NoClassDefFoundError: org/aopalliance/intercept/MethodInterceptor at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:412) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:243) at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127) at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93) at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130) at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:451) at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext. (ClassPathXmlApplicationContext.java:83) at hellospring.Main.main(Main.java:13) Caused by: java.lang.NoClassDefFoundError: org/aopalliance/intercept/MethodInterceptor at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(Unknown Source) at java.security.SecureClassLoader.defineClass(Unknown Source) at java.net.URLClassLoader.defineClass(Unknown Source) at java.net.URLClassLoader.access$100(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser$AopAutoProxyConfigurer.configureAutoProxyCreator(AnnotationDrivenBeanDefinitionParser.java:126) at org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser.parse(AnnotationDrivenBeanDefinitionParser.java:84) at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:73) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1438) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1428) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:185) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:139) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:108) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390) ... 14 more Caused by: java.lang.ClassNotFoundException: org.aopalliance.intercept.MethodInterceptor at java.net.URLClassLoader$1.run(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) ... 36 more
Se você ganhou um desses também, leia a stacktrace: ClassNotFoundException. Sim... vamos baixar outro jar, o aopalliance.jar.
Baixe-o, copie e cole no projeto, e adicione no classpath.
Você sabe como fazer... Confio em você!
Depois disso, pra fechar com chave de ouro, modifique o Agenda.java e deixe-o desse jeito:
package hellospring.beans;
import hellospring.entity.Contato;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class Agenda {
@PersistenceContext
private EntityManager em;
@Transactional
public void salvar(Contato c) {
em.persist(c);
}
@Transactional
public void excluir(int id) {
em.createQuery("delete from Contato c where c.id = :id")//
.setParameter("id", id).executeUpdate();
}
public List listar() {
return em.createQuery("select c from Contato c", Contato.class)
.getResultList();
}
}
Ao executar novamente seu teste, seus dados estarão sendo salvos perfeitamente.
Lindo, não?
E é isso, simples assim.
Não, sério mesmo. Só isso.
Se você olhar, seu esforço foi pouco, para um grande benefício.
E isto conclui a parte 2, now with lasers, ;-)
Vejo vocês depois, até a próxima!










muito bom Leonardo!
ResponderExcluirshow de bola, parabéns.
ResponderExcluir