Displaying images from MySQL database in JSF datatable

13,798

You can use <p:graphicImage> to display images stored in a byte[], regardless of the byte[] source (DB, disk file system, network, etc). Simplest example is:

<p:graphicImage value="#{bean.streamedContent}" />

which refers a StreamedContent property.

This has however a pitfall, particularly when used in an iterating component such as a data table: the getter method will be invoked twice; the first time by JSF itself to generate the URL for <img src> and the second time by webbrowser when it needs to download the image content based on the URL in <img src>. To be efficient, you should not be hitting the DB in the first getter call. Also, to parameterize the getter method call so that you can use a generic method wherein you pass a specific image ID, you should be using a <f:param> (please note that EL 2.2 feature of passing method arguments won't work at all as this doesn't end up in URL of <img src>!).

Summarized, this should do:

<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>

The #{item.imageId} obviously returns the unique idenfitier of the image in the DB (the primary key) and thus not the byte[] content. The #{imageStreamer} is an application scoped bean which look like this:

@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()));
        }
    }

}

The Image class is in this particular example just an @Entity with a @Lob on bytes property (as you're using JSF, I of cource assume that you're using JPA to interact with the DB).

@Entity
public class Image {

    @Id
    @GeneratedValue(strategy = IDENTITY) // Depending on your DB, of course.
    private Long id;

    @Lob
    private byte[] bytes;

    // ...
}

The ImageService is just a standard @Stateless EJB, nothing special to see here:

@Stateless
public class ImageService {

    @PersistenceContext
    private EntityManager em;

    public Image find(Long id) {
        return em.find(Image.class, id);
    }

}

See also:

Share:
13,798
NiÑo
Author by

NiÑo

Updated on June 15, 2022

Comments

  • NiÑo
    NiÑo almost 2 years

    I have MySQL database which stores images in a blob column. I would like to show them in a PrimeFaces <p:dataTable>. How can I achieve this?

  • NiÑo
    NiÑo almost 11 years
    That's it, unfortunately i'm working with Primefaces and it doesn't provide this kind of component like RichFaces. I found tutorials which suggest to define a Servlet to return the blob like you said...i just post the question to find if it is possible to do that in another way. Thanks any way :)
  • NiÑo
    NiÑo almost 11 years
    thanks a lot. it helps me a lot