- Pesquisar por algum produto baseado no nome ou na descrição
- Navegar através de uma lista de produtos classificados por categoria
- Selecionar um produto e ver seus detalhes
- Colocar o produto em um carrinho de compras
- Ver e alterar os produtos que estão no carrinho de compras
- Fazer o pedido e finalizar a compra
JPA: Modelando o negócio e criando o banco de dados
Java Persistence API (JPA) é a especificação padrão Java EE para persistencia de dados. O JPA realiza sozinho todo mapeamento a partir do modelo orientado a objetos e constrói toda base de dados relacional independente do banco dados que a aplicação vá utilizar.
O diagrama de classes abaixo nos mostra como será o modelo de negócios do projeto:
Um cliente pode realizar vários pedidos. Cada pedido é feito por apenas um cliente. Uma categoria tem vários produtos. Cada produto pertence a somente uma categoria. Um pedido pode ter vários produtos e um produto pode estar em vários pedidos.
Produtos e Pedidos representam uma relação muitos-para-muitos. Esse tipo de relação precisa ser normnalizado. Assim, criamos a classe orderProduct que contem a quantidade de itens de um pedido e o subtotal (mais sobre normalização em seguida...).
Produtos e Pedidos representam uma relação muitos-para-muitos. Esse tipo de relação precisa ser normnalizado. Assim, criamos a classe orderProduct que contem a quantidade de itens de um pedido e o subtotal (mais sobre normalização em seguida...).
Codificando o modelo (para clareza, as declarações import foram omitidas)
Abra a IDE NetBeans, crie um novo projeto Java Web, dê o nome de StarkHouseECommerce e finalize. Delete o arquivo index.html que o NetBeans cria automaticamente.
Para utilizar o JPA você precisa ter as seguintes biblioteca no seu classpath, conforme a imagem da janela de projetos do NetBeans:
Você pode baixar as bibliotecas aqui hibernate 4.3.5.Final (todos os arquivos na pasta /lib/required). Também deve usar esta hibernate-entitymanager. E o driver do banco de dados PostgreSQL.
A especificação do JPA nos diz que precisamos ter o arquivo persistence.xml no projeto. É nele que ficam as informações de acesso ao banco de dados. No nosso exemplo, o arquivo deve ser como segue:
Criando as Entidades
Classe EClient.java, a entidade que realiza as compras no nosso site.
De acordo com o nosso digrama de classes, Product e EOrder têm entre si uma relação N para N, isto é, muitos-para-muitos. Esse tipo de relação só existe conceitualmente, na hora de implementar precisamos normaliza-la, tranformando-a em 2 relações 1 para N, uma-para-muitos. Dessa forma, criamos uma classe extra para armazenar a quantidade de produtos de cada pedido, bem como o subtotal (o cliente pode ter ganho um desconto no dia do pedido, mas o preço real do produto continua inalterado na base de dados, por exemplo). Criamos a classe OrderProduct, a qual possui uma referência tanto para Product quanto para EOrder, mais os campos quantity e total.
De acordo com a especificação do JPA, o ID dessa nova entidade deve ficar em uma classe separada, vamos chamá-la de OrderProductId:
Agora que temos todo o modelo pronto, é hora de popular as tabelas do banco de dados. Não se esqueça de criar um banco de dados chamado ecommerce. O JPA criará todas as tabelas e os relacionamentos para você.
Para preencher as tabelas crie uma classe chamada teste com um método principal e execute-a:
O JPA nos auxilia na construção do modelo e no relacionamento com o banco de dados.
O próximo passo na parte 2 deste artigo é criar a interface com o usuário para que ele possa se cadastrar e comprar os produtos registrados em nosso banco de dados. Para nos auxiliar nesse tarefa utilizaremos os frameworks Servlets e Java Server Pages (JSP)!
Você pode baixar as bibliotecas aqui hibernate 4.3.5.Final (todos os arquivos na pasta /lib/required). Também deve usar esta hibernate-entitymanager. E o driver do banco de dados PostgreSQL.
A especificação do JPA nos diz que precisamos ter o arquivo persistence.xml no projeto. É nele que ficam as informações de acesso ao banco de dados. No nosso exemplo, o arquivo deve ser como segue:
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="ecommerce" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/ecommerce"/> <property name="javax.persistence.jdbc.user" value="postgres"/> <property name="javax.persistence.jdbc.password" value="postgres"/> <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="true"/> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> <property name="hibernate.hbm2ddl.auto" value="update"/> </properties> </persistence-unit> </persistence>No meu banco, usuário e senha são ambos postgres. E a porta geralmente é 5432. Se no seu caso for diferente, apenas faça as adequações. Crie um banco de dados chamado ecommerce.
Criando as Entidades
Classe EClient.java, a entidade que realiza as compras no nosso site.
//imports omitidos @Entity @Table(name = "eclient") public class EClient implements Serializable{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; //chave primária gerada sequencialmente @Column private String firstName; @Column private String lastName; @Column @Temporal(TemporalType.TIMESTAMP) private Date birthDate; //campo tipo data e tempo @Column private String creditCard; @Column private String email; @Column private String login; //esta anotação indica uma relação "um-pra-muitos" entre cliente e pedido @OneToMany(mappedBy = "client") private List<EOrder> orders; //construtor public EClient() { orders = new ArrayList<>(); } //getters & setters para cada atributo }A classe EOrder que representa os pedidos do nosso sistema:
@Entity public class EOrder { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column @Temporal(TemporalType.TIMESTAMP) private Date date; @ManyToOne //cada pedido pertence a um cliente @JoinColumn(name = "CLI_ID") //equivale a chave estrangeira da classe EClient private EClient client; @OneToMany(mappedBy = "eorder") //um pedido tem muitos produtos private List<OrderProduct> orderProduct; public EOrder() { client = new EClient(); orderProduct = new ArrayList<>(); } //getters e setters omitidos }A classe Product:
@Entity @Table(name = "product") public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String name; @Column private Double price; @Column private String description; @ManyToOne //cada produto pertence a uma categoria @JoinColumn(name = "CAT_ID", nullable = false) //chave estrangeira de Category private Category category; @OneToMany(mappedBy = "product") //um produto está em muitos pedidos private List<OrderProduct> orderProduct; public Product() { category = new Category(); orderProduct = new ArrayList<>(); } //getters e setters omitidos }Normalizando a relação Produto e Pedido
De acordo com o nosso digrama de classes, Product e EOrder têm entre si uma relação N para N, isto é, muitos-para-muitos. Esse tipo de relação só existe conceitualmente, na hora de implementar precisamos normaliza-la, tranformando-a em 2 relações 1 para N, uma-para-muitos. Dessa forma, criamos uma classe extra para armazenar a quantidade de produtos de cada pedido, bem como o subtotal (o cliente pode ter ganho um desconto no dia do pedido, mas o preço real do produto continua inalterado na base de dados, por exemplo). Criamos a classe OrderProduct, a qual possui uma referência tanto para Product quanto para EOrder, mais os campos quantity e total.
De acordo com a especificação do JPA, o ID dessa nova entidade deve ficar em uma classe separada, vamos chamá-la de OrderProductId:
@Entity @IdClass(OrderProductId.class) //indica a classeId de OrderProduct public class OrderProduct { @Id @ManyToOne @JoinColumn(name = "prd_id") Product product; @Id @ManyToOne @JoinColumn(name = "ord_id") EOrder eorder; @Column private Integer quantity; //a quantidade de produtos no pedido @Column //valor total deste produto no pedido, geralmente preço x quantidade private Double total; //getters e setters omitidos }A classe OrderProductId:
public class OrderProductId implements Serializable{ int eorder; int product; //getters e setters omitidos //é obrigatório a implementação dos métodos hashCode() e equals() utilizando os dois campos }A classe Category:
@Entity @Table(name = "category") public class Category { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String name; @OneToMany(mappedBy = "category", fetch = FetchType.LAZY) private List<Product> products; //uma categoria tem muitos produtos public Category() { products = new ArrayList<>(); } //getters e setters omitidos }Populando o banco de dados
Agora que temos todo o modelo pronto, é hora de popular as tabelas do banco de dados. Não se esqueça de criar um banco de dados chamado ecommerce. O JPA criará todas as tabelas e os relacionamentos para você.
Para preencher as tabelas crie uma classe chamada teste com um método principal e execute-a:
public class teste { public static void main(String[] args) { //"ecommerce" é o nome da unidade de persistencia conforme definido no arquivo persistence.xml EntityManagerFactory emf = Persistence.createEntityManagerFactory("ecommerce"); EntityManager em = emf.createEntityManager(); //criando as categorias Category eletronicos = new Category("eletrônicos", null); Category suplementos = new Category("suplementos", null); Category livros = new Category("livros", null); //criando os produtos e passando a respectiva categoria no construtor Product ps4 = new Product("PS4", 566.23, "Adquira o PS4™ e prepare-se para a experiência de jogo mais imersiva possível!", eletronicos); Product noteDell = new Product("NoteBook Dell", 303.99, "Linux, 15.6, 8GB, i7", eletronicos); Product IPhone = new Product("IPhone 5S", 299.99, "16GB, 4G, Explore o mundo do iPhone!", eletronicos); Product wheyProt = new Product("Whey Protein ON", 32.01, "Whey Protein Isolada ON. Rápida absorção", suplementos); Product multiAz = new Product("Multi AZ Final", 11.0, "Multi AZ para homens e mulheres", suplementos); Product omega3 = new Product("Omega 3", 65.99, "Puro Omega 3 importado 120 caps", suplementos); Product javaHowTo = new Product("Java como Programar", 80.15, "Java como Programar, Deitel, Deitel, 1100 páginas", livros); Product jsf = new Product("Core JSF", 80.15, "Core JSF, Geary Horstmann, 400 páginas", livros); Product cronicasGeloFogo = new Product("Crônicas de Gelo e Fogo", 55.88, "O Festim dos Corvos, RR Martin, 800 páginas", livros); //antes de salvar as categorias e os produtos, precisamos abrir uma transação em.getTransaction().begin(); //persist() é o método de EntityManger para persistir os objetos no banco em.persist(eletronicos); em.persist(suplementos); em.persist(livros); em.persist(ps4); em.persist(noteDell); em.persist(IPhone); em.persist(wheyProt); em.persist(multiAz); em.persist(omega3); em.persist(javaHowTo); em.persist(jsf); em.persist(cronicasGeloFogo); //para finalizar confirme a transação e feche os recursos utilizados em.getTransaction().commit(); emf.close(); } }Repare como ficou nossa janela de projetos no NetBans. Repare também que no console da IDE o JPA exibe as declarações sql que foram geradas no banco:
O JPA nos auxilia na construção do modelo e no relacionamento com o banco de dados.
O próximo passo na parte 2 deste artigo é criar a interface com o usuário para que ele possa se cadastrar e comprar os produtos registrados em nosso banco de dados. Para nos auxiliar nesse tarefa utilizaremos os frameworks Servlets e Java Server Pages (JSP)!