abr 25 2010

Segurança passo a passo com Spring Security 3.0

Category: SpringEdson Gonçalves @ 6:48

Olá, tudo bom? Como vão vocês?

Este artigo é o primeiro de uma série que falaremos sobre segurança em aplicações Java, começando com a primeira parte do artigo sobre Spring Security.  Dúvidas e críticas são bem vindas.

Segurança de dados através do Spring Security

A segurança de áreas restritas em aplicações Web escritas em Java não é uma tarefa das mais triviais.

Sabendo que não era simples criar áreas de segurança, em 2003 surge o Acegi Security System for Spring, um framework extremamente configurável  e complexo. Comum na época, suas configurações eram baseadas em XML e demorava um tempo para que o desenvolvedor o dominasse completamente.

O projeto Acegi evoluiu e, em 2007, foi incorporado aos projetos do Spring Framework, sendo renomeado para Spring Security.

A versão 2.0 foi lançada em 2008 e em 2010 a versão 3.0, a que iremos utilizar neste artigo.

Download do Framework

Para trabalhar com o Spring Security, você deve realizar o download no endereço http://www.springsource.org/download. No momento em que este artigo é escrito, a versão utilizada é a Spring Security 3.0.2. Clique em Download.

Figura 1 – Local de download do Spring Security 3.0.2

Figura 1 – Local de download do Spring Security 3.0.2

Baixe a versão spring-security-3.0.2.RELEASE.zip. Ao baixar, descompacte o arquivo extraindo todos os JARs existentes no diretório lib.

Figura 2 – Download do Spring Security

Figura 2 – Download do Spring Security

Também será preciso baixar o Spring Framework. No momento em que este artigo é escrito, a versão utilizada é a Spring Framework 3.0.2.

Figura 3 – Download do Spring Framework

Figura 3 – Download do Spring Framework

Como o Spring Security trabalha

Da mesma forma que faríamos se estivéssemos utilizando JAAS, o Spring Security trabalha a segurança através de declarações baseadas em papéis (roles). Seja em XML ou Anotações, o Spring Security  não necessita chamar método algum para realizar uma autenticação ou autorização.

Através dos roles definidos, podemos informar ao aplicativo em questão, ao qual está sendo assegurada  uma área, quais recursos podem ser acessados ou restringidos a uma determinada pessoa que acessou a área restrita.

Preparando o ambiente de trabalho

Para este artigo, iremos utilizar a IDE da Spring Source, divisão da VMware,  criada sobre a plataforma Eclipse, chamada de SpringSource Tools Suite.

Para baixar o SpringSource Tools Suite, clique aqui, preencha o formulário e faça o Download. Como a ferramenta possui uma opção de instalador, use-a como facilitador se desejar. Na própria página onde baixar o arquivo, haverá a explicação da instalação em cada plataforma, em Installation Instructions.

Criando um projeto

No SpringSource Tools Suite, clique no menu File>New>Dynamic Web Project. Na caixa de diálogo New Dynamic Web Project, digite ProjSpringSecurity (ou o nome que desejar) em Project name.

O SpringSource Tools Suite possui embutido um servidor de aplicações Java Web baseado no Apache Tomcat 6, só que com algumas modificações. Entretanto, vamos utilizar o Tomcat, que pode ser adicionado como mostro neste artigo.

Confirme a criação do projeto no botão Finish.

Adicionando as bibliotecas ao Projeto

Com o direito do mouse sobre o projeto, na view Project Explorer, vá até Properties. Na  caixa de diálogo das propriedades do projeto, vá até Java EE Module Dependencies. Clique em Add External JARs e adicione os seguintes arquivos:

  1. org.springframework.aop-3.0.2.RELEASE.jar
  2. org.springframework.asm-3.0.2.RELEASE.jar
  3. org.springframework.beans-3.0.2.RELEASE.jar
  4. org.springframework.context-3.0.2.RELEASE.jar
  5. org.springframework.core-3.0.2.RELEASE.jar
  6. org.springframework.expression-3.0.2.RELEASE.jar
  7. org.springframework.transaction-3.0.2.RELEASE.jar
  8. org.springframework.web-3.0.2.RELEASE.jar
  9. spring-security-config-3.0.2.RELEASE.jar
  10. spring-security-core-3.0.2.RELEASE.jar
  11. spring-security-taglibs-3.0.2.RELEASE.jar
  12. spring-security-web-3.0.2.RELEASE.jar
  13. commons-logging-1.1.1.jar

Note que o 13º item é um JAR que não pertence a família do Spring Framework. Você pode baixar o arquivo compactado, contendo a biblioteca commons-logging-1.1.1.jar, clicando aqui.

Figura 4 – Arquivos JARs adicionados ao projeto

Figura 4 – Arquivos JARs adicionados ao projeto

Uma aplicação simples com Spring Security

Para exemplificar como funciona o Spring Security, vamos criar uma aplicação simples com apenas uma área segura. Esta área segura será representada dentro de um diretório, chamado admin.

