4

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?

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
NiÑo
  • 133
  • 1
  • 3
  • 11
  • 1
    What have you tried? Why did it not work? What is your exact error? Have you tried displaying it simply on a page instead of in a table? – Menno Jun 05 '13 at 08:10
  • 1
    possible duplicate [Link](http://stackoverflow.com/questions/9360710/how-to-display-images-from-database-in-jsf) – Jubin Patel Jun 05 '13 at 08:17
  • @Aquillo : yes, i tried but it seems that Primefaces tag `` needs an url to the image and it doesn't accept to stream the blob from the database – NiÑo Jun 05 '13 at 09:38
  • Try this http://java.dzone.com/articles/dynamic-images-primefaces – newuser Jun 05 '13 at 10:14

2 Answers2

12

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:

Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
-1

If you are using Richfaces, you can use a4j:mediaOutput component to stream the blob from a bean.

If that's not the case, I'm afraid I'm not familiar with Primefaces. If it doesn't provide any component for that you need a way of generating a URL that points to a servlet that returns the blob. That way you can use h:graphicImage with that auto-generated URL.

MaQy
  • 481
  • 3
  • 10
  • 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 Jun 05 '13 at 09:45