Falaa galeraaa, blz?

Então, to sem postar aqui faz um tempinho, estou meio sem tempo devido a vida pessoal e profissional. Mas como prometido vou postar hoje sobre um assunto que muitos tem duvida. Como fazer um CRUD com imagens.

Nosso sistema final ficará com essa cara:

Vamos lá..

Nesse tutorial estarei utilizando a IDE Eclipse e banco de dados mysql como em todos os outros posts.

Veja como vai ficar o relacionamento do banco de dados:

Basicamente iremos cadastrar produtos e as imagens destes produtos.

Este projeto consistira de um sistema que iremos cadastrar o produto e depois iremos inserir as imagens utilizando o componente fileupload do primefaces ou iremos visualizar as imagem com o componente galleria também do primefaces.

Não irei entrar em muitos detalhes referente a criação do projeto ou configuração dos dependentes, para isso vocês podem olhar os outros posts que contenham CRUDs.

Estarei disponibilizando o download do .WAR no fim do post.

Além das bibliotecas mostradas nas outras postagem devemos adicionar estas duas extras:

E estas configurações adicionais no web.xml:

	<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>

Vou seguir a mesma estrutura de projetos que havia dito nos outros posts. Teremos os seguintes pacotes:

  • controller
  • dao
  • model
  • util

Vamos mapear nossas classes de banco de dados, primeiro a classe Produto:

@Entity
@Table(name = "PRODUTO")
public class Produto implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "PROD_ID")
	private long id;
	@Column(name = "PROD_NOME")
	private String nome;
	@Column(name = "PROD_PRECO")
	private double preco;

	// getters and setters

Classe Foto:

@Entity
@Table(name = "FOTO")
public class Foto implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "FOTO_ID")
	private long id;
	@Lob
	@Column(name = "FOTO_IMAGEM", columnDefinition = "LONGBLOB")
	private byte[] imagem;
	@Column(name = "FOTO_DESCRICAO")
	private String descricao;
	@ManyToOne
	@JoinColumn(name = "PROD_ID")
	private Produto produto;

	// getters and setters

Nossos DAOs, primeiramente o ProdutoDAO:

public class ProdutoDAO implements Serializable {
	private static final long serialVersionUID = 1L;

	protected Session session;

	public void save(Produto p) {
		session = HibernateUtil.getSessionfactory().openSession();

		try {
			session.getTransaction().begin();
			session.save(p);
			session.getTransaction().commit();
		} catch (HibernateException ex) {
			ex.printStackTrace();
		} finally {
			session.close();
		}
	}

	@SuppressWarnings("unchecked")
	public List<Produto> listAll() {
		session = HibernateUtil.getSessionfactory().openSession();

		try {
			return session.createCriteria(Produto.class, "p").list();
		} catch (HibernateException ex) {
			ex.printStackTrace();
		} finally {
			session.close();
		}

		return null;
	}
}

Agora o FotoDAO:

public class FotoDAO implements Serializable {
	private static final long serialVersionUID = 1L;

	protected Session session;

	public void save(Foto f) {
		session = HibernateUtil.getSessionfactory().openSession();

		try {
			session.getTransaction().begin();
			session.save(f);
			session.getTransaction().commit();
		} catch (HibernateException ex) {
			ex.printStackTrace();
		} finally {
			session.close();
		}
	}

	@SuppressWarnings("unchecked")
	public List<Foto> listByProdutos(long ID) {
		session = HibernateUtil.getSessionfactory().openSession();

		try {
			return session.createCriteria(Foto.class, "f")
					.createAlias("produto", "p")
					.add(Restrictions.eq("p.id", ID)).list();
		} catch (HibernateException ex) {
			ex.printStackTrace();
		} finally {
			session.close();
		}

		return null;
	}
}

A unica diferença dos outros posts será o nosso bean, que obrigatoriamente deve ser @SessionScoped para o fileupload funcionar, veja como ficou:

