1

I created a fileupload dialog and a image gallery on a jsf page. After each image upload the gallery should show all so far uploaded images. The images will be stored in a backend bean and should be fetched by the gallery dynamically from the backend bean. For some reason the gallery shows the image labels uploaded but not the referring image since the image resource could not be found.

I use spring, primefaces on tomcat. Thanks for any help in advance!

My JSF Page:

<p:fileUpload id="imageUpldoad" update="galleryPanel" fileUploadListener="#{wizzardBean.handleFileUpload}" mode="advanced" dragDropSupport="true" 
              sizeLimit="10000000"  multiple="true" auto="false" fileLimit="100" allowTypes="/(\.|\/)(gif|jpe?g|png)$/" />


<p:panel id="galleryPanel">
   <p:galleria id="gallery" value="#{wizzardBean.getHotelImages()}" var="img" panelWidth="500" panelHeight="313" showCaption="true" rendered="#{wizzardBean.showGallery()}">
        <p:graphicImage name="#{img.name}" value="#{wizzardBean.hotelImage}" alt="Image Description for #{img.name}" title="#{img}">
            <f:param id="imgId" name="imgId" value="#{img.id}" />
        </p:graphicImage>
</p:galleria>

My Backend Bean:

public class WizzardBean extends BaseBean {
    private List<HotelImage> hotelImages;

    public void handleFileUpload(FileUploadEvent event) throws IOException {
        if (event.getFile() != null) {
            HotelImage hotelImage = new HotelImage(hotelImages.size(), event.getFile().getFileName(), event.getFile());
            hotelImages.add(hotelImage);
        }
    }



    public StreamedContent getHotelImage() {
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        String photoId = externalContext.getRequestParameterMap().get("imgId");
        if (photoId == null || photoId.equals("")) {
            return null;
        } else {
            int parsedId = Integer.parseInt(photoId);
            return hotelImages.get(parsedId).getImage();
        }
    }
}

The HotelImage class:

public class HotelImage {

private int id;
private String name;
private StreamedContent image;

public HotelImage(int id, String name, UploadedFile file) {
    this.id = id;
    this.name = name;
    try {
        image = new DefaultStreamedContent(file.getInputstream(), "image/jpg");
    } catch (IOException e) {
    }
}

public int getId() {
    return id;
}

public String getName() {
    return name;
}

public StreamedContent getImage() {
    return image;
}

The browser says:

<img id="mainFormId:j_idt52:j_idt55" src="RES_NOT_FOUND" alt="Image Description for twitter.png" title="twitter.png">
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
Ugur Teker
  • 169
  • 1
  • 12

1 Answers1

0

There are several problems with this approach. Those boil down to the incorrect assumption that an uploaded file, an InputStream and StreamedContent can be read and reused multiple times. This is incorrect. The uploaded file will be sent only once and only be available during the original request, and the streams can be read only once after they are created.

Moreover, having a PrimeFaces-specific StreamedContent or even UploadedFile as a bean property is wrong. The bean property should at least be a File referring the physical file on server's local disk file system, or a byte[] representing the raw content in server memory or a Long representing the insert ID of blob entry in database.

You need to adjust your code to save the uploaded file content to a permanent storage location as soon as possible it comes in and then assign the result as a bean property of type File or byte[] or Long. Then, let the rest of the code use that bean property instead to create a StreamedContent within the getter method. Do absolutely not assign that StreamedContent to another bean property.

You can find concrete and elaborate examples in the answer of the questions linked below.

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • Thanks for answer. I checked the first link you send me but in there you stated that the images **can** be fetched from a stream (instead having a static file on hard drive)...or did you mean that reading from the same stream multiple times is not valid and i should better read from a file (or other pysical resource) and create a seperate input stream for each http request? – Ugur Teker Mar 02 '15 at 15:51
  • As stated in the answer, the problem is indeed the "multiple times" part. An `InputStream` can be read only once. Then it's EOF. The `read()` method will keep returning `-1`. Nothing which can change that. You just need to create a new one. And that's obviously only possible if it's permanently stored somewhere. – BalusC Mar 02 '15 at 16:35