Retornar vários objetos por um método [Resolvido]

isso:

<c:forEach var="imovel" items="${imovel}">

não é certo…

items tem que ser uma lista, e o var é a variável que vc chama cada elemento da lista…

o código está funcionando por coincidência…

se vc deu um result.include(“fotos”, …), vc tem que acessar no jsp via ${fotos}, e colocar isso na parte items:

 <c:forEach var="foto" items="${fotos}">    
         <tr>  
             <td>${foto.nome}</td>    
             <td>${foto.urlFoto}</td>
        </tr>
     </c:forEach>

Agradeço aos dois pela ajuda. :smiley:
Sabem me dizer como carrego um objeto pela FK neste exemplo?

public Foto carrega(Long idImovel) {
		    return (Foto) this.session.load(Foto.class, idImovel);
	 }

No exemplo o id é do imóvel que é a FK de foto e não a PK.
Tô dando ctrl+space pra descobrir qual seria o parâmetro pra isso mas não consegui descobrir.

session.createQuery("from Foto f where f.idImovel = :id")
   .setParameter("id", idImovel)
   .uniqueResult();

Obrigado Lucas. =)
Vou ver o que consigo aqui.

Consegui pegar os endereços e jogar na JSP, mas aconteceu o que eu imaginava, tá pegando o caminho como se fosse dentro do contexto da aplicação, quando na verdade está fora:
Tá mostrando assim:

http://localhost:8080/imobiliaria/home/bruno/fotos/42.xx.252(1).jpg

O código na JSP que usei foi este:

<img src="${pageContext.request.contextPath}/home/bruno/fotos/${foto.urlFoto }"/> 

Alguém conhece alguma EL ou taglib que consiga acessar o contexto externo?
Tõ pesquisando por “external context path”.
Abraço!

<img src="<c:url value="/home/bruno/fotos/${foto.urlFoto }"/>" />

Oi Lucas!
Não deu certo, ele continua pegando como se fosse dentro do contexto da aplicação:

http://localhost:8080/imobiliaria/home/bruno/fotos/42.xx.252(1).jpg

Será que rola criar um contexto apontando para a pasta dentro de algum xml? Algo como:

<Context path="/home/bruno/fotos" docBase="/home/bruno/fotos"
//alguma coisa aqui que não faço idéia.
</Context>

vc quer que vá pra uma pasta física dentro do seu computador?

você não deveria fazer isso nunca na vida… imagina se eu chamar: http://localhost:8080/imobiliaria/etc/passwd
eu veria seus passwords!

se vc quiser fazer essa correspondência, crie uma lógica do tipo:

@Path("/imagens/{caminho*}")
public InputStream imagem(String caminho) {
    try {
        return new FileInputStream("/home/bruno/fotos/" + caminho);
    } catch (FileNotFoundException e) {
         result.notFound();
         return null;
    }
}

daí vc só acessa http://localhost:8080/imobiliaria/imagens/42.xx.252(1).jpg e ele mapeia para a pasta física

(claro que vc vai mudar o código que eu passei, pra ele ficar mais configurável e tal, isso eh soh um exemplo)

Beleza Lucas!
Vou tentar aqui com essa lógica.
Eu tentei aqui com:

 <img src="<c:url value="file:///home/bruno/fotos/${foto.urlFoto }"/>" /> 

Na JSP não mostra a imagem, mas se eu pegar o endereço file:///home/bruno/fotos/42.xx.252(1).jpg que aparece num pequeno retângulo onde deveria aparecer a imagem e jogar no browser a imagem aparece. Essa tática de usar o endereço físico file:/// tb é furada?
Abraço!

Na JSP não mostra a imagem mas o caminho mostra corretamente:

http://localhost:8080/imobiliaria/imagem/42.xx.252(1).jpg

No Controller:

@Get
	 @Path("/imagem/")
	 public InputStream getPasta() {		 
	    return imagens.getPasta(); 
	 }

	 public void adiciona(Long idImovel) {
		 result.include("imovel", imovelDAO.carrega(idImovel));	
		 result.include("fotos", fotoDAO.getGaleria(idImovel));	// aqui eu mando o nome completo da foto
	 }

No Componente Imagens:

public InputStream getPasta() {		 
		 try {
	         return new FileInputStream(pastaImagens);
	     } catch (java.io.FileNotFoundException e) {
	          return null;
	     }	
	 }

Mas não está instanciando o método InputStream, coloquei um breakpoint nos retornos de cada método mas passa batido.
Se o método funcionar acredito que a imagem apareça na JSP. =)

não use file://

faça o controller exatamente do jeito que eu coloquei na minha última mensagem…

Então Lucas, o método está retornando null, colocando no componente ou no controller:

public InputStream getPasta() {		 
		 try {
	         return new FileInputStream(pastaImagens);
	     } catch (FileNotFoundException e) {
	          return null;
	     }	
	 }

Retorna null no debug.
Eu tô colocando no componente pq lá já tenho o caminho:

public Imagens() {			  		 
		String pastaImagens = "/home/bruno/fotos";
		this.pastaImagens = new File(pastaImagens);   
		File destino = new File(pastaImagens);
		destino.mkdir();
	}

