Możesz użyć <p:graphicImage>
aby wyświetlić obrazy przechowywane w byte[]
, niezależnie od byte[]
źródło (DB, dyskowy system plików, sieć itp.). Najprostszy przykład to:
<p:graphicImage value="#{bean.streamedContent}" />
który odwołuje się do StreamedContent
właściwość.
Ma to jednak pewną pułapkę, szczególnie gdy jest używana w komponencie iteracyjnym, takim jak tabela danych:metoda pobierająca zostanie wywołana dwukrotnie; po raz pierwszy przez samo JSF, aby wygenerować adres URL dla <img src>
i drugi raz przez przeglądarkę internetową, gdy musi pobrać zawartość obrazu na podstawie adresu URL w <img src>
. Aby być wydajnym, nie powinieneś uderzać DB w pierwszym wywołaniu gettera. Ponadto, aby sparametryzować wywołanie metody pobierającej, aby można było użyć metody ogólnej, w której przekazujesz określony identyfikator obrazu, powinieneś użyć <f:param>
(proszę zauważyć, że funkcja przekazywania argumentów metody w wersji EL 2.2 nie będzie działać w ogóle, ponieważ nie kończy się to na adresie URL <img src>
!).
Podsumowując, powinno to wystarczyć:
<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>
#{item.imageId}
oczywiście zwraca unikalny identyfikator obrazu w bazie danych (klucz podstawowy), a zatem nie byte[]
zawartość. #{imageStreamer}
to bean o zakresie aplikacji, który wygląda tak:
@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()));
}
}
}
Image
klasa jest w tym konkretnym przykładzie po prostu @Entity
z @Lob
na bytes
właściwość (ponieważ używasz JSF, oczywiście zakładam, że używasz JPA do interakcji z bazą danych).
@Entity
public class Image {
@Id
@GeneratedValue(strategy = IDENTITY) // Depending on your DB, of course.
private Long id;
@Lob
private byte[] bytes;
// ...
}
ImageService
to tylko standardowy @Stateless
EJB, nic specjalnego do zobaczenia:
@Stateless
public class ImageService {
@PersistenceContext
private EntityManager em;
public Image find(Long id) {
return em.find(Image.class, id);
}
}