@ManagedBean(name = "mbProduto")
@SessionScoped
public class ProdutoBean implements Serializable {
	private static final long serialVersionUID = 1L;

	private List<Produto> produtos;
	private Produto produto = new Produto();
	private Produto produtoSelecionado = new Produto();;
	private ProdutoDAO produtoDAO;

	private List<Foto> fotos;
	private Foto foto = new Foto();
	private FotoDAO fotoDAO = new FotoDAO();

	public ProdutoBean() {
		produtoDAO = new ProdutoDAO();
		fotoDAO = new FotoDAO();

		produtos = produtoDAO.listAll();
	}

	public void salvaProduto() {

		try {
			produtoDAO.save(produto);
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			produto = new Produto();
			produtos = produtoDAO.listAll();

			FacesContext.getCurrentInstance().addMessage(
					null,
					new FacesMessage(FacesMessage.SEVERITY_INFO,
							"Produto adicionado", "Produto adicionado"));
		}
	}

	public void salvaFoto() {

		try {
			fotoDAO.save(foto);
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			foto = new Foto();

			FacesContext.getCurrentInstance().addMessage(
					null,
					new FacesMessage(FacesMessage.SEVERITY_INFO,
							"Foto adicionada", "Foto adicionada"));
		}

	}

	public void processFileUpload(FileUploadEvent uploadEvent) {

		try {
			foto.setProduto(produtoSelecionado);
			foto.setImagem(uploadEvent.getFile().getContents());
		} catch (Exception ex) {
			ex.printStackTrace();
		}

	}