Teremos duas páginas index.jsp: uma na raiz do aplicativo e outra dentro do diretório admin, como mostra a Figura 5.

Figura 5 – As páginas do Projeto

Figura 5 – As páginas do Projeto

As páginas JSP

A página index.jsp, existente dentro do diretório admin exibe apenas uma mensagem simples, como mostra a Figura 6, com apenas HTML.

O conteúdo é mostrado na Listagem 1.

Figura 6 – Página index.jsp exibida após logar na área admin

Figura 6 – Página index.jsp exibida após logar na área admin

Listagem 1 – O conteúdo HTML da página /admin/index.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01

Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<title>Usuário Logado</title>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

</head>

<body>

<h2>Parabéns, você está logado!</h2>

</body>

</html>

A página index.jsp encontrada na raiz exibe apenas um link que o leva até a área administrativa. Sua aparência é idêntica a Figura 7.

O conteúdo da página index.jsp encontrada na raiz da aplicação é mostrado na Listagem 2.

Figura 7 – Página index.jsp exibida quando acessada a aplicação

Figura 7 – Página index.jsp exibida quando acessada a aplicação

Listagem 2 – O conteúdo HTML da página /index.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

"http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<title>Página Inicial</title>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

</head>

<body>

<h2>Uma aplicação simples com Spring Security</h2>

<hr />

<a href="admin">Clique aqui para acessar a área administrativa</a>

</body>

</html>

Configurando o web.xml

Para que o Spring Security, assim como o Spring, precisamos configurar o web.xml. O Spring Security utiliza um filtro HTTP para interceptar as URLs acessadas e verificar as permissões de acesso.

A Listagem 3 exibe a configuração do arquivo web.xml.

Listagem 3 – O arquivo web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns="http://java.sun.com/xml/ns/javaee"

xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

id="WebApp_ID" version="2.5">

<display-name>ProjSpringSecurity</display-name>

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

<filter>

<filter-name>springSecurityFilterChain</filter-name>

<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

</filter>

<filter-mapping>

<filter-name>springSecurityFilterChain</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

<welcome-file-list>

<welcome-file>index.jsp</welcome-file>

</welcome-file-list>

</web-app>

Para configurar o Spring Security, utilizamos o filtro org.springframework.web.filter.DelegatingFilterProxy, devidamente configurado na Listagem 3. O filtro está sendo aplicado em todo o aplicativo, podendo ser visto no elemento <url-pattern />.

Atenção: Um detalhe importante que precisa ser notado é o nome do filtro, colocado no elemento <filter-name/>.  Não o altere, pois o Spring já espera pelo nome springSecurityFilterChain.

Configurando o applicationContext.xml

O Spring Security será configurado no arquivo applicationContext.xml. Este arquivo deverá ser criado dentro do diretório WEB-INF, com o conteúdo mostrado na Listagem 4.

Listagem 4 – O arquivo applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/security"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:beans="http://www.springframework.org/schema/beans"

xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">

<http auto-config="true">

<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />

</http>

<authentication-manager>

<authentication-provider>

<user-service>

<user name="edson" password="integrator" authorities="ROLE_ADMIN" />

</user-service>

</authentication-provider>

</authentication-manager>

</beans:beans>

No Spring Security, as configurações de autenticação e autorização estão sendo feitas no arquivo de contexto padrão do Spring (applicationContext.xml). Para que este arquivo seja lido, adicionamos no web.xml o elemento <listener />, contendo o listener org.springframework.web.context.ContextLoaderListener.

O listener do Spring faz com que as configurações sejam carregadas na inicialização da aplicação Web.

Ao ser carregado pelo listener, o arquivo da Listagem 4 declara os usuários e suas regras de acesso ao aplicativo.

O controle de acesso é feito pelo elemento <http />, do applicationContext.xml. Este controle é definido no sub-elemento <intercept-url />. O atributo pattern, de <intercept-url />, informa, através de uma expressão, em qual local o filtro deve agir, bem como define a sua regra de acesso, através do atributo access.

Para que possamos definir que qualquer elemento dentro do diretório admin fique acessível somente para os usuários do role ROLE_ADMIN, adicionamos uma expressão comum no Apache Ant.

