Transformar JPG em BLOB e salvar no BD - Usando Hibernate

Pessoal,

Estou com um grande desafio aqui: como pegar, atraves de um form html, uma imagem em JPG e transforma-la em BLOB para salva-la no BD?
Estou usando MySQL + Hibernate + Struts.
Pesquisei na net, mas não achei nada de util com essa minha configuração, geralmente é usando JDBC puro e nenhum exemplo, até agora encontrado, com Struts. Estou cheio de dúvida, de como receber essa imagem no action do struts, tranforma-la e ainda persistr com o Hibernate, se algume puder me da uma luz, agradeço.

Talvez isso ajude…
Receba a imagem e converta em bytes…

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package javaapplication9;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

/**
 *
 * @author suporte
 */
@Entity
@Table(name = "imagem")
@NamedQueries({
    @NamedQuery(name = "Imagem.findAll", query = "SELECT i FROM Imagem i"),
    @NamedQuery(name = "Imagem.findById", query = "SELECT i FROM Imagem i WHERE i.id = :id")})
public class Imagem implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    @Basic(optional = false)
    @Lob
    @Column(name = "imagem")
    private byte[] imagem;

    public Imagem() {
    }

    public Imagem(Integer id) {
        this.id = id;
    }

    public Imagem(Integer id, byte[] imagem) {
        this.id = id;
        this.imagem = imagem;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public byte[] getImagem() {
        return imagem;
    }

    public void setImagem(byte[] imagem) {
        this.imagem = imagem;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Imagem)) {
            return false;
        }
        Imagem other = (Imagem) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "javaapplication9.Imagem[id=" + id + "]";
    }
}

Beleza, criar a classe pra persistir e a tabela no BD é mole, na verdade eu não estou usando uma classe Imagem, estou colocando direto o campo BLOB na tabela que eu quero, que é a tabela funcionario, eu tenho um campo chamado foto do tipo blob dentro da tabela. Mas se for preciso faço uma classe soh pra imagem, mas como recuperar a imagem e converte-la, usando Struts?

Não é Mais fácil salvar em um pasta depois recuperar pelo caminho /fotos/imagen.jpg

mas se for obrigatório.

cria a coluna do tipo byte[] na entidade funcionario, nao precisa converter pra imagem, se quiser gravar num arquio eh so usar o metodo write do outputstream ou se quiser visualizar no browser faca do mesmo modo usando o outputstream do HttpServletResponse, mas setando o response.setContentType(“image/jpeg”).

Criei o atributo foto na classe Funcionario, coloquei como byte[], mas como que vou pegar o caminho que o usuario fornece no form html, jogar para uma action do struts e salvar no BD? Colocano o campo foto como byte[] basta eu salvar agora? Nao preciso converter nada, quero converter o arquivo em jpg para poder salva-lo no BD, ja que n aminha tabela o campo é do tipo blob, entendeu? Prefiro fazer direto no BD, pois fazendo com diretorios, vai ser mais dificil o bakcup

Na minha classe Funcionario, fiz o seguinte:

...
@Column(name = "foto")
    private byte[] foto;

...

public byte[] getFoto() {
        return foto;
    }

    public void setFoto(byte[] foto) {
        this.foto = foto;
    }

    public void setFotoBlob(Blob imageBlob) {
        this.foto = this.toByteArray(imageBlob);
    }

    /** Don't invoke this.  Used by Hibernate only. */
    public Blob getFotoBlob() {
        return (Blob) Hibernate.createBlob(this.foto);
    }

    private byte[] toByteArray(Blob fromBlob) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        
        try {
            return toByteArrayImpl(fromBlob, baos);
        }
        catch (SQLException e) {
            throw new RuntimeException(e);
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
        finally {
            if (baos != null) {
                try {
                    baos.close();
                }
                catch (IOException ex) {
                }
            }
        }
    }

    private byte[] toByteArrayImpl(Blob fromBlob, ByteArrayOutputStream baos)
            throws SQLException, IOException {
        byte[] buf = new byte[4000];
        InputStream is = fromBlob.getBinaryStream();
        try {
            for (;;) {
                int dataSize = is.read(buf);
                if (dataSize == -1)
                    break;
                baos.write(buf, 0, dataSize);
            }
        }
        finally {
            if (is != null) {
                try {
                    is.close();
                }
                catch (IOException ex) {
                }
            }
        }
        return baos.toByteArray();
    }

...

Mas nao sei como usar isso, peguei em um tutorial do Hibernate

Alguma ideia de como posso fazer isso?
Dei mais uma pesquisada aqui e li que é colocar a anotação @Lob que o hibernate se vira, achei muito estranho, acho que pelo menos tenho que cosneguir pegar o arquivo em si atraves do form hmtl para ai sim o hibernate persistir, alguma ideia, por favor?

Fiz o seguinte:

Meu jsp:

...
<label>Foto:</label>
<input type="file" name="foto" />
...

CdastroFuncionarioForm: (BeanForm)

   ...

   private String caminhoFoto;

   public String getCaminhoFoto() {
        return caminhoFoto;
    }

    public void setCaminhoFoto(String foto) {
        this.caminhoFoto = foto;
    }
    ...

CadastroFuncionarioAction: (Ação do Struts)

        CadastrarFuncionarioForm funcionarioForm = (CadastrarFuncionarioForm) form;
        Funcionario funcionario = new Funcionario();


        File file = new File(funcionarioForm.getCaminhoFoto());
        FileInputStream fis = new FileInputStream(file);
        byte[] bytes = new byte [(int) file.length()];
        fis.read (bytes);

        funcionario.setFoto(bytes);

Na minha entidade Funcionario coloquei os seguintes metodos:

...
    @Column(name = "foto")
    @Lob
    private byte[] foto;
...

public byte[] getFoto() {
        return foto;
    }

    public void setFoto(byte[] foto) {
        this.foto = foto;
    }
...

Aparece esse erro aqui, fazendo desse jeito:

javax.servlet.ServletException: java.lang.NullPointerException

java.lang.NullPointerException
java.io.File.(File.java:222)
catalogo.controle.actions.CadastrarFuncionarioAction.execute(CadastrarFuncionarioAction.java:40)
org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:425)
org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:228)
org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:462)
javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:390)

Se alguem puder me ajudar a resolver esse problema e conseguir salvar a imagem direto no BD, eu acho que esta faltando eu pegar o caminho completo da imagem, mas enfim estou cheio de duvida pra fazer isso.

Pessoal,

Fiz assim na minha ação do Struts:

[code]
File file = new File(funcionarioForm.getFoto());
//File file = new File(“C:\Documents and Settings\Jefferson\Meus documentos\catalogo\publico\fotos\edson.jpg”);
FileInputStream fis = new FileInputStream(file);
byte[] bytes = new byte [(int) file.length()];
fis.read (bytes);

    // funcionario.setFoto(bytes);
    BeanUtils.copyProperties(funcionario, funcionarioForm); [/code]

O problema é que só funciona se eu setar o camindo completo de algum arquivo na mão, como comentado na segunda linha do codigo, pelo que puder perceber o problema é que o meu CadastroFuncionarioForm esta com metodos diferentes da minha entidade Funcionario, entao quando eu mando copiar as propriedades de um para o outro me dar erro, como mudar isso?

Pessoal,

Continuo tentando salvar a iamgem no Bd com o codigo postado acima:

        File file = new File(funcionarioForm.getCaminhoFoto());       
        FileInputStream fis = new FileInputStream(file);
        byte[] bytes = new byte [(int) file.length()];
        fis.read (bytes);

Não sei se essa é a melhotr maneira de fazer isso, se alguem souber de alguma outra maneira de fazer isso me ajude, por favor.
Com esse código, eu seto o meu atributo foto na minha classe Funcionario, no BeanForm tambem tenho esse mesmo atributo foto, mas mesmo assim nao consigo salvar no BD, consegui uma vez só, mas construindo a classe File setando o valor na mão, o erro agora é esse:

[code]javax.servlet.ServletException: BeanUtils.populate
org.apache.struts.util.RequestUtils.populate(RequestUtils.java:469)
org.apache.struts.action.RequestProcessor.processPopulate(RequestProcessor.java:818)
org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:194)
org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:462)
javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:390)

root cause

java.lang.IllegalArgumentException: Cannot invoke catalogo.controle.forms.CadastrarFuncionarioForm.setCaminhoFoto - argument type mismatch
org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:1778)
org.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:1759)
org.apache.commons.beanutils.PropertyUtilsBean.setNestedProperty(PropertyUtilsBean.java:1648)
org.apache.commons.beanutils.PropertyUtilsBean.setProperty(PropertyUtilsBean.java:1677)
org.apache.commons.beanutils.BeanUtilsBean.setProperty(BeanUtilsBean.java:1022)
org.apache.commons.beanutils.BeanUtilsBean.populate(BeanUtilsBean.java:811)
org.apache.commons.beanutils.BeanUtils.populate(BeanUtils.java:298)
org.apache.struts.util.RequestUtils.populate(RequestUtils.java:467)
org.apache.struts.action.RequestProcessor.processPopulate(RequestProcessor.java:818)
org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:194)
org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:462)
javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:390)

[/code]

Se alguem puder me ajudar, agradeço.

tou com a mesma situação. Mas não consigui ainda salvar no banco a imagem.
Estou usando o Seam. Captura a imagem no meu bean, passo para minha entidade, do tipo byte[] com anotação @Lob maaaas ao pesistir o hibernate salva com NULL o campo.

Se achar uma solução aviso.

Tambem uso a anotação Lob e meu atributo é do tipo byte[] tambem, voce viu o pedaço de codigo que coloquei aqui? Criando um File e convertendo para bytes? Isso é a metade do caminho, quando eu coloco o caminho da foto na mao salva, quando tento pegar do form html que da erro.
Avisa sim, por favor, se eu descobrir algo, aviso tambem.
Valeu.

File file = new File(funcio.getFoto());
fis = new FileInputStream(file);
pstm.setBinaryStream(10, fis, (int) file.length());