How to use <p:graphicImage> with DefaultStreamedContent in an ui:repeat?

Solution 1:

It is not possible to use <p:graphicImage> this way. You should rather iterate over a collection of unique image identifiers, not over a collection of StreamedContent. Those unique image identifiers have then to be passed as a <f:param> to <p:graphicImage> which in turn will generate the right URLs for the browser.

<ui:repeat value="#{data.imageIds}" var="imageId">
    <p:graphicImage value="#{imageStreamer.image}">
        <f:param name="id" value="#{imageId}" />
    </p:graphicImage>
</ui:repeat>

Your #{data} managed bean must just have a:

private List<Long> imageIds; // +getter

The #{imageStreamer} should be a separate application scoped managed bean which look basically 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 view. Return a stub StreamedContent so that it will generate right URL.
            return new DefaultStreamedContent();
        }
        else {
            // So, browser is requesting the image. Get ID value from actual request param.
            String id = context.getExternalContext().getRequestParameterMap().get("id");
            Image image = service.find(Long.valueOf(id));
            return new DefaultStreamedContent(new ByteArrayInputStream(image.getBytes()));
        }
    }

}