>美观且易于管理(但可选)
>上传时快速且永不失败
>包括进度条
>显示预览
>多文件上传支持
>上传文件大小和类型限制
>拖放
>客户端图像可调整大小(这是我的主要功能,因为我上传的所有文件都是图像)
有一个插件MultiFileUpload.是的,它非常适合我的大多数要求,但不适用于客户端大小的图像大小调整.所以我决定使用JQuery FileUpload,因为它支持Client side Image Resizing.
我用vaadin Window上传图片.但是我在创建窗口时遇到了问题,分别很难创建每个HTML元素(可能我的exp少了).所以我使用CustomLayout with HTML轻松创建和编辑我的图像上传窗口的设计.
下面是我的自定义布局HTML文件. (两个脚本是图像预览模板)
<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"> </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 & Drop Photos<br>(jpg,jpeg,png,gif only) </div> </div> </form> </div> </td> </tr> </tbody>
下面是ImageUpload窗口
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); } }
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; } }); }
你需要额外的javascripts文件用于图像上传器,我在我的UI类中导入它们,如下所示
@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 Notice for JS Files Order !
下面是我的图像上传窗口的自定义CSS文件(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.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,0.15) 25%,transparent 25%,transparent 50%,0.15) 50%,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,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.15) inset; color: #FFFFFF; float: left; font-size: 12px; height: 100%; text-align: center; text-shadow: 0 -1px 0 rgba(0,0.25); transition: width 0.4s ease 0s; width: 0; }
我需要服务器端控制来保存图像.你需要两个罐子apache-common-io和apache-common-fileupload.下面是这两个罐子的maven存储库.
<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>
最后,下面是服务器端控制的代码.
@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(); } }
我知道我的代码可能有风险和一些弱点.欢迎提出任何建议.但我相信新手有一些用处(我也是新手).抱歉格式太长,不好.
最后一件事是我的问题….
为什么预览图像(上传后不上传之前)自动包含url而不是filepath?我找不到图像错误
"NetworkError: 404 Not Found - http://localhost:8080/myproject/VAADIN/themes/myTheme/data/photo/20140723/23/123_235918346.jpg"
实际上这个图像路径应该是data / photo / 20140723/23 / 111_235918346.jpg.我不知道为什么前缀url http:// localhost:8080 / myproject / VAADIN / themes / myTheme /是自动包含的(可能是由于我的CustomLayout HTML文件路径)?文件路径来自HTTP响应(使用JSON).我认为这是由于VAADIN,因为它适用于我的GWT项目,或者可能是我错了.有什么建议么 ?感谢您阅读我的问题.
解决方法
<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>
现在每个人都很好.如果您没有立即看到图像,请检查您的IDE(Eclipse或STS)设置如下
Preference > General > Workspace
并选中复选框访问时刷新和使用本机挂钩或轮询刷新.