Solucionado (ver solução)
Solucionado
(ver solução)
42
respostas

Trabalhar com imagens externas no VRaptor

Boa tarde pessoal!

Eu preciso carregar uma imagem no meu .jsp As imagens estão em diretório do meu servidor, como por exemplo F:\Produtos\Imagens Na minha tabela de Produtos eu tenho dois atributos para isso "localImagem" e "imagem", que refere-se ao nome da imagem Ao selecionar um registro na tabela de produtos eu quero carregar essa imagem em um input

<label>Imagem:</label>
<img scr="localImagem" + "imagem">

Eu tentei implementar com base no e-book vraptor-desenvolvimento-agil-para-web-com-java, com base no Cap 8 - Downloads e Uploads de arquivos.

Eu criei a interface Diretório:

import java.net.URI;

public interface Diretorio {

    URI salva(Arquivo arquivo);

    Arquivo recupera(URI chave);
}

E criei a classe Arquivo:

public class Arquivo {

    private String caminho;
    private String nome;

    public Arquivo(String caminho, String nome) {
        this.caminho = caminho;
        this.nome = nome;
    }

    public String getCaminho() {
        return caminho;
    }

    public void setCaminho(String caminho) {
        this.caminho = caminho;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }
}

Como eu consigo carregar essa imagem ??

OBSERVAÇÃO : Me pediram para evitar ao MÁXIMO o uso de JAVA SCRIPT no projeto.

Obrigado!

42 respostas
@Controller
public class ImagensController {
    public Download download(String caminho) {
        File file = new File(caminho);
        return new FileDownload(file);
    }
}

Na sua página, pode ficar parecido com o seguinte:

<img scr="<c:url value="/imagens/download?caminho=${arquivo.caminho}"/>"/>

O último passo é que vc vai precisar disponibilizar um objeto do tipo arquivo na página, com as informações necessárias.

Tem mais dicas na documentação do vraptor => http://www.vraptor.org/pt/docs/download-e-upload/

Alberto, vendo seu exemplo e a documentação, criei o controller:

package br.com.ebf.controller;

import java.io.File;
import br.com.caelum.vraptor.Controller;
import br.com.ebf.modelo.Produto;

@Controller
public class ImagemController {
    public File imgProduto(Produto produto) {
        File arquivo = new File(produto.getLocalImagem() + produto.getImagem());
        return arquivo;
    }
}

Ai eu tenho o input no form.jsp:

<img src = "<c:url value="/imagem/imgProduto?..."/>"/>

Depois do interrogação como fica?

Então, o exemplo que eu deixei indica que vc retorne um FileDownload.. é ele que vc deve retornar, como está demonstrado. E eu também deixei o exemplo de como ficaria a tag de imagem... Aí vc tem duas opções:

1) ou vc faz daquele jeito 2) ou vc adapta, testa e me diz se deu algum erro. Em vez de receber um produto, eu receberia o id do produto, recuperaria ele do banco e chamaria os métodos que dão o caminho da imagem.

Na documentação do VRaptor, ao "pé da letra" a implementação está desse forma:

@Controller
public class PerfilController {

    public File foto(Perfil perfil) {
        return new File("/path/para/a/foto." + perfil.getId()+ ".jpg");
    }
}

Eu adaptei para :

package br.com.ebf.controller;

import java.io.File;

import br.com.caelum.vraptor.Controller;
import br.com.ebf.modelo.Produto;

@Controller
public class ImagemController {

    public File imgProduto(Produto produto) {
        return new File(produto.getLocalImagem() + produto.getImagem());        
    }
}

Teoricamente eu preciso de um controller, para informar para a View (.jsp) qual o endereço e o nome do arquivo que deve ser passado como parâmetro para a tag Pois quando eu dou um produto.getLocalImagem(), retorna por exemplo "F:\Produtos\Imagens" E no produto.getImagem()), retorna "bike.jpg"

<img src="<c:url value= ... " />"/>

Está correta essa implementação ? Se sim qual o próximo passo...

