Você pode usar
<p:graphicImage>
para exibir imagens armazenadas em um byte[]
, independentemente do byte[]
fonte (DB, sistema de arquivos em disco, rede, etc). O exemplo mais simples é:<p:graphicImage value="#{bean.streamedContent}" />
que se refere a um
StreamedContent
propriedade. No entanto, isso tem uma armadilha, principalmente quando usado em um componente de iteração, como uma tabela de dados:o método getter será invocado duas vezes; pela primeira vez pelo próprio JSF para gerar a URL para
<img src>
e a segunda vez pelo navegador da web quando precisar baixar o conteúdo da imagem com base na URL em <img src>
. Para ser eficiente, você não deve atingir o DB na primeira chamada de getter. Além disso, para parametrizar a chamada do método getter para que você possa usar um método genérico no qual você passa um ID de imagem específico, você deve usar um <f:param>
(observe que o recurso EL 2.2 de passar argumentos de método não funcionará, pois isso não termina na URL de <img src>
!). Resumido, isso deve fazer:
<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>
O
#{item.imageId}
obviamente retorna o identificador exclusivo da imagem no banco de dados (a chave primária) e, portanto, não o byte[]
contente. O #{imageStreamer}
é um bean com escopo de aplicativo que se parece com isso:@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()));
}
}
}
A
Image
class é neste exemplo em particular apenas um @Entity
com um @Lob
em bytes
propriedade (como você está usando JSF, é claro que assumo que você está usando JPA para interagir com o banco de dados). @Entity
public class Image {
@Id
@GeneratedValue(strategy = IDENTITY) // Depending on your DB, of course.
private Long id;
@Lob
private byte[] bytes;
// ...
}
O
ImageService
é apenas um padrão @Stateless
EJB, nada de especial para ver aqui:@Stateless
public class ImageService {
@PersistenceContext
private EntityManager em;
public Image find(Long id) {
return em.find(Image.class, id);
}
}