Criando uma aplicação EJB + JPA

Vamos desenvolver uma aplicação utilizando EJB + JPA, o projeto em questão possui um cadastro de livro, um cadastro de pessoa e podemos emprestar livros para as pessoas.

Tendo este escopo vamos criar um Projeto EJB no NetBeans:

Criando o Projeto EJB

Na área Projetos, clique com o botão direito do mouse, e em seguida clique em Novo projeto....

Na tela Novo projeto, selecione na aba Categorias a opção Java EE, na aba Projetos a opção Módulo EJB e clique em Próximo.

Na tela de Novo Módulo EJB, vamos definir os seguintes campos:

  • Nome do projeto: EmprestimoEJB
  • Localização do projeto: (Escolha o local para salvar o projeto no micro)

Clique em Próximo.

Na tela de Novo Módulo EJB, vamos definir os seguintes campos:

  • Servidor: GlassFish Server 3.1
  • Versão do Java EE: JavaEE 6

Clique em Finalizar.

Desta forma criamos um Projeto EJB chamado EmprestimoEJB que será publicado dentro do servidor de aplicação web GlassFish.

Criando as classes de negócio

Com base no escopo do projeto teremos inicialmente três classes Livro, Pessoa e Emprestimo.

A figura a seguir apresenta o diagrama de classes de negócio do projeto.

Diagrama de classes

Com base no diagrama de classes, vamos criar essas classes dentro do nosso projeto EmprestimoEJB:

Clique com o botão direito do mouse sobre Pacotes de código fonte, depois selecione a opção Novo, depois selecione Classe Java....

Na tela de Novo Classe Java, vamos definir os seguintes valores:

  • Nome da classe: Livro
  • Pacote: pbc.emprestimo.modelo (utilizamos o pacote para separar os arquivos Java dentro da aplicação).

Clique em Finalizar.

Repita este mesmo processo para as classes Pessoa e Emprestimo.

Seguindo o modelo UML, vamos adicionar nas classes os atributos, métodos get / set e anotações referentes ao JPA, depois nossas classes ficaram da seguinte forma:

Classe Livro:

package pbc.emprestimo.modelo;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * Classe utilizada para representar um Livro.
 */
@Entity
@SequenceGenerator(name="LIVRO_SEQ", sequenceName="LIVRO_SEQ",
  initialValue=1, allocationSize=1)
public class Livro implements Serializable {
  /* Serial Version UID. */
  private static final long serialVersionUID =
    6775900088322385451L;

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE,
    generator = "LIVRO_SEQ")
  private Long id;
  private String titulo;
  private String autor;
  private boolean emprestado;

  public Livro() {
    this.emprestado = false;
  }

  public String getAutor() { return autor; }
  public void setAutor(String autor) { this.autor = autor; }

  public boolean isEmprestado() { return emprestado; }
  public void setEmprestado(boolean emprestado) {
    this.emprestado = emprestado;
  }

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

  public String getTitulo() { return titulo; }
  public void setTitulo(String titulo) {
    this.titulo = titulo;
  }
}

Classe Pessoa:

package pbc.emprestimo.modelo;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * Classe utilizada para representar uma Pessoa.
 */
@Entity
@SequenceGenerator(name="PESSOA_SEQ", sequenceName="PESSOA_SEQ", 
  initialValue = 1, allocationSize = 1)
public class Pessoa implements Serializable {
  /* Serial Version UID */
  private static final long serialVersionUID =
    5486103235574819424L;

  @Id
  @GeneratedValue(strategy=GenerationType.SEQUENCE, 
    generator="PESSOA_SEQ")
  private Long id;
  private String nome;

  public Pessoa() { }

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

  public String getNome() { return nome; }
  public void setNome(String nome) { this.nome = nome; }
}

Classe Emprestimo:

package pbc.emprestimo.modelo;

import java.io.Serializable;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;

/**
 * Classe utilizada para representar o Emprestimo 
 * de um Livro feito por uma Pessoa.
 */
