Forums

Home » Liferay Portal » Español » General »

Combination View Flat View Tree View
Threads [ Previous | Next ]
toggle
Borxa Varela Bouzas
Descargar un archivo mediante un servlet en un portlet
July 24, 2007 11:37 AM
Answer

Borxa Varela Bouzas

Rank: Junior Member

Posts: 58

Join Date: December 26, 2006

Recent Posts

Estoy intentando crear un portlet de mapas con puntos geoposicionados.

Estoy utilizando las librerías java de mapserver, mapscript.jar, la cuales he integrado sin problemas.

Dichas librerías para trabajar necesitan un archivo de configuración para cada mapa, que llamaré mapa.map

En la configuración del portlet he creado la estructura para añadir el archivo, y funciona sin problemas para subirlo, borrarlo o cambiarlo. Pero además me gustaría, que al pinchar sobre el, pudiese descargar el archivo, y es cuando aparecen los problemas.

En el archivo edit_configuration.jsp del portlet he añadido:

<form action="<liferay-portlet:actionURL portletConfiguration="true"/>" class="uni-form" method="post" name="<portlet:namespace />fm_getfile">
    <input name="<portlet:namespace /><%= Constants.CMD %>" type="hidden" value="get_file" />
    <input name="<portlet:namespace />mapId" type="hidden" value="<%= new Long(plid).toString() %>" />
    <%= PrefsParamUtil.getString(prefs, request, "fileName") %></a>
</form>


Y luego en la clase EditConfigurationAction del portlet he creado un metodo para obtener el fichero, que se llama cuando el parametro cmd es igual a get_file (enviado por el formulario):

protected void getFileEntry(int mapId, HttpServletResponse res)
                throws Exception {
            
            String fileName = MapFilesLocalServiceUtil.getFileName(mapId);
                  
            res.getOutputStream().write(MapFilesLocalServiceUtil.getFileAsBytes(mapId,fileName));
            res.getOutputStream().flush();
          //InputStream is = MapFilesLocalServiceUtil.getFileAsStream(mapId,fileName);   
          //ServletResponseUtil.sendFile(res, fileName, is);      
          //ServletResponseUtil.cleanUp(is);
        }


Pero tanto probando con el codigo actual, como con la versión que tengo comentada, me devuelve el mismo error:

18:06:03,891 ERROR [taglib.util.IncludeTag] java.lang.IllegalStateException
        at com.liferay.filters.strip.StripResponse.getWriter(StripResponse.java:84)
        at org.apache.jasper.runtime.JspWriterImpl.initOut(JspWriterImpl.java:125)
        at org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:118)
        at org.apache.jasper.runtime.JspWriterImpl.write(JspWriterImpl.java:326)
        at org.apache.jasper.runtime.JspWriterImpl.write(JspWriterImpl.java:342)
        at org.apache.jasper.runtime.JspWriterImpl.print(JspWriterImpl.java:468)
        at com.liferay.taglib.util.ThemeUtil.includeVM(ThemeUtil.java:201)
        ...


He estado buscando por los foros de habla inglesa, y he encontrado que el posible problema sea un estado que tiene que tener el portlet para poder enviar el archivo (Exclusive state).
http://www.liferay.com/web/guest/community/forums/message_boards/message/112909

Y no se donde o como indicarle dicho estado al portlet, o si el error está en otro lado. ¿Alguién que ten un portlet en el que se pueda descargar un archivo en la parte de configuración me podría hechar una mano?
Jorge Ferrer
RE: Descargar un archivo mediante un servlet en un portlet
July 29, 2007 1:20 PM
Answer

Jorge Ferrer

LIFERAY STAFF

Rank: Liferay Legend

Posts: 2645

Join Date: August 31, 2006

Recent Posts

Hola Borxa,

El motivo por el que te lanza una IllegalAccessException es porque no has indicado el ContentType de la respuesta aún. En tu caso probablemente se solucionaría añadiendo la siguiente línea antes de invocar getWriter():

res.setContentType("text/xml");


Con eso conseguirás producir como respuesta el fichero, pero el portal lo insertará en el espacio dedicado al portlet, como hace con cualquier otro contenido producido por el mismo. Para evitar esto puedes usar el WindowState que mencionas, llamado exclusive. La forma de indicarlo sería algo así:

&lt;liferay-portlet:actionURL windowState="&lt;%=LiferayWindowState.EXCLUSIVE.toString()%&gt; ...
Daniel Rodriguez
RE: Descargar un archivo mediante un servlet en un portlet
February 21, 2008 6:55 AM
Answer

Daniel Rodriguez

Rank: Junior Member

Posts: 38

Join Date: August 9, 2006

Recent Posts

Hola!

Tenía el mismo problema que se describe en este foro y gracias a él he podido avanzar. Gracias! emoticon

