Vaadin with jQuery FileUpload

I would like to create FileUploader with Vaadin . But I need to get more features over regular Vaadin download .

  • beautiful and easy to manage (but optional)
  • fast and never crash while loading
  • turn on progress bar
  • show preview
  • support for multiple files.
  • Download file size and file size limits
  • drag and drop
  • resizing the client side (this is the main function for me, because all my downloaded files were images)

There is an addon MultiFileUpload . Yes, this is ideal for most of my requirements, but not for resizing a client image . Therefore, I decided to use jQuery FileUpload , because it is support Client side Resize image .

I used vaadin Window to download the image. But I had a problem creating my window, it is very difficult to create each HTML element accordingly (maybe I have less exp). Therefore, I used CustomLayout with HTML to conveniently create and edit the window design of my image downloader.

Below is my custom HTML file layout. (two scenarios were templates for previewing images)

<script id="template-upload" type="text/x-tmpl"> {% for (var i=0, file; file=o.files[i]; i++) { %} <tr class="template-upload"> <td width="100px" align="center"> <span class="preview"></span> </td> <td width="400px" align="center"> <p class="name">{%=file.name%}</p> {% if (!o.files.error) { %} <div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="bar" style="width:0%;"></div></div> {% } %} {% if (file.error) { %} <div><span class="label label-important">Error</span> {%=file.error%}</div> {% } %} </td> <td width="100px" align="center"> {% if (!i) { %} <button style="display: none;" class="start" type="button"> <span>Start</span> </button> <div class="v-button v-widget cancel" type = "button"> <span class="v-button-wrap" style="color: red;"> <span class="v-button-caption">Cancel</span> </span> </div> {% } %} <br> {%=o.formatFileSize(file.size)%} </td> </tr> {% } %} </script> <!-- The template to display files available for download --> <script id="template-download" type="text/x-tmpl"> {% for (var i=0, file; file=o.files[i]; i++) { %} <tr class="template-download"> <td width="100px" align="center"> <span class="preview"> {% if (file.path) { %} <img src="../{%=file.path%}" width="100px"> {% } %} </span> </td> <td width="400px" align="center"> <p class="name"> {%=file.name%} </p> {% if (file.error) { %} <div><span class="label label-important">Error</span> {%=file.error%}</div> {% } %} </td> <td width="100px" align="center"> <span class="size">{%=o.formatFileSize(file.size)%}</span> </td> </tr> {% } %} </script> <table cellpadding="5" style="width: 100%;"> <colgroup> <col> </colgroup> <tbody> <tr> <td width="90px"> <div style="text-align: right; width: 120px;">UploadPhoto :</div> </td> <td> <div id="pnlProgress" aria-valuenow="0" aria-valuemax="100" aria-valuemin="0" style="display: none;" class="progress progressall progress-success progress-striped active"> <div style="width: 0%;" class="allbar" id="pnlProgressBar">&nbsp;</div> </div> </td> </tr> <tr> <td colspan="3"> <div id="imageForm" style="width: 600px;"> <form id="fileupload"> <div style="margin-bottom: 10px; border: 1px solid #DDD; width: 600px; height: 300px; overflow: scroll"> <table cellspacing="0" cellpadding="5"> <tbody class="files"></tbody> </table> </div> <div style="margin-bottom: 10px;" class="fileupload-buttonbar"> <div class="v-button v-widget btnPlus"> <span class="v-button-caption">Add Files</span> <input type="file" multiple="" name="files[]"> </div> <div class="v-button v-widget start" type = "submit"> <span class="v-button-wrap"> <span class="v-button-caption">StartUpload</span> </span> </div> <div class="v-button v-widget cancel" type = "reset"> <span class="v-button-wrap"> <span class="v-button-caption">Cancel All</span> </span> </div> </div> <div style="border: 1px solid #999; width: 600px; height: 100px;" id="dropZone"> <div class="carPhotoDropMsg"> Draft &amp; Drop Photos<br>(jpg, jpeg, png, gif only) </div> </div> </form> </div> </td> </tr> </tbody> 

Below for the ImageUpload window

 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); } } 

And below is my upload.js file to initialize my image downloader

 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 > 20) { $('.allbar').text(progress + '% Completed'); } }, stop: function (e) { return; } }); } 

And you need additional javascripts files for the image uploader, and I imported them into my user interface class below

 @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 { .............. } 

Please note that to order JS! Files

Below is my custom CSS file for the image upload window (imageUpload.css)

 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; } 

I need a server control to save the image. You need two banks apache-common-io and apache-common-fileupload . Below is the maven repository of these two jars.

  <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> 

Finally, below are the codes for server-side management.

 @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<FileItem> 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<FileItem> sessionFiles) { List<Map<String, Object>> ret = new ArrayList<Map<String, Object>>(); 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<String, Object> res = new HashMap<String, Object>(); // 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<String, Object> result = new HashMap<String, Object>(); 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(); } } 

I know that my codes may have risks and some weaknesses. All suggestions are welcome. But I believe that there is something useful for beginners (I am also a beginner). Sorry for the too long and bad format.

The last thing is my problem ....

Why does previewing the image (after downloading not before downloading) automatically include the url instead of the file path? I received an image not found error

 "NetworkError: 404 Not Found - http://localhost:8080/myproject/VAADIN/themes/myTheme/data/photo/20140723/23/123_235918346.jpg" 

Actually this path should be data/photo/20140723/23/111_235918346.jpg . I don’t know why the url prefix http://localhost:8080/myproject/VAADIN/themes/myTheme/ was automatically turned on (maybe because of my path to the CustomLayout HTML file)? File paths were obtained from an HTTP response (using JSON). I think this is due to VAADIN because it is working on my GWT project or maybe I'm wrong. Any suggestions? Thanks for reading my question.

+1
file-upload image-uploading vaadin jquery-file-upload vaadin7
source share
1 answer

I fixed it by correcting the src value of the preview template after loading the image as ...

 <script id="template-download" type="text/x-tmpl"> {% for (var i=0, file; file=o.files[i]; i++) {; %} <tr class="template-download"> <td width="100px" align="center"> <span class="preview"> {% if (file.path) { %} <img src="/myproject/{%=file.path%}" width="100px"> {% } %} </span> </td> <td width="400px" align="center"> <p class="name"> {%=file.name%} </p> {% if (file.error) { %} <div><span class="label label-important">Error</span> {%=file.error%}</div> {% } %} </td> <td width="100px" align="center"> <span class="size">{%=o.formatFileSize(file.size)%}</span> </td> </tr> {% } %} </script> 

Now everything was in order. If you do not see the image without changes, check the IDE settings (Eclipse or STS) below

Preferences> General> Workspace

and check the boxes for Refresh on access and Refresh using native hooks or polling .

+1
source share

All Articles