@Entity
@SequenceGenerator(name = "EMPRESTIMO_SEQ", sequenceName =
  "EMPRESTIMO_SEQ", initialValue = 1, allocationSize = 1)
public class Emprestimo implements Serializable {
  /* Serial Version UID */
  private static final long serialVersionUID =
    4621324705834774752L;

  @Id
  @GeneratedValue(strategy=GenerationType.SEQUENCE,
    generator="EMPRESTIMO_SEQ")
  private Long id;
  @ManyToOne
  private Livro livro;
  @ManyToOne
  private Pessoa pessoa;    
  @Temporal(javax.persistence.TemporalType.DATE)
  private Date dataEmprestimo;
  @Temporal(javax.persistence.TemporalType.DATE)
  private Date dataDevolucao;

  public Emprestimo() { }

  public Date getDataDevolucao() { return dataDevolucao; }
  public void setDataDevolucao(Date dataDevolucao) {
    this.dataDevolucao = dataDevolucao;
  }

  public Date getDataEmprestimo() { return dataEmprestimo; }
  public void setDataEmprestimo(Date dataEmprestimo) {
    this.dataEmprestimo = dataEmprestimo;
  }

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

  public Livro getLivro() { return livro; }
  public void setLivro(Livro livro) { this.livro = livro; }

  public Pessoa getPessoa() { return pessoa; }
  public void setPessoa(Pessoa pessoa) {
    this.pessoa = pessoa;
  }
}

Classes DAO

Vamos criar a camada de persistência dos dados, para isso criaremos as classes DAO, que utilizam o EntityManager para executar as operações no Banco de Dados. Estas classes devem ser criadas no pacote pbc.emprestimo.dao.

Classe EmprestimoDAO:

package pbc.emprestimo.dao;

import javax.persistence.EntityManager;
import pbc.emprestimo.modelo.Emprestimo;

/**
 * Classe utilizada para realizar as operações com
 * o bando de dados.
 */
public class EmprestimoDAO {
  private EntityManager entityManager;

  /**
   * Construtor da classe DAO que chama os métodos do
   * EntityManager.
   * @param entityManager
   */
  public EmprestimoDAO(EntityManager entityManager) {
    this.entityManager = entityManager;
  }

  /**
   * Método para salvar ou atualizar o empréstimo.
   * @param emprestimo
   * @return
   * @throws java.lang.Exception
   */
  public Emprestimo salvar(Emprestimo emprestimo) 
    throws Exception {
    System.out.println("Emprestando o livro " + 
      emprestimo.getLivro().getTitulo() +
      " para a pessoa " + emprestimo.getPessoa().getNome());

    /* Verifica se o emprestimo ainda não está salvo no 
      banco de dados. */
    if(emprestimo.getId() == null) {
      /* Salva o emprestimo no banco de dados. */
      this.entityManager.persist(emprestimo);
    } else {
      /* Verifica se o emprestimo não está no estado managed. */
      if(!this.entityManager.contains(emprestimo)) {
        /* Se o emprestimo não está no estado managed 
          verifica se ele existe na base. */
        if (consultarPorId(emprestimo.getId()) == null) {
          throw new Exception("Livro não existe!");
        }
      }
      /* Faz uma atualização do empréstimo. */
      return entityManager.merge(emprestimo);
    }

    /* Retorna o empréstimo que foi salvo, este retorno ocorre
      para modemos ter o id que foi salvo. */
    return emprestimo;
  }

  /**
   * Método que exclui o Emprestimo do banco de dados.
   * @param id
   */
  public void excluir(Long id) {
    /* Consulta o emprestimo na base de dados através de
      seu ID. */
    Emprestimo emprestimo = consultarPorId(id);
    System.out.println("Excluindo o emprestimo: " +
      emprestimo.getId());

    /* Remove o emprestimo da base de dados. */
    entityManager.remove(emprestimo);
  }

  /**
   * Método que consulta um Emprestimo através do Id.
   * @param id
   * @return
   */
  public Emprestimo consultarPorId(Long id) {
    return entityManager.find(Emprestimo.class, id);
  }
}

