Cargue imágenes desde fuera de la carpeta webapps/webcontext/implementar usando la etiqueta <h:graphicImage> o <img>
Necesito mostrar imágenes que residen fuera de la carpeta de implementación en la aplicación web usando <h:graphicimage>
una etiqueta JSF o <img>
una etiqueta HTML. ¿Cómo puedo lograr eso?
Hasta el punto, debe ser accesible mediante una URL pública. Por lo tanto, en <img src>
última instancia, debe hacer referencia a un http://
URI, no a algo así como un file://
URI o algo así. En última instancia, la fuente HTML se ejecuta en la máquina del usuario final y el navegador web descarga las imágenes individualmente durante el análisis de la fuente HTML. Cuando el navegador web encuentra un file://
URI como C:\path\to\image.png
, buscará la imagen en el sistema de archivos del disco local del usuario final en lugar de en el del servidor web. Obviamente, esto no funcionará si el navegador web se ejecuta en una máquina físicamente diferente al servidor web.
Hay varias maneras de lograr esto:
Si tiene control total sobre la carpeta de imágenes, simplemente suelte la carpeta con todas las imágenes, por ejemplo,
/images
directamente en la carpeta de implementación del servletcontainer, como la/webapps
carpeta en el caso de Tomcat y/domains/domain1/applications
la carpeta en el caso de GlassFish. No es necesaria ninguna configuración adicional.O agregue un nuevo contexto de aplicación web al servidor que apunte a la ubicación absoluta del sistema de archivos del disco de la carpeta con esas imágenes. Cómo hacerlo depende del recipiente utilizado. Los siguientes ejemplos suponen que las imágenes se encuentran en http://.../images
/path/to/images
y que le gustaría acceder a ellas a través de .En el caso de Tomcat, agregue la siguiente nueva entrada al
/conf/server.xml
interior de Tomcat<Host>
:<Context docBase="/path/to/images" path="/images" />
En el caso de GlassFish, agregue la siguiente entrada a
/WEB-INF/glassfish-web.xml
:<property name="alternatedocroot_1" value="from=/images/* dir=/path/to" />
En el caso de WildFly, agregue la siguiente entrada dentro
<host name="default-host">
de/standalone/configuration/standalone.xml
...<location name="/images" handler="images-content" />
... y más abajo en
<handlers>
la entrada de lo mismo<subsystem>
que arriba<location>
:<file name="images-content" path="/path/to/images" />
O cree un archivo
Servlet
que transmita la imagen desde el disco a la respuesta:@WebServlet("/images/*") public class ImageServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String filename = request.getPathInfo().substring(1); File file = new File("/path/to/images", filename); response.setHeader("Content-Type", getServletContext().getMimeType(filename)); response.setHeader("Content-Length", String.valueOf(file.length())); response.setHeader("Content-Disposition", "inline; filename=\"" + filename + "\""); Files.copy(file.toPath(), response.getOutputStream()); } }
Si utiliza OmniFaces, entonces
FileServlet
puede resultar útil ya que también tiene en cuenta las solicitudes de encabezado, almacenamiento en caché y rango.O utilice OmniFaces
<o:graphicImage>
, que admite la devolución de una propiedad de beanbyte[]
oInputStream
:@Named @ApplicationScoped public class Bean { public InputStream getImage(String filename) { return new FileInputStream(new File("/path/to/images", filename)); } }
O utilice PrimeFaces
<p:graphicImage>
, que admite un método de bean que devuelve archivos específicos de PrimeFacesStreamedContent
.@Named @ApplicationScoped public class Bean { public StreamedContent getImage() throws IOException { FacesContext context = FacesContext.getCurrentInstance(); if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) { // So, we're rendering the view. Return a stub StreamedContent so that it will generate right URL. return new DefaultStreamedContent(); } else { // So, browser is requesting the image. Return a real StreamedContent with the image bytes. String filename = context.getExternalContext().getRequestParameterMap().get("filename"); return new DefaultStreamedContent(new FileInputStream(new File("/path/to/images", filename))); } } }
Para la primera forma y los enfoques Tomcat y WildFly en la segunda, las imágenes estarán disponibles en http://example.com/images/filename.ext y, por lo tanto, se podrán consultar en HTML simple de la siguiente manera
<img src="/images/filename.ext" />
Para el enfoque GlassFish en la segunda y tercera forma, las imágenes estarán disponibles en http://example.com/context/images/filename.ext y, por lo tanto, se podrán consultar en HTML simple de la siguiente manera
<img src="#{request.contextPath}/images/filename.ext" />
o en JSF de la siguiente manera (la ruta de contexto se antepone automáticamente)
<h:graphicImage value="/images/filename.ext" />
Para el enfoque OmniFaces en la cuarta vía, haga referencia a él de la siguiente manera
<o:graphicImage value="#{bean.getImage('filename.ext')}" />
Para el enfoque PrimeFaces en la quinta vía, haga referencia a él de la siguiente manera:
<p:graphicImage value="#{bean.image}">
<f:param name="filename" value="filename.ext" />
</p:graphicImage>
Tenga en cuenta que el ejemplo #{bean}
es @ApplicationScoped
tal como representa básicamente un servicio sin estado. También puedes hacerlo @RequestScoped
, pero luego el bean se recreará en cada solicitud, sin costo alguno. No puedes hacerlo @ViewScoped
, porque en el momento en que el navegador necesita descargar la imagen, el servidor no crea una página JSF. Puedes hacerlo @SessionScoped
, pero luego se guarda en la memoria, para nada.
Ver también:
- Forma recomendada de guardar archivos cargados en una aplicación de servlet
- La forma más sencilla de servir datos estáticos desde fuera del servidor de aplicaciones en una aplicación web Java
- Plantilla abstracta para un servlet de recursos estático (que admite el almacenamiento en caché HTTP)
- Mostrar imagen como byte [] de la base de datos como imagen gráfica en la página JSF
- Muestre una imagen dinámica desde la base de datos con p:graphicImage y StreamedContent
- ¿Cómo elegir el alcance del frijol adecuado?
Para lograr lo que necesita usando etiquetas <h:graphicImage>
o <img>
, debe crear un alias de Tomcat v7 para asignar la ruta externa al contexto de su aplicación web.
Para hacerlo, deberá especificar el contexto de su aplicación web . Lo más sencillo sería definir un archivo META-INF/context.xml con el siguiente contenido:
<Context path="/myapp" aliases="/images=/path/to/external/images">
</Context>
Luego, después de reiniciar su servidor Tomcat, puede acceder a sus archivos de imágenes usando <h:graphicImage
> o <img>
etiquetas de la siguiente manera:
<h:graphicImage value="/images/my-image.png">
o
<img src="/myapp/images/my-image.png">
*Tenga en cuenta que la ruta de contexto es necesaria para la etiqueta pero no para la
Otro enfoque posible si no necesita que las imágenes estén disponibles a través del método HTTP GET, podría ser usar la <p:fileDownload>
etiqueta Primefaces (usando etiquetas commandLink o commandButton - método HTTP POST ).
En tu Facelet:
<h:form>
<h:commandLink id="downloadLink" value="Download">
<p:fileDownload value="#{fileDownloader.getStream(file.path)}" />
</h:commandLink>
</h:form
En tu frijol:
@ManagedBean
@ApplicationScope
public class FileDownloader {
public StreamedContent getStream(String absPath) throws Exception {
FileInputStream fis = new FileInputStream(absPath);
BufferedInputStream bis = new BufferedInputStream(fis);
StreamedContent content = new DefaultStreamedContent(bis);
return content;
}
}
}
En PrimeFaces puedes implementar tu bean de esta manera:
private StreamedContent image;
public void setImage(StreamedContent image) {
this.image = image;
}
public StreamedContent getImage() throws Exception {
return image;
}
public void prepImage() throws Exception {
File file = new File("/path/to/your/image.png");
InputStream input = new FileInputStream(file);
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
setImage(new DefaultStreamedContent(input,externalContext.getMimeType(file.getName()), file.getName()));
}
En su faceta HTML:
<body onload="#{yourBean.prepImage()}"></body>
<p:graphicImage value="#{youyBean.image}" style="width:100%;height:100%" cache="false" >
</p:graphicImage>
Sugiero configurar el atributo cache="false" en el componente GraphicImage.