Negócio – DAOs
Utilizarei um DAO genérico para operações de CRUD e criarei um DAO para classe Dog e outro para User. Ficará bem claro o modo como serão utilizadas:
package com.dao;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;
public abstract class GenericDAO<T> {
private final static String UNIT_NAME = "CrudPU";
@PersistenceContext(unitName = UNIT_NAME)
private EntityManager em;
private Class<T> entityClass;
public GenericDAO(Class<T> entityClass) {
this.entityClass = entityClass;
}
public void save(T entity) {
em.persist(entity);
}
protected void delete(Object id, Class<T> classe) {
T entityToBeRemoved = em.getReference(classe, id);
em.remove(entityToBeRemoved);
}
public T update(T entity) {
return em.merge(entity);
}
public T find(int entityID) {
return em.find(entityClass, entityID);
}
// Using the unchecked because JPA does not have a
// em.getCriteriaBuilder().createQuery()<T> method
@SuppressWarnings({ "unchecked", "rawtypes" })
public List<T> findAll() {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return em.createQuery(cq).getResultList();
}
// Using the unchecked because JPA does not have a
// ery.getSingleResult()<T> method
@SuppressWarnings("unchecked")
protected T findOneResult(String namedQuery, Map<String, Object> parameters) {
T result = null;
try {
Query query = em.createNamedQuery(namedQuery);
// Method that will populate parameters if they are passed not null and empty
if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}
result = (T) query.getSingleResult();
} catch (Exception e) {
System.out.println("Error while running query: " + e.getMessage());
e.printStackTrace();
}
return result;
}
private void populateQueryParameters(Query query, Map<String, Object> parameters) {
for (Entry<String, Object> entry : parameters.entrySet()) {
query.setParameter(entry.getKey(), entry.getValue());
}
}
}
package com.dao;
import javax.ejb.Stateless;
import com.model.Dog;
@Stateless
public class DogDAO extends GenericDAO<Dog> {
public DogDAO() {
super(Dog.class);
}
public void delete(Dog dog) {
super.delete(dog.getId(), Dog.class);
}
}
package com.dao;
import java.util.HashMap;
import java.util.Map;
import javax.ejb.Stateless;
import com.model.User;
@Stateless
public class UserDAO extends GenericDAO<User> {
public UserDAO() {
super(User.class);
}
public User findUserByEmail(String email){
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("email", email);
return super.findOneResult(User.FIND_BY_EMAIL, parameters);
}
}
Observações sobre o código acima:
- Eu optei por esconder alguns “warnings” uma vez que alguns códigos do JPA não fornecem suporte a Generics.
- Deixei o método “findOneResult” como protected para que ele não seja acessado externamente, pois é necessária uma lógica de preenchimento dos parâmetros e esses parâmetros eu deixo a cargo do UserDAO de preencher.
- O GenericDAO tem um CRUD completo e ainda um método que retorna apenas um único objeto de uma NamedQuery.
- Repare que a classe UserDAO tem um método específico dela (findUserByEmail), mas herda o CRUD da classe genérica, com isso podemos ter uma maior flexibilidade em nossos DAOs.
- Já a classe DogDAO não tem nenhum método específico, mas caso você queira, você poderia implementar sem problema algum os métodos da classe DogDAO.
- Você poderia utilizar ao invés de um método para Salvar e outro para Editar, apenas um realizando o “entityManager.merge()”. Terá o mesmo resultado, mas fique atento ao Cascade do seu relacionamento.
- Não utilizei interfaces nas classes pois o EJB 3.1 permite que uma classe seja injetada localmente sem precisar de interface. Caso você use um EJB mais antigo, você irá precisar implementar a interface (como será feito nos Façades que iremos ver mais a frente). Não irei programar o meu modelo/DAO para interface, apenas para poupar espaço. Lembre de sempre programar para interface (Design Pattern – Strategy).
- Caso você esteja utilizando JBoss 4.2 anotação do JBoss chamada org.jboss.annotation.ejb.LocalBinding ou org.jboss.annotation.ejb.RemoteBinding e indicar qual o nome a ser mapeado e que será utilizado na view para ser localizado.


Olá Hebert, como ficaria esse protected T findOneResult(String namedQuery, Map parameters)
e public User findUserByEmail(String email)
sendo que em Hibernate, já rodei aqui para tentar implementar utilizando a mesma ideologia que vc usou mais até agora nao obtive sucesso.
Marcos, boa tarde.
Do modo como se encontra no projeto ele está funcionando.
Caso você tenha alguma exception após realizar alguma alteração poste o código no guj que ficará mais fácil de ajudar.
Obrigado pela visita.
Pingback: 1389 Ideias para aplicativos Android – GUJ | S60Aplicativos
Hebert, boa tarde.
Parabéns pelo post.
Só uma dúvida. A estrutura que você propõe pode gerar um inconveniente na aplicação. Se você atualizar a página gerará um “re-post” no seu CRUD. Já pensou em implementar o padrão POST-Redirect-GET para resolver o problema?
Roger, boa noite.
Esse patern é bom de ser utilizado, não o coloquei no post para não adicionar mais complexidade para quem está começando agora. [=
Obrigado pela visita e pelo apoio.
Cara parei na parte “adicione o EJB no JBoss”, adicionei, criei o crudDB no Postgres, executei o JBoss e nada, nenhuma tabela foi criada.
Sou iniciante, segui todos os passos certinho até aqui, mas não deu certo.
Eu uso Linux, Eclipse Indigo, JBoss 7 e Postgres 9.1.18
Você criou o módulo do postgres? E também configurou o standalone.xml?
Até mais.
Hebert, boa tarde.
Estou recebendo o seguinte erro quando autenticado pelo servidor:
HTTP Status 408 – The time allowed for the login process has been exceeded. If you wish to continue you must either click back twice and re-click the link you requested or close and re-open your browser.
Já procurei algumas soluções e nada de me ajudarem. Teria alguma solução mais explicita para aumentar o tempo de sessão para o Login? (acho que é esse o problema).
Obrigado!
Marcos, boa noite.
Nunca tomei esse erro.
Baixe o projeto aqui do post e tente executá-lo.
Obrigado pela visita.
Só pra complementar na linha 58 do código:
Query query = em.createNamedQuery(namedQuery);
// Method that will populate parameters if they are passed not null and empty
if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}
result = (T) query.getSingleResult();
Existe sim um método tipado,
TypedQuery javax.persistence.EntityManager.createNamedQuery(String arg0, Class arg1)
Diogo, boa tarde.
Na época que criei esse post eu conhecia apenas o JPA 1.0 e não havia o método tipado.
O TypedQuery veio com o JPA 2.0 que vim aprender algum tempo depois.
Obrigado pela visita. [=
Hebert, mais uma dúvida:
No seu exemplo, listalldogs.xhml já estava no diretório protected, logo ao tentar acessar esta página o JAAS chama a página de login, que após validado já redireciona para a página desejada (listalldogs.xhtml). Porém, como faço, sendo a página de login a primeira por exemplo, para após o login, redirecionar para uma outra página qualquer?
Bruno, bom dia.
Olhe no arquivo de web.xml tem o welcome-page que indica qual a página de login.
Quando o usuário acessar http://localhost:8080/suaAplicacao após login ele será direcionado para a página demarcada lá.
Caso você queira um controle mais refinado, como caso ADM envie para página A se for usuário para a página B, você teria que criar um módulo de JAAS.
Até mais.