Ewerton, acho que não entendi. Qual o próximo passo que vc quer? Vc já tem o controller e já sabe o que colocar na view. Para mim, o próximo passo eh vc tentar implementar. Eu só não receberia o produto como argumento, receberia uma string representando parte do endereço, ou o endereço completo.

Na implementação que vc postou:

1    public Download download(String caminho) {
2        File file = new File(caminho);
3        return new FileDownload(file);
    }

Na linha "3", primeiro o Eclipse acusa => Add argument to match FileDownload(File, String) Depois ele pede para adicionar Try/Catch

E o código fica:

    public Download download(String caminho) {
        File file = new File(caminho);
        try {
            return new FileDownload(file, caminho);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

E no jsp:

<img scr="<c:url value="/imagens/download?caminho=${arquivo.caminho}"/>"/>

Não gerou erro no browser e nem no console, porém também não carregou a imagem...

Alberto, o problema está no controller... Adicionei no jsp, a linha abaixo, para ver o que ele mostraria na tela:

${linkTo[ImagemController].download()}

Mostrou:

 /ebf-catalogo/imagem/download

Sendo que deveria ter mostrado:

C:\Users\edonati\Pictures\foto.jpg

Que no caso é o conteúdo dos dois atributos, concatenados...

Mas o linkTo não vai mostrar o caminho para sua imagem.. o linkTo é para mostrar o caminho do método do controller, está certo. Para vc montar a url da imagem, vc vai precisar do produto e dos métodos que são chamados para retornar o caminho da imagem.

Em relação ao erro, é o que tem na documentação:

@Controller
public class PerfilController {
    public Download foto(Perfil perfil) {
        File file = new File("/caminho/para/a/foto." + perfil.getId()+ ".jpg");
        String contentType = "image/jpg";
        String filename = perfil.getNome() + ".jpg";

        return new FileDownload(file, contentType, filename);
    }
}

Você precisa passar o contentType e o nome do arquivo. E é como vc disse, pode deixar só o file também, já que a documentação diz que o Vraptor aceita :).

Isso:

    public Download imgProduto(Produto produto) {
        File file = new File("/caminho/para/a/foto." + produto.getId() + ".jpg");
        String contentType = "image/jpg";
        String filename = produto.getLocalImagem() + produto.getImagem() + ".jpg";
        try {
            return new FileDownload(file, contentType, filename);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

Alberto, achei o pq não estava gerando erro no console e no browser... Ao invéz de "src ", estava "scr"... Alterei:

<img src="<c:url value="/imagem/imgProduto?caminho=${arquivo.caminho}"/>"/>

Agora gera o erro no browser:

GET http://localhost:8080/ebf-catalogo/imagem/imgProduto?caminho= 404 ()

E no console:

java.io.FileNotFoundException: File foto.null.jpg doesn't exists
    at br.com.caelum.vraptor.observer.download.FileDownload.checkFile(FileDownload.java:70)
    at br.com.caelum.vraptor.observer.download.FileDownload.<init>(FileDownload.java:54)
    at br.com.caelum.vraptor.observer.download.FileDownload.<init>(FileDownload.java:46)
    at br.com.ebf.controller.ImagemController.imgProduto(ImagemController.java:19)
    at br.com.ebf.controller.ImagemController$Proxy$_$$_WeldClientProxy.imgProduto(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)

O caminho está "null"

http://localhost:8080/ebf-catalogo/imagem/imgProduto?caminho=

No ProdutoController eu tenho o método atualiza(), que por sua vez chama o buscaPorId()... Dei um syso no localImagem e imagem, e me retournou a informação correta... Eu não poderia usar esse método para carregar a url da imagem ??

.....

Para o código funcionar vc precisa passar o parâmetro no link da imagem. Você precisa fazer chegar um objeto na view, chamar os métodos necessários para montar o caminho físico da imagem e passar isso como argumento ali na ?.

Com base no e-book vraptor-desenvolvimento-agil-para-web-com-java, fiz as alterações...

Criei a interface Diretorio:

package br.com.ebf.modelo;

import java.net.URI;

public interface Diretorio {

    URI grava(Arquivo arquivo);

    Arquivo recupera(URI chave);
}

Criei a classe DiretorioDeImagens:

package br.com.ebf.modelo;

import java.net.URI;

import javax.inject.Inject;
import javax.persistence.EntityManager;

public class DiretorioDeImagens implements Diretorio {

    private EntityManager manager;
    private Produto produto;

    @Inject
    public DiretorioDeImagens(EntityManager manager, Produto produto) {
        this.manager = manager;
        this.produto = produto;
    }

    // PARA USO DO CDI
    public DiretorioDeImagens() {
    }

    @Override
    public URI grava(Arquivo arquivo) {
        return null;
    }

    @Override
    public Arquivo recupera(URI chave) {
        if (chave == null)
            return null;

        if (!chave.getScheme().equals(produto.getLocalImagem())) {
            throw new IllegalArgumentException(chave + "não é uma URI do diretório de imagens.");
        }

        Long id = Long.valueOf(chave.getAuthority());
        return manager.find(Arquivo.class, id);
    }
}

Criei a classe Arquivo:

package br.com.ebf.modelo;

public class Arquivo {

    private String nome;
    private byte[] conteudo;
    private String contentType;

    public Arquivo(String nome, byte[] conteudo, String contentType) {
        this.nome = nome;
        this.conteudo = conteudo;
        this.contentType = contentType;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public byte[] getConteudo() {
        return conteudo;
    }

    public void setConteudo(byte[] conteudo) {
        this.conteudo = conteudo;
    }

    public String getContentType() {
        return contentType;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }
}

Alterei o construtor do ProdutoController:

    @Inject
    public ProdutoController(ProdutoDao produtoDao, Diretorio imagens, Result result, Validator validator) {
        this.produtoDao = produtoDao;
        this.imagens = imagens;
        this.result = result;
        this.validator = validator;

    }

E no ProdutoController, criei o método para retornar a imagem:

    @Get("/produto/{id}/imgProduto")
    public Download imgProduto(Integer id) {
        Produto produto = produtoDao.buscaPorId(id);
        Arquivo imgProduto = imagens.recupera(produto.getLocalImagem());
        return new ByteArrayDownload(imgProduto.getConteudo(), imgProduto.getContentType(), imgProduto.getNome());
    }

Porém o Eclise está reclamando dessa implementação... Erro:

The method recupera(URI) in the type Diretorio is not applicable for the arguments (String)

3 quick fixes avaliable:

Change method 'recupera URI' to 'recupera String'
Change return method type 'getLocalImagem(...)' to 'URI'
Change method 'recupera (String)' in type 'Diretorio'

Escolhi a segunda opção, e alterei o getLocalImagem, na classe Produto:

    public URI getLocalImagem() {
        if (localImagem == null)
            return null;
        return URI.create(localImagem);
    }

    public void setLocalImagem(URI localImagem) {
        this.localImagem = localImagem == null ? null : localImagem.toString();
    }

Porém ao tentar carregar a lista de produtos, não carregou mais os itens da tabela, verifiquei que no console do Eclipse, gerou erro:

fev 06, 2017 9:55:29 AM org.apache.catalina.core.ApplicationDispatcher invoke
GRAVE: Servlet.service() for servlet jsp threw exception
java.net.URISyntaxException: Illegal character in opaque part at index 2: C:\Users\edonati\Pictures
    at java.net.URI$Parser.fail(Unknown Source)
    at java.net.URI$Parser.checkChars(Unknown Source)
    at java.net.URI$Parser.parse(Unknown Source)
    at java.net.URI.<init>(Unknown Source)
    at java.net.URI.create(Unknown Source)
    at br.com.ebf.modelo.Produto.getLocalImagem(Produto.java:472)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)

Mais abaixo outra msg do erro:

fev 06, 2017 9:55:29 AM org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: Servlet.service() for servlet [default] in context with path [/ebf-catalogo] threw exception [/WEB-INF/jsp/produto/listaVaz.jsp raised an exception] with root cause
java.net.URISyntaxException: Illegal character in opaque part at index 2: C:\Users\edonati\Pictures
    at java.net.URI$Parser.fail(Unknown Source)
    at java.net.URI$Parser.checkChars(Unknown Source)
    at java.net.URI$Parser.parse(Unknown Source)
    at java.net.URI.<init>(Unknown Source)
    at java.net.URI.create(Unknown Source)
    at br.com.ebf.modelo.Produto.getLocalImagem(Produto.java:472)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)

Essa "\"(barra ao contrário típica do windows) não é suportada... vc precisa escapar.. Basicamente o caminho tem que ficar assim:

URI.create("C:\\Users\\edonati\\Pictures");

Alterei o registro de um produto, colocando em o valor "C:\Users\edonati\Pictures", para localImagem...

Não carregou a listagem e gerou o erro, no console do Eclipse:

fev 06, 2017 11:57:41 AM org.apache.catalina.core.ApplicationDispatcher invoke
GRAVE: Servlet.service() for servlet jsp threw exception
java.net.URISyntaxException: Illegal character in opaque part at index 2: C:\\Users\\edonati\\Pictures
    at java.net.URI$Parser.fail(Unknown Source)
    at java.net.URI$Parser.checkChars(Unknown Source)
    at java.net.URI$Parser.parse(Unknown Source)
    at java.net.URI.<init>(Unknown Source)
    at java.net.URI.create(Unknown Source)

Alterando na classe Produto o getLocalImagem, para:

    public URI getLocalImagem() {
        if (localImagem == null)
            return null;
        return URI.create("C:\\Users\\edonati\\Pictures");
    }

Não carregou a listagem e gerou o msm erro no console do Eclipse:

fev 06, 2017 11:52:25 AM org.apache.catalina.core.ApplicationDispatcher invoke
GRAVE: Servlet.service() for servlet jsp threw exception
java.net.URISyntaxException: Illegal character in opaque part at index 2: C:\Users\edonati\Pictures
    at java.net.URI$Parser.fail(Unknown Source)
    at java.net.URI$Parser.checkChars(Unknown Source)
    at java.net.URI$Parser.parse(Unknown Source)
    at java.net.URI.<init>(Unknown Source)
    at java.net.URI.create(Unknown Source)

Não fica melhor se eu atualizar o fonte no Drive, acho q fica mais fácil de vc me ajudar...

Não estou conseguindo ver o seu drive.. e tb não consigo rodar mas nada. De todo jeito, coloca lá e vamos vendo.

Atualizei => https://drive.google.com/drive/folders/0B1n2t9Tjxu9GckdsZEowUGRxT2s?usp=sharing

Caso vc não consiga abrir o drive, me passe um e-mail que eu te mando um ".zip" do projeto....

Obrigado pela ajuda, Alberto!!

Pessoal ??

Opa Ewerton, lembra que o fórum é para te ajudar.. enquanto ninguém responde, você tem que ir testando. Só assim para você aprender e não passar pelos mesmos problemas que está enfrentando agora.

@Controller
public class ImagemController {

    @Inject
    private ProdutoDao produtoDao;

    public File imgProduto(Integer id) {
        Produto produto = produtoDao.buscaPorId(id);
        //aqui vc precisa colocar duas barras ao contrário.
        //se certifique que esse caminho aponta para uma imagem também, não é para apontar para um diretório.
        String caminho = produto.getLocalImagem() + produto.getImagem();
        File arquivo = new File(caminho);
        return arquivo;
    }
}

Esse é o código que vc deve escrever no seu controller. .. é como eu disse, se vc receber o erro, não tentar interpretar e só ficar postando aqui, vai ficar sempre a mercê do tempo de resposta do fórum. Tentamos responder o mais rápido possível, mas não na velocidade que vc ta esperando.

Opa Alberto, só lembrando que eu não estou de braços cruzados esperando a resposta não... Estou tentando resolver também... Implemento, posto as alterações feiras e o erro... Eu abri três posts, para esse msm projeto... Dois eu consegui resolver...

A estrutura criada está correta?

A interface Diretorio;
A classe DiretorioDeImagens;
A classe Arquivo;
O método imgProduto do tipo Dowload, no ProdutoController;
Os métodos get e set LocalImagem retornando uma URI;
E por fim o ImagemController;

Preciso dessa estrutura toda, para carregar uma imagem em um diretório da rede.

Eu gostaria de implementar com base em alguma documentação, pesquisei no blog da Caelum, mas não encontrei... Dessa forma não está dando certo, meu prazo já terminou, e uma coisa que teoricamente deveria ser simples está fazendo o projeto atrasar. Por gentileza, se alguém tiver algum material que possa me ajudar, favor me encaminhar.

Obrigado!

O que vc mandou aqui não é compatível com o código do zip que vc me enviou.. no seu zip, como eu já escrevi aqui, usa o file para retornar no método do controller. Eu já coloquei o código que eu tenho certeza que é suficiente para funcionar.

A exception que vc posta se refere a classe URI, que também não é utilizada no método de download do controller.

Alberto, adicionei as duas linhas no ImagemController:

Trocando '/' por '\'


caminho.replaceAll("\\", "\\\\");

e verificando se o caminho aponta para uma imagem:

if (!caminho.contains(".jpg")) {
    return null;
    } else {
        File arquivo = new File(caminho);
        return arquivo;
    }

Gerou o erro no console do Eclipse:

GRAVE: Servlet.service() for servlet [default] in context with path [/ebf-catalogo-mysql] threw exception
java.lang.NullPointerException
    at br.com.ebf.controller.ImagemController.imgProduto(ImagemController.java:19)
    at br.com.ebf.controller.ImagemController$Proxy$_$$_WeldClientProxy.imgProduto(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)

A linha se refere a:

String caminho = produto.getLocalImagem() + produto.getImagem();

O getLocalImagem e getImagem estão vindo nulos...

Adicionei um construtor para o ImagemController

    @Inject
    public ImagemController(ProdutoDao produtoDao, Produto produto, Result result) {
        this.produtoDao = produtoDao;
        this.produto = produto;
        this.result = result;
    }

E abaixo do produtoDao.buscaProdutoPorId():

result.include(produto);

Mas continuou retornando NPE...

Como eu consigo carregar as informações, alterando o método atualiza() do ProdutoController ? Passo produto, para o ImagemController lá... De alguma forma o ProdutoController, tem que se comunicar com o ImagemController, correto?

Então, enquanto vc não fizer exatamente o código que eu passei para você, não tenho como te ajudar mais. O seu controller só precisa do dao como dependência, o método de download recebe o id do produto.

Quando vc tiver esse código implementado, posta aqui a jsp, controller e aí, se eu souber, te ajudo.

Mas eu implementei como vc me passou:

package br.com.ebf.controller;

import java.io.File;

import javax.inject.Inject;

import br.com.caelum.vraptor.Controller;
import br.com.ebf.dao.ProdutoDao;
import br.com.ebf.modelo.Produto;

@Controller
public class ImagemController {

    @Inject
    private ProdutoDao produtoDao;

    public File imgProduto(Integer id) {
        Produto produto = produtoDao.buscaProdutoPorId(id);
        String caminho = produto.getLocalImagem() + produto.getImagem();

        /* Trocando '/' por '\\' */
        caminho.replaceAll("\\", "\\\\");

        /* Verificando se o caminho aponta para uma imagem */
        if (!caminho.contains(".jpg")) {
            return null;
        } else {
            File arquivo = new File(caminho);
            return arquivo;
        }
    }
}

Vc não falou pra eu implementar as duas linhas... Uma para trocar o o "\" pelo "\\" E outro para verificar se o caminho aponta para uma imagem...

Passei o produto no método atualiza do ProdutoController e agora está carregando, as informações que eu preciso...

    public void atualizaVaz(Integer id, Result result) {
        Produto produto = produtoDao.buscaProdutoPorId(id);
        result.include(produto);
        imagemController.imgProduto(produto.getId());        
        listaTipoProduto("VAZ");
        listaMontadora("VAZ");
        result.of(this).formVaz();
    }

Está gerando o erro:

fev 09, 2017 12:42:14 PM org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: Servlet.service() for servlet [default] in context with path [/ebf-catalogo-mysql] threw exception
java.util.regex.PatternSyntaxException: Unexpected internal error near index 1
\
 ^
    at java.util.regex.Pattern.error(Unknown Source)
    at java.util.regex.Pattern.compile(Unknown Source)
    at java.util.regex.Pattern.<init>(Unknown Source)
    at java.util.regex.Pattern.compile(Unknown Source)
    at java.lang.String.replaceAll(Unknown Source)

Na conversão... Linha:

caminho.replaceAll("\\", "\\\\");

É... tem que descobrir qual é o problema de parse aí.. infelizmente não sei qual é.

O problema do replace, já consegui resolver...

Quando eu chamei o método imgProduto() do ImagemController, "dentro" do atualiza() do ProdutoController, as variáveis produto.getId(); produto.getLocalImagem(); produto.getImagem() e a variável caminho foram populadas corretamente...

Mas no caso eu não preciso chamar método imgProduto() do ImagemController, no atualiza() do ProdutoController...

Quem deve chamar esse método é a View, correto?

Porém quando a view chama o método imgProduto(), do ImagemController as variáveis não são preenchidas... retornam "NULL"...

Por isso o erro NPE...

Se eu chamar o imgProduto() do ImagemController no método atualiza do ProdutoController...

Na primeira vez que o método é executado as variáveis são populadas... Mas depois a View chama novamente o método e os valores são perdidos...

Como eu consigo passar o "id" pro ImagemController ?

<img src="<c:url value="/imagem/imgProduto?id=${produto.id}"/>"/>

Como o produto vai chegar na sua jsp, é algo do seu projeto.

Sim essa é alinha que está no meu jsp.

Pq eu tentei passar no método atualiza() do ProdutoController, aconteceu o que eu descrevi antes... O projeto popula as variáveis no atualiza() e quando o jsp chama o imgProduto() do ImagemController as variáveis vem "null"

Onde eu devo passar a id pro Imagemcontroller, na chamada no meu form() no Produtocontroller ?

No src da imagem não é para ter link para o atualiza, apenas para o ImgController direto. O que acontece nas outras partes do código, aí já não sei.

Eu sei que não é pra ter link do atualiza no src da imagem... Vc não entendeu o q eu disse...

solução!

Por gentileza se você não quer ajudar, PARE de acompanhar meus posts, e tenha o mínimo de bom senso e profissionalismo de NÃO ATRAPALHAR !!! Deixe outra pessoa ajudar !!!

Ewerton, se vc olhar, já trocamos muitas mensagens... Isso representa a minha vontade em te ajudar, mas nem sempre é suficiente. Você tem casos que são específicos e realmente não é simples para a gente que tá de fora. De todo jeito, tomara que mais gente apareça para te ajudar

Bom dia Alberto!

Cara consegui resolver o problema... Verifiquei que não havia a necessidade de um controller para carregar a imagem... Exclui o ImagemController, e criei um método no ProdutoController:

    @Get("produto/{id}/imgProduto")
    public File imgProduto(Integer id) {
        Produto produto = produtoDao.buscaProdutoPorId(id);
        String caminho = produto.getLocalImagem() + "\\" + produto.getImagem();
        if (!caminho.contains("jpg")) {
            return null;
        } else {
            File arquivo = new File(caminho);
            return arquivo;
        }
    }

E no .jsp alterei para:

                    <label>Imagem do produto:</label>
                    <c:if test="${produto.localImagem != null && produto.imagem != null}">
                        <img src="${linkTo[ProdutoController].imgProduto(produto.id)}" width="200" height="200">
                    </c:if>

Ficou perfeito!! Obrigado pela ajuda!!

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software