No Controller:

 @Get
	 @Path("/imagem/")
	 public InputStream imagem() {
			 return imagens.getPasta();
	 }	

Mesmo colocando o código todo no controller retorna null, não está criando a pasta.

a idéia da lógica do controller NÃO é retornar a pasta…

é retornar a imagem direto! vc não pode retornar uma pasta como inputStream!!! nem faz sentido…

o que vc tem que fazer no controller é o que eu falei pra vc fazer naquela mensagem:

 @Get  
 @Path("/imagem/{caminho*}")  
 public InputStream imagem(String caminho) {  
    try {
       return new FileInputStream(new File(caminho, imagens.getPasta()));  
    } catch (FileNotFoundException e) {
        result.notFound();
        return null;
    }
 }

quanto a não criar a pasta, vc deu uma olhada no sistema pra ver se ela existe mesmo? vc tem permissão pra criar essa pasta, a partir da sua app?

Oi Lucas!
A pasta está liberada para incluir e deletar fotos, eu segui a sua lógica, mas o problema é que preciso passar a ID do imóvel para que sejam carregadas as fotos daquele imóvel, não dá pra colocar apenas uma String caminho, preciso da ID do imóvel, então fiz assim:
No componente:

public InputStream getPasta(Long idImovel) {
		FileInputStream destino = null;
		FotoDAO fotoDAO = new FotoDAO();
		List<Foto> fotos = fotoDAO.getGaleria(idImovel);
		for (Foto foto : fotos) {
			try {
				destino = new FileInputStream(new File(pastaImagens, foto.getUrlFoto()));
			} catch (java.io.FileNotFoundException e) {
				e.printStackTrace();
			}

		}
		return destino;
	}

Coloquei um breakpoint pra saber se o return tá mandando alguma coisa:

E no controller eu envio esse InputStream via result.include quando a página adiciona.jsp é chamada:

public void adiciona(Long idImovel) {
		 result.include("imovel", imovelDAO.carrega(idImovel));	
		 result.include("fotos", imagens.getPasta(idImovel));		 
	 }

Agora o que eu não consegui achar é como mostrar isso na JSP.

vc não vai conseguir mostrar o inputStream via variável… vc precisa criar uma lógica que retorna esse inputStream mesmo, e na jsp vc chama essa lógica dentro de uma tag img, por exemplo:

<img src="/imagem/${imovel.id}" alt="imovel.nome"/>

e a lógica que responde por /imagem/{imovel.id} vai retornar o InputStream…

Fiz uns testes aqui e constatei que só o result.include consegue trazer os dados das fotos, se eu colocar o método no Controller vêm td null.

@Path("/imagem/{imovel.idImovel}/")
	public InputStream imagem(Long idImovel) {
FileInputStream destino = null;
		FotoDAO fotoDAO = new FotoDAO();
		List<Foto> fotos = fotoDAO.getGaleria(idImovel);
		for (Foto foto : fotos) {
			try {
				destino = new FileInputStream(new File("/home/bruno/fotos", foto.getUrlFoto()));
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}

		}
		return destino;
	}

se vc tem um parâmetro Long idImovel, o parâmetro no @Path tem que se chamar idImovel

@Path("/imagem/{idImovel}/")

e se vc tem várias imagens por imóvel, vc precisa pegar pelo id da Foto, não pelo id do imóvel…

        @Path("/imagem/{idFoto}")
	public InputStream imagem(Long idFoto) {
		FotoDAO fotoDAO = new FotoDAO();// vc não deveria fazer isso aqui! receba no construtor!
		Foto foto = fotoDAO.carrega(idFoto);
		
		try {
			return new FileInputStream(new File("/home/bruno/fotos", foto.getUrlFoto()));
		} catch (FileNotFoundException e) {
			result.notFound(); // receba esse result no construtor tb
			return null;
		}
	}

e na listagem do imóvel vc vai criar as <img baseado no id de cada foto do imóvel

Não entendo uma coisa… você faz um loop em várias fotos mas retorna apenas o stream da última? Analise o seu loop e veja que você retorna o stream apenas da última. Além disso você não deveria retornar um stream para o JSP, e sim retornar um FileDownloadStream no seu método.

Outra coisa, não esconda as exceptions, isso é muito perigoso. Se algum erro acontecer você nunca saberá. Apenas faça um catch se você quer tratar a exception.

Segue um exemplo meu usando os componentes de download do vraptor. No meu caso esse código é de uma ferramenta de geoprocessamento que a partir de uma coordenada geografica traz o mapa do local.

[code] @Path("/l10n/map/{coordX}/{coordY}/")
public Download map(double coordX, double coordY)
throws IOException {
FilePNG png = gisRemote.find(coordX, coordY);

    return new InputStreamDownload(file.getStream(), "image/png", file.getName());
}

[/code]

se vc retorna um InputStream o vraptor transforma em download automaticamente

Hmm, achei que era apenas <? implements Download> (nos docs não diz isso). Mas faz sentido já que o File também faz download.