	public void listaFotosProduto() {

		try {
			ServletContext sContext = (ServletContext) FacesContext
					.getCurrentInstance().getExternalContext().getContext();

			fotos = fotoDAO.listByProdutos(produtoSelecionado.getId());

			File folder = new File(sContext.getRealPath("/temp"));
			if (!folder.exists())
				folder.mkdirs();

			for (Foto f : fotos) {
				String nomeArquivo = f.getId() + ".jpg";
				String arquivo = sContext.getRealPath("/temp") + File.separator
						+ nomeArquivo;

				criaArquivo(f.getImagem(), arquivo);
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}

	}

	private void criaArquivo(byte[] bytes, String arquivo) {
		FileOutputStream fos;

		try {
			fos = new FileOutputStream(arquivo);
			fos.write(bytes);

			fos.flush();
			fos.close();
		} catch (FileNotFoundException ex) {
			ex.printStackTrace();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}

Explicação dos métodos:

processFileUpload() (LINHA: 56):

Método que será chamado pela view e será responsável pelo que deve ser feito com o arquivo, neste caso estamos definindo de qual produto é a foto.

listaFotosProduto() (LINHA: 67):

Método que será responsável por gerar a imagem para ser exibida na tela.

Acho que aqui é onde mais a galera tem dúvida, os arquivos devem ser criados dinamicamente e jogados dentro de uma pasta para serem exibidos na tela, pois o graphicImage não suporta conteúdos dinâmicos em listas.

criaArquivo (LINHA: 92):

Método responsável por criar uma pasta temporária no servidor para guardar as imagens para serem exibidas na tela.

Por fim, temos a nossa view, veja como ficou:

<h:body>

	<p:ajaxStatus
		style="width:64px;height:64px;position:fixed;right:5px;bottom:5px">
		<f:facet name="start">
			<p:graphicImage value="/images/loading.gif" />
		</f:facet>

		<f:facet name="complete">
			<h:outputText value="" />
		</f:facet>
	</p:ajaxStatus>

	<h:form id="form" enctype="multipart/form-data">
		<p:growl id="msgs" showDetail="false" showSummary="true" />

		<p:panel>
			<h:panelGrid columns="2">
				<h:outputText value="Nome:" />
				<p:inputText value="#{mbProduto.produto.nome}" />

				<h:outputText value="Preço:" />
				<p:inputText value="#{mbProduto.produto.preco}" />

				<p:commandButton value="Salvar" action="#{mbProduto.salvaProduto()}"
					update=":form:msgs, :form:dtProdutos, :form" />
				<p:commandButton value="Limpar" onclick="form.reset()" />
			</h:panelGrid>
		</p:panel>

		<p:dataTable id="dtProdutos" value="#{mbProduto.produtos}" var="p"
			style="text-align: center;" emptyMessage="Nenhum produto cadastrado.">
			<p:column headerText="ID" style="width:2%; font-weight: bold;">
				<h:outputText value="#{p.id}" />
			</p:column>

			<p:column headerText="Nome" style="width:24%">
				<h:outputText value="#{p.nome}" />
			</p:column>

			<p:column headerText="Preço" style="width:24%">
				<h:outputText value="#{p.preco}" />
			</p:column>

			<p:column style="width:4%">
				<p:commandButton id="addButton" update=":form:infoFoto"
					oncomplete="fotoDialog.show()" icon="ui-icon-plus"
					title="Adicionar imagens">
					<f:setPropertyActionListener value="#{p}"
						target="#{mbProduto.produtoSelecionado}" />
				</p:commandButton>

				<p:spacer width="10" />

				<p:commandButton id="showButton" update=":form:infoProduto"
					oncomplete="produtoDialog.show()" icon="ui-icon-search"
					title="Visualizar imagens" action="#{mbProduto.listaFotosProduto}">
					<f:setPropertyActionListener value="#{p}"
						target="#{mbProduto.produtoSelecionado}" />
				</p:commandButton>
			</p:column>
		</p:dataTable>

		<p:dialog header="Detalhes do produto" widgetVar="produtoDialog"
			resizable="false" id="produtoDlg" showEffect="fade"
			hideEffect="explode" modal="true" draggable="true" maximizable="true"
			minimizable="true">

			<h:panelGrid id="infoProduto" columns="2" style="margin:0 auto;">

				<h:outputText value="Nenhnuma imagem encontrada"
					rendered="#{mbProduto.fotos.size() == 0}" />

				<p:galleria var="f" value="#{mbProduto.fotos}" effect="slide"
					effectSpeed="100" panelHeight="250" panelWidth="500"
					frameHeight="70" frameWidth="160" filmstripPosition="bottom"
					showOverlays="true">

					<p:graphicImage value="/temp/#{f.id}.jpg" cache="false" width="500"
						height="250" />
					<p:galleriaOverlay title="Descrição:">
						<h:outputText value="#{f.descricao}" />
					</p:galleriaOverlay>

				</p:galleria>
			</h:panelGrid>
		</p:dialog>

		<p:dialog header="Adicionar imagens" widgetVar="fotoDialog"
			position="center" resizable="false" id="fotoDlg" showEffect="fade"
			hideEffect="explode" modal="true" width="800">

			<h:panelGrid id="infoFoto" columns="2">

				<h:outputText value="Foto: " />
				<p:fileUpload fileUploadListener="#{mbProduto.processFileUpload}"
					label="Escolher" cancelLabel="Cancelar" sizeLimit="400000"
					invalidSizeMessage="Imagem muito grande" auto="true"
					invalidFileMessage="Tipo de imagem não suportado"
					allowTypes="/(\.|\/)(jpe?g|png)$/" />

				<h:outputText value="Descrição: " />
				<p:inputText value="#{mbProduto.foto.descricao}" />

				<p:commandButton value="Adicionar" icon="ui-icon-plus"
					action="#{mbProduto.salvaFoto()}" update="infoFoto, form" />

			</h:panelGrid>
		</p:dialog>
	</h:form>
</h:body>

Download do projeto final: Produtos.war

Bom, acho que é isso pessoal. Caso tenham alguma dúvida podem perguntar ai nos comentários, responderei o mais rápido possível.

Se tiverem sugestões também fiquem a vontade para postar.

Até mais !!

Anúncios