Caso tenhamos mais de um sub-elemento <intercept-url />, teremos sua interpretação sendo feita por ordem de definição, sendo que, a primeira que atender a regra, será chamada. Na prática, isto significa que, se houver /admin/relatorios/** e /admin/**, o primeiro caso deverá ser lido primeiro, portanto será o primeiro a ser adicionado na ordem em  applicationContext.xml.

O atributo auto-config, com o valor true, indica a configuração automática da aplicação para utilizar um formulário de login. O JSP do formulário é gerado automaticamente pelo Spring Security neste caso. A Figura 8 exibe o formulário gerado pelo Spring Security.

Figura 8 – Formulário de login gerado automaticamente pelo Spring Security

Figura 8 – Formulário de login gerado automaticamente pelo Spring Security

Com o atributo <authentication-manager>, gerenciamos os usuários e seus respectivos roles  que darão permissão ao diretório especificado anteriormente, em <intercept-url />, pelo filtro.

Para facilitar a compreensão do exemplo, adicionamos apenas um usuário, através de <user/>, informando o nome de usuário, a senha e o seu papel de acesso.

Ao logar no aplicativo, o Spring analisará qual role é permitido no diretório e quem possui  tal permissão.

Personalizando o formulário de acesso a área restrita

É interessante ter uma geração automática de formulário no Spring Security, ajuda a testar a codificação, com certeza. Mas não é agradável ao aplicativo como um todo, pois sempre precisamos criar o formulário com as características gerais desenvolvidas no layout das páginas.

Criando a página personalizada de login

Para isso, o Spring Security nos fornece a personalização do formulário.  A Listagem 5 exibe o conteúdo da página /login.jsp que ficará na raiz do seu aplicativo, junto com index.jsp.

Listagem 5 – A página login.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

<title>Área Restrita</title>

</head>

<body>

<h2>Área Restrita</h2>

<hr />

<%

if(request.getParameter("error") != null){

if (request.getParameter("error").equals("invalido")){

%>

<p>

<span style="color:red">

Usuário ou Senha inválidos

</span>

</p>

<%

} //fim do if equals

}//fim do if null

%>

<form action="j_spring_security_check" method="post">

Usuário: <input name="j_username" type="text" value="${not empty login_error ? SPRING_SECURITY_LAST_USERNAME : ''}" />

<br />

Senha: <input type="password" name="j_password"><br />

<input type="submit" value="Efetuar Login"><br />

<a href="index.jsp">Retornar para a Página Inicial</a>

</form>

</body>

</html>

Para que o formulário funcione com o Spring Security, as regras mais básicas são:

  • O atributo action deve apontar para j_spring_security_check;
  • O atributo name da caixa de entrada de  texto, do nome de usuário, deve ser j_username;
  • O atributo name da caixa de entrada de senha deve ser j_ password.

Estes princípios básicos farão com que seu formulário funcione com o Spring Security. Entretanto, precisamos mostrar uma mensagem de erro, caso o usuário não tenha colocado as informações necessárias ou, as mesmas não sejam compatíveis com o registrado no sistema para permitir a entrada na área restrita.

É exatamente o papel do if(request.getParameter(“error”) e if (request.getParameter(“error”).equals(“invalido”)),  na página login.jsp, personalizado, com um parâmetro que iremos transmitir, através do Spring Security, caso ocorra um erro na permissão.

A página personalizada pode ser vista na Figura 9.

Figura 9 – Formulário de acesso a área restrita personalizado

Figura 9 – Formulário de acesso a área restrita personalizado

Alterando o arquivo applicationContext.xml

Por fim, mas não menos importante, precisamos alterar o arquivo applicationContext.xml para que o Spring Security passe a trabalhar com a página de login personalizada que criamos. A seguir você tem o trecho, contendo o elemento <form-login/>, que deve ser inserido por entre o elemento <http />:

<form-login login-page=“/login.jsp” authentication-failure-url=“/login.jsp?error=invalido”/>

O elemento <form-login/> é de simples compreensão, pois temos atributos que descrevem bem sua função:

login-page: A página personalizada com o formulário de substituição do padrão existente no framework

authentication-failure-url: URL de retorno caso ocorra um erro. Note que adicionamos,  após “?” , error=invalido. Isto demonstra, claramente, que não é uma regra fixa o que pode ser transmitido, caso ocorra um erro, na entrada de uma determinada área restrita.

Figura 10 – Resultado final do projeto com todos os arquivos criados

Figura 10 – Resultado final do projeto com todos os arquivos criados

No próximo artigo sobre Spring Security

Embora tenhamos conhecido os elementos básicos de utilização do Spring Security, restou colocar o acesso ao banco de dados para fazer uma autenticação verdadeira, como ocorre em sistemas.

No próximo artigo veremos como fazer para trabalhar com Spring Security e o acesso ao banco de dados, com um exemplo completo, passo a passo.

Até o próximo artigo pessoALL.

Tags: , , , , , , ,


abr 10 2010

JPA 2.0 na Prática – Parte 3

Category: JPA 2.0Edson Gonçalves @ 6:48

Olá, tudo bom? Como vão vocês?

Este artigo é o terceiro de uma série ao qual vou ensiná-los a trabalhar com a Java Persistence API 2.0 (JPA 2.0).  Dúvidas e críticas são bem vindas.

Conhecendo as anotações básicas em uma Entidade

Como pudemos perceber no artigo  JPA 2.0 na Prática – Parte 2, as entidades representam as tabelas encontradas no banco de dados. Entretanto, nem sempre refletirão exatamente o modelo da entidade relacional encontrado no banco de dados mas, com certeza, são suas representações, só que em formato de objetos – o que chamamos de O/R (Object-to-Relational).

Anotando uma classe simples

Entidades são classes Java Simples (POJOs) na JPA.  Ao fazer a Entidade Bean Categoria, em JPA 2.0 na Prática – Parte 2, adicionamos anotações que representavam certas características que deveriam ser refletidas na entidade relacional, como nome da tabela e o campo de chave primária.

A entidade Categoria é simples e possui atributos privados que  são refletidos, tais como escritos na entidade, em seu equivalente, na tabela da entidade relacional.

A classe Categoria também é formada por métodos públicos getters e setters, tais como são os JavaBeans comuns.

Para que uma classe, como no caso da Categoria criada, não seja considerada um simples JavaBean e sim uma Entidade Bean da Java Persistence, precisamos de duas anotações básicas:

javax.persistence.Entity Informa que classe é uma Entidade;

javax.persistence.Id – Informa o atributo na classe que será utilizado como chave primária;

Na ausência das demais anotações, o nome da tabela e das colunas existentes na entidade relacional, do banco de dados, são tidos pelo provedor de persistência como sendo exatamente iguais aos encontrados na Entidade Bean.

Desta forma, se mapearmos uma entidade bean como na Listagem 1, teremos uma tabela no banco de dados, procurada ou criada pelo provedor de persistência similar ao da Listagem 2.

Listagem 1 – Entidade Bean Categoria



package br.com.integrator;

import java.io.Serializable;

import java.lang.*;

import javax.persistence.*;

@Entity

public class Categoria implements Serializable {

@Id

private Long id;

private String categoria;

private String descricao;

//getters e setters omitidos

}

Listagem 2 – A tabela Categoria no banco de dados MySQL

create table Categoria(

id bigint(20) primary key not null,

categoria varchar(255),

descricao varchar(255)

);

Anotações @Table, @Column e @Id

Se necessitarmos definir o nome de uma tabela, como foi feito em JPA 2.0 na Prática – Parte 2, utilizamos a notação @Table, de javax.persistence.Table. O mesmo também pode ser feito para dar nomes a colunas, utilizando a anotação @Column, de javax.persistence.Column. Desta forma, se fizermos a modificação na classe Categoria, como na Listagem 3, teremos o resultado mostrado na Figura 1.

Listagem 3 – Utilizando as anotações @Table e @Column

@Entity

@Table(name="categorias")

public class Categoria implements Serializable {

@Id

@Column(name="categoria_id", nullable=false, columnDefinition="integer")

private Long id;

@Column(name="categoria_nome", length=30, nullable=false)

private String categoria;

@Column(columnDefinition="text")

private String descricao;

//getters e setters omitidos

}
Figura 1 – Anotações da Entidade Categoria refletida na tabela categorias no banco de dados

Figura 1 – Anotações da Entidade Categoria refletida na tabela categorias no banco de dados

A Listagem 3 exibe os atributos contidos na anotação @Column, que são úteis no mapeamento de uma tabela equivalente no banco de dados. Temos os seguintes atributos utilizados no exemplo:

name – Nome da coluna na tabela do banco de dados, recebe como valor uma String;

columnDefinition – Recebe uma String com o tipo que será usado pela coluna equivalente na tabela do banco de dados. Um exemplo é a coluna descricao que possui columnDefinition como text.

length – Alguns tipos de colunas nas tabelas dos bancos de dados possuem um valor variável de largura do campo. Um exemplo são os campos varchar(). No MySQL, se não definirmos um valor de largura para o tipo varchar, este é criado em seu tamanho máximo de caracteres, que no caso é 255. Cada banco de dados possui um limite máximo em seu determinado tipo.

nullable – Recebe um valor booleano cujo o padrão é true, caso não declarado. Se false,  este campo é obrigatório.

A anotação @Id, mostrada pela primeira vez em JPA 2.0 na Prática – Parte 2, possui  uma anotação dependente, chamada de @javax.persistence.GeneratedValue.  Esta anotação é utilizada quando desejamos que o provedor de persistência gere as chaves para nós.

A anotação @GeneratedValue possui um atributo chamado strategy, que define a estratégia de geração de valores incrementados. A estratégia mais comum é javax.persistence.GeneratorType.AUTO, mas no exemplo visto na parte 2 dos artigos sobre JPA, utilizamos javax.persistence.GeneratorType. IDENTITY.

Entretanto, alguns gerenciadores de banco de dados, como Oracle, possuem uma estrutura predefinida para gerar valores seqüenciais. Nestes casos, utilizamos a anotação @javax.persistence.SequenceGenerator. A Listagem 4 exibe esta anotação utilizada em um banco de dados ORACLE.

Listagem 4 – Utilizando a anotação @SequenceGenerator

@Entity

@Table(name="CATEGORIAS_TABLE")

@SequenceGenerator(name="CATEGORIA_SEQUENCE", sequenceName="MINHA_SEQ", initialValue=1, allocationSize=1)

public class Categoria implements Serializable {

@Id

@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CATEGORIA_SEQUENCE")

private Long id;

@Column(length=30, nullable=false)

private String categoria;

@Column(length=3500)

private String descricao;

//getters e setters omitidos

}

A anotação @SequenceGenerator possui um atributo name do qual é referenciado em @GeneratedValue, através do atributo generator. A anotação @GeneratedValue também precisa utilizar, no atributo strategy, o valor GenerationType.SEQUENCE.

O nome da sequence gerada no Oracle, por exemplo, seria a colocada no atributo sequenceName, de @SequenceGenerator.

Também, em @SequenceGenerator temos os atributos initialValue e  allocationSize[1].  O resultado de uma sequence criada no banco de dados Oracle, com estas informações fornecidas pela entidade, através da JPA, pode ser vista na Figura 2.

Figura 2 – Sequencia gerada no Oracle XE e visualizada pelo Browser de Objetos

Figura 2 – Sequencia gerada no Oracle XE e visualizada pelo Browser de Objetos

Atenção: A forma como adicionamos a anotação @javax.persistence.Id na Entidade determina como podemos declarar as demais anotações no Bean. Se colocarmos a anotação @Id nos atributos, as demais precisam estar nos atributos. Se colocarmos no método getter, as demais precisarão estar nos métodos getters.

Na próxima parte

Na Parte 3 da série JPA 2.0 na Prática aprendemos as anotações básicas que podemos utilizar para criar uma entidade bean e tê-la refletida em uma tabela no banco de dados relacional.


[1] Sem o atributo allocationSize em 1, o Oracle, por exemplo, usando o Hibernate como provedor JPA, criará uma sequence com valor de 50 em 50.

Tags: , , , ,


mar 09 2010

JPA 2.0 na Prática com Hibernate 3.5

Category: JPA 2.0Edson Gonçalves @ 21:07

Olá, tudo bom? Como vão vocês?
Embora meus artigos sobre JPA 2.0 tenham uma sequencia, este em especial está sendo postado para sanar as dúvidas de vários leitores que me pediram para ensiná-los a usar o Hibernate 3.5, como ORM provider, para trabalhar com JPA 2.0.
Dúvidas e críticas são bem vindas.

Preparação do ambiente de trabalho

Se você olhou o artigo JPA na Prática – Parte 1, será similar no banco de dados e  na ferramenta porém, haverá uma modificação na biblioteca JPA.

A  biblioteca JPA

O Hibernate é um ORM como o EclipseLink, muito utilizado no desenvolvimento Web com Java,  cujo a versão 3.5 possui suporte a Java Persistence API 2.0.  Você pode baixá-la clicando aqui. Clique em Download, no menu lateral esquerdo.

A versão, no momento em que escrevo, é a 3.5.0-CR-2 (ainda em desenvolvimento).

Os arquivos que terá de baixar serão:

  • Hibernate Core
  • Hibernate JPAModelGen

Ao baixar os arquivos, descompacte-os.  Você precisará das seguintes bibliotecas:

  • hibernate3.jar
  • antlr-2.7.6.jar
  • commons-collections-3.1.jar
  • dom4j-1.6.1.jar
  • javassist-3.9.0.GA.jar
  • jta-1.1.jar
  • slf4j-api-1.5.8.jar
  • hibernate-jpa-2.0-api-1.0.0-CR-1.jar

Além destes arquivos, será necessário utilizar as bibliotecas da Simple Logging Facade for Java, SLF4J. Baixe o arquivo com todas as bibliotecas da SLF4J aqui.

Descompacte o arquivo após baixá-lo.  Você precisará das seguintes bibliotecas:

  • slf4j-jdk14-1.5.11.jar
  • slf4j-log4j12-1.5.11.jar

O Projeto

O projeto para este pequeno tutorial é o mesmo do criado no artigo JPA na Prática – Parte 1, portanto não será explicado novamente como fazê-lo.

As bibliotecas no projeto

Podemos tanto criar uma biblioteca de usuário, contendo todas elas ou, simplesmente, adicionar todas ao seu projeto.

Figura 1 – Bibliotecas do Hibernate 3.5 e SLF4J adicionadas ao projeto

Figura 1 – Bibliotecas do Hibernate 3.5 e SLF4J adicionadas ao projeto

Configurando o arquivo persistence.xml

Similar ao mostrado na JPA 2.0 na Prática – Parte 2, no arquivo persistence.xml, altere-o conforme a Listagem 1 abaixo:
Listagem 1 – O arquivo persistence.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="JpaNaPratica" transaction-type="RESOURCE_LOCAL">

<class>br.com.integrator.Categoria</class>

<properties>

<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpapratica"></property>

<property name="javax.persistence.jdbc.user" value="edson"></property>

<property name="javax.persistence.jdbc.password" value="integrator"></property>

<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"></property>

<property name="hibernate.show_sql" value="true" />

<property name="hibernate.format_sql" value="true" />

<property name="hibernate.hbm2ddl.auto" value="create"/>

</properties>

</persistence-unit>

</persistence>

Infelizmente, nem todas as propriedades de persistence.xml são padronizadas, conforme já dito no artigo JPA na Prática – Parte 2. Para exibir a saída das instruções SQL geradas, assim como outras informações, as seguintes propriedades foram  adicionadas ao arquivo persistence.xml:

<property name="hibernate.show_sql" value="true" />

<property name="hibernate.format_sql" value="true" />

Para criar a tabela, utilizamos a seguinte adição:

<property name=”hibernate.hbm2ddl.auto” value=”create”/>

Testando o Projeto

Similar ao mostrado na JPA 2.0 na Prática – Parte 2, execute a classe com o método main() e veja os resultados refletidos no banco de dados.

Hibernate ou EclipseLink?

Muitos me perguntam isso, querendo saber qual é o melhor. O ideal, como sempre, é conhecer ambos e tirar as suas próprias conclusões. Em JPA 2.0, ao menos por enquanto, no que foi mostrado, não há diferença.

Abraço a todos e até o próximo artigo.

Tags: , , , , ,


fev 03 2010

JPA 2.0 na Prática – Parte 2

Category: JPA 2.0Edson Gonçalves @ 14:13

Olá, tudo bom? Como vão vocês?

Este artigo é o segundo de uma série ao qual vou ensiná-los a trabalhar com a Java Persistence API 2.0 (JPA 2.0).  Dúvidas e críticas são bem vindas.

Os primeiros passos na JPA

Com o ambiente configurado, agora podemos  configurar a JPA e dar nossos primeiros passos em sua execução, entendendo como funciona e o que podemos fazer.

Esta parte do artigo está baseada na configuração, criação da entidade e manipulação básica do banco de dados.

Caso você tenha chegado agora, a Parte 1 do artigo ensina como configurar o seu ambiente de desenvolvimento e testes.

Configurando o arquivo persistence.xml

Ao criar o projeto, também foram criados um diretório e arquivo. Note o arquivo chamado persistence.xml,  encontrado no diretório META-INF, dentro de src.

Abra o arquivo persistence.xml e verá que o Eclipse IDE possui um editor do arquivo.

Sua estrutura básica é como mostrada na Listagem 1 abaixo:
Listagem 1 – O arquivo persistence.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>

</persistence-unit>

</persistence>

Ela pode ser visualizada no Editor do Eclipse, em Source.

Configurando a conexão com o banco de dados

No editor do Eclipse, vá na aba Connection, em persistence.xml.

Adicionando as configurações de conexão ao persistence.xml

Adicionando as configurações de conexão ao persistence.xml

Comece alterando para Resource Local em Transaction type.

Esta pequena alteração adiciona o atributo transaction-type com o valor “RESOURCE_LOCAL” em <persistence-unit/> no arquivo persistence.xml.  O atributo transaction-type está definindo que a unidade de persistência terá sua integridade gerida  através da API local (RESOURCE_LOCAL), que é o nosso caso, onde não haverá um servidor de aplicativos Java EE por enquanto envolvido para transações JTA (Java Transaction API).

Mais abaixo, em EclipseLink Connection Pool, clique em Populate from Connection.

Adicionando os parâmetros de conexão no arquivo persistence.xml

Adicionando os parâmetros de conexão no arquivo persistence.xml

Ao abrir a caixa de diálogo Connection Selection, selecione a conexão do MySQL que fez na criação do projeto e confirme.

Conexão do MySQL feita na criação do Projeto

Conexão do MySQL feita na criação do Projeto

Ao retornar ao arquivo persistence.xml, os dados pertencentes ao banco de dados estarão preenchidos.

Configurações para a conexão ao banco de dados

Configurações para a conexão ao banco de dados

Esta mudança da conexão alterou o arquivo persistence.xml da seguinte forma:

<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpapratica"/>
<property name="javax.persistence.jdbc.user" value="edson"/>
<property name="javax.persistence.jdbc.password" value="integrator"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
</properties>

Na JPA 2.0, algumas propriedades foram padronizadas. As propriedades que foram adicionadas ao arquivo persistence.xml são padrões para se conectar ao banco de dados. Veja o que significa cada uma delas:

  • javax.persistence.jdbc.driver — o nome do driver da classe totalmente qualificado
  • javax.persistence.jdbc.url — URL específico do driver
  • javax.persistence.jdbc.user — usuário do banco de dados para a conexão
  • javax.persistence.jdbc.password — senha do banco de dados para a conexão

Vá agora até a aba Logging e, em Logging level, altere para All. Isso tornará visível todas as operações que fizemos, utilizando a JPA, no Console do Eclipse.

Alterando o nível de logging para ALL

Alterando o nível de logging para ALL

Infelizmente, nem todas as propriedades de persistence.xml foram padronizadas. A seguinte propriedade foi adicionada ao arquivo:

<property name=“eclipselink.logging.level” value=“ALL”/>

Ainda em persistence.xml, vá até a aba Schema Generation.  Nesta aba temos DDL generation type. Como não fizemos nenhuma tabela no banco de dados, teremos que criá-la ao executar nossa primeira entidade.

Temos três opções:

  • None – não ocorre nada;
  • Create Tables – cria as tabelas baseando-se nas informações contidas nas entidades;
  • Drop and Create Tables – exclui e cria as tabelas através das informações contidas nas entidades;

Para o nosso trabalho inicial, vamos manter um ciclo de criação e exclusão,  selecionando Drop and Create Tables.

Gerando tabelas através da configuração de persistence.xml

Gerando tabelas através da configuração de persistence.xml

As últimas alterações incluíram a seguinte propriedade:

<property name=“eclipselink.ddl-generation” value=“drop-and-create-tables”/>

Com estas mudanças, temos tudo pronto para trabalhar com a JPA.

Criando sua primeira entidade

Clique com o direito do mouse sobre src, do seu projeto JPA. Selecione no menu de contexto New>Entity.

Criando uma entidade JPA no Eclipse IDE

Criando uma entidade JPA no Eclipse IDE

Na caixa de diálogo New JPA Entity, preencha Java package e Class name, no caso: br.com.integrator e Categoria, respectivamente. Mantenha Entity em Inheritance e clique no botão Next.

Criando a classe/entidade Categoria

Criando a classe/entidade Categoria

Na segunda etapa, definimos o nome da tabela que será utilizada pela entidade Categoria e seus respectivos campos/colunas.

Segunda etapa da criação da Entidade JPA

Segunda etapa da criação da Entidade JPA

O Eclipse IDE, através do seu assistente, irá manter o nome da tabela como padrão existente ao nome da entidade. Desmarque Use default e altere para categorias em Table name.

Esta pequena alteração informa que a entidade Categoria está ligada a tabela categorias do banco de dados.

Alteração do nome da tabela para o banco de dados

Alteração do nome da tabela para o banco de dados

Abaixo você vai encontrar Entity fields. Clique em Add para adicionar as os atributos que existirão na entidade Categoria e seus respectivos tipos.

Detalhe da adição de atributos na entidade Categoria

O diálogo Entity Fields possui Type para colocar o tipo ( que também é acessível com Ctrl+Space) e o nome.

Adicionando um atributo

Adicionando um atributo

Os atributos da entidade são mostrados na Figura abaixo:

Atributos da entidade Categoria

Atributos da entidade Categoria

Veja que foi marcado id como key. Isso fará com que este atributo/campo seja a chave primária.

Diálogo completamente preenchido

Diálogo completamente preenchido

Com tudo preenchido, clique no botão Finish para gerar a classe Categoria com as devidas anotações que a fará uma Entidade da JPA.

A classe/entidade Categoria possui a estrutura como mostrado na Listagem 2 após sua geração:

Listagem 2 – A entidade Categoria

package br.com.integrator;
import java.io.Serializable;
import java.lang.Long;
import java.lang.String;
import javax.persistence.*;
@Entity
@Table(name="categorias")
public class Categoria implements Serializable {
@Id
private Long id;
private String categoria;
private String descricao;
//getters e setters omitidos
}

As entidades, na especificação da JPA, são POJOS (Plain Old Java Objects ), onde podemos alocar com o operador new, assim como faríamos com qualquer outro objeto Java simples. As instâncias de uma classe do tipo entidade não se tornam persistentes até estarem associadas a um EntityManager.

No arquivo persistence.xml, verá a classe adicionada em General>Managed Classes.

Detalhe de Managed Classes em persistence.xml

Detalhe de Managed Classes em persistence.xml

No XML de persistence.xml, haverá a seguinte linha adicionada:

<class>br.com.integrator.Categoria</class>

O elemento <class/> lista explicitamente as classes que são consideradas entidades no persistence.xml.

Para finalizar, vá até a classe Categoria. Na view JPA Structure, clique em id. Marque Primary key generation na view JPA Details e selecione Identity em Strategy. Isso informa a entidade que o campo da chave primária é auto-incrementado e, portanto, gerado pela tabela do banco de dados.

Definindo a estratégia de auto-incremento no campo id da entidade

Definindo a estratégia de auto-incremento no campo id da entidade

Na classe veremos a seguinte anotação: @GeneratedValue(strategy = IDENTITY), onde IDENTITY é de javax.persistence.GenerationType.

Testando a JPA

Antes de explicar qualquer coisa, vamos fazer um teste para saber se está tudo corretamente funcionando, simplesmente chamando a persistence-unit através de uma simples classe Java com um método main().

Crie uma classe no próprio projeto JPA , chamando-a de TesteDaJPA. Coloque em um pacote diferente do qual vem usando e marque public static void main(String[] args). Confirme a criação da classe no botão Finish.

Criação da classe de testes

Criação da classe de testes

Altere a classe TesteDaJPA conforme a Listagem 3:

Listagem 3 – A classe TesteDaJPA

package br.com.integrator.teste;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class TesteDaJPA {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("JpaNaPratica");
EntityManager em = emf.createEntityManager();
em.close();
emf.close();
 }
}

Execute a classe através do menu Run>Run As>Java Application.

Graças à configuração que fizemos de logging no arquivo persistence.xml (em <property name=“eclipselink.logging.level” value=“ALL”/>) , possuímos uma saída bem detalhada do que ocorreu ao gerar este simples teste.

Assim que iniciada a classe, veremos a saída contendo a conexão ao banco de dados:

[EL Finest]: 2010-02-03 04:33:36.007--Thread(Thread[main,5,main])--DBPlatform: org.eclipse.persistence.platform.database.MySQLPlatform, RegularExpression: (?i)mysql.*.
[EL Fine]: 2010-02-03 04:33:36.007--Thread(Thread[main,5,main])--Detected Vendor platform: org.eclipse.persistence.platform.database.MySQLPlatform
[EL Config]: 2010-02-03 04:33:36.022--ServerSession(11025290)--Connection(29232906)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
 platform=>MySQLPlatform
 user name=> "edson"
 datasource URL=> "jdbc:mysql://localhost:3306/jpapratica"
))
[EL Config]: 2010-02-03 04:33:36.022--ServerSession(11025290)--Connection(9616314)--Thread(Thread[main,5,main])--Connected: jdbc:mysql://localhost:3306/jpapratica
 User: edson@localhost
 Database: MySQL Version: 5.1.43-community
 Driver: MySQL-AB JDBC Driver Version: mysql-connector-java-5.1.10 ( Revision: ${svn.Revision} )
[EL Config]: 2010-02-03 04:33:36.022--ServerSession(11025290)--Connection(23255990)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
 platform=>MySQLPlatform
 user name=> "edson"
 datasource URL=> "jdbc:mysql://localhost:3306/jpapratica"
))
[EL Config]: 2010-02-03 04:33:36.038--ServerSession(11025290)--Connection(16496587)--Thread(Thread[main,5,main])--Connected: jdbc:mysql://localhost:3306/jpapratica
 User: edson@localhost
 Database: MySQL Version: 5.1.43-community
 Driver: MySQL-AB JDBC Driver Version: mysql-connector-java-5.1.10 ( Revision: ${svn.Revision} )
[EL Finest]: 2010-02-03 04:33:36.069--ServerSession(11025290)--Thread(Thread[main,5,main])--sequencing connected, state is NoPreallocation_State

Entre a saída, veremos que, devido a configuração no persistence.xml (em <property name=“eclipselink.ddl-generation” value=“drop-and-create-tables”/>) , primeiro houve uma tentativa de fazer um drop table na tabela categorias. Como não existia tal tabela, veremos este erro:

Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'categorias'
Error Code: 1051
Call: DROP TABLE categorias
Query: DataModifyQuery(sql="DROP TABLE categorias")
Em seguida veremos a criação da tabela na seguinte linha:
[EL Finest]: 2010-02-03 04:33:36.163--ServerSession(11025290)--Thread(Thread[main,5,main])--Execute query DataModifyQuery(sql="CREATE TABLE categorias (ID BIGINT AUTO_INCREMENT NOT NULL, CATEGORIA VARCHAR(255), DESCRICAO VARCHAR(255), PRIMARY KEY (ID))")

Por fim, será possível ver que ocorre a desconexão ao banco de dados.

A tabela gerada no banco de dados

Ao entrar no banco de dados, veremos que a simples classe anotada se transformou em uma tabela. Evidentemente que o POJO, sem a devida configuração no arquivo persistence.xml, antes da sua chamada pela classe executora que fizemos de teste, não teria esse poder.

A tabela gerada no MySQL

A tabela gerada no MySQL

Graças a anotação @Table, pudemos dar o nome da tabela que seria gerada, através do atributo name.

Atributos convertidos em colunas

Observe que cada atributo da classe se transformou em uma coluna na tabela. A coluna chave, tida por ID, foi gerada graças à anotação @Id. Além disso, o MySQL considerou esta coluna como auto-incrementada, ou seja, ela possui um modificador que incrementa em um toda vez que uma informação é inserida na tabela. Isso é automático e gerenciado pelo banco de dados. A anotação @GeneratedValue foi a responsável pela geração do auto-increment do MySQL.

Os tipos de cada coluna são gerados pelo similar em Java. Logo, Long se transformou em bigint e String em varchar. Cada tipo de coluna, na tabela do banco de dados, possui também um tamanho definido na sua criação. Como não especificamos isso na classe Categoria, através de anotações, a tabela foi gerada utilizando o tamanho máximo obtido pelo tipo, isso no banco de dados em questão. Logo, Long se transformou em bigint(20) e String em varchar(255).

Na próxima parte

Na Parte 2 da série JPA 2.0 na Prática finalmente fizemos a configuração da JPA, possibilitando a conexão ao banco de dados. Também foi possível gerar uma tabela baseada em uma entidade da JPA através de um pequeno teste de utilização.

Em JPA 2.0 na Prática – Parte 3, começaremos a compreender a Entidade em questão, suas várias anotações e implicações no banco de dados.

As entidades, na especificação da JPA, são POJOS (Plain Old Java Objects ), onde podemos alocar com o operador new, assim como faríamos com qualquer outro objeto Java simples. As instâncias de uma classe do tipo entidade não se tornam persistentes até estarem associadas a um EntityManager.

No arquivo persistence.xml, verá a classe adicionada em General>Managed Classes.

Tags: , , , , ,


Próxima página »