一、認識FineUploader的功能:
進入示例網站:https://fineuploader.com/demos.html#basic-setup;
二、準備相關的js,css
Build Fine Uploader yourself from the GitHub repo
git clone https://github.com/FineUploader/fine-uploader.git
cd fine-uploader
npm install
make build
make build之後將生成一個“_build”目錄,其中包含CSS、JS、圖像和模板文件,以供所有可能構建的Fine Uploader。
上面是下載的fine-Uploader前臺所需的代碼。下面來看看後臺代碼:
三:服務器示例代碼:
git clone https://github.com/FineUploader/server-examples/blob/master/java/UploadReceiver.java
我們所需要的java代碼就在java那個目錄下:
到現在,準備工作已經完成。
四、新建一個自己的web項目:
1、輸入工程名,finish之後目錄結構是這樣的:
2、添加剛纔在server-example中的java文件到src下:
然後這樣直接會報錯,應該在java文件中修改所在包名,並引入所有需要的jar包:
目前暫時引入了這些包。
3、接下來新建html了:
從剛纔在git上下載的fine-Uploader文件夾中的client/html/templates中找到這次示例要用的html文件:gallery.html
(https://docs.fineuploader.com/features/styling.html 這裏會涉及這幾個文件的講解)
<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文件,
以上是假如有圖片上傳的顯示模板,那麼得需要一個供圖片拖動到的位置:(如示例網站):
此時此刻,我們需要對定義的該位置,“綁定”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的作用就是將前臺傳過來的文件信息獲取,並填充自己的屬性:
獲得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的安裝目錄。
我這寫的是絕對路徑。
寫入的文件會這樣存放:
每個文件的上層文件夾的名字就是其對應的uuid。
5、運行項目,添加缺少的文件,比如前臺需要的gif圖:
將報錯的這幾個文件都加入到css文件夾中。這樣還可以完成刪除操作。
這樣就完成了fineuploader的例子使用。