Alessandro Lemser
Hibernate 3.2Ago/2006Softplan/PoligraphAlessandro Lemser
Alessandro Lemser
Hibernate é uma ferramenta de mapeamento objeto-relacional para Java de alta performance.
Inclui associação, Herança, polimorfismo, composição e compatibilidade com o framework de coleções do Java.
O Hibertate Query Language (HQL) adiciona extensões orientadas a objeto ao SQL.
Fornece suporte a inúmeras bases relacionais, tais como Oracle, Informix, SQL Server, Interbase, Postgre entre muitas outras.
Introdução
Alessandro Lemser
O hibernate espera que seja criado um arquivo XML de mapeamento para a classe que deseja-se persistir.
O arquivo XML faz a ligação entre a classe Java e uma tabela no banco de dados.
Caso a minha classe possui um relacionamento com outra (Cliente possui um Endereço), é no mapeamento que informamos ao hibernate.
Não é necessário codificar SQL para tarefas mais comuns.
Introdução
Alessandro Lemser
Introdução
public class Usuario implements Serializable {private String cdUsuario;private Integer nmUsuario;private String nuCpf;private java.util.Date dtCadastro;
//getters e settters}
A classe não precisa ter nada de especial.
Deve seguir as especificações do Javabean
É preciso somente saber qual o campo que será a chave primária na tabela.
<hibernate-mapping> <class name="br.com.softplan.curso.Usuario“ table=“ECURUSUARIO">
<id name=“cdUsuario" type=“int” />
<property name="nmUsuario" type="string"/> <property name=“dtCadastro" type="string"/> <property name=“nuCpf“ type="string"/>
</class></hibernate-mapping>
Introdução
<hibernate-mapping> <class name="br.com.softplan.curso.Usuario“ table=“ECURUSUARIO">
<id name=“cdUsuario" type=“int” />
<property name="nmUsuario" type="string"/> <property name=“dtCadastro" type="string"/> <property name=“nuCpf“ type="string"/>
</class></hibernate-mapping>
Introdução
Aqui eu digo qual é a minha classe e com qual tabela ela se relaciona!
<hibernate-mapping> <class name="br.com.softplan.curso.Usuario“ table=“ECURUSUARIO">
<id name=“cdUsuario" type=“int” />
<property name="nmUsuario" type="string"/> <property name=“dtCadastro" type="string"/> <property name=“nuCpf“ type="string"/>
</class></hibernate-mapping>
Introdução
Identifico minha chave primária.
Obs: posso ter chaves compostas e posso, ao invés de informar uma propriedade, informar também uma classe de chave primária.
<composite-id name="enderecoPK" class="br.com.softplan.curso.EnderecoPK"> <key-property name="cdEndereco" type="int"/> <key-property name="cdUsuario" type="int"/></composite-id>
<hibernate-mapping> <class name="br.com.softplan.curso.Usuario“ table=“ECURUSUARIO">
<id name=“cdUsuario" type=“int” />
<property name="nmUsuario" type="string"/> <property name=“dtCadastro" type=“date"/> <property name=“nuCpf“ type="string"/>
</class></hibernate-mapping>
Introdução
Demais propriedades da minha classe que eu quero mapear com tabelas do banco.
Se o nome da minha propriedade NÃO coincide com o nome da minha coluna no banco de dados, devo informar o atributo column, contendo o nome da coluna correspondente no banco de dados.
Alessandro Lemser
Colocando em funcionamentoAgo/2006Softplan/PoligraphAlessandro Lemser
Alessandro Lemser
É necessário ter um arquivo XML, chamado hibernate.cgf.xml, contendo informações úteis para o Hibernate. (posso também informar, ao invés de um XML, o arquivo hibernate.properties).
Neste arquivo basicamente temos:
- Como o hibernate vai conseguir as conexões com o banco
- Qual o dialeto (Oracle, SQLServer, DB2, etc...)
- Quais são e onde estão os arquivos XML de mapeamento
Funcionamento
Alessandro Lemser
Funcionamento<hibernate-configuration> <session-factory>
<property name="connection.driver_class"> oracle.jdbc.driver.OracleDriver </property> <property name="connection.url"> jdbc:oracle:thin:@server23:1531:DERBADES </property> <property name="connection.username">sider</property> <property name="connection.password">projeto1</property> <property name="show_sql">true</property> <property name="use_outer_join">true</property>
<property name="hibernate.dialect"> org.hibernate.dialect.OracleDialect </property>
<!-- mapeamentos --> <mapping resource="Usuario.hbm.xml"/> <mapping resource="Endereco.hbm.xml"/>
</session-factory></hibernate-configuration>
Alessandro Lemser
Funcionamento<hibernate-configuration> <session-factory>
<property name="connection.driver_class"> oracle.jdbc.driver.OracleDriver </property> <property name="connection.url"> jdbc:oracle:thin:@server23:1531:DERBADES </property> <property name="connection.username">sider</property> <property name="connection.password">projeto1</property> <property name="show_sql">true</property> <property name="use_outer_join">true</property>
<property name="hibernate.dialect"> org.hibernate.dialect.OracleDialect </property>
<!-- mapeamentos --> <mapping resource="Usuario.hbm.xml"/> <mapping resource="Endereco.hbm.xml"/>
</session-factory></hibernate-configuration>
Informações sobre a conexão:
Posso informar conexões standalone ou um datasource
<property name=“connection.datasource”> java:CURSODS</property>
Alessandro Lemser
Funcionamento<hibernate-configuration> <session-factory>
<property name="connection.driver_class"> oracle.jdbc.driver.OracleDriver </property> <property name="connection.url"> jdbc:oracle:thin:@server23:1531:DERBADES </property> <property name="connection.username">sider</property> <property name="connection.password">projeto1</property> <property name="show_sql">true</property> <property name="use_outer_join">true</property>
<property name="hibernate.dialect"> org.hibernate.dialect.OracleDialect </property>
<!-- mapeamentos --> <mapping resource="Usuario.hbm.xml"/> <mapping resource="Endereco.hbm.xml"/>
</session-factory></hibernate-configuration>
Informações de runtime:
Se usa outer join por padrão e se mostra os SQLs enviados ao banco no console.
Alessandro Lemser
Funcionamento<hibernate-configuration> <session-factory>
<property name="connection.driver_class"> oracle.jdbc.driver.OracleDriver </property> <property name="connection.url"> jdbc:oracle:thin:@server23:1531:DERBADES </property> <property name="connection.username">sider</property> <property name="connection.password">projeto1</property> <property name="show_sql">true</property> <property name="use_outer_join">true</property>
<property name="hibernate.dialect"> org.hibernate.dialect.OracleDialect </property>
<!-- mapeamentos --> <mapping resource="Usuario.hbm.xml"/> <mapping resource="Endereco.hbm.xml"/>
</session-factory></hibernate-configuration>
DIALETO:
Permite gerar SQL customizados para cada banco de dados.
Alessandro Lemser
Para começar a usar o hibernate agora só utilizamos duas linhas. Só lembrando que as bibliotecas do hibernate esteja configuradas no ambiente.
Configurarion cfg = new Configuration().configure(); SessionFactory factory = cfg.buildSessionFactory();
... public void initHibernate() { Configuration cfg = new Configuration().configure(); this.sessionFactory = cfg.buildSessionFactory(); }
Funcionamento
Alessandro Lemser
QueriesO procedimento para realizar uma query com Hibernate é o seguinte:
1. Ter um SessionFactory válido
2. Obter o objeto Session do SessionFactory
3. *Iniciar uma transação (obter o objeto Transaction)
4. Executar a query
5. *Comitar
6. Fechar a sessão.
* exceto selects e transações gerenciadas pelo Container
Alessandro Lemser
Queriespublic Usuario getUsuario( Integer cdUsuario )
throws ObjectNotFoundException {
Session session = this.sessionFactory.openSession(); try {
Transaction t = session.beginTransaction();
Object usr = session.get(Usuario.class, cdUsuario);
t.commit();
return (Usuario) usr;
} finally {
session.close(); }return null;
}
1,2
3
4
5
6
Alessandro Lemser
Queriespublic List getUsuariosByNome(String nome)
throws ObjectNotFoundException {
Session session = this.sessionFactory.openSession();
Transaction t = session.beginTransaction();
String hql = "From Usuario as usuario " + "Where usuario.nmUsuario LIKE '%" + nome + "%'";
Query query = this.currentSession.createQuery( hql );
List usrs = query.list();
t.commit(); session.close();
return usrs;
}
Alessandro Lemser
Insert, delete e updatepublic void saveOrUpdate(Object obj) {
Transaction t = this.currentSession.beginTransaction();
try {
this.currentSession.saveOrUpdate( obj );
} catch (Exception ex) { t.rollback(); }
t.commit();
}
Alessandro Lemser
Insert, delete e updatepublic void delete(Object obj) { Transaction t = this.currentSession.beginTransaction();
try {
this.currentSession.delete( obj );
} catch (Exception ex) {t.rollback();
}
t.commit();}
Alessandro Lemser
Relacionamentos Com hibernate é relativamente simples realizar mapeamentos do tipo: one-to-many, one-to-one, many-to-one, many-to-many...
Imagine que a classe Usuario possua um relacionamento com Endereco.
public class Usuario implements Serializable {private String cdUsuario;private Integer nmUsuario;private String nuCpf;private java.util.Date dtCadastro;
private Endereco endereco;
//getters e settters}
Alessandro Lemser
Relacionamentos Agora eu quero que quando eu selecione um cliente, seu endereço venha junto. Para isso, tenho que fazer um relacionamento no arquivo de mapeamento do hibernate.
<hibernate-mapping> <class name="br.com.softplan.curso.Usuario“ table=“ECURUSUARIO"> <id name=“cdUsuario" type=“int” /> <property name="nmUsuario" type="string"/> <property name=“dtCadastro" type="string"/> <property name=“nuCpf“ type="string"/>
<property name=“cdEndereco” type=“int”/>
<many-to-one name=”endereco” insert=“false”
update=“false” cascade=“none” outer-join=“true”/>
</class>
</hibernate-mapping>
Alessandro Lemser
Exercícios
Modifique os testes feitos até agora utilizando a pesquisa com relacionamentos.
Alessandro Lemser
Hibernate no SPWAgo/2006Softplan/PoligraphAlessandro Lemser
Alessandro Lemser
O Hibernate está associado ao SPW na forma do pattern DAO (Data Access Objects)
Elementos:- Interface e classe de implementação Ex. Interface: br.com.softplan.curso.dao.UsuarioDAO Ex. impl: br.com.softplan.curso.dao.hbn.HbnUsuarioDAO
- Fábrica de DAOs Ex: br.com.softplan.curso.dao.CursoDAOFactory
- dao.properties: lugar onde a fábrica de DAO vai buscar a classe que realiza a implementação do DAO solicitado.
Ex: UsuarioDAO=br.com.softplan.curso.dao.hbn.HbnUsuarioDAO
Hibernate/SPW
Alessandro Lemser
Mapeamentos em XML: O hibernate realiza o mapeamento do objeto Entity com a tabela no banco por meio de um arquivo XML, conforme visto.
Ex: Pedido.hbm.xml
hibernate.mappings: Listagem de todos os mapeamentos existentesbr/com/softplan/sider/alx/dao/hbn/mapping/Orgaosetor.hbm.xmlbr/com/softplan/sider/alx/dao/hbn/mapping/Tipoexpediente.hbm.xmlbr/com/softplan/sider/alx/dao/hbn/mapping/Almoxarifado.hbm.xmlbr/com/softplan/sider/alx/dao/hbn/mapping/Usuario.hbm.xmlbr/com/softplan/sider/alx/dao/hbn/mapping/Material.hbm.xmlbr/com/softplan/sider/alx/dao/hbn/mapping/Pedido.hbm.xmlbr/com/softplan/sider/alx/dao/hbn/mapping/Pedidoitem.hbm.xml
hibernate.properties: Informações úteis para o hibernate rodarhibernate.session_factory_name=br.com.softplan.sider.alx.dao/SessionFactoryhibernate.connection.datasource=java:/ALXDShibernate.dialect=net.sf.hibernate.dialect.OracleDialecthibernate.show_sql=truehibernate.use_outer_join=true
Hibernate/SPW
Alessandro Lemser
List findAll() - Retorna todos os elementos da entidade.
List findAll(Object obj) - Retorna todos os elementos da entidade, e utiliza o objeto passado como parâmetro como filtro. O objeto pode ser um Entity ou um EntityPK
Usuario usuario = new Usuario():usuario.setNmUsuario(“Maria”);List usuarios = usuarioEJB.findAll( usuario );
Entity findByPrimaryKey( EntityPK entityPK ) - Retorna o elemento correspondente a chave primária passada como parâmetro
Hibernate/SPW
Alessandro Lemser
void save(Entity entity) - Salva, atualiza ou apaga uma entidade do modelo - Rotina de gerar código é integrada, não é preciso se preocupar em gerar um código para a entidade. O SPW espera que o último campo da chave primária é o que deve ser gerado.
void saveAll(List entities) - Salva, atualiza ou apaga uma lista de entidades do banco de dados.
Hibernate/SPW
Alessandro Lemser
Mapeamentos para a classe Pedido
Hibernate/SPW
cd Data Model
Pedido
Pedidoitem
Usuario
1..*
1
1
0..*
Alessandro Lemser
Código da classe Pedido
Hibernate/SPWpublic class Pedido extends Entity { private Usuario usuario; private List itens;
//getters e setters
}
Alessandro Lemser
Após declarar os atributos no XML, declaram-se os relacionamentos
<many-to-one name=“usuario" column="cdUsuario" cascade="none" insert="false" update="false" outer-join="true"/>
Relacionamentos many-to-one
Hibernate/SPW
Alessandro Lemser
Mapeamentos para a classe Pedido
Hibernate/SPW
cd Pedidoitem
Data Model::Pedido
Data Model::Pedidoitem
Material
1..*1
1
0..*
Alessandro Lemser
<bag name="itens"> <key> <column name="cdPedido"/>
<column name="nuSeqpedido"/> </key> <one-to-many class="br.com.softplan.sider.alx.Pedidoitem"/> </bag>
Mapeando coleçõesNome da propriedade do tipo List em Pedido
Hibernate/SPW
Alessandro Lemser
<many-to-one name="material" class="br.com.softplan.sider.alx.Material" column="cdMaterial" unique="true" insert="false" update="false"/>
Mapeando alternate-keys
Hibernate/SPW
Alessandro Lemser
Hibernate/SPW...concluindo
O hibernate oferece uma maneira fácil, intuitiva e transparente para se fazer o mapeamento objeto relacional com performance.
Alessandro Lemser
SPW 3.4Ago/2006Softplan/PoligraphAlessandro Lemser
Alessandro Lemser
TópicosIntroduçãoComponentes - Persistência - Lógica - Apresentação
WizardGrids - Search - Associative - Grid - List - PaginadaInputSelect
Alessandro Lemser
Framework para desenvolvimento de aplicações multicamadas usando tecnologia J2EE.
Baseado em outros frameworks Open Source que, no mercado atual, são considerados padrão de facto (Struts, Hibernate).
A camada de lógica de negócios é baseada basicamente em Stateless SessionBeans.
Aproveita a infra-estrutura fornecida pelo servidor de aplicação e container EJB (transações, pool de conexões, segurança, etc...).
Introdução
Alessandro Lemser
Automatiza tarefas comuns e repetitivas da WEB, especializando o Struts e os SessionBeans para a realidade de desenvolvimento da empresa.
Gera automaticamente os arquivos necessários para a aplicação com base no modelo de dados (wizard).
É integrado com o Hibernate.
Define um padrão para o desenvolvimento e ajuda a promover fraco acoplamento entre camadas.
Possui componentes para as 3 camadas vistas anteriormente...
Introdução
Alessandro Lemser
Componentes para as camadasSPW 3.4
Alessandro Lemser
Persistência
Utiliza o Hibernate em uma estrutura de DAO.
Para cada tabela no banco, são gerado os seguintes Objetos. Abaixo segue um exemplo do que seria gerado para a tabela esegUsuario.
br.com.softplan.curso.UsuarioRepresenta a entidade
br.com.softplan.curso.UsuarioPKRepresenta a chave primária da entidade
br.com.softplan.curso.UsuarioValidatorClasse de validação que sempre é chamada
antes de operações sobre o banco de dados.
Componentes
Alessandro Lemser
Persistência
Componentes
public class Usuario extends Entity { private UsuarioPK usuarioPK; private String nmUsuario; .....}
public class UsuarioPK extends EntityPK { private String cdUsuario; public String getCdUsuario() { return this.cdUsuario; } public void setCdUsuario(String newCdUsuario) { this.cdUsuario = newCdUsuario; } }
esegUsuario
cdUsuario (PK)
nmUsuariodtCadastrodeEmail....
A partir da tabela do banco de dados, são geradas as classes...
Alessandro Lemser
Persistência
Componentes
public class Usuario extends Entity { private UsuarioPK usuarioPK; private String nmUsuario; .....}
public class UsuarioPK extends EntityPK { private String cdUsuario; public String getCdUsuario() { return this.cdUsuario; } public void setCdUsuario(String newCdUsuario) { this.cdUsuario = newCdUsuario; } }
esegUsuario
cdUsuario (PK)
nmUsuariodtCadastrodeEmail....
Alessandro Lemser
Persistência
Componentes
public class Usuario extends Entity { private UsuarioPK usuarioPK; private String nmUsuario; .....}
public class UsuarioPK extends EntityPK { private String cdUsuario; public String getCdUsuario() { return this.cdUsuario; } public void setCdUsuario(String newCdUsuario) { this.cdUsuario = newCdUsuario; } }
Superclasse do SPW.
Contém algumas implementações comuns para as subclasses.
Superclasse do SPW.
Contém algumas implementações comuns para as subclasses. Uma importante é a informação sobre o estado (isStatusInsert, isStatusDelete, getStatus(), setStatus, etc...)
Alessandro Lemser
ComponentesPersistência
O Validator possui pouco uso, devido à requisitos de campos obrigatórios que são diferentes em cada sistema, porém, pode ser útil em algumas situações.
public class UsuarioValidator implements Validator { public boolean supports(Class clazz) { return clazz.equals(Usuario.class); } public void validate(Object obj, Errors errors) { Usuario usuario = (Usuario) obj;
if( usuario.getDeEmail() == null ) { errors.add(new Error(“Email invalido”)); } }}
Alessandro Lemser
Persistência
Como o SPW usa o Hibernate, são gerados os mapeamentos das classes para a tabela e a estrutura de DAO, com os métodos mais comuns já implementados.
Além das classes são gerados os seguintes artefatos:- DAOFactory: responsável por criar objetos que implementam a Interface DAO.
- dao.properties: Permite maior flexibilidade na troca da classe que implementa o DAO, ligando um nome à uma classe de implementação da Interface DAO.
- hibernate.mappings: Contém a localização de todos os arquivos de mapeamento do hibernate.
- hibernate.properties: Configurações do hibernate.
Componentes
Alessandro Lemser
Persistência
Componentes
O arquivo de XML de mapamento:
<hibernate-mapping>
<class name="br.com.softplan.curso.Usuario“ table="ESEGUSUARIO">
<composite-id name=“usuarioPK“ class="br.com.softplan.curso.UsuarioPK"> <key-property name="cdUsuario" type="int"/> </composite-id>
<property name="nmUsuario" type="string"/>
<!– demais propriedades -->
</hibernate-mapping>
Alessandro Lemser
Persistência
Componentes A interface e a classe de implementação do DAO.
public interface UsuarioDAO extends EntityDAO { //se precisar de métodos customizados, declarar aqui
}
public class HbnUsuarioDAO extends AlxHbnEntityDAO implements UsuarioDAO { //se precisar de métodos customizados, implementar aqui
}
Alessandro Lemser
Persistência
Componentes A interface e a classe de implementação do DAO.
public interface UsuarioDAO extends EntityDAO { }
public class HbnUsuarioDAO extends AlxHbnEntityDAO implements UsuarioDAO { }
Interface do framework que contém a declaração dos métodos implementados por ele.
Classe do framework que contém a implementação dos métodos implementados por ele.
Alessandro Lemser
Persistência
Componentes DAOFactory.
public class DAOFactory implements DAOServiceProvider { public static final String DAO_FILE_NAME = NameConventionUtil.getDAOFileName(DAOFactory.class, "dao.properties"); public Object getDAO(String daoname) { return ObjectFactory.getObject(daoname, DAO_FILE_NAME); } public UsuarioDAO getUsuarioDAO() { return (UsuarioDAO) getDAO(“UsuaioDAO"); }}
Alessandro Lemser
Persistência
Componentes dao.properties.
UsuarioDAO=br.com.softplan.curso.dao.hbn.HbnUsuarioDAOXyzDAO=br.com.softplan.curso.dao.hbn.HbnXyzDAO
#outros...
hibernate.mappings.
br/com/softplan/curso/dao/hbn/mapping/Usuario.hbm.xml
#outros...
Alessandro Lemser
Persistência
Componentes hibernate.properties.
hibernate.session_factory_name=br.com.softplan.cursodao/SessionFactoryhibernate.connection.datasource=java:/SIDERDShibernate.dialect=org.hibernate.dialect.OracleDialecthibernate.show_sql=truehibernate.use_outer_join=true
Alessandro Lemser
Lógica
Componentes Composta por Stateless SessionBeans.
Os Session Beans são gerados automaticamente, um para cada tabela do banco (granularidade fina).
As operações mais comuns (insert, update, delete, seleção por chave, seleção de todos (select *) e seleção com filtros) já está implementada.
Alessandro Lemser
LógicaArtefatos que são gerados
Componentesbr.com.softplan.curso.CursoServiceLocatorAbstrai do cliente a localização de serviços
como EJBs, DataSources etc...
br.com.softplan.curso.ejb.UsuarioEJBInterface remota
br.com.softplan.curso.ejb.UsuarioHomeInterface Home
br.com.softplan.curso.ejb.impl.UsuarioBeanBean de implementação
...e os arquivos XML necessários:META-INF/ejb-jar.xmlMETA-INF/jboss.xml
Alessandro Lemser
Lógica
Componentespublic interface UsuarioEJB extends EntityEJBObject {
}
public interface UsuarioHome extends EJBHome { UsuarioEJB create() throws CreateException, RemoteException;
}
public class UsuarioBean extends EntitySessionBean {
}
Alessandro Lemser
Lógica
Componentespublic interface UsuarioEJB extends EntityEJBObject {
}
public interface UsuarioHome extends EJBHome { UsuarioEJB create() throws CreateException, RemoteException;
}
public class UsuarioBean extends EntitySessionBean {
}
Interface do framework
Classe do framework
Alessandro Lemser
LógicaExemplo de uso
Componentespublic ActionForward execute(...) throws Exception {
UsuarioEJB usuarioEJB = CursoServiceLocator.getUsuarioEJB();
try {
} catch (Exception ex) { //trata exceção } finally { usuarioEJB.remove(); }
}
Alessandro Lemser
LógicaExemplo de uso
Componentespublic ActionForward execute(...) throws Exception {
UsuarioEJB usuarioEJB = CursoServiceLocator.getUsuarioEJB();
try { //todos os usuários List usuarios = usuarioEJB.findAll();
} catch (Exception ex) { //trata exceção } finally { usuarioEJB.remove(); }}
Alessandro Lemser
LógicaExemplo de uso
Componentespublic ActionForward execute(...) throws Exception {
UsuarioEJB usuarioEJB = CursoServiceLocator.getUsuarioEJB();
try {
//determinado usuário UsuarioPK usuarioPK = new UsuarioPK(); usuarioPK.setCdUsuario(‘TESTE’); Usuario usuario = usuarioEJB.findByPrimaryKey(usuarioPK);
} catch (Exception ex) { //trata exceção } finally { usuarioEJB.remove(); }}
Alessandro Lemser
LógicaExemplo de uso
Componentespublic ActionForward execute(...) throws Exception {
UsuarioEJB usuarioEJB = CursoServiceLocator.getUsuarioEJB();
try {
//filtrando... UsuarioForm usuarioForm = (UsuarioForm) form; Usuario usuario = (Usuario) usuarioForm.getEntity(); List usuarios = usuarioEJB.findAll( usuario );
} catch (Exception ex) { //trata exceção } finally { usuarioEJB.remove(); }}
Alessandro Lemser
Apresentação
Componentes A camada WEB consiste, atualmente, nos seguintes componentes:
a) Action do strutsb) Form do Strutsc) Filtros, Servlets e TAGLIBS d) Arquivos JSPe) Demais recursos estáticos (js, ccs, html, imagens, etc...)
O SPW estende o Struts na maioria de suas TAGs
Fornece um componente de Grid, derivado do <logic:iterate>
As Grids estão divididas em funcionalidades (grid, list, associative, e list pagination)
Existe um conjunto de estilos CSS e JavaScripts disponíveis para uso
Alessandro Lemser
ApresentaçãoArtefatos gerados
br.com.softplan.curso.struts.action.UsuarioFormFormulário para a entidade Usuario
br.com.softplan.curso.struts.action.UsuarioActionAction para interações com Usuario
Conjunto de TAGs
...e os mapeamentos no struts-config.xml
* O SPW também irá gerar um arquivo JSP. Os elementos que serão criados irão depender das escolhas no Wizard. Na maioria da vezes, o JSP gerado serve mais como um exemplo.
Componentes
Alessandro Lemser
ApresentaçãoArtefatos gerados
public class UsuarioForm extends SpjActionForm { protected Entity newEntity() { return new Usuario(); }
}
Componentes
Alessandro Lemser
ApresentaçãoArtefatos gerados
public class UsuarioForm extends SpjActionForm { protected Entity newEntity() { return new Usuario(); }
}
Componentes
Todo formulário do SPW estende SpjActionForm.
A superclasse contém dois atributos importantes:
private Entity entity;private List rows;
Entity representa a entidade (DTO) que está sendo visualizada/cadastrada e rows é uma lista desta mesma entidade (DTO).
Alessandro Lemser
ApresentaçãoArtefatos gerados
public class UsuarioForm extends SpjActionForm { protected Entity newEntity() { return new Usuario(); }
}
Componentes
Todo formulário deve sobrescrever este método e informar qual a “entidade” para este formulário.
Caso o formulário represente mais de uma entidade, deve-se criar novos atributos no UsuarioForm (neste caso) para atender a visualização.
Na página JSP para escrever o nome do usuário, por exemplo, faz-se:
<bean:write name=“usuarioForm” property=“entity.nmUsuario”/>
Alessandro Lemser
ApresentaçãoArtefatos gerados
Componentes O SPW especializa praticamente todas as TAGS do Struts adicionando mais funcionalidades.
Estas tags escrevem os dados já formatados
<spjhtml:writeDate name=“sujeito” property=“dtCadastro”/> <spjhtml:writeCNPJ name=“sujeito” property=“nuCpf”/>
...
Estas tags criam os campos de input com as devidas máscaras de formatação
<spjhtml:date name=“sujeito” property=“dtCadastro”/> <spjhtml:cpf name=“sujeito” property=“nuCpf”/>
Alessandro Lemser
As TAGs utilizadas pelo SPW são extensões das TAGs padrão do Struts.
O SPW adiciona às TAGs facilidades para formatações dos valores e validação dos mesmos.
Existem alguns atributos a mais que não existem no Struts, alguns deles são:
- rotulo e rotuloKey: quando ocorre erro de validação Javascript no campo, o rórulo indica o nome do campo.
- obrigatorio (true ou false): indica que um campo deve ser valido na submissão do formulário.
- formato: Os campos numéricos possuem este atributo para formatar os valores. Valores válidos são: formato=‘5.2’; formato=‘$5.2’; formato=‘4’.
Componentes
Alessandro Lemser
ApresentaçãoArtefatos gerados
Componentes Existe um conjunto de TAGs para montagem de Grid...
<spjgrid:grid id=“usr” name=“usuarioForm” property=“rows”>
<spjgrid:gridColumn title=“Nome”> <spjhtml:write name=“usr” property=“nmUsuario”/> </spjgrid:gridColumn>
</spjgrid:grid>
...as grid podem possuir outros tipos e formatos: <spjgrid:[grid, list, associative, listPaginada]>
Alessandro Lemser
JSP
JSP
SujeitoAction
MaterialAction MaterialEJB
SujeitolEJB SujeitoDAO
MaterialDAO
(Apresentação) (Lógica) (Persistência)
Componentes
Alessandro Lemser
Observações
- A Action localiza o EJB por meio do ServiceLocator, se o sistema for o ALX, o nome será AlxServiceLocator.
- O EJB localiza o DAO por meio do DAOFactory, se o sistema for o ALX, o nome será AlxDAOFactory.
Componentes
Segurança• As actions e as chamadas AJAX, através do framework DWR, devem ser
cadastradas na base de segurança, seguindo uma norma de nomenclatura.– Facilitar a identificação da ação e fornecimento de permissões pelo
analista de sistemas
• Actions não cadastradas, não ficam acessíveis
• As normas de segurança e nomenclatura estão definidas em um documento disponível através da intranet– http://intranet/assuntos/web/dt-pd-spw.2006.0001.doc
Alessandro Lemser
WizardSPW 3.4
Alessandro Lemser
Todas as classes e outros artefatos vistos anteriormente são previamente gerados através do Wizard do SPW.
Ele permite que, a partir de um conjunto de tabelas do banco de dados, gere-se todos os recursos necessários para desenvolver a aplicação.
O Wizard ainda não traz facilidades para manutenções (criar novas classes rearranjando a estrutura).
Wizard
Alessandro Lemser
Passo a passo
Wizard Execute o arquivo spwAppBuilder.jar (certifique-se que o diretório lib esteja junto dele).
Com o spwAppBuilder aberto, clique no menu Projeto>Novo
Na tela que aparece, deve-se preencher as informações essenciais para o projeto
Alessandro Lemser
WizardcdSistema: Código do sistema na esegSistema
ID: Identificação única para o projeto (ex: ALX)
Descrição: Breve descrição do sistema
Pacote: deve ir até o sistema.
Esquema: esquema do banco de dados
Banco: Qual banco de dados em uso - Manter o case: se for escolhido manter o case dos objetos, no oracle todas as classes serão criadas em caixa alta)!
- Manter o prefixo: Para a tabela esegUsuario, manter o prefixo significater uma classe com o nome SegUsuario.
Os dados de conexão são autoexplicativos...
Alessandro Lemser
Wizard Coloque parte do nome da tabela no campo de filtro e pressione o botão Consultar.
Selecione as tabelas necessárias para a aplicação em Tabelas diposníveis e mova as mesmas para Tabelas Selecionadas.
Escolha o tipo de tela que deseja gerar e pressione o botão Gerar.
Alessandro Lemser
Passo a passo
1. Gerar o modelo de dados.
2. Gerar a aplicação pelo wizard.
3. Descompactar o spw-blank.war no diretório "xxxWeb\WebRoot". NOTA: Não sobrescrever os arquivos quando o WinZip perguntar se é para fazer isto.
4. Copiar o CONTEÚDO do diretório "lib" da distribuição do framework SPW para diretório "xxxEAR".
5. Criar os projetos com o MyEclipse (observar os padrões descritos no documento DOC-PD-SPW-2003.0002-Estrutura da aplicação.pdf).
6. Configurar o build path dos projetos EJB e WEB.
7. No projeto Web, clicar com botão direito, selecionar o menu "MyEclipse" | "Add Struts Capabilities..." (desmarcar as opções de copiar JARs e TLDs)
8. Criar o datasource no JBOSS.
9. Ajustar o arquivo "ApplicationResources.properties".
Wizard
Alessandro Lemser
Configurando o DataSource:
Por default o SPW cria as informações do DataSource com base no ID do sistema. Se foi dado o ID de ALX, então o nome do DataSource no arquivo hibernate.properties vai ser ALXDS.
Wizard
Alessandro Lemser
Exercício Gerar com o Wizard a aplicação para o protótipo fornecido com
base nas seguintes tabelas:•
• ecurPedido• ecurUsuario• ecurPedidoitem• ecurMaterial
O banco de dados é Oracledriver: oracle.jdbc.driver.OracleDriverurl: jdbc:oracle:thin:@server23:1531:derbadesusuário: sidersenha: projeto1
Alessandro Lemser
GridsSPW 3.4
Alessandro Lemser
As grids no SPW são uma extensão da TAG <logic:iterate> do Struts.
Muitos atributos são comuns à TAG <logic:iterate> como: id, name, property, etc...
Existem 5 tipos de Grids. Todas elas descendem de um típo básico e são especializadas.
<spjgrid:list><spjgrid:grid><spjgrid:associative>
<spjgrid:search> <spjgrid:listPaginada>
Grids
Alessandro Lemser
Grid search
Grids
<spjhtml:text property="entity.sgOrgaosetor" style="width=100%"/>
<spjhtml:text property="entity.cdHierarquia" style="width=100%"/>
<spjhtml:text property="entity.nmOrgaosetor" style="width=100%"/>
<spjhtml:search id="os" searchURL="/orgaosetorSearch.jsp">
</spjhtml:search>
Alessandro Lemser
Grid search
Página que será aberta após clicar na lupa ao lado do campo...
Grids
Alessandro Lemser
Grids<spjhtml:search id="os" searchURL="/orgaosetorSearch.jsp">
</spjhtml:search>
Atributos:
Id: Identificação do ‘sender’ da grid
searchURL: Endereço da página ou ação do struts que contém a grid de pesquisa, no caso, de setores.
Obs: Use searchURL indicando uma página para que a grid apareça sem dados. Use searchURL indicando um Action, quando para que a grid venha populada.
Página orgaosetorSearch.jsp...
Alessandro Lemser
Grids
Alessandro Lemser
Grids<spjgrid:search id="row" name="orgaosetorForm" property="rows" srcType="DB" idFilterParams="entity" >
Atributos spjhtml:search:
- id, name e property: Atributos comuns à TAG logic:iterate.
- srcType: O valor DB está indicando que os valores para preenchimento da GRID serão trazidos do banco. Uma outra opção seria XML, porém, ainda precisa ser implementada, pois não está compatível com as atuais grids.
- idFilterParans: Útil para implementação dos campos que serão filtros na grid de pesquisa. Identifica o objeto associado no form.
Alessandro Lemser
Grids As colunas da grid são definidas pelo elemento <spjgrid:searchColumn>
<spjgrid:searchColumn titleKey="label.field.alx.Orgaosetor.sgOrgaosetor" reference="entity.sgOrgaosetor" width="60" styleClass="spwCelulaGrid"> <spjhtml:text name="row" property="sgOrgaosetor" styleClass="spwCampoTexto" style="width:100%"/> </spjgrid:searchColumn>
- titleKey: Nome da chave a ser pega no arquivo de recursos que definirá o título da coluna
- reference: Nome do campo de input a ser referenciado pelo coluna. Ao fazer uma seleção, o valor da coluna será definido no campo indicado por este atributo.
- width: Largura da coluna
- styleClass: Classe CSS para as células de uma coluna.
Alessandro Lemser
Grid search
Grids
Alessandro Lemser
GridsGrid search
Alessandro Lemser
Grid associative
Grids A grid associative é semelhante a grid vista anteriormente, mas só é possível adicionar novas linhas na própria grid, através de outra grid de consulta.
Alessandro Lemser
Grid associative
Grids <spjgrid:associative id="row"
name="pedidoitemForm" property="rows" indexed="true" searchURL="/materialSearch.jsp">
<spjgrid:gridColumn titleKey="label.field.alx.Pedidoitem.cdMaterial"
width="120">
<spjhtml:text property="cdMaterial" name="row" styleClass="spwCampoTextoGrid" size="60" formato="50" obrigatorio="TRUE" readonly="true" rotuloKey="label.field.alx.Pedidoitem.cdMaterial"/>
</spjgrid:gridColumn>
<!-- Demais colunas da grid -- >
</spjgrid:associative>
Alessandro Lemser
Grid associative
Grids <spjhtml:form action="/saveGridPedidoitem">
<spjgrid:associative id="row" name="pedidoitemForm" property="rows" indexed="true" searchURL="/materialSearch.jsp">
Os atributos são semelhantes à grid anterior, sendo necessário na associative, indicar o valor do atributos searchURL, que indica qual página que contém a grid de pesquisa para a grid associative.
Alessandro Lemser
Grid associative
Grids <spjgrid:gridColumn titleKey="label.field.alx.Pedidoitem.cdMaterial"
width="120">
<spjhtml:text property="cdMaterial" name="row" styleClass="spwCampoTextoGrid" size="60" formato="50" obrigatorio="TRUE" readonly="true" rotuloKey="label.field.alx.Pedidoitem.cdMaterial"/>
</spjgrid:gridColumn>
As colunas da grid associative não diferem das já vistas até agora
Alessandro Lemser
Ação que salva os dados da grid (serve também para o exemplo da grid normal)
Grid associative
Grids
Alessandro Lemser
Grid que permite realizar alterações nos objetos na própria grid.
Grid grid
Grids
Alessandro Lemser
Grid grid
Grids
<spjhtml:form action="saveGridTipoexpediente.do">
<spjgrid:grid id="row" name="tipoexpedienteForm" property="rows"
indexed="true">
Atributos adicionais:
indexed: Indica que a grid é indexada para trabalhar com Lists. Existem também o atributo mapped, que é utilizado para se trabalhar com Maps.
allowInsert: Definindo este atributo como false irá fazer com que a o botão inserir da grid desapareça.
postAllRows: O comportamento padrão da grid é enviar para o servidor somente as linhas alteradas (adicionadas, excluídas ou atualizadas). Para fazer com que o grid envie todas as linhas para o servidor, é necessário definir postAllRows como true.
Alessandro Lemser
Grid grid
Grids
Alessandro Lemser
Colunas das grids
<spjgrid:gridColumn titleKey="label.field.alx.Tipoexpediente.tipoexpedientePK.cdTipoexpediente" width="60">
<spjhtml:number property="tipoexpedientePK.cdTipoexpediente"
name="row" styleClass="spwCampoTextoGrid alignRight" size="13" formato="3" obrigatorio="TRUE" rotuloKey="label.field.alx.Tipoexpediente.tipoexpedientePK.cdTipoexpediente"/>
</spjgrid:gridColumn>
Os atributos são idênticos aos da searchColumn
Grid grid
Grids
Alessandro Lemser
Colunas de ação das grids
<spjgrid:actionColumn action="DEL"/>
Este tipo de coluna pode ter duas ações: DEL ou EDIT- DEL: marca a linha para exclusão- EDIT: irá encaminhar o request para a página de edição dos dados
É possível anular a ação padrão e indicar outra para ser realizada, basta colocar o atributo cancelAction=‘true’ e definir o atributo link para a ação ou página de edição ou exclusão dos dados.
Grid grid
Grids
Alessandro Lemser
O tipo de grid mais simples. Não passa de uma tabela onde os dados são somente listados.
É como utilizar a <logic:iterate/> sem precisar escrever o HTML adicional para montar uma tabela. É utilizada a tabela padrão do SPW.
A grid permite apenas que registros sejam excluídos da tabela.
Existe uma versão mais aprimorada que permite paginação
Grid list
Grids
Alessandro Lemser
Grid list
Grids
Alessandro Lemser
public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
PedidoForm pedidoForm = (PedidoForm) form;PedidoEJB pedidoEJB = AlxServiceLocator.getPedidoEJB();try {
if( mapping.getPath().equals("/listarPedidos") ) { PedidoPK pedidoPK = new PedidoPK(); pedidoPK.setNuAnopedido(new Integer(2004)); petPedidoPK.setCdTppedido(new Integer(1)); pedidoForm.setRows( pedidoEJB.findAll(pedidoPK) ); return mapping.findForward("listar");}
} catch (Exception e) {e.printStackTrace();pedidoEJB.remove();
} return null;}
Conteúdo da Action para montar a lista de pedidosGrid list
Grids
Alessandro Lemser
GridsGrid paginada
A grid paginada requer uma configuração extra, a qual as demais grid não possuem.
A primeira consulta para apresentar a grid e as demais consultas subseqüentes, devem ser originadas no mesmo form que a grid está inserida.
Deve-se ter a declaração do AjaxServlet no arquivo web.xml. Atualmente, devido a essa configuração, é necessário colocar um arquivo chamado input-select.xml dentro do diretório WEB-INF (este arquivo não se refere a grid paginada).
Configurar a action para pesquisar com paginação...
Alessandro Lemser
GridsGrid paginada
if (mapping.getPath().equalsIgnoreCase("/consultarPedido")) { Pedido pedido = (Pedido) pedidoForm.getEntity(); List list = pedidoEJB.findObjectPagination( pedido, 0, 5, "pedidoPK.cdPedido");
pedidoForm.setRows( list ); AjaxServlet.saveFilterPaginationInSession( request, "pedidoGrid", pedido ); return mapping.findForward("gridPedido"); }
Alessandro Lemser
GridsGrid paginada
if (mapping.getPath().equalsIgnoreCase("/gridPedido")) { Pedido pedido = new Pedido(); List list = pedidoEJB.findObjectPagination( pedido, 0, 5, "pedidoPK.cdPedido");
pedidoForm.setRows( list ); AjaxServlet.saveFilterPaginationInSession( request, "pedidoGrid", pedido ); return mapping.findForward("gridPedido"); }
Método que faz pesquisa com paginação.Parâmetros:
pedido: Objeto a ser utilizado como filtro0: posição inicial5: quantidade de registros a serem retornados“pedidoPK.cdPedido”: Order by...
Alessandro Lemser
GridsGrid paginada
if (mapping.getPath().equalsIgnoreCase("/gridPedido")) { Pedido pedido = new Pedido(); List list = pedidoEJB.findObjectPagination( pedido, 0, 5, "pedidoPK.cdPedido");
pedidoForm.setRows( list ); AjaxServlet.saveFilterPaginationInSession( request, "pedidoGrid", pedido ); return mapping.findForward("gridPedido"); }
Guarda na sessão o objeto utilizado como filtro para a pesquisa, para realizar as consultas subsequentes.
Parâmetros:request: A requisição em questão“pedidoGrid”: Identificador único da gridpedido: Entity de filtro
Alessandro Lemser
GridsGrid paginada
Na página, a grid também apresenta novos atributos...
<spjgrid:listPaginada id="row" name="pedidoForm" property="rows" beanClass="br.com.softplan.curso.alx.Pedido" referenceName="pedidoGrid“ pageSize=“5”>
beanClass: classe que representa os elementos da grid.
referenceName: Nome que identifica unicamente a grid (é usado na Action!!!)
pageSize: Quantidade de registros máximo que aparecerão na grid.
Alessandro Lemser
GridsGrid paginada
É possível intervir entre o clique do usuário e a consulta de paginação.
Classes que implementam a interface ObjectPaginationHandler são notificadas de consultas de paginação.
Caso seja necessário utilizá-lo, leia a RAV da última versão e veja como proceder. Este assunto não será abordado neste curso...
Alessandro Lemser
InputSelectSPW 3.4
Alessandro Lemser
InputSelectInputSelect
Tag que proporciona “auto-complete” em campos de texto, usando AJAX.
Necessitam de um arquivo XML que liga o bean (Entity) e os campos do HTML.
Se tornaram indispensáveis, pois os clientes da Empresa já estas acostumados com tal funcionalidade.
*Não é preciso criar uma Action ou codificar qualquer coisa além do arquivo XML e a declaração das TAGs na página JSP.
* Em alguns casos é necessário intervir no processo e o mecanismo de funcionamento da TAG pode ser estendido.
Alessandro Lemser
InputSelect :: O Arquivo XML
<?xml version="1.0" encoding="UTF-8"?><inputs-select> <input-select id="usuario"> <entity>br.com.softplan.curso.alx.Usuario</entity> <bindings> <binding property="usuarioPK.cdUsuario" reference="usuarioPK.cdUsuario"/> <binding property="nmUsuario" reference="nmUsuario"/> </bindings> </input-select> </inputs-select>
InputSelect
Alessandro Lemser
InputSelect :: O Arquivo XML
<?xml version="1.0" encoding="UTF-8"?><inputs-select> <input-select id="usuario"> <entity>br.com.softplan.curso.alx.Usuario</entity> <bindings> <binding property="usuarioPK.cdUsuario" reference="usuarioPK.cdUsuario"/> <binding property="nmUsuario" reference="nmUsuario"/> </bindings> </input-select> </inputs-select>
Podem existir vários elementos deste dentro do arquivo.
O atributo id deve identificar unicamente uma TAG de input-select.
InputSelect
Alessandro Lemser
InputSelect :: O Arquivo XML
<?xml version="1.0" encoding="UTF-8"?><inputs-select> <input-select id="usuario"> <entity>br.com.softplan.curso.alx.Usuario</entity> <bindings> <binding property="usuarioPK.cdUsuario" reference="usuarioPK.cdUsuario"/> <binding property="nmUsuario" reference="nmUsuario"/> </bindings> </input-select> </inputs-select>
Indica qual a entidade (classe) que está relacionada com a pesquisa que será realizada.
InputSelect
Alessandro Lemser
InputSelect :: O Arquivo XML
<?xml version="1.0" encoding="UTF-8"?><inputs-select> <input-select id="usuario"> <entity>br.com.softplan.curso.alx.Usuario</entity> <bindings> <binding property="usuarioPK.cdUsuario" reference="usuarioPK.cdUsuario"/> <binding property="nmUsuario" reference="nmUsuario"/> </bindings> </input-select> </inputs-select>
É dentro deste elemento que iremos relacionar as propriedades da entidade (classe) com os campos do HTML.
InputSelect
Alessandro Lemser
InputSelect :: O Arquivo XML
<?xml version="1.0" encoding="UTF-8"?><inputs-select> <input-select id="usuario"> <entity>br.com.softplan.curso.alx.Usuario</entity> <bindings> <binding property="usuarioPK.cdUsuario" reference="usuarioPK.cdUsuario"/> <binding property="nmUsuario" reference="nmUsuario"/> </bindings> </input-select> </inputs-select>
Relaciona uma propriedade da classe com o campo correspondente na página HTML.
InputSelect
Alessandro Lemser
InputSelect :: A TAG
<spjhtml:inputSelect inputSelectId="usuario“ id="usuario“
searchUrl=“searchUsuario.jsp”>
<spjhtml:inputSelectNumber property="entity.usuarioPK.cdUsuario" formato="3“/>
<spjhtml:inputSelectText property="entity.nmUsuario"/>
</spjhtml:inputSelect>
InputSelect
Alessandro Lemser
InputSelect :: A TAG
<spjhtml:inputSelect inputSelectId="usuario“ id="usuario“
searchUrl=“searchUsuario.jsp”>
<spjhtml:inputSelectNumber property="entity.usuarioPK.cdUsuario" formato="3“/>
<spjhtml:inputSelectText property="entity.nmUsuario"/>
</spjhtml:inputSelect>
É necessário relacionar a TAG com as declarações do arquivo XML com o atributo inputSelectId.
InputSelect
Alessandro Lemser
InputSelect :: A TAG
<spjhtml:inputSelect inputSelectId="usuario“ id="usuario“
searchUrl=“searchUsuario.jsp”>
<spjhtml:inputSelectNumber property="entity.usuarioPK.cdUsuario" formato="3“/>
<spjhtml:inputSelectText property="entity.nmUsuario"/>
</spjhtml:inputSelect>Os campos que vão internos à TAG são particulares a ela (inputSelectNumber, inputSelectText, etc...).
InputSelect
Alessandro Lemser
InputSelect
Existem outras configurações que podem ser feitas no arquivo XML.
Por default a TAG chama o método findAll do EJB, porém, pode-se no arquivo XML indicar outro método ou até outro EJB.
Existe também o InputSelectHandler, que podem ser codificados para customizar o processo de consulta do InputSelect.
InputSelect
Alessandro Lemser
Exercício
Fazer o refactoring da aplicação desenvolvida até agora, par utilizar grids e o InputSelect:
Alessandro Lemser
SPW...concluindo
O SPW leva o uso de EJBs e Struts a um patamar mais alto. Tornando ainda mais fácil e produtivo o desenvolvimento de aplicações comerciais com as estas tecnologias.
É importante lembrar que existem padrões de projeto que podem trazer benefícios para a aplicação. Alguns deles trazem benefícios para melhor compreensão e delimitação de escopo outros melhoram performance, outros facilitam a migração para novas tecnologias... Enfim, é um assunto que vale a pena aprimorar os conhecimentos
Alessandro Lemser
SPW...pendências para este ppt
1. Adicionar tópico sobre controle de reenvio de formulários.2. Melhorar exemplos com grid.3. Melhorar exemplos com InputSelect (pai e filho)