title: Vaadin with JQuery FileUpload
body: <p>I would like to create <em>FileUploader</em>  with <strong>Vaadin</strong> . But I need to get more features over <a href="http://demo.vaadin.com/sampler/#ui/data-input/other/upload" rel="nofollow">normal Vaadin Upload</a>. </p>
  
  <ol>
  <li>beautiful and easy to manage (but optional)</li>
  <li>fast and never failed while uploading</li>
  <li>include progress bar</li>
  <li>show preview</li>
  <li>multi file upload support</li>
  <li>upload file size and type restriction</li>
  <li>drag and drop</li>
  <li>client-side image resizable <em>(it is main feature for me because all of my uploaded files were images)</em></li>
  </ol>
  
  <p>There has an addon <a href="https://vaadin.com/directory#addon/multifileupload" rel="nofollow">MultiFileUpload</a>. Yes , it is perfect for most of my requirements but not for <strong>client-size image resizing</strong>. So I decided to use <a href="http://blueimp.github.io/jQuery-File-Upload/" rel="nofollow">JQuery FileUpload</a> because it is support for <a href="https://github.com/blueimp/jQuery-File-Upload/wiki/Client-side-Image-Resizing" rel="nofollow">Client side Image Resizing</a>. </p>
  
  <p>I used vaadin <a href="https://vaadin.com/api/com/vaadin/ui/Window.html" rel="nofollow">Window</a> for upload image. But I got a problem while creating my window , very hard to create each HTML elements respectively (<em>may be I have less exp</em>). So I used <a href="https://vaadin.com/book/-/page/layout.customlayout.html" rel="nofollow">CustomLayout with HTML</a> for easy to create and edit  design of my image uploader window.</p>
  
  <p>Below is my custom layout HTML file. (<em>two scripts were templates for image preview</em>)</p>
  
  <pre><code>&lt;script id="template-upload" type="text/x-tmpl"&gt;
  {% for (var i=0, file; file=o.files[i]; i++) { %}
  &lt;tr class="template-upload"&gt;
      &lt;td width="100px" align="center"&gt;
          &lt;span class="preview"&gt;&lt;/span&gt;
      &lt;/td&gt;
      &lt;td width="400px" align="center"&gt;
          &lt;p class="name"&gt;{%=file.name%}&lt;/p&gt;
          {% if (!o.files.error) { %}
              &lt;div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"&gt;&lt;div class="bar" style="width:0%;"&gt;&lt;/div&gt;&lt;/div&gt;
          {% } %}
          {% if (file.error) { %}
              &lt;div&gt;&lt;span class="label label-important"&gt;Error&lt;/span&gt; {%=file.error%}&lt;/div&gt;
          {% } %}
      &lt;/td&gt;
      &lt;td width="100px" align="center"&gt;
          {% if (!i) { %}
              &lt;button style="display: none;" class="start" type="button"&gt;
                  &lt;span&gt;Start&lt;/span&gt;
              &lt;/button&gt;
              &lt;div class="v-button v-widget cancel" type = "button"&gt;
                  &lt;span class="v-button-wrap" style="color: red;"&gt;
                      &lt;span class="v-button-caption"&gt;Cancel&lt;/span&gt;
                  &lt;/span&gt;
              &lt;/div&gt;
          {% } %}
          &lt;br&gt;
          {%=o.formatFileSize(file.size)%}
      &lt;/td&gt;
  &lt;/tr&gt;
  {% } %}
  &lt;/script&gt;
  &lt;!-- The template to display files available for download --&gt;
  &lt;script id="template-download" type="text/x-tmpl"&gt;
  {% for (var i=0, file; file=o.files[i]; i++) { %}
  &lt;tr class="template-download"&gt;
      &lt;td width="100px" align="center"&gt;
          &lt;span class="preview"&gt;
              {% if (file.path) { %}
                  &lt;img src="../{%=file.path%}" width="100px"&gt;
              {% } %}
          &lt;/span&gt;
      &lt;/td&gt;
      &lt;td width="400px" align="center"&gt;
          &lt;p class="name"&gt;
              {%=file.name%}
          &lt;/p&gt;
          {% if (file.error) { %}
              &lt;div&gt;&lt;span class="label label-important"&gt;Error&lt;/span&gt; {%=file.error%}&lt;/div&gt;
          {% } %}
      &lt;/td&gt;
      &lt;td width="100px" align="center"&gt;
          &lt;span class="size"&gt;{%=o.formatFileSize(file.size)%}&lt;/span&gt;
      &lt;/td&gt;
  &lt;/tr&gt;
  {% } %}
  &lt;/script&gt;
  &lt;table cellpadding="5" style="width: 100%;"&gt;
  &lt;colgroup&gt;
  &lt;col&gt;
  &lt;/colgroup&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td width="90px"&gt;
              &lt;div style="text-align: right; width: 120px;"&gt;UploadPhoto :&lt;/div&gt;
          &lt;/td&gt;
          &lt;td&gt;
              &lt;div id="pnlProgress" aria-valuenow="0" aria-valuemax="100" aria-valuemin="0" style="display: none;" class="progress progressall progress-success progress-striped active"&gt;
                  &lt;div style="width: 0%;" class="allbar" id="pnlProgressBar"&gt;&amp;nbsp;&lt;/div&gt;
              &lt;/div&gt;
          &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td colspan="3"&gt;
              &lt;div id="imageForm" style="width: 600px;"&gt;
                  &lt;form id="fileupload"&gt;
                      &lt;div style="margin-bottom: 10px; border: 1px solid #DDD; width: 600px; height: 300px; overflow: scroll"&gt;
                          &lt;table cellspacing="0" cellpadding="5"&gt;
                              &lt;tbody class="files"&gt;&lt;/tbody&gt;
                          &lt;/table&gt;
                      &lt;/div&gt;
                      &lt;div style="margin-bottom: 10px;" class="fileupload-buttonbar"&gt;
                          &lt;div class="v-button v-widget btnPlus"&gt;
                              &lt;span class="v-button-caption"&gt;Add Files&lt;/span&gt; 
                              &lt;input type="file" multiple="" name="files[]"&gt;
                          &lt;/div&gt;
                          &lt;div class="v-button v-widget start" type = "submit"&gt;
                              &lt;span class="v-button-wrap"&gt;
                                  &lt;span class="v-button-caption"&gt;StartUpload&lt;/span&gt;
                              &lt;/span&gt;
                          &lt;/div&gt;
                          &lt;div class="v-button v-widget cancel" type = "reset"&gt;
                              &lt;span class="v-button-wrap"&gt;
                                  &lt;span class="v-button-caption"&gt;Cancel All&lt;/span&gt;
                              &lt;/span&gt;
                          &lt;/div&gt;
                      &lt;/div&gt;
                      &lt;div style="border: 1px solid #999; width: 600px; height: 100px;" id="dropZone"&gt;
                          &lt;div class="carPhotoDropMsg"&gt;
                              Draft &amp;amp; Drop Photos&lt;br&gt;(jpg, jpeg, png, gif only)
                          &lt;/div&gt;
                      &lt;/div&gt;
                  &lt;/form&gt;
              &lt;/div&gt;
          &lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
  </code></pre>
  
  <p></p>
  
  <p>Below is for ImageUpload window</p>
  
  <pre><code>public final class ImageUploadDialog extends CustomComponent {
  private Window window;
  
  public void show() {
      UI.getCurrent().addWindow(window);
   // 123 is seq for save in database or other use
      Page.getCurrent().getJavaScript().execute("initImageuploader(123)");
  }
  
  public ImageUploadDialog() {
      CustomLayout layout = new CustomLayout("imageUploadLayout");
      window = new Window("Uploading Photos");
      window.center();
      window.setWidth("615px");
      window.setModal(true);
      window.setResizable(false);
      window.setClosable(true);
      window.setContent(layout);
  }
  }
  </code></pre>
  
  <p>And below is my upload.js file for initialize my image uploader</p>
  
  <pre><code>function initImageuploader(seq) {
  $('#fileupload').fileupload({
      url : 'photo/upload.html?s=' + seq,
      sequentialUploads : true,
      disableImageResize : false,
      imageMaxWidth : 1024,
      imageMaxHeight : 1024,
      previewCrop : true,
      dropZone : $("#dropZone"),
      acceptFileTypes : /(\.|\/)(gif|jpe?g|png)$/i,
      progress : function(e, data) {
          if (data.context) {
              var progress = data.loaded / data.total * 100;
              progress = Math.floor(progress);
              $('.progress').attr('aria-valuenow', progress);
              $('.progress').css('display', 'block');
              $('.bar').css('width', progress + '%');
          }
      },
      progressall : function(e, data) {
          var progress = data.loaded / data.total * 100;
          progress = Math.floor(progress);
          $('.progressall').attr('aria-valuenow', progress);
          $('.progressall').css('display', 'block');
          $('.allbar').css('width', progress + '%');
          if (progress &gt; 20) {
              $('.allbar').text(progress + '% Completed');
          }
      },
      stop: function (e) {
          return;
      }
  });
  }
  </code></pre>
  
  <p>And you need additional javascripts files for image uploader and I imported them at my UI class as below</p>
  
  <pre><code>@JavaScript({ "vaadin://themes/myproject/js/load-image.min.js",
      "vaadin://themes/myproject/js/tmpl.min.js",
      "vaadin://themes/myproject/js/jquery/jquery-1.10.1.min.js",
      "vaadin://themes/myproject/js/jquery/vendor/jquery.ui.widget.js",
      "vaadin://themes/myproject/js/jquery/jquery.iframe-transport.js",
      "vaadin://themes/myproject/js/jquery/jquery.fileupload.js",
      "vaadin://themes/myproject/js/jquery/jquery.fileupload-ui.js",
      "vaadin://themes/myproject/js/jquery/jquery.fileupload-process.js",
      "vaadin://themes/myproject/js/jquery/jquery.fileupload-image.js",
      "vaadin://themes/myproject/js/jquery/jquery.fileupload-validate.js",
      "vaadin://themes/myproject/js/canvas-to-blob.min.js",
      "vaadin://themes/myproject/js/upload.js" })
  @StyleSheet({ "vaadin://themes/myproject/css/jquery-ui-1.10.3.custom.min.css",
      "vaadin://themes/myproject/css/imageUpload.css" })
  public class EntryPoint extends UI {
  ..............
  }
  </code></pre>
  
  <blockquote>
    <p><strong>Please Notice for JS Files Order !</strong></p>
  </blockquote>
  
  <p>Below is my Custom CSS file for image upload window (<em>imageUpload.css</em>)</p>
  
  <pre><code>table.upld-status {
  display: none;
  }
  .fileupload-buttonbar .btnPlus {
  float: left;
  position: relative;
  overflow: hidden;
  color: blue;
  text-align: center;
  margin-right : 10px;
  }
  .fileupload-buttonbar .btnPlus input {
  margin: 0px;
  position: absolute;
  top: 0px;
  right: 0px;
  line-height: 30px;
  font-size: 23px;
  direction: ltr;
  opacity: 0;
  }
  .carPhotoDropMsg {
  color: #DDD;
  font-size: 20pt;
  height: 82%;
  padding: 9px;
  text-align: center;
  }
  .progress {
  background-color: #F7F7F7;
  background-image: linear-gradient(to bottom, #F5F5F5, #F9F9F9);
  background-repeat: repeat-x;
  border-radius: 4px 4px 4px 4px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) inset;
  height: 17px;
  overflow: hidden;
  }
  .progress-success.progress-striped .bar, .progress-success.progress-striped .allbar, .progress
  striped .bar-success {
  background-color: #62C462;
  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
  }
  .progress.active .bar, .progress.active .allbar {
  animation: 2s linear 0s normal none infinite progress-bar-stripes;
  }
  .progress-success .bar, .progress-success .allbar, .progress .bar-success {
  background-color: #5EB95E;
  background-image: linear-gradient(to bottom, #62C462, #57A957);
  background-repeat: repeat-x;
  }
  .progress-striped .bar, .progress-striped .allbar {
  background-color: #149BDF;
  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
  background-size: 40px 40px;
  }
  .progress .bar, .progress .allbar {
  -moz-box-sizing: border-box;
  background-color: #0E90D2;
  background-image: linear-gradient(to bottom, #149BDF, #0480BE);
  background-repeat: repeat-x;
  box-shadow: 0 -1px 0 rgba(0, 0, 0, 0.15) inset;
  color: #FFFFFF;
  float: left;
  font-size: 12px;
  height: 100%;
  text-align: center;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
  transition: width 0.4s ease 0s;
  width: 0;
  }
  </code></pre>
  
  <p>I need server-side control for save image . You need two jars <a href="http://commons.apache.org/proper/commons-io/" rel="nofollow">apache-common-io</a> and <a href="http://mvnrepository.com/artifact/commons-fileupload/commons-fileupload/1.3" rel="nofollow">apache-common-fileupload</a>. Below is for maven repository of these two jars.</p>
  
  <pre><code>    &lt;dependency&gt;
          &lt;groupId&gt;commons-fileupload&lt;/groupId&gt;
          &lt;artifactId&gt;commons-fileupload&lt;/artifactId&gt;
          &lt;version&gt;1.2.2&lt;/version&gt;
      &lt;/dependency&gt;
  
      &lt;dependency&gt;
          &lt;groupId&gt;commons-io&lt;/groupId&gt;
          &lt;artifactId&gt;commons-io&lt;/artifactId&gt;
          &lt;version&gt;2.4&lt;/version&gt;
      &lt;/dependency&gt;
  </code></pre>
  
  <p>Finally , below is codes for server-side control .</p>
  
  <pre><code>@WebServlet(value = "/photo/upload.html")
  public class UploadServletController extends HttpServlet {
  protected final void doPost(final HttpServletRequest request,
          final HttpServletResponse response) throws ServletException, IOException {
  
      response.setContentType("application/json");
      PrintWriter out = response.getWriter();
      FileItemFactory factory = new DiskFileItemFactory();
      ServletFileUpload upload = new ServletFileUpload(factory);
      List&lt;FileItem&gt; fields = null;
      try {
          fields = upload.parseRequest(request);
      }
      catch (FileUploadException e) {
          throw new RuntimeException("Error Parsing File Item " + e.getMessage(), e);
      }
      if (fields != null) {
          String message = uploadPhoto(request, fields);
          out.write(message);
      }
  }
  public final synchronized String uploadPhoto(final HttpServletRequest request,
          final List&lt;FileItem&gt; sessionFiles) {
  
      List&lt;Map&lt;String, Object&gt;&gt; ret = new ArrayList&lt;Map&lt;String, Object&gt;&gt;();
      for (FileItem item : sessionFiles) {
          if (!item.isFormField()) {
              Long seq = Long.parseLong(request.getParameter("s"));
  // get from vm arguments (eg:-DstaticDir=/Applications/springsource/workspace/myproject/src/main/webapp)
              String staticDir = System.getProperty("staticDir");
  
              Date today = new Date();
              SimpleDateFormat fmtYMD = new SimpleDateFormat("/yyyyMMdd/HH");
              SimpleDateFormat fmtHMS = new SimpleDateFormat("HHmmssS");
  
              String saveDir = "data/photo" + fmtYMD.format(today);
              String format = ".jpg";
              try {
                  format = item.getName().substring(item.getName().lastIndexOf("."), item.getName().length())
                          .toLowerCase();
              }
              catch (Exception e) {
                  // nothing to do!
              }
  
              String fileName = seq + "_" + fmtHMS.format(today) + format;
              Map&lt;String, Object&gt; res = new HashMap&lt;String, Object&gt;();
              // Save image in specify location
              String filePath = staticDir + "/" + saveDir;
              saveFile(filePath, fileName, item);
  
              res.put("seq", seq);
              res.put("path", saveDir + "/" + fileName);
              res.put("ext", format.substring(1));
  
              res.put("name", item.getName());
              res.put("size", item.getSize());
              ret.add(res);
          }
      }
      Map&lt;String, Object&gt; result = new HashMap&lt;String, Object&gt;();
      result.put("files", ret);
      JSONObject obj = new JSONObject(result);
  
      return obj.toString();
  }
  public static String saveFile(final String filePath, final String fileName, final FileItem item) {
      File file = new File(filePath);
      if (!file.exists()) {
          file.mkdirs();
      }
      File imageFile = new File(file, fileName);
      try {
          item.write(imageFile);
      }
      catch (Exception e) {
          e.printStackTrace();
      }
      item.setFieldName(filePath + fileName);
      return item.toString();
  }
  }
  </code></pre>
  
  <p>I know my codes may have risks and some weakpoints . Every suggestions were welcome . But I believe there has some useful for newbie (<em>I am also a newbie</em>). Sorry for too long and bad format.</p>
  
  <p>The last thing is my problem ....</p>
  
  <p>Why preview image (<em>after upload not before upload</em>) automatically include <strong>url</strong> instead of filepath ? I got image not found error</p>
  
  <pre><code>"NetworkError: 404 Not Found - http://localhost:8080/myproject/VAADIN/themes/myTheme/data/photo/20140723/23/123_235918346.jpg"
  </code></pre>
  
  <p>Actually this image path should be <code>data/photo/20140723/23/111_235918346.jpg</code>. I have no idea why prefix url <code>http://localhost:8080/myproject/VAADIN/themes/myTheme/</code> was automatically include (<em>may be due to my CustomLayout HTML file path</em>) ? File paths were got from HTTP response (with JSON). I think it is due to VAADIN because it works on my GWT project or may be I am wrong. Any suggestions ? Thanks for reading my question.</p>