Note que agora não precisamos mais criar a EntityManager manualmente, podemos deixar para quem for utilizar o DAO (no nosso caso o EJB) passar uma referencia para o EntityManager.

Os métodos do DAO que fazem manipulação no banco de dados agora não precisam mais iniciar e finalizar uma transação, pois como serão chamados a partir de um EJB, os métodos do EJB que chamam os métodos do DAO já possuem transação por padrão.

Classe LivroDAO:

package pbc.emprestimo.dao;

import javax.persistence.EntityManager;
import pbc.emprestimo.modelo.Livro;

/**
 * Classe utilizada para realizar as operações com o
 * bando de dados.
 */
public class LivroDAO {
  private EntityManager entityManager;

  /**
   * Construtor da classe DAO que chama os métodos
   * do EntityManager.
   * @param entityManager
   */
  public LivroDAO(EntityManager entityManager) {
    this.entityManager = entityManager;
  }

  /**
   * Método para salvar ou atualizar o livro.
   * @param livro
   * @return
   * @throws java.lang.Exception
   */
  public Livro salvar(Livro livro) throws Exception{
    System.out.println("Salvando o livro: " 
      + livro.getTitulo());

    /* Verifica se o livro ainda não está salvo no banco
      de dados. */
    if(livro.getId() == null) {
      /* Salva o livro no banco de dados. */
      this.entityManager.persist(livro);
    } else {
      /* Verifica se o livro não está no estado managed. */
      if(!this.entityManager.contains(livro)) {
        /* Se o livro não está no estado managed verifica se 
          ele existe na base. */
        if (entityManager.find(Livro.class, livro.getId())
          == null) {
          throw new Exception("Livro não existe!");
        }
      }
      /* Faz uma atualização do livro que estava gravado na base
        de dados. */
      return entityManager.merge(livro);
    }

    /* Retorna o livro que foi salvo, este retorno ocorre para
      podermos ter o id que foi salvo. */
    return livro;
  }

  /**
   * Método que exclui o livro do banco de dados.
   * 
   * @param id
   */
  public void excluir(Long id) {
    /* Consulta o livro na base de dados através 
      de seu ID. */
    Livro livro = entityManager.find(Livro.class, id);
    System.out.println("Excluindo o livro: " 
      + livro.getTitulo());

    /* Remove o livro da base de dados. */
    entityManager.remove(livro);
  }

  /**
   * Método que consulta o livro pelo ID.
   * 
   * @param id
   * @return
   */
  public Livro consultarPorId(Long id) {
    return entityManager.find(Livro.class, id);
  }
}

Classe PessoaDAO:

package pbc.emprestimo.dao;

import javax.persistence.EntityManager;
import pbc.emprestimo.modelo.Pessoa;

/**
 * Classe utilizada para realizar as operações com o
 * bando de dados.
 */
public class PessoaDAO {
  private EntityManager entityManager;

  /**
   * Construtor da classe DAO que chama os métodos do
   * EntityManager.
   * @param entityManager
   */
  public PessoaDAO(EntityManager entityManager) {
    this.entityManager = entityManager;
  }

  /**
   * Método para salvar ou atualizar a pessoa.
   * @param pessoa
   * @return
   * @throws java.lang.Exception
   */
  public Pessoa salvar(Pessoa pessoa) throws Exception{
    System.out.println("Salvando o pessoa: "
      + pessoa.getNome());

    /* Verifica se a pessoa ainda não está salva no 
      banco de dados. */
    if(pessoa.getId() == null) {
      /* Salva a pessoa no banco de dados. */
      this.entityManager.persist(pessoa);
    } else {
      /* Verifica se a pessoa não está no estado managed. */
      if(!this.entityManager.contains(pessoa)) {
        /* Se a pessoa não está no estado managed verifica 
          se ele existe na base. */
        if (entityManager.find(Pessoa.class, pessoa.getId())
          == null) {
          throw new Exception("Livro não existe!");
        }
      }
      /* Faz uma atualização da pessoa que estava gravado na 
        base de dados. */
      return entityManager.merge(pessoa);
    }

    /* Retorna a pessoa que foi salva, este retorno ocorre para
      podermos ter o id que foi salvo. */
    return pessoa;
  }

