在 JSF 数据表中显示来自 MySQL 数据库的图像

2021-12-28 00:00:00 image mysql datatable jsf primefaces

我有将图像存储在 blob 列中的 MySQL 数据库.我想在 PrimeFaces 中显示它们.我怎样才能做到这一点?

解决方案

您可以使用

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?

解决方案

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:

  • Display dynamic image from database with p:graphicImage and StreamedContent

相关文章