Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
596 views
in Technique[技术] by (71.8m points)

jsf - Display database blob images in <p:graphicImage> inside <ui:repeat>

I'm using PrimeFaces 3.2 on JBoss 7.1.1.

I am trying to display an image which is stored in a BLOB in a MySQL database in <ui:repeat>. The image is stored in a byte[] and then converted to a StreamedContent as follows:

InputStream stream = new ByteArrayInputStream(ingredient.getImage());
ingredient.setJsfImage(new DefaultStreamedContent(stream, "image/jpg"));

Then I am trying to display it in a Facelet as follows:

<ui:repeat var="ingredient" value="#{formBean.ingredientResultSet}">
    <p:panel id="resultsPanel" header="#{ingredient.location.shopName}">
        <p:graphicImage value="#{ingredient.jsfImage}" alt="No picture set" />
...

However, when loading the page, I get the following error in JBoss:

SEVERE [org.primefaces.application.PrimeResourceHandler] (http--127.0.0.1-8080-12) Error in streaming dynamic resource.

How is this caused and how can I solve it?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You need to realize that the <p:graphicImage> actually renders a <img src> element with just an URL which is then later individually invoked by the webbrowser when it's about to parse the obtained HTML markup and present the results.

So, whatever you do in the getter method of <p:graphicImage> it must be designed that way that it can be invoked on a per-request basis. So, the most sane approach would be to create a <p:graphicImage> with a <f:param> wherein the <p:graphicImage value> points an entirely standalone request or application scoped bean (and thus absolutely not view or session scoped), and the <f:param value> points the unique image identifier.

E.g.

<p:graphicImage value="#{images.image}">
    <f:param name="id" value="#{someBean.imageId}" />
</p:graphicImage>

Where the Images backing bean can look like this:

@Named
@ApplicationScoped
public class Images {

    @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. Return a real StreamedContent with the image bytes.
            String id = context.getExternalContext().getRequestParameterMap().get("id");
            Image image = service.find(Long.valueOf(id));
            return new DefaultStreamedContent(new ByteArrayInputStream(image.getBytes()));
        }
    }

}

Or, if you're already using OmniFaces 2.0 or newer, then consider using its <o:graphicImage> instead which can be used more intuitively, almost exectly the way as you expected. See also the blog on the subject.

See also:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...