  /**
   * Método que exclui a pessoa do banco de dados.
   * @param id
   */
  public void excluir(Long id) {
    /* Consulta a pessoa na base de dados através de seu ID. */
    Pessoa pessoa = entityManager.find(Pessoa.class, id);
    System.out.println("Excluindo a pessoa: " + pessoa.getNome());

    /* Remove a pessoa da base de dados. */
    entityManager.remove(pessoa);
  }

  /**
   * Consulta a pessoa por ID.
   * @param id
   * @return
   */
  public Pessoa consultarPorId(Long id) {
    return entityManager.find(Pessoa.class, id);
  }
}

Componentes EJB

Vamos criar os componentes EJB que possuem a lógica de negócio. Lembrando que cada EJB é formado por uma interface e uma classe.

Crie uma interface chamada EmprestimoRemote e uma classe chamada EmprestimoBean no pacote pbc.emprestimo.ejb.

Interface EmprestimoRemote:

package pbc.emprestimo.ejb;

import javax.ejb.Remote;
import pbc.emprestimo.modelo.Emprestimo;

/**
 * Interface que possui os métodos que o EJB de Emprestimo
 * precisa implementar.
 */
@Remote
public interface EmprestimoRemote {
  public Emprestimo salvar(Emprestimo emprestimo)
    throws Exception;

  public void excluir(Long id);

  public Emprestimo consultarPorId(Long id);
}

Estamos declarando uma interface chamada EmprestimoRemote e adicionamos a anotação @Remote que irá informar que este componente EJB pode ser acessado remotamente ou forá do seu container.

Na interface nós declaramos todos os métodos que o componente EJB poderá disponibilizar.

Classe EmprestimoBean:

package pbc.emprestimo.ejb;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import pbc.emprestimo.dao.EmprestimoDAO;
import pbc.emprestimo.modelo.Emprestimo;

/**
 * EJB de Emprestimo com a lógica de negocio.
 */
@Stateless
public class EmprestimoBean implements EmprestimoRemote {
  @PersistenceContext(unitName = "EmprestimoPU")
  private EntityManager em;

  public Emprestimo salvar(Emprestimo emprestimo)
    throws Exception {

    EmprestimoDAO dao = new EmprestimoDAO(em);
    return dao.salvar(emprestimo);
  }

  public void excluir(Long id) {
    EmprestimoDAO dao = new EmprestimoDAO(em);
    dao.excluir(id);
  }

  public Emprestimo consultarPorId(Long id) {
    EmprestimoDAO dao = new EmprestimoDAO(em);
    return dao.consultarPorId(id);
  }
}

A classe EmprestimoBean implementa a interface EmprestimoRemote, portanto ela implementa todos os métodos declarados na interface. Também adicionamos a anotação @Stateless para informar que este componente é do tipo Stateless Session Bean e que não irá manter o valor dos seus atributos (estado).

Note que declaramos um atributo chamado em do tipo EntityManager a adicionamos a anotação @PersistenceContext, dessa forma o componente EJB recebe do Container EJB uma instancia do tipo EntityManager com a conexão com o banco de dados.

Quando utilizamos @PersistenceContext especificamos qual o nome da unidade de persistência queremos obter (O nome da unidade de persistência é especificado no arquivo persistence.xml).

Vamos agora criar o EJB para o Livro e Pessoa:

Interface LivroRemote:

package pbc.emprestimo.ejb;

import javax.ejb.Remote;
import pbc.emprestimo.modelo.Livro;

/**
 * Interface que possui os métodos que o EJB de Livro
 * precisa implementar.
 */
@Remote
public interface LivroRemote {
  public Livro salvar(Livro livro) throws Exception;

  public void excluir(Long id);

  public Livro consultarPorId(Long id);
}

Classe LivroBean:

