一、认识FineUploader的功能:

进入示例网站:https://fineuploader.com/demos.html#basic-setup;

二、准备相关的js,css 

Build Fine Uploader yourself from the GitHub repo

  1. git clone https://github.com/FineUploader/fine-uploader.git

  2. cd fine-uploader

  3. npm install

  4. make build


make build之后将生成一个“_build”目录,其中包含CSS、JS、图像和模板文件,以供所有可能构建的Fine Uploader

初步学习FineUploader(java)_Fine

上面是下载的fine-Uploader前台所需的代码。下面来看看后台代码:

三:服务器示例代码:

git clone https://github.com/FineUploader/server-examples/blob/master/java/UploadReceiver.java

初步学习FineUploader(java)_Uploader_02

我们所需要的java代码就在java那个目录下:


初步学习FineUploader(java)_Uploader_03

到现在,准备工作已经完成。


四、新建一个自己的web项目:

初步学习FineUploader(java)_Fine_04

1、输入工程名,finish之后目录结构是这样的:

初步学习FineUploader(java)_Fine_05

2、添加刚才在server-example中的java文件到src下:

然后这样直接会报错,应该在java文件中修改所在包名,并引入所有需要的jar包:

初步学习FineUploader(java)_Uploader_06


目前暂时引入了这些包。

3、接下来新建html了:

从刚才在git上下载的fine-Uploader文件夹中的client/html/templates中找到这次示例要用的html文件:gallery.html

https://docs.fineuploader.com/features/styling.html  这里会涉及这几个文件的讲解)

初步学习FineUploader(java)_Uploader_07

<script type="text/template" id="qq-template">
    <div class="qq-uploader-selector qq-uploader qq-gallery" 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" role="region" aria-live="polite" aria-relevant="additions removals">
            <li>
                <span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span>
                <div class="qq-progress-bar-container-selector qq-progress-bar-container">
                    <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>
                <div class="qq-thumbnail-wrapper">
                    <img class="qq-thumbnail-selector" qq-max-size="120" qq-server-scale>
                </div>
                <button type="button" class="qq-upload-cancel-selector qq-upload-cancel">X</button>
                <button type="button" class="qq-upload-retry-selector qq-upload-retry">
                    <span class="qq-btn qq-retry-icon" aria-label="Retry"></span>
                    Retry
                </button>

                <div class="qq-file-info">
                    <div class="qq-file-name">
                        <span class="qq-upload-file-selector qq-upload-file"></span>
                        <span class="qq-edit-filename-icon-selector qq-btn qq-edit-filename-icon" aria-label="Edit filename"></span>
                    </div>
                    <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-delete-selector qq-upload-delete">
                        <span class="qq-btn qq-delete-icon" aria-label="Delete"></span>
                    </button>
                    <button type="button" class="qq-btn qq-upload-pause-selector qq-upload-pause">
                        <span class="qq-btn qq-pause-icon" aria-label="Pause"></span>
                    </button>
                    <button type="button" class="qq-btn qq-upload-continue-selector qq-upload-continue">
                        <span class="qq-btn qq-continue-icon" aria-label="Continue"></span>
                    </button>
                </div>
            </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>

将上面的代码全部复制到新建的html文件:

然后在代码中引入fineUploader的核心js和css:

gallery.html必须使用fine-uploader-gallery.css文件,

以上是假如有图片上传的显示模板,那么得需要一个供图片拖动到的位置:(如示例网站):
初步学习FineUploader(java)_Fine_08

此时此刻,我们需要对定义的该位置,“绑定”fine-Uploader组件:

<script type="text/javascript">  
function createUploader() {  
    uploader = new qq.FineUploader({  
    		
        	element: document.getElementById('fine-uploader-gallery'),  
                autoUpload: true,  //是否自动上传,true就会自动上传
        	multiple : true, //multiple选项:默认为true,用户可以一次选择多个文件并上传。
            request: {  //后台接受文件上传的URL路径。设置其中的endpoint属性。
                endpoint: '/FineUploaderServerExample/servlet/UploadReceiver'
            },  
            /**
            session: {  
                endpoint: '<%=request.getContextPath()%>/XXXX/XXXX',  
                params: {'id': ${bulletin.id}}  
            },
            */
            deleteFile: {  //用于删除已上传的文件。可以删除的文件必须是在同一个页面中已经成功上传,或者由session选项初始化的文件列表。
                enabled: true,  
                endpoint: '/FineUploaderServerExample/servlet/UploadReceiver',  //后台用于删除文件的URL地址。返回值和上传时一样必须含有“success”属性
                method: 'POST',//必须设置为'post'
                forceConfirm: true,  //是否出现删除确认的对话框,默认值为false
                confirmMessage: '确定要删除文件 {filename} 吗? 不可恢复!!', 
                params: {
                    foo: "bar"
                },
                deletingFailedText: '删除失败!'  
            }, 
            text : {
            	uploadButton : "<a href='#' class='add_files'><span class='icon-attachment'></span>浏览</a>"
            	},
            
            validation: 
            	      {
            	           allowedExtensions: ['jpeg', 'jpg', 'gif', 'png'],
            	           itemLimit:12,
            	           sizeLimit: 2048 // 200 kB = 200 * 1024 bytes
            	     },
            editFilename: {  
                   enabled: false  
            }, 
            onSubmit:  function(id,  fileName)  {
            	
            },
            onUpload: function(id, fileName) {
            	
            },
            //loaded:表示已经上传到服务器端数据的大小[byte].
            //total: 需要上传文件的大小.
            onProgress:  function(id,  fileName,  loaded,  total)  {
            	
            },
            onComplete:  function(id,  fileName,  responseJSON)  {
            	
            },
            //id表示第几个开始上传的文件,Fine Uploder定义是默认从0开始计数.
           //fileName:上传文件的文件名.
            onCancel:  function(id,  fileName)  {
            	
            },
            callbacks: {  
                onAllComplete:  function(successIDs, failIDs)  {  
                    if(submitFile)  
                        submitdata(successIDs);  
                }  
            },
            params:{
            	param1:"value1",
            	param2:"value2"
            },
            retry: {
                enableAuto: true
            },
            
            debug:true
    });  
}  
window.onload = createUploader;  
</script>
 endpoint: '/FineUploaderServerExample/servlet/UploadReceiver',

