4

I would like to know how to use dropzone.js with JSF for upload a file. In the documentation (http://www.dropzonejs.com/#usage) it says that using dropzone is like using:

   <input type="file" name="file" />

But I don't know how to implement the server-side part in JSF to get the file and store it in disk.

Aliuk
  • 1,249
  • 2
  • 17
  • 32

1 Answers1

6

It appears that you don't exactly realize that JSF is in the context of this question merely a HTML code generator. JSF offers a <h:inputFile> component which generates a HTML <input type="file"> element.

Try it yourself:

<h:form id="uploadForm" enctype="multipart/form-data">
    <h:inputFile id="file" value="#{bean.file}" />
    <h:commandButton id="submit" value="submit" />
</h:form>

If you open the JSF page in a webbrowser and do rightclick and View Page Source, then you should see something like this:

<form id="uploadForm" name="uploadForm" method="post" action="/playground/test.xhtml" enctype="multipart/form-data">
    <input type="hidden" name="uploadForm" value="uploadForm" />
    <input id="uploadForm:file" type="file" name="uploadForm:file" />
    <input type="submit" name="uploadForm:submit" value="submit" />
    <input type="hidden" name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="3646344859491704387:-5449990057208847169" autocomplete="off" />
</form>

Look, there is your <input type="file"> element!

Now, if we configure Dropzone as per its documentation (and you install the dropzone.js file in your JSF project as per the instructions in How to reference CSS / JS / image resource in Facelets template?), then we should end up in the JSF page with something like this:

<h:head>
    ...
    <h:outputScript name="dropzone.js" />
    <h:outputScript>Dropzone.options.uploadForm = { paramName: "uploadForm:file" };</h:outputScript>
</h:head>
<h:body>
    <h:form id="uploadForm" enctype="multipart/form-data" styleClass="dropzone">
        <div class="fallback">
            <h:inputFile id="file" value="#{bean.file}" />
            <h:commandButton id="submit" value="submit" />
        </div>
    </h:form>
</h:body>

The bean looks just like this:

@Named
@RequestScoped
public class Bean {

    private Part file;

    public void save() throws IOException {
        String fileName = file.getSubmittedFileName();
        String contentType = file.getContentType();
        long size = file.getSize();
        InputStream content = file.getInputStream();
        // ...
    }

    public Part getFile() {
        return file;
    }

    public void setFile(Part file) throws IOException {
        this.file = file;
        save();
    }

}

There are 3 things to take into account with JSF:

  1. The Dropzone paramName option must be set to exactly the name of the generated <input type="file"> element, which is uploadForm:file in the above example.
  2. The JSF input file and command button components must be wrapped in an element with Dropzone-specific class="fallback" in order to be hidden (and provide a fallback for JavaScript/Ajax-deficient clients). Do not remove them, otherwise JSF will refuse to process the uploaded file, because it needs to perform its job based on the component tree.
  3. The save() method is invoked directly by the setter. This is kind of fishy, but as Dropzone doesn't offer an opportunity to directly trigger a backing bean action method, this is the easiest workaround. Another workaround is to attach a valueChangeListener on the <h:inputFile> and queue the event to the INVOKE_APPLICATION phase as per How to get updated model values in a valueChangeListener method?

Your next question shall probably be "How should I save it?". In that case, continue here:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • If I need to pass a parameter to the save method, how can I do it? I need to pass #{album.id} – Aliuk Jun 24 '16 at 20:57
  • Just add `` the usual way. – BalusC Jun 24 '16 at 21:08
  • I'm sorry but I cannot get the album id. I am using this: and String albumId = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("hiddenAlbumId"); but it doesn't work I received null always – Aliuk Jun 24 '16 at 22:58
  • Just ask a new question. This detail was nowhere covered in the question in its current form. I have no idea what context you're talking about. The answer works for the question in its current form. Or didn't it? – BalusC Jun 25 '16 at 14:05
  • @BalusC I followed the steps mentioned above, but when I drop a file into the dropzone the getter is called in the bean, not the setter. Actually the setter is never called. Do you have any idea what could cause this behaviour? – sinclair Oct 27 '16 at 11:35
  • @sinclair: sorry, problem is not visible in information provided so far. Perhaps you didn't try in a scratchpad project. – BalusC Oct 27 '16 at 11:38