package pbc.emprestimo.ejb;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import pbc.emprestimo.dao.LivroDAO;
import pbc.emprestimo.modelo.Livro;

/**
 * EJB de Livro com a lógica de negocio.
 */
@Stateless
public class LivroBean implements LivroRemote {
  @PersistenceContext(unitName = "EmprestimoPU")
  private EntityManager em;

  public Livro salvar(Livro livro) throws Exception {
    LivroDAO dao = new LivroDAO(em);
    return dao.salvar(livro);
  }

  public void excluir(Long id) {
    LivroDAO dao = new LivroDAO(em);
    dao.excluir(id);
  }

  public Livro consultarPorId(Long id) {
    LivroDAO dao = new LivroDAO(em);
    return dao.consultarPorId(id);
  }
}

Interface PessoaRemote:

package pbc.emprestimo.ejb;

import javax.ejb.Remote;
import pbc.emprestimo.modelo.Pessoa;

/**
 * Interface que possui os métodos que o EJB de Pessoa
 * precisa implementar.
 */
@Remote
public interface PessoaRemote {
  public Pessoa salvar(Pessoa pessoa) throws Exception;

  public void excluir(Long id);

  public Pessoa consultarPorId(Long id);
}

Classe PessoaBean:

package pbc.emprestimo.ejb;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import pbc.emprestimo.dao.PessoaDAO;
import pbc.emprestimo.modelo.Pessoa;

/**
 * EJB de Pessoa com a lógica de negocio.
 * @author Rafael Guimarães Sakurai
 */
@Stateless
public class PessoaBean implements PessoaRemote {
  @PersistenceContext(unitName = "EmprestimoPU")
  private EntityManager em;

  public Pessoa salvar(Pessoa pessoa) throws Exception {
    PessoaDAO dao = new PessoaDAO(em);
    return dao.salvar(pessoa);
  }

  public void excluir(Long id) {
    PessoaDAO dao = new PessoaDAO(em);
    dao.excluir(id);
  }

  public Pessoa consultarPorId(Long id) {
    PessoaDAO dao = new PessoaDAO(em);
    return dao.consultarPorId(id);
  }
}

Até o momento criamos a seguinte estrutura, note que as interfaces e classes são bem coesas, ou seja, todas elas tem um propósito especifico, na camada de EJB temos apenas lógica de negocio, na camada de persistência temos apenas classes que fazem o trabalho com o banco de dados.

A figura a seguir mostra as classes e interfaces criadas até o momento:

Projeto Emprestimo

Criando a base de dados

A seguir temos o script para o banco de dados Oracle para criar as sequences e tabelas:

CREATE SEQUENCE LIVRO_SEQ INCREMENT BY 1 
  START WITH 1 NOCACHE NOCYCLE;

CREATE SEQUENCE PESSOA_SEQ INCREMENT BY 1 
  START WITH 1 NOCACHE NOCYCLE;

CREATE SEQUENCE EMPRESTIMO_SEQ INCREMENT BY 1 
  START WITH 1 NOCACHE NOCYCLE;

CREATE TABLE livro (
  id NUMBER(5) NOT NULL PRIMARY KEY,
  titulo VARCHAR2(100) NOT NULL,
  autor VARCHAR2(100) NOT NULL,
  emprestado NUMBER(1) NOT NULL
);

CREATE TABLE pessoa (
  id NUMBER(5) NOT NULL PRIMARY KEY,
  nome VARCHAR2(100) NOT NULL
);

CREATE TABLE emprestimo (
  id NUMBER(5) NOT NULL PRIMARY KEY,
  livro_id NUMBER(5) NOT NULL,
  pessoa_id NUMBER(5) NOT NULL,
  dataemprestimo DATE,
  datadevolucao DATE
);

Configuração da camada de persistência

Quando utilizamos o JPA para fazer a persistência com o banco de dados, precisamos fazer as seguintes configurações:

  • Adicionar driver do banco de dados Oracle no Glassfish;
  • Criar um data source com pool de conexão no Glassfish;
  • Criar arquivo persistence.xml.

