Puede usar <p:graphicImage>
para mostrar imágenes almacenadas en un byte[]
, independientemente del byte[]
fuente (base de datos, sistema de archivos de disco, red, etc.). El ejemplo más simple es:
<p:graphicImage value="#{bean.streamedContent}" />
que se refiere a un StreamedContent
propiedad.
Sin embargo, esto tiene un escollo, particularmente cuando se usa en un componente iterativo como una tabla de datos:el método getter se invocará dos veces; la primera vez que JSF genera la URL para <img src>
y la segunda vez por el navegador web cuando necesita descargar el contenido de la imagen según la URL en <img src>
. Para ser eficiente, no debe presionar la base de datos en la primera llamada del captador. Además, para parametrizar la llamada del método getter para que pueda usar un método genérico en el que pase una ID de imagen específica, debe usar un <f:param>
(Tenga en cuenta que la función EL 2.2 de pasar argumentos de método no funcionará en absoluto, ya que esto no termina en la URL de <img src>
!).
Resumiendo, esto debería hacer:
<p:dataTable value="#{bean.items}" var="item">
<p:column>
<p:graphicImage value="#{imageStreamer.image}">
<f:param name="id" value="#{item.imageId}" />
</p:graphicImage>
</p:column>
</p:dataTable>
El #{item.imageId}
obviamente devuelve el identificador único de la imagen en la base de datos (la clave principal) y, por lo tanto, no el byte[]
contenido. El #{imageStreamer}
es un bean con ámbito de aplicación que tiene este aspecto:
@ManagedBean
@ApplicationScoped
public class ImageStreamer {
@EJB
private ImageService service;
public StreamedContent getImage() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the HTML. 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 imageId = context.getExternalContext().getRequestParameterMap().get("imageId");
Image image = imageService.find(Long.valueOf(imageId));
return new DefaultStreamedContent(new ByteArrayInputStream(image.getBytes()));
}
}
}
La Image
class es en este ejemplo particular solo un @Entity
con un @Lob
en bytes
propiedad (como está usando JSF, por supuesto asumo que está usando JPA para interactuar con la base de datos).
@Entity
public class Image {
@Id
@GeneratedValue(strategy = IDENTITY) // Depending on your DB, of course.
private Long id;
@Lob
private byte[] bytes;
// ...
}
El ImageService
es solo un @Stateless
estándar EJB, nada especial que ver aquí:
@Stateless
public class ImageService {
@PersistenceContext
private EntityManager em;
public Image find(Long id) {
return em.find(Image.class, id);
}
}