Aplicação Web Completa JSF EJB JPA JAAS

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.

241 Thoughts on “Aplicação Web Completa JSF EJB JPA JAAS

  1. Marcos Filho on April 26, 2013 at 6:38 pm said:

    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.

    • uaihebert on April 29, 2013 at 7:35 pm said:

      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.

  2. Pingback: 1389 Ideias para aplicativos Android – GUJ | S60Aplicativos

  3. Roger on April 15, 2013 at 1:25 pm said:

    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?

    • uaihebert on April 20, 2013 at 8:21 pm said:

      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.

  4. 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

  5. Marcos Fontana on March 18, 2013 at 4:41 pm said:

    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!

    • uaihebert on April 4, 2013 at 8:17 pm said:

      Marcos, boa noite.

      Nunca tomei esse erro.

      Baixe o projeto aqui do post e tente executá-lo.

      Obrigado pela visita.

  6. 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)

    • uaihebert on April 4, 2013 at 8:15 pm said:

      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. [=

  7. Bruno on March 4, 2013 at 10:02 am said:

    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?

    • uaihebert on March 4, 2013 at 12:37 pm said:

      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.

Comment navigation

 

Leave a Reply

Post Navigation