El problema es que ahora el fichero adjunto que quiero descargar intenta ser abierto por el navegador en vez de que se me muestre el diáolgo de descarga. ¿Hay algo que necesite poner además en el enlace de descarga o en el Action?

Este es mi enlace:
<a href="<portlet:actionURL windowState="<%= LiferayWindowState.EXCLUSIVE.toString() %>">
     <portlet:param name="groupId" value="<%= String.valueOf(fullGroupId) %>" />
     <portlet:param name="articleId" value="<%= articleId %>" />
     <portlet:param name="fileName" value="<%= fullArticle.getDescription() %>" />
     <portlet:param name="actionType" value="<%= IndicatorUtil.ACTION_GET_FILE %>" />
</portlet:actionURL>">


Y este es el contenido de mi método getFile:
is = DLLocalServiceUtil.getFileAsStream(
                article.getCompanyId(), 0,
                getArticleDirectory(articleId, groupId) + "/" + fileName);

String contentType = MimeTypesUtil.getContentType(fileName);

ServletResponseUtil.sendFile(httpResponse, fileName, is, contentType);


Si muestro el contenido de contentType, este es correcto: "text/html", "application/msword", "image/png" ... pero si hago click en salvar enlace como, la sugerencia del navegador es "home.htm". Si le indico el nombre con una extensión apropiada, el archivo es descargado y funciona correctamente.

Muchas Gracias por adelantado!!
Ezequiel Chavez
RE: Descargar un archivo mediante un servlet en un portlet
February 21, 2008 9:09 AM
Answer

Ezequiel Chavez

Rank: Regular Member

Posts: 135

Join Date: January 19, 2006

Recent Posts

Daniel Rodriguez:
...El problema es que ahora el fichero adjunto que quiero descargar intenta ser abierto por el navegador en vez de que se me muestre el diáolgo de descarga. ¿Hay algo que necesite poner además en el enlace de descarga o en el Action?


Hola Daniel, para indicarle al navegador que muestre el diálogo para abrir o guardar, tienes que establecer el response-header "Content-Disposition" de la siguiente manera:
httpResponse.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");

No conozco con exactitud el comportamiento del método ServletResponseUtil.sendFile(), si tiene alguna forma (sobrecarga) de indicar este header y si tienes que establecer el header antes o después de la invocación del sendFile(), has las respectivas pruebas y nos comentas tu resultado.

Salu2.
Daniel Rodriguez
RE: Descargar un archivo mediante un servlet en un portlet
February 22, 2008 2:55 AM
Answer

Daniel Rodriguez

Rank: Junior Member

Posts: 38

Join Date: August 9, 2006

Recent Posts

Ezequiel Chavez:
...No conozco con exactitud el comportamiento del método ServletResponseUtil.sendFile(), si tiene alguna forma (sobrecarga) de indicar este header y si tienes que establecer el header antes o después de la invocación del sendFile(), has las respectivas pruebas y nos comentas tu resultado.


Gracias por la rápida respuesta!

He probado antes y también después, pero obtengo el mismo resultado que antes. emoticon

Es extraño porque si hago clic en el enlace desde IExplorer se abre una nueva ventana con el archivo (pdf, png...) correctamente visualizado, pero si lo hago desde firefox, se muestran los caracteres ascii que lo componen.

También me he dado cuenta de que si hago clic con el botón derecho y luego en "guardar enlace como", Firefox siempre me sugiere guardarlo como "home.htm", aunque puedo renombrarlo con la extensión correcta y entonces el fichero se puede abrir bien. Sin embargo IExplorer me sugiere un fichero con la extensión correcta (home.pdf, home.png...).

Creo que firefox no consigue la extensión del fichero y Explorer si. Esto sigue ocurriendo después de haber establecido la cabecera como me has sugerido, antes o después del método sendFile.

¿Cómo podría comprobar si la cabecera ha sido establecida correctamente?

Saudos y gracias!
Ezequiel Chavez
RE: Descargar un archivo mediante un servlet en un portlet
February 22, 2008 7:55 AM
Answer

Ezequiel Chavez

Rank: Regular Member

Posts: 135

Join Date: January 19, 2006

Recent Posts

Daniel Rodriguez:
¿Cómo podría comprobar si la cabecera ha sido establecida correctamente?


He revisado el fuente de ServletResponseUtil y en el método sendFile contempla el establecimiento de valores en el header como:

if (Validator.isNotNull(contentType)) {
  res.setContentType(contentType);
}
res.setHeader(HttpHeaders.CACHE_CONTROL, HttpHeaders.PUBLIC);
res.setHeader(HttpHeaders.PRAGMA, HttpHeaders.PUBLIC);
if (Validator.isNotNull(fileName)) {
  ...
  res.setHeader(HttpHeaders.CONTENT_DISPOSITION, contentDisposition);
}