endpoint这里:FineUploaderServerExample是工程名,/servlet/UploaderReceiver是访处理post请求的servlet的类。

至此,test.html就基本完成了。(然后加上web.xml)

4、修改刚才复制到项目中的server-example中的Java代码:

通过代码结构可以看出,UploadReceiver.java是直接处理上传和删除请求的类:

由于前台endpoint中请求的后台url都是post请求的,所以我们首先来看看doPost方法:

大致来看,第一步,根据请求的HttpRequest,临时存放文件的文件夹,上下文传入MultipartUploadParser这个类。

根据MultipartUploadParser类的构造方法,返回一个MultipartUploadParser实体。那我们看看在构造方法里是执行了什么操作:

public MultipartUploadParser(HttpServletRequest request, File repository, ServletContext context) throws Exception
	{
	//创建临时文件夹
	    if (!repository.exists() && !repository.mkdirs())
	    {
		throw new IOException("Unable to mkdirs to " + repository.getAbsolutePath());
	    }
            //servlet实现文件上传---核心API—DiskFileItemFactory
	    fileItemsFactory = setupFileItemFactory(repository, context);
            //在setupFileItemFactory中指定临时文件目录,并给该目录设置了一个文件清理跟踪器
            //临时文件在不再被使用的时候(如果相应的java.io.File是可回收的则更好)会自动被删除.(文件清理跟踪器)
            ServletFileUpload upload = new ServletFileUpload(fileItemsFactory);
            List<FileItem> formFileItems = upload.parseRequest(request);
                //将request进行解析并添加到FileItem中
		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())
			{
				System.out.println("log.isDebugEnabled");
				writeDebugInfo(request);
			}
		}
	}

获得一个 MultipartUploadParser之后,再据此获得一个RequestParser类的实例。

static RequestParser getInstance(HttpServletRequest request, MultipartUploadParser multipartUploadParser) throws Exception
    {
        RequestParser requestParser = new RequestParser();

        if (multipartUploadParser == null)
        {
            if (request.getMethod().equals("POST") && request.getContentType() == null)
            {
                parseXdrPostParams(request, requestParser);
            }
            else
            {
                requestParser.filename = request.getParameter(FILENAME_PARAM);
                parseQueryStringParams(requestParser, request);
            }
        }
        else
        {
            requestParser.uploadItem = multipartUploadParser.getFirstFile();
            requestParser.filename = multipartUploadParser.getFirstFile().getName();

            //params could be in body or query string, depending on Fine Uploader request option properties
            parseRequestBodyParams(requestParser, multipartUploadParser);
            parseQueryStringParams(requestParser, request);
        }

        removeQqParams(requestParser.customParams);

        return requestParser;
    }

RequestParser的作用就是将前台传过来的文件信息获取,并填充自己的属性:

初步学习FineUploader(java)_Uploader_09

获得RequestParser之后,用writeFileForMultipartRequest方法写到指定位置:

private void writeFileForMultipartRequest(RequestParser requestParser) throws Exception {
		File dir = new File(UPLOAD_DIR, requestParser.getUuid());//在指定的文件夹下,创建一个子文件夹,名为对应的uuid
		dir.mkdirs();
		System.out.println("writeFileForMultipartRequest === ");
		if (requestParser.getPartIndex() >= 0) {
			writeFile(requestParser.getUploadItem().getInputStream(),
					new File(dir, requestParser.getUuid() + "_" + String.format("%05d", requestParser.getPartIndex())),
					null);

			if (requestParser.getTotalParts() - 1 == requestParser.getPartIndex()) {
				File[] parts = getPartitionFiles(dir, requestParser.getUuid());
				File outputFile = new File(dir, requestParser.getOriginalFilename());//timg.jpg
				for (File part : parts) {
					mergeFiles(outputFile, part);
				}

				assertCombinedFileIsVaid(requestParser.getTotalFileSize(), outputFile, requestParser.getUuid());
				deletePartitionFiles(dir, requestParser.getUuid());
			}
		} else {
			writeFile(requestParser.getUploadItem().getInputStream(), new File(dir, requestParser.getFilename()), null);
		}
	//	option.add(++id, requestParser.getFilename(), requestParser.getUuid(), requestParser.getUuid().substring(5, 8));
	}

//需要注意的是,这个文件夹如果没有指定绝对路径,那么遇到过的情况是:1、在桌面,2、在eclipse的安装目录。

我这写的是绝对路径。

写入的文件会这样存放:

初步学习FineUploader(java)_Fine_10

每个文件的上层文件夹的名字就是其对应的uuid。

5、运行项目,添加缺少的文件,比如前台需要的gif图:

初步学习FineUploader(java)_Uploader_11

将报错的这几个文件都加入到css文件夹中。这样还可以完成删除操作。

初步学习FineUploader(java)_Uploader_12

这样就完成了fineuploader的例子使用。