Vous pouvez utiliser <p:graphicImage>
pour afficher les images stockées dans un byte[]
, quel que soit le byte[]
source (DB, système de fichiers sur disque, réseau, etc.). L'exemple le plus simple est :
<p:graphicImage value="#{bean.streamedContent}" />
qui fait référence à un StreamedContent
propriété.
Cela présente cependant un écueil, en particulier lorsqu'il est utilisé dans un composant itératif tel qu'une table de données :la méthode getter sera invoquée deux fois; la première fois par JSF lui-même pour générer l'URL pour <img src>
et la deuxième fois par le navigateur Web lorsqu'il doit télécharger le contenu de l'image en fonction de l'URL dans <img src>
. Pour être efficace, vous ne devez pas toucher la base de données lors du premier appel getter. De plus, pour paramétrer l'appel de la méthode getter afin que vous puissiez utiliser une méthode générique dans laquelle vous transmettez un ID d'image spécifique, vous devez utiliser un <f:param>
(veuillez noter que la fonctionnalité EL 2.2 de transmission des arguments de méthode ne fonctionnera pas du tout car cela ne se retrouve pas dans l'URL de <img src>
!).
En résumé, cela devrait faire :
<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>
Le #{item.imageId}
renvoie évidemment l'identifiant unique de l'image dans la BD (la clé primaire) et donc non le byte[]
teneur. Le #{imageStreamer}
est un bean étendu à l'application qui ressemble à ceci :
@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()));
}
}
}
L'Image
la classe est dans cet exemple particulier juste un @Entity
avec un @Lob
sur bytes
propriété (comme vous utilisez JSF, je suppose bien sûr que vous utilisez JPA pour interagir avec la base de données).
@Entity
public class Image {
@Id
@GeneratedValue(strategy = IDENTITY) // Depending on your DB, of course.
private Long id;
@Lob
private byte[] bytes;
// ...
}
Le ImageService
est juste un @Stateless
standard EJB, rien de spécial à voir ici :
@Stateless
public class ImageService {
@PersistenceContext
private EntityManager em;
public Image find(Long id) {
return em.find(Image.class, id);
}
}