插件下载地址:http://pan.baidu.com/s/1mhqRCyk(表示虽然有官网,但是官网的貌似不对)
Fine Uploader特点如下:
Fine Uploader Features:
A:支持文件上传进度显示.
B:文件拖拽浏览器上传方式
C:Ajax页面无刷新.
D:多文件上传.
F:跨浏览器.
E:跨后台服务器端语言.
qq.FineUploader对象还有如下控制参数:
validation:该参数一般用来在执行上传文件操作前.在客户端做一些验证.验证操作包含文件格式.文件大小.等添加格式如下:
1: validation:
2: {
3: allowedExtensions: ['jpeg', 'jpg', 'gif', 'png'],
4: sizeLimit: 204800 // 200 kB = 200 * 1024 bytes
5: }
allowedExtensions控制上传文件的后缀格式数组.
sizeLimit上传文件大小的上限,单位为byte的数值.浏览器不一定支持本设置.也可以在服务器端里设置.
minSizeLimit:上传文件大小的下限,单位为byte的数值.同上有些浏览器存在适配问题.建议统一在服务端设置.
另外针对qq.FineUploder对象在执行上传操作整个过程.定义了五个客户端可控做额外操作的事件.可以再callback参数下设置定义:
1: callbacks:
2: {
3: onSubmit: function(id, fileName) {
4: $messages.append('<div id="file-' + id + '" class="alert" style="margin: 20px 0 0"></div>');
5: },
6: onUpload: function(id, fileName) {
7: $('#file-' + id).addClass('alert-info')
8: .html('<img src="client/loading.gif" alt="Initializing. Please hold."> ' +
9: 'Initializing ' +
10: '“' + fileName + '”');
11: }
12: }
onSubmit事件:文件开始提交.调用参数格式如下:onSubmit: function(id, fileName) {}.
onUpload事件: 文件开始上传.调用参数格式如下:onUpload: function(id, fileName) {}.
onProgress事件: 文件正在上传.调用参数格式如下:onProgress: function(id, fileName, loaded, total) {}.
onComplete事件: 文件上传成功. 调用参数格式如下:onComplete: function(id, fileName, responseJSON) {}.
onCancel事件: 取消文件上传.调用参数格式如下:onCancel: function(id, fileName) {}.
如上五个事件基本覆盖整个上传文件操作中所有过程.完全以开放的形式可以再客户端操作.关于调用如上事件参数说明如下:
Id:表示第几个开始上传的文件.Fine Uploder定义是默认从0开始计数.
fileName:上传文件的文件名.
loaded:表示已经上传到服务器端数据的大小[byte].
total: 需要上传文件的大小.
responseJSON: 用来在上传操作完成后返回的Json格式的数据.通过Jquery反序列化出来对象.其中包含一个IsSuccess属性用来判断此次上传是否成功.
如果你想在上传过程向服务器端传递数据.可以通过如下参数控制:
params:用来向服务器端传递数据.注意params采用key-value的数组存储.采用Post方式发送给服务器端.一般传递参数格式如下:
1: params:
2: {
3: argument1: "value1",
4: argument2: "value2"
5: },
ok.这时基本关于Fine Uploader客户端初始化和控制操作选项基本完成.当我们需要上传操作时.如果IsAuto=false时可以通过已经定义qq.FineUploader对象的uploadStoreFiles()方式手工触发上传操作:
1: $('#triggerUpload').click(function() {
2: uploader2.uploadStoredFiles();
3: });
如果我们此时点击上传会发现.则提示上传失败. 因为还没有对上传服务器端做任何处理:
1: request:
2: {
3: endpoint: 'server/handlerfunction'
4: },
这时我们需要在EndPoint指定处理文件上传的Php文件[这里是phpdemo]
index.html
- <!DOCTYPE html>
- <html>
- <head>
- <title>上传文件测试</title>
- <link href="fine-uploader/fineuploader-new.css" rel="stylesheet">
- <!-- <link href="fine-uploader/bootstrap.min.css" rel="stylesheet"> -->
- <script src="fine-uploader/fine-uploader.min.js"></script>
- <script type="text/template" id="qq-template">
- <div class="qq-uploader-selector qq-uploader" qq-drop-area-text="Drop files here">
- <div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container">
- <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div>
- </div>
- <div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
- <span class="qq-upload-drop-area-text-selector"></span>
- </div>
- <div class="qq-upload-button-selector qq-upload-button">
- <div>Upload a file</div>
- </div>
- <span class="qq-drop-processing-selector qq-drop-processing">
- <span>Processing dropped files...</span>
- <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
- </span>
- <ul class="qq-upload-list-selector qq-upload-list" aria-live="polite" aria-relevant="additions removals">
- <li>
- <div class="qq-progress-bar-container-selector">
- <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-progress-bar-selector qq-progress-bar"></div>
- </div>
- <span class="qq-upload-spinner-selector qq-upload-spinner"></span>
- <img class="qq-thumbnail-selector" qq-max-size="100" qq-server-scale>
- <span class="qq-upload-file-selector qq-upload-file"></span>
- <span class="qq-edit-filename-icon-selector qq-edit-filename-icon" aria-label="Edit filename"></span>
- <input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
- <span class="qq-upload-size-selector qq-upload-size"></span>
- <button type="button" class="qq-btn qq-upload-cancel-selector qq-upload-cancel">Cancel</button>
- <button type="button" class="qq-btn qq-upload-retry-selector qq-upload-retry">Retry</button>
- <button type="button" class="qq-btn qq-upload-delete-selector qq-upload-delete">Delete</button>
- <span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span>
- </li>
- </ul>
- <dialog class="qq-alert-dialog-selector">
- <div class="qq-dialog-message-selector"></div>
- <div class="qq-dialog-buttons">
- <button type="button" class="qq-cancel-button-selector">Close</button>
- </div>
- </dialog>
- <dialog class="qq-confirm-dialog-selector">
- <div class="qq-dialog-message-selector"></div>
- <div class="qq-dialog-buttons">
- <button type="button" class="qq-cancel-button-selector">No</button>
- <button type="button" class="qq-ok-button-selector">Yes</button>
- </div>
- </dialog>
- <dialog class="qq-prompt-dialog-selector">
- <div class="qq-dialog-message-selector"></div>
- <input type="text">
- <div class="qq-dialog-buttons">
- <button type="button" class="qq-cancel-button-selector">Cancel</button>
- <button type="button" class="qq-ok-button-selector">Ok</button>
- </div>
- </dialog>
- </div>
- </script>
- </head>
- <body>
- <div id="fine-uploader"></div>
- <script>
- var uploader = new qq.FineUploader({
- debug: true,
- element: document.getElementById('fine-uploader'),
- request: {
- endpoint: 'uploadhandler.php'
- },
- deleteFile: {
- enabled: true,
- endpoint: ''
- },
- retry: {
- enableAuto: true
- },
- callbacks:{
- onComplete: function(id, fileName, responseJSON) {
- console.log(responseJSON);
- }
- }
- });
- </script>
- </body>
- </html>
===================================================================================
近来做一个需要有附件管理的公告版,于是发现了这个FineUploader,纯Javascript实现,Ajax方式,上传文件不刷新页面,不依赖于任何第三方库,非常好用。但刚开始使用时google了很多资料,包括官方的文档和demo。发现网上的很多资料要么很老,要么对我参考意义不大。至这个功能完成,写下自己的心得,给自己留点记录,如果能对别人有点参考价值则更佳。
FineUploader官方网站:http://fineuploader.com/ ,打包好的js是要收费的,价格还不便宜。
开源的项目:https://github.com/FineUploader/fine-uploader
本文中用到的FineUploader已上传到http://download.youkuaiyun.com/detail/jxiaoliu/8071341(已精简,去掉了所有用不到的文件,包括模板)
一、FineUploader所需的代码
首先,引入必须的js文件和css
- <link href="<%=request.getContextPath()%>/fineuploader5/fineuploader-5.0.2.css" rel="stylesheet"/>
- <script src="<%=request.getContextPath()%>/fineuploader5/fineuploader-5.0.2.js" type="text/javascript"></script>
接下来,就可以在js中实例化这个uploader:
- var submitFile = false;//用于控制仅在”提交“按钮按下时提交文件
- var uploader = null;
- function createUploader() {
- uploader = new qq.FineUploader({
- element: document.getElementById('fine-uploader'),
- autoUpload: false,
- request: {
- endpoint: '<%=request.getContextPath()%>/updownfile/UploadFile?op=add'
- },
- session: {
- endpoint: '<%=request.getContextPath()%>/manage/Bulletin?op=getattach',
- params: {'id': ${bulletin.id}}
- },
- deleteFile: {
- enabled: true,
- endpoint: '<%=request.getContextPath()%>/manage/Bulletin?op=del',
- method: 'POST',
- forceConfirm: true,
- confirmMessage: '确定要删除文件 {filename} 吗? 不可恢复!!',
- deletingFailedText: '删除失败!'
- },
- editFilename: {
- enabled: false
- },
- callbacks: {
- onAllComplete: function(successIDs, failIDs) {
- if(submitFile)
- submitdata(successIDs);
- }
- }
- });
- }
- window.onload = createUploader;
- <div id="fine-uploader"></div>
- <script type="text/template" id="qq-template">
- <div class="qq-uploader-selector qq-uploader">
- <div class="qq-upload-button-selector qq-upload-button">
- <div>上传附件</div>
- </div>
- <ul class="qq-upload-list-selector qq-upload-list">
- <li>
- <div class="qq-progress-bar-container-selector">
- <div class="qq-progress-bar-selector qq-progress-bar"></div>
- </div>
- <span class="qq-upload-spinner-selector qq-upload-spinner"></span>
- <span class="qq-edit-filename-icon-selector qq-edit-filename-icon"></span>
- <span class="qq-upload-file-selector qq-upload-file"></span>
- <span class="qq-upload-size-selector qq-upload-size"></span>
- <a class="qq-upload-cancel-selector qq-upload-cancel" href="#">放弃上传</a>
- <a class="qq-upload-retry-selector qq-upload-retry" href="#">Retry</a>
- <a class="qq-upload-delete-selector qq-upload-delete" href="#">删除</a>
- <span class="qq-upload-status-text-selector qq-upload-status-text"></span>
- </li>
- </ul>
- </div>
- </script>
该模板的样式可以通过fineuploader-5.0.2.css文件进行所需的修改,这里不再赘述。
至此,FineUploader已完整,当然要运行必须要后台代码的上传支持。
二、后台Java代码
借助于apache.commons.fileupload组件进行文件的上传,代码如下:
- try {
- MultipartUploadParser UploadParser = new MultipartUploadParser(request, new File(System.getProperty("java.io.tmpdir")));
- FileItem uploadfile = UploadParser.getFirstFile();
- Path file = java.nio.file.Paths.get(uploadfile.getName());
- uploadfile.write(new File(rootpath + "/temp/" + file.getFileName().toString()));
- result.put("success", true);
- } catch (Exception e) {
- result.put("success", false);
- response.getWriter().print(result.toString());
- e.printStackTrace();
- }
必须注意的是,文件上传成功后,必须返回前台一个JSON格式的对象,其中必须含有一个"success"对象,其值为true或者false,代表着文件上传的成功或失败。
另外,当用户选择多个文件并上传时,是以多线程的方式各自独立同时进行的。每一个文件上传成功都会触发callbacks中的onComplete事件,所有文件上传成功后触发onAllComplete事件。
其中的MultipartUploadParser类对象定义如下:
- package updownfile;
- import org.apache.commons.fileupload.FileItem;
- import org.apache.commons.fileupload.FileUploadException;
- import org.apache.commons.fileupload.disk.DiskFileItemFactory;
- import org.apache.commons.fileupload.servlet.ServletFileUpload;
- import org.apache.commons.lang3.StringUtils;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import javax.servlet.http.HttpServletRequest;
- import java.io.File;
- import java.io.IOException;
- import java.io.UnsupportedEncodingException;
- import java.util.*;
- public class MultipartUploadParser
- {
- final Logger log = LoggerFactory.getLogger(MultipartUploadParser.class);
- private Map params = new HashMap();
- private List files = new ArrayList();
- // fileItemsFactory is a field (even though it's scoped to the constructor) to prevent the
- // org.apache.commons.fileupload.servlet.FileCleanerCleanup thread from attempting to delete the
- // temp file before while it is still being used.
- //
- // FileCleanerCleanup uses a java.lang.ref.ReferenceQueue to delete the temp file when the FileItemsFactory marker object is GCed
- private DiskFileItemFactory fileItemsFactory;
- @SuppressWarnings("unchecked")
- public MultipartUploadParser(HttpServletRequest request, File repository) throws Exception
- {
- if (!repository.exists() && !repository.mkdirs())
- {
- throw new IOException("Unable to mkdirs to " + repository.getAbsolutePath());
- }
- fileItemsFactory = setupFileItemFactory(repository);
- ServletFileUpload upload = new ServletFileUpload(fileItemsFactory);
- List formFileItems = upload.parseRequest(request);
- parseFormFields(formFileItems);
- if (files.isEmpty())
- {
- log.warn("No files were found when processing the requst. Debugging info follows.");
- writeDebugInfo(request);
- throw new FileUploadException("No files were found when processing the requst.");
- }
- else
- {
- if (log.isDebugEnabled())
- {
- writeDebugInfo(request);
- }
- }
- }
- private DiskFileItemFactory setupFileItemFactory(File repository)
- {
- DiskFileItemFactory factory = new DiskFileItemFactory();
- factory.setSizeThreshold(10*1024*1024);
- factory.setRepository(repository);
- // FileCleaningTracker pTracker = FileCleanerCleanup.getFileCleaningTracker(context);
- // factory.setFileCleaningTracker(pTracker);
- return factory;
- }
- private void writeDebugInfo(HttpServletRequest request)
- {
- log.debug("-- POST HEADERS --");
- for (String header : Collections.list(request.getHeaderNames()))
- {
- log.debug("{}: {}", header, request.getHeader(header));
- }
- log.debug("-- POST PARAMS --");
- for (String key : params.keySet())
- {
- log.debug("{}: {}", key, params.get(key));
- }
- }
- private void parseFormFields(List items) throws UnsupportedEncodingException
- {
- for (FileItem item : items)
- {
- if (item.isFormField())
- {
- String key = item.getFieldName();
- String value = item.getString("UTF-8");
- if (StringUtils.isNotBlank(key))
- {
- params.put(key, StringUtils.defaultString(value));
- }
- }
- else
- {
- files.add(item);
- }
- }
- }
- public Map getParams()
- {
- return params;
- }
- public List getFiles()
- {
- if (files.isEmpty())
- {
- throw new RuntimeException("No FileItems exist.");
- }
- return files;
- }
- public FileItem getFirstFile()
- {
- if (files.isEmpty())
- {
- throw new RuntimeException("No FileItems exist.");
- }
- return files.iterator().next();
- }
- }
三、代码中各选项含义
- autoUpload选项:控制用户选择文件后是否立即自动上传选中的文件,默认为true,即选中后自动上传到服务器,上传完毕后,会依次显示文件名、文件大小及一个“删除”链接(删除上传文件的解释见deleteFile选项)。这里设置值为false,表示用户选择文件后仅列出文件(此时文件名右侧会出现“放弃”链接,点此链接会去除对应的文件),在需要时手动通过uploadStoredFiles()方法进行上传。
- multiple选项:默认为true,用户可以一次选择多个文件并上传。
- request选项:后台接受文件上传的URL路径。设置其中的endpoint属性。
- editFilename选项:设置是否可修改上传的文件名(本人测试时好像没发现有什么作用~~)
- callbacks选项:回调函数,可以监听各种事件。具体的可参见官方文档。
- deleteFile选项:用于删除已上传的文件。可以删除的文件必须是在同一个页面中已经成功上传,或者由session选项初始化的文件列表。其重要的子选项解释如下:
endpoint:后台用于删除文件的URL地址。返回值和上传时一样必须含有“success”属性
method:重要,必须设置为'post'
forceConfirm:是否出现删除确认的对话框,默认值为false - session选项:该选项确定控件初始化时需要初始化的文件列表。若不设置该项,则初始化控件时其文件列表为空。若需要给出用户以前已经上传的文件列表,则必须设置其子选项endpoint的值以从后台返回文件列表。后台返回的值必须是一个JSON格式的数组,每个数组的对象是JSON格式的对象,必须包含“name”和“uuid”两个属性,以分别指定文件名和文件的唯一代号。具体可参看官方文档。
四、几张简单的样图
1. 文件已选择,待上传: