Um problema que me deu dor de cabeça:
Fazer upload de imagem via ajax e dar um preview, utilizando o componente fileupload do Primefaces. Já estava me sentindo derrotado com o problema.
O componente é bizonho, (Spoiler alert!) ele não funciona fora de um SessionScoped . Mas, como sou guerreiro, e como a arquitetura da minha aplicação precisa de ManagedBeans com ViewScoped , Entoado por canções de cunho moral, eu insisti e consegui contornar o problema.
Outro alerta de spoiler:
Ainda não testei em plenos vapores de ambiente de produção, se alguém encontrar um erro, por favor relate e talvez em menos de um ano eu responda.
Primeiro passo:
Criar um ManagedBean, do tipo SessionScoped :
@ManagedBean @SessionScoped public class ImageBean { StreamedContent st; public void uploadImagem(byte[] imagem){ st = new DefaultStreamedContent(new ByteArrayInputStream(imagem)); } public StreamedContent getSt() { return st; } }
Nesse ManagedBean, incluímos um objeto StreamedContent , que vai possibilitar o preview da imagem no componente graphicimage do Primefaces, e um método que recebe um bytearray que é a imagem. No caso, esse método pode ser adaptado, eu estou utilizando um tipo bytearray porque gravo a imagem no banco.
Depois disso, vamos tratar do nosso ManagedBean da página:
@ManagedBean @ViewScoped public class CadastrarPessoaBean { @EJB PessoaFacade pessoaFacade; @ManagedProperty(value="#{imageBean}") ImageBean imageBean; Pessoa pessoa = new Pessoa(); public void anexaArquivo(FileUploadEvent event) { try { this.pessoa.setFoto(IOUtils.toByteArray(event.getFile().getInputstream())); imageBean.uploadImagem(this.pessoa.getFoto()); } catch (IOException e) { /* Joga alguma mensagem na tela! */ } } }
Aqui, criei um método chamado anexaArquivo, este método vai primeiro, popular meu objeto Pessoa para salvar a foto em banco, e depois vai popular o ImageBean.
Por fim, adicionamos os componentes nas páginas, e é só aproveitar a magia:
<h:panelGroup id="imagemJogador"> <p:graphicImage id="foto_jogador" style="max-width: 300px;max-height: 300px;" cache="false" value="#{imageBean.st}"> </p:graphicImage><br/> </h:panelGroup> <p:fileUpload fileUploadListener="#{jogadorCadastrarBean.anexaArquivo}" mode="advanced" showButtons="false" label="#{lang.procurar}" update="imagemJogador" auto="true" sizeLimit="#{jogadorCadastrarBean.maxSize}" allowTypes="/(\.|\/)(gif|jpe?g|png)$/" ></p:fileUpload> <p:growl id="messages" showDetail="true" />
Vejam só, o componente p:fileUpload possui um método chamado fileUploadListener, que foi colocado no ManagedBean da página, e o componente p:graphicImage busca o StreamedContent lá no Imagebean
É claro isso é um exemplo cru, eu deixei desta forma para que fique simples e fácil de entender(Eu acho). Algo direto, dentro disso você pode(e DEVE) garantir validações de arquivo, tamanho de arquivo, e etc. dentro do ManagedBean.
Muito bom! Tirei minha dúvida e vou implementas deste forma!!
Parabéns.
Obrigado pelo comentário. Caso haja algum problema ou melhoramento, mande novo comentário que eu atualizo o Post!