Revisa que fileName no sea null y que tenga un nombre correcto de archivo (*.ext), de todas formas para comprobar los valores que vienen en el reponse te recomiendo, primero que uses Firefox y uses el plugin Firebug, con el cual a parte de poder ver los valores del request y response, tiene otras utilidades para debug de aplicaciones web que te pueden ayudar.

Salu2.
Daniel Rodriguez
RE: Descargar un archivo mediante un servlet en un portlet
February 25, 2008 2:53 AM
Answer

Daniel Rodriguez

Rank: Junior Member

Posts: 38

Join Date: August 9, 2006

Recent Posts

Ezequiel Chavez:
Revisa que fileName no sea null y que tenga un nombre correcto de archivo (*.ext), de todas formas para comprobar los valores que vienen en el reponse te recomiendo, primero que uses Firefox y uses el plugin Firebug, con el cual a parte de poder ver los valores del request y response, tiene otras utilidades para debug de aplicaciones web que te pueden ayudar.


Hola Ezequiel!

Pues he hecho comprobaciones imprimiendo el contenido de las variables fileName y contentType antes de llamar a sendFile y son correctas. Sin embargo si las veo con el plug in que me recomendaste (por cierto, muy bueno) es distinto.

Por ejemplo, para un fichero .pdf tengo:
fileName: att.pdf
contentType: application/pdf

Sin embargo si miro en FireBug, la cabecera es esta:
Response Headers
Server
    Apache-Coyote/1.1
Content-Type    text/html;charset=UTF-8
Transfer-Encoding    chunked
Date    Mon, 25 Feb 2008 10:40:30 GMT


He estado mirando el código de ServletResponseUtil.java y no encuentro ninguna forma dentro de los diferentes if que produzca esta salida. Algo que no he comentado antes y que tal vez podría influir es que esto está ocurriendo dentro de un processAction que originalmente utiliza un actionResponse, así que he tenigo que hacer un casting a httpResponse para poder utilizar el método sendFile (esta solución la he visto en el getFile del MessageBoards).

Este es el código:
HttpServletResponse httpResponse = ((ActionResponseImpl)response).getHttpServletResponse();


¿Puede esto del ActionResponse tener algo que ver con el resultado que estoy obteniendo?

Muchas gracias por la ayuda!
Ezequiel Chavez
RE: Descargar un archivo mediante un servlet en un portlet
February 26, 2008 2:38 PM
Answer

Ezequiel Chavez

Rank: Regular Member

Posts: 135

Join Date: January 19, 2006

Recent Posts

Daniel, mi apreciación es que Liferay (MainServlet) al final del ciclo de vida del request establece o sobreescribe los valores del responseHeaders, independientemente de lo que tu Action ponga en dichos headers, el httpRequest y httpResponse que obtienes en el action son wrappers de los verdaderos request y response. Mientras no logres controlar el valor de los headers no podrás obtener el resultado esperado en el browser; ya que Firefox si maneja bien esos parametros cuando han sido establecidos.

Suerte y salu2.
Daniel Rodriguez
RE: Descargar un archivo mediante un servlet en un portlet
February 28, 2008 1:46 AM
Answer

Daniel Rodriguez

Rank: Junior Member

Posts: 38

Join Date: August 9, 2006

Recent Posts

Hola,

He entrado en modo debug y puedo ver como la instrucción setContentType es ejecutada con cualquier contentType (image/gif por ejemplo) y siempre permanece text/html.

Incluso ejecutando este código:
httpResponse.setContentType("image/gif");
System.out.println("httpResponse contentType: "+httpResponse.getContentType());

La salida es text/html...

Puede ser por lo que dices que no controlo los verdaderos response que no funcione, pero ¿no deberían cambiar las cabeceras al menos dentro de mi código y que luego fuesen sobreescritas? Ni siquiera puedo modificar el objeto httpResponse.

Si en modo debug modifico el valor de contentType dentro del objeto httpResponse, la salida funciona correctamente y me muestra la imagen, el pdf o lo que sea. Lo que ocurre es que no se modifica y no sé por qué, no encuentro nada en los ficheros de log, ni aparece ningún error.

¿Habría alguna forma de conseguir el verdadero httpResponse para poder modificarlo?
Carlos Sanchez Ruiz
RE: Descargar un archivo mediante un servlet en un portlet
February 24, 2010 6:33 AM
Answer

Carlos Sanchez Ruiz

Rank: Junior Member

Posts: 57

Join Date: February 3, 2010

Recent Posts

Hola Daniel,

Conseguiste solucionar esto? Alguien sabe como modificar los parametros necesarios para que coja application/zip?

Saludos y muchas gracias,

Carlos Sánchez