Adicionar do driver do banco de dados

Coloque o driver do banco de dados na pasta de instalação do Glassfish.

..\glassfish-vx\domains\domain1\lib

Como estamos usando o Oracle nesse exemplo, devemos colocar na pasta de bibliotecas do Glassfish o jar ojdbc6.jar.

Criar um data source com pool de conexão no Glassfish

Inicie o Glassfish e entre na url: http://localhost:4848/login.jsf que abrirá a tela de administração.

Na tela de administração do Glassfish, selecione o menu Recursos, dentro dele escolha JDBC e depois escolha o menu JDBC Connection Pools.

Na tela de JDBC Connection Pools, clique no botão Novo....

Na tela Novo grupo de conexões JDBC (Etapa 1 de 2) (Novo Pool de Conexão JDBC), configure as seguintes opções:

  • Pool Name: Emprestimo
  • Tipo de Recurso: javax.sql.ConnectionPoolDataSource
  • Fornecedor do Banco de Dados: Oracle

Se estivermos trabalhando com outra base de dados é só escolher no combo de Fornecedor do Banco de Dados.

Depois clique em Avançar.

Na tela de Novo grupo de conexões JDBC (Etapa 2 de 2), desça até a parte de Adicionar Propriedades.

Clique no botão Selecionar todos, depois clique em Excluir Propriedades.

Depois adicione as seguintes propriedades:

  • user: nome do usuário no banco de dados
  • password: senha do usuário no banco de dados
  • url: caminho para encontrar o banco de dados.

No Oracle utilizamos a URL:

jdbc:oracle:thin:@localhost:1521:XE

ou de acordo com sua instalação.

Volte para o topo da página e clique em Finalizar.

Clique no pool de conexão que acabamos de criar Emprestimo, e clique no botão Ping para verificar se o Glassfish encontra o banco de dados como apresentado na figura a seguir:

Ping na conexão

Deve aparecer na tela a mensagem Ping executado com êxito, informando que conseguiu encontrar no banco de dados.

Agora vamos criar o recurso JDBC que será utilizado por nosso projeto EJB:

Clique na menu Recursos, dentro dele escolha JDBC e depois escolha JDBC Resources.

Na tela de Recursos JDBC clique no botão Novo....

Na tela de Novo Recuros JDBC configure os itens:

  • Nome JNDI: jdbc/Emprestimo
  • Nome do grupo: Emprestimo

Depois clique no botão OK. Pronto, criamos o pool de conexão no Glassfish.

Criar arquivo persistence.xml

Agora vamos criar uma Unidade de Persistência, que utiliza o Pool de Conexão que acabamos de criar no Glassfish:

Clique com o botão direito sobre o projeto EmprestimoEJB, selecione a opção Novo e depois selecione Unidade de persistência....

Na tela de Novo Unidade de persistência, configure os seguintes itens:

  • Nome da unidade de persistência: EmprestimoPU
  • Provedor de persistência: Hibernate JPA (1.0)
  • Fontes de dados: jdbc/Emprestimo
  • Estratégia de geração de tabela: Nenhum

Depois clique no botão Finalizar.

Abra o arquivo persistence.xml dentro da pasta Arquivos de configuração e escreva o seguinte código:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.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_1_0.xsd">
  <persistence-unit name="EmprestimoPU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/Emprestimo</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="hibernate.show_sql" value="true"/>
    </properties>
  </persistence-unit>
</persistence>

Note que o nome da unidade de persistência EmprestimoPU que acabamos de criar, é o mesmo nome que utilizamos na anotação @PersistenceContext como mostrado na figura a seguir, pois é através dessa unidade de persistência que o Container EJB cria um EntityManager.

Persistence Context

Feito isto nossa aplicação EmprestimoEJB já está pronta, com a estrutura igual a da figura a seguir:

Estrutura do projeto

A figura a seguir mostra como publicar a aplicação EmprestimoEJB no Glassfish.

Publicar projeto no Glassfish

results matching ""

    No results matching ""