quinta-feira, 5 de janeiro de 2012

FileUpload com JSF + Primefaces + Hibernate + MySql

Nesse tutorial, tentarei explicar como fazer o upload de imagem, salvar o arquivo em um diretório e gravar o nome dele no banco (mysql) para depois ser exibido em uma view (usando o JSF).

O projeto que vamos fazer é simples, será o cadastro de um produto com os seguintes atributos:
id, nome, preço e foto do produto.

==> Crie a base de dados ou utilize uma já existente, no meu caso, irei criar uma nova base de dados com o nome fileUpload.

==> Crie um novo projeto web com suporte a JSF, Primefaces e Hibernate (utilizando o banco criado acima).

==> Crie a estrutura de pacotes
- managedBean (controller)
- dao (persistência)
- entidades (POJO)

==> Agora vamos fazer o POJO de produtos. Dentro do pacote entidades crie uma nova classe com o nome Produto


2
5package entidades;
6
7/**
8 *
9 * @author Mara
10 */
11import javax.persistence.*;
12@Entity
13@Table(name="tb_produto")
14public class Produto{
15@Id
16@GeneratedValue(strategy=GenerationType.AUTO)
17@Column(name="prod_id")
18private int id;
19@Column(name="prod_nome")
20private String nome;
21@Column(name="prod_preco")
22private double preco;
23@Column(name="prod_foto")
24private String foto;
25

// Construtor getters e setters
29


Obs.: faça o import das anotações do pacote javax.persistence.*

==> Crie a classe HibernateUtil dentro do pacote dao.
caso tenha dúvida de como implementar a HibernateUtil consulte http://meninajava.blogspot.com/2011/11/configurar-o-hibernate-utilizando.html

==> Adicione o mapeamento da classe Produto no arquivo hibernate.cfg.xml e habilite para hibernate criar automaticamente a tabela no banco.





10<property name="hibernate.hbm2ddl.auto">update</property>
11<mapping class="entidades.Produto"/>
12


Agora vamos fazer a classe ProdutoDao que terá os metódos para persistir e consultar os dados do banco.

==> Dentro do pacote dao, crie uma nova classe com o nome ProdutoDao e implemente pelo menos os metódos de salvar e consultar todos os produtos, para este tutorial iremos utilizar somente estes dois.



3package dao;
4
8import entidades.Produto;
9import java.util.List;
10import org.hibernate.Session;
11
12public class ProdutoDao {
13public void salvar(Produto produto){
14Session session = HibernateUtil.getSession();
15session.beginTransaction().begin();
16session.saveOrUpdate(produto);
17session.getTransaction().commit();
18session.close();
19System.out.println("Salvo com sucesso");
20}
21
22public List<Produto> listar(){
23Session session= HibernateUtil.getSession();
24String sql = "SELECT p FROM Produto p";
25return (List<Produto>) session.createQuery(sql).list();
26}
27}



==> Faça o download de duas bibliotecas extras:




Após baixar os arquivos, adicione as depedências ao seu projeto.


==> Configure o arquivo web.xml adicionando o filter do fileUpload.

<filter>
       <filter-name>PrimeFaces FileUpload Filter</filter-name>
  
<filter-class> org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>

   <filter-mapping>
       <filter-name>PrimeFaces FileUpload Filter</filter-name>
       <servlet-name>Faces Servlet</servlet-name>
   </filter-mapping>  



No post anterior fiz o método de upload do arquivo no mangedBean, para faciliar as futuras implementações desta funcionalidade, criei uma classe UploadArquivo que ficará responsável pelo upload. Assim quando o usuário pressionar o botão salvar do formulário, é armazenado o arquivo e os dados no banco.

==> No pacote managedBean crie uma nova classe com o nome UploadArquivo e implemente o código abaixo.

5package managedBean;
6
7import java.io.File;
8import java.io.FileOutputStream;
9import java.util.logging.Level;
10import java.util.logging.Logger;
11import javax.faces.context.ExternalContext;
12import javax.faces.context.FacesContext;
13import javax.servlet.ServletContext;
14import javax.servlet.http.HttpServletResponse;
15import org.primefaces.event.FileUploadEvent;
16



21public class UploadArquivo {
22private String diretorio;
23private String caminho;
24private byte[] arquivo;
25private String nome;
26
27public UploadArquivo() {
28}


46public String getNome() {
47return nome;
48}



54public String getRealPath() {
55ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
56HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
57
58FacesContext aFacesContext = FacesContext.getCurrentInstance();
59ServletContext context = (ServletContext) aFacesContext.getExternalContext().getContext();
60
61return context.getRealPath("/");
62}
63
64public void fileUpload(FileUploadEvent event, String type, String diretorio) {
65try {
66this.nome = new java.util.Date().getTime() + type;
67this.caminho = getRealPath() + diretorio + getNome();
68this.arquivo = event.getFile().getContents();
69
70File file = new File(getRealPath() + diretorio);
71file.mkdirs();
72
73} catch (Exception ex) {
74System.out.println("Erro no upload do arquivo" + ex);
75}
76}
77
78public void gravar(){
79
80try {
81
82FileOutputStream fos;
83fos = new FileOutputStream(this.caminho);
84fos.write(this.arquivo);
85fos.close();
86
87} catch (Exception ex) {
88System.out.println(ex);
89}
90
91}
92}


Linha 54 - O método getRealPath pega o diretório completo da sua aplicação no servidor.
Linha 64 - O método fileUpload irá fazer o carregamento do arquivo e prepara-lo para ser gravado.
Linha 78 - O método salvar, grava o arquivo no diretório informado.
Os arquivos serão armazenados na pasta build/web/nomediretorio do seu projeto.

==> No pacote managedBean crie uma nova classe com o nome ProdutoManagedBean e implemente o código abaixo.



5package managedBean;
6
7import javax.faces.bean.ManagedBean;
8import javax.faces.bean.SessionScoped;
9import entidades.Produto;
10import dao.ProdutoDao;
11import java.util.ArrayList;
12import java.util.List;
13import org.primefaces.event.FileUploadEvent;
14/**
15 *
16 * @author Mara
17 */
18@ManagedBean(name="produtoMB")
19@SessionScoped
20public class ProdutoManagedBean {
21private Produto produto;
22private List<Produto> listarProdutos;
23private UploadArquivo arquivo = new UploadArquivo();
24
25public ProdutoManagedBean() {
26this.produto = new Produto();
27this.listarProdutos = new ArrayList<Produto>();
28}
29
30public List<Produto> getListarProdutos() {
31return new ProdutoDao().listar();
32//return this.listarProdutos;
33}
34
35public void setListarProdutos(List<Produto> listarProdutos) {
36this.listarProdutos = listarProdutos;
37}
38
39public Produto getProduto() {
40return produto;
41}
42
43public void setProduto(Produto produto) {
44this.produto = produto;
45}
46
47public void uploadAction (FileUploadEvent event){
48this.arquivo.fileUpload(event, ".jpg", "/image/");
49this.produto.setFoto(this.arquivo.getNome());
50}
51
52public void salvar(){
53new ProdutoDao().salvar(produto);
54this.arquivo.gravar();
55
56this.produto = new Produto();
57this.arquivo = new UploadArquivo();
58}
59}



Linha 47 - Método que será chamado pela view para o upload do arquivo. O arquivo será carregado mas ainda não será salvo no diretório.
Linha 54 - Quando o usuário pressionar no botão salvar do formulário, os dados serão persistidos no banco e o arquivo será gravado no diretório.

==> Agora vamos fazer a view, no arquivo index implemente o código abaixo:


1<?xml version='1.0' encoding='UTF-8' ?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3<html xmlns="http://www.w3.org/1999/xhtml"
4xmlns:p="http://primefaces.prime.com.tr/ui"
5xmlns:h="http://java.sun.com/jsf/html"
6xmlns:f="http://java.sun.com/jsf/core">
7<h:head>
8<title>File Upload</title>
9</h:head>
10<h:body>
11<h1>Inserir Produto</h1>
12<h:form>
13<h:panelGrid columns="2">
14Nome: <h:inputText value="#{produtoMB.produto.nome}"/>
15Preço: <h:inputText value="#{produtoMB.produto.preco}"/>
16
17Foto: <p:fileUpload id="upload" update="foto"
18fileUploadListener="#{produtoMB.uploadAction}" auto="true"/>
19
20<h:commandButton action="#{produtoMB.salvar}" value="Salvar" />
21</h:panelGrid>
22</h:form>
23
24<h2>Produtos Cadastrados</h2>
25<h:form>
26<h:dataTable var="produto" value="#{produtoMB.listarProdutos}" >
27<h:column>
28<f:facet name="header">Foto</f:facet>
29<h:graphicImage value="./image/#{produto.foto}"/>
30</h:column>
31<h:column>
32<f:facet name="header">Nome</f:facet>
33<h:outputText value="#{produto.nome}"/>
34</h:column>
35<h:column>
36<f:facet name="header">Preço</f:facet>
37<h:outputText value="#{produto.preco}"/>
38</h:column>
40</h:dataTable>
41</h:form>
42</h:body>
43</html>
44


Acesse https://github.com/MaraRegina/FileUpload, visualize o projeto completo ou faça o download para testar.

23 comentários:

  1. hahahahaha outro nivel, o tutorial ficou bem mais legal e ta brincando com o layout do blog, #curti

    ResponderExcluir
  2. 100%, foi de muita ajuda esse tutorial

    ResponderExcluir
  3. Olá, consegui fazer tudo que você ensinou... tá salvando no arquivo e tudo certinho... só que estou tendo problema na hora de apresentar na tela pelo componente primefaces graphicImage... alguém sabe pq a imagem não está sendo carregada?

    ResponderExcluir
    Respostas
    1. Olá Douglas,

      Qual o erro que esta sendo exibido, é erro de componente utilizado?
      Se possível, verifique se o caminho colocado para carregar a imagem corresponde com o caminho do diretório onde ela foi salva.

      Excluir
    2. não é erro do componente, a imagem só não é carregada... e eu coloquei até o endereço estático pra testar e ela não é carregada... a imagem que aparece no lugar é uma que não é aquele "x" vermelho, não sei explicar direito qual é essa imagem.

      Excluir
  4. Olá, boa tarde...
    seria possível utilizar este tutorial para salvar um arquivo em um banco na rede?
    Se sim, poderia me dizer onde posso achar alguma informação?
    Obrigado.

    ResponderExcluir
    Respostas
    1. Sim, no exemplo do tutorial utilizei o conceito de Dao utilizando o hibernate para salvar os dados e imagem no banco.

      Da uma olhada neste tutorial tem um exemplo de conexão ao banco usando o hibernate.
      http://meninajava.blogspot.com/2011/11/configurar-o-hibernate-utilizando.html

      Excluir
    2. Agora que fui me atentar a sua pergunta...
      se vc deseja salvar o arquivo da imagem no banco em vez de gravar somente o nome no banco e deixar a imagem salva em um diretorio. Não tenho nenhum exemplo em mãos.

      Mas vou verificar

      Excluir
  5. Obrigado , Me ajudou bastante

    ResponderExcluir
  6. oi tudo bem..primeiramente parabens..
    estou com um problema na implementaçao.

    log do servidor apache:

    SEVERE: null
    java.lang.NullPointerException
    Hibernate:
    /* insert br.com.ecommerceetelj.model.Produto
    */ insert
    into
    produto
    (id_cat, desconto_produto, descricao_produto, imagem_produto, nome_produto, preco_produto, qtd_produtodisponivel_produto, id_produto)
    values
    (?, ?, ?, ?, ?, ?, ?, ?)
    at java.io.FileOutputStream.(FileOutputStream.java:172)

    OBS: ESSE ERRO DE CIMA CAI EM
    if (name == null) {
    throw new NullPointerException();
    }

    at java.io.FileOutputStream.(FileOutputStream.java:70)

    OBS: O ERRO DE CIMA CAI EM
    public FileOutputStream(String name) throws FileNotFoundException {
    this(name != null ? new File(name) : null, false);
    }

    at br.com.ecommerceetelj.bean.UploadArquivo.gravar(UploadArquivo.java:89)
    at br.com.ecommerceetelj.bean.ProdutoBean.salvar(ProdutoBean.java:41)

    OBS: O ERRO ACIMA CAI EM QUE ESTA DENTRO DO MEU METODO SALVAR
    this.arquivo.gravar(); //chama metoda da classe UploadArquivo

    O ERRO DE NULL POINTER ESTA NA LINHA 83 DO SEU TUTORIAL
    83 fos = new FileOutputStream(this.caminho);

    NO BANCO O MEu PRODUTO SALVA NORMALMENTE , MAIS O CAMPO IMAGEM DO BANCO FICA "Null".

    DESDE JA AGRADEÇO!!


    ResponderExcluir
  7. Excelente post. Parabéns!

    ResponderExcluir
  8. Olá Mara!

    Gostaria de salvar imagens em uma pasta dentro do container ( Tomcat ) exemplo webapps\documentos\
    porque ? bem o sistema poderia ser republicado e perder a pasta de documentos caso estivesse sendo gravado dentro do contexto da aplicação vc saberia me dizer como?

    Há ficou muito bom! Parabens

    Robson

    ResponderExcluir
  9. Agradeço por compartilhar, deu tudo certo aqui.
    Obrigado e sucesso.

    ResponderExcluir
  10. Parabéns! Grande iniciativa, continue compartilhando conhecimento.

    Carlos Júnior.

    ResponderExcluir
  11. Parabéns. Me ajudou muito!!

    Obrigado.

    ResponderExcluir
  12. obrigado pelo tutorial
    o meu deu esse erro to quebrando a cabeça aqui mas não consigo descobrir o porque
    Cannot find component with expression ":produtoMB:produto:foto" referenced from "j_idt6:upload"

    ResponderExcluir
  13. Parabéns pelo tutorial.

    Na linha 68 do metodo UploadArquivo - this.arquivo = event.getFile().getContents();
    Esta retornando sempre null, ai na hora de gravar da erro que o arquivo esta null, você tem ideia do que pode ser isso?

    Obrigado

    ResponderExcluir
  14. Bom dia!

    Meu arquivo chega com null. O nome consigo pegar, mas o getContents() dá NullPointer...

    ResponderExcluir
  15. Olá, muito bom o tutorial, parabéns!
    Em que pasta ele deveria gravar o arquivo?
    está salvando no banco, mas não exibe a imagem, parece que nao está criando o arquivo, pode me ajudar por favor?

    ResponderExcluir
  16. Olá, muito bom o tutorial, parabéns!
    Em que pasta ele deveria gravar o arquivo?
    está salvando no banco, mas não exibe a imagem, parece que nao está criando o arquivo, pode me ajudar por favor?

    ResponderExcluir
  17. Meu problema é que uso o Wildfly, e quando crio o diretorio e salvo a imagem ele restarta... ai da o erro javax.faces.application.ViewExpiredException se eu tentar fazer qualquer navegação após a exibição da imagem. O código da escrita da imagem que to usando é:
    Path path = Paths.get(FacesContext.getCurrentInstance().getExternalContext().getRealPath("/").toString()+"/temp/carro");

    Files.createDirectories(path);

    FileOutputStream fos = new FileOutputStream(path.toRealPath() + "/" + carroSelecionado.getCodigo() + ".jpg");

    fos.write(carroSelecionado.getImagem());

    fos.close();

    ResponderExcluir
  18. Beleza beleza, so que ñ esta listando as fotos estão na pasta build/web/image.

    ResponderExcluir
  19. Dai pessoal, resolvi o problema de não carregar as imagens no JSF, é só mudar o nome da pasta (diretório) de "image" para "temp", assim ele salva direto em uma pasta temporária e não cria uma pasta image.

    ResponderExcluir