2014-12-03 60 views
1

我使用字段輸入的文件類型加載多個文件列表。問題是我想在表單發佈之前從原始列表中刪除它們中的一些。 Couse FileList在js中是不可變的,我不能創建新的輸入來重寫FileList(js安全原因)。我必須用我想提交的文件構建數組。使用wicket ajax從js發送文件數組到文件

但我不知道如何發佈和使用它接收Wicket.Ajax.post(由於上述我不能發佈形式)

標準fileUploadField get請求爲IMultipartWebRequest的情況下對形式帖子。如何使用Wicket.Ajax.post做同樣的事情?

+0

嗨Jedi先生,你能解決這裏描述的問題嗎?我處於同樣的情況:如果我一次上載多個文件/在一個文件輸入字段中,我想從文件列表中刪除特定文件。 Wicket 6.x中提供的'MultiFileUploadField'刪除所有文件,如果它們一起被選中,這不是我想要的。 因爲我正在爲現有軟件製作一種插件,所以我無法將Wicket升級到更新的版本,也無法在Wicket應用程序中安裝資源。 – Vertongen 2017-05-17 16:57:19

+0

@Vertongen據我所知,我使用了某種jQuery uploder插件,並用隱藏的輸入做一些技巧來發送這些帶有形式的文件。但我不確定,這是前一段時間,我沒有項目來源。 – 2017-05-18 07:16:07

+0

非常感謝您的快速回復。爲了不好,你再也沒有消息來源。當我找到它的時候,我會堅持併發佈一個答案。 – Vertongen 2017-05-18 12:10:54

回答

0

Wicket.Ajax.post()是http://api.jquery.com/jquery.ajax/的包裝。 它只是給你鉤子,你可以操縱請求或響應:onBefore,onPrecondition,onSuccess等。 所以,如果你找到一種方法來做你需要的普通jQuery,然後在onBeforeSend掛鉤添加這個邏輯。

0

您可以使用MultiFileUpload來做到這一點嗎?你不需要自己構建它。

看到這個檢票例如: http://www.wicket-library.com/wicket-examples/upload/multi

+0

我不能從列表中刪除一個文件,如果我一次上傳X文件。它提供了刪除所有文件但不是一個(如果他們在一起選擇) – 2014-12-04 14:21:17

0

我是在同樣的情況:我想從文件列表中刪除特定的文件時,我上傳多個文件一次/在一個文件中輸入字段。 Wicket 6.x中提供的'MultiFileUploadField'刪除所有文件,如果它們一起被選中,這不是我想要的。因爲我正在爲現有軟件製作一種插件,所以我無法將Wicket升級到更新的版本,也無法在Wicket應用程序中安裝資源。

絕地先生在評論中提到:

至於我記得我用某種的jQuery插件uploder,做一些技巧與隱藏的輸入發送與形式的文件。但我不確定,這是前一段時間,我沒有項目來源。

我的解決方案尚未完成,不使用上傳插件(還?)。它可以作爲「基礎」來使用JavaScript將文件上傳到Wicket應用程序。
的關鍵部件是所添加的ajaxBehavior其接收FORMDATA對象將其提交jQuery.ajax()

謹慎的一句話我使用jQuery.ajax()來向Wicket應用程序發送數據,而沒有回退。
這可能不適用於舊版瀏覽器。檢查jQuery browser support欲知更多信息。
另請注意,所有瀏覽器尚未完全支持FormData objects

首先,我擴展了現有MultiFileUploadField:

public class MyMultiFileUploadField extends MultiFileUploadField { 

    private static final long serialVersionUID = 1L; 

    private static final ResourceReference JS = new JavaScriptResourceReference(
        MyMultiFileUploadField.class, "MyMultiFileUploadField.js"); 

    private final WebComponent upload; 
    private final WebMarkupContainer container; 
    private final AbstractAjaxBehavior ajaxBehavior; 

    private final String componentIdPrefix; 
    private final int maxUploads; 
    private final boolean useMultipleAttr; 

我們提供我們自己的構造函數,我們添加ajaxBehavior到組件:

public MyMultiFileUploadField(String id, IModel<? extends Collection<FileUpload>> model, int max, 
        boolean useMultipleAttr) { 
     super(id, model, max); 

     this.maxUploads = max; 
     this.useMultipleAttr = useMultipleAttr; 

     upload = (WebComponent) get("upload"); // Created by parent as: new WebComponent("upload"); 
     container = (WebMarkupContainer) get("container"); // Created by parent as: new WebMarkupContainer("container"); 

     ajaxBehavior = new MyMultiFileUploadBehavior(); 
     add(ajaxBehavior); 
    } 

而且覆蓋renderHead方法,這樣我們就可以使我們自己的JavaScript 。
重要的是,我們提供ajaxBehavior.getCallbackUrl()的腳本。

@Override 
    public void renderHead(IHeaderResponse response) { 
     response.render(JavaScriptHeaderItem.forReference(JS)); 
     response.render(OnDomReadyHeaderItem.forScript("new MultiFileUpload('" + getInputName() + "', document.getElementById('" 
         + container.getMarkupId() + "'), " + maxUploads + ", " + useMultipleAttr + ", '" + ajaxBehavior.getCallbackUrl() 
         + "').addElement(document.getElementById('" + upload.getMarkupId() + "'));")); 
    } // new MultiFileUpload(uploadFieldName, uploadContainer, maxUploads, useMultipleAttr, callbackUrl).addElement(fileInput); 

ajaxBehavior將接收文件並將它們傳遞給FileHandler類進行保存。
非常感謝David Tanzer在他的文章jQuery Wicket中解釋這一點。

import org.apache.wicket.behavior.AbstractAjaxBehavior; 
import org.apache.wicket.markup.html.form.upload.FileUpload; 
import org.apache.wicket.protocol.http.servlet.MultipartServletWebRequest; 
import org.apache.wicket.protocol.http.servlet.ServletWebRequest; 
import org.apache.wicket.request.cycle.RequestCycle; 
import org.apache.wicket.request.handler.TextRequestHandler; 
import org.apache.wicket.util.lang.Bytes; 
import org.apache.wicket.util.upload.FileItem; 
import org.apache.wicket.util.upload.FileUploadException; 

public class MyMultiFileUploadBehavior extends AbstractAjaxBehavior { 

    private static final long serialVersionUID = 1L; 

    @Override 
    public void onRequest() { 
     final RequestCycle requestCycle = RequestCycle.get(); 
     readRequest(requestCycle); 
     sendResponse(requestCycle); 
    } 

    private void readRequest(final RequestCycle requestCycle) { 
     Map<String, List<FileItem>> multiPartRequestFiles = null; 

     final ServletWebRequest webRequest = (ServletWebRequest) requestCycle.getRequest(); 

     try { 
      MultipartServletWebRequest multiPartRequest = webRequest.newMultipartWebRequest(Bytes.megabytes(1), "UploadInfo"); 
      multiPartRequest.parseFileParts(); 
      multiPartRequestFiles = multiPartRequest.getFiles(); 
     } catch (FileUploadException e) { 
      e.printStackTrace(System.out); 
      return; 
     } 

     if (multiPartRequestFiles != null && !multiPartRequestFiles.isEmpty()) { 
      for (Entry<String, List<FileItem>> entry : multiPartRequestFiles.entrySet()) { 
       // For debug: iterate over the map and print a list of filenames 
       final String name = entry.getKey(); 
       System.out.println("Entry name: '" + name + "'"); 

       final List<FileItem> fileItems = entry.getValue(); 
       for (FileItem file : fileItems) { 
        System.out.println("Entry file: '" + file.getName() + "'"); 
       } 

       List<FileUpload> fileUploads = buildFileUploadList(fileItems); 
       FileUploadForm.getUploadFileHandler().persistFiles(fileUploads); 
      } 
     } 
    } 

    private void sendResponse(final RequestCycle requestCycle) { 
     requestCycle.scheduleRequestHandlerAfterCurrent(
      new TextRequestHandler("application/json", "UTF-8", "[]")); 
    } 

    private List<FileUpload> buildFileUploadList(List<FileItem> fileItems) { 
     List<FileUpload> fileUploads = new ArrayList<>(fileItems.size()); 
     for (FileItem fileItem : fileItems) { 
      fileUploads.add(new FileUpload(fileItem)); 
     } 
     return fileUploads; 
    } 
} 

你可以堅持的文件相同的方式,顯示在Wicket Examples(也由RobAU提到)。

至於JavaScript我基於隨Stickman製作的Wicket 6.x附帶的腳本。請注意,這個腳本仍然非常基礎。
有關using wicket abstractajaxbehavior with jquery ajax的更多詳細信息。
有關sending multipart formdata with jquery ajax的詳細信息。

/** 
    * @author Stickman -- http://the-stickman.com 
    * @author Vertongen 
    * @see /org/apache/wicket/markup/html/form/upload/MultiFileUploadField.js 
    */ 
function MultiFileUpload(uploadFieldName, uploadContainer, maxUploads, useMultipleAttr, callbackUrl) { 
    "use strict"; 
    console.log("Params: " + uploadFieldName+ ", " + uploadContainer + ", " + maxUploads + ", " + useMultipleAttr + ", " + callbackUrl); 

    // Is there a maximum? 
    if (!maxUploads) { 
     maxUploads = -1; 
    } 
    // Map to hold selected files. Key is formatted as: 'upload_' + uploadId 
    var formDataMap = new Map(); 
    //this.formDataMap = formDataMap; 
    var uploadId = 0; 
    // Reference to the file input element 
    var fileInputElement = null; 

    /** 
    * Add a new file input element 
    */ 
    this.addElement = function(fileInput) { 
     // Make sure it's a file input element 
     if (fileInput.tagName.toLowerCase() === 'input' && fileInput.type.toLowerCase() === 'file') { 

      if (useMultipleAttr) { 
       fileInput.multiple = useMultipleAttr; 
       if (Wicket && Wicket.Browser.isOpera()) { 
        // in Opera 12.02, changing 'multiple' this way 
        // does not update the field 
        fileInput.type = 'button'; 
        fileInput.type = 'file'; 
       } 
      } 

      // Keep a reference to this MultiFileUpload object 
      fileInput.multiFileUpload = this; 
      // Keep a reference to the file input element 
      fileInputElement = fileInput; 

      // What to do when a file is selected 
      fileInput.onchange = function() { 
       // Check to see if we don't exceed the max. 
       if (maxUploads !== -1) { 
        if (this.files.length > maxUploads) { 
         console.warn("More files selected than allowed!"); 
         this.value = ""; 
         return; 
        } 
        if((this.files.length + formDataMap.size) > maxUploads) { 
         console.warn("Total amount of files for upload exceeds the maximum!"); 
         this.value = ""; 
         return; 
        } 
       } 

       // Put selected files in the FormDataMap 
       for (var i = 0, numFiles = this.files.length; i < numFiles; i++) { 
        uploadId++; 
        var fileId = "upload_" + uploadId; 
        var fileObj = this.files[i]; 

        formDataMap.set(fileId, fileObj); 
        // Update uploadContainer add filenames to the list 
        this.multiFileUpload.addFileToUploadContainer(fileId, fileObj); 
       } 

       // Clear file input 
       this.value = ""; 

       // If we've reached maximum number, disable file input element 
       if (maxUploads !== -1 && formDataMap.size >= maxUploads) { 
        this.disabled = true; 
       }   
      };   
     } else if (Wicket && Wicket.Log) { 
      Wicket.Log.error('Error: not a file input element'); 
     } 
    }; 

    this.addFileToUploadContainer = function(fileId, fileObj) { 
     // Row div 
     var new_row = document.createElement('tr'); 
     var contentsColumn = document.createElement('td'); 
     var buttonColumn = document.createElement('td'); 

     // Delete button 
     var new_row_button = document.createElement('input'); 
     new_row_button.id = fileId; 
     new_row_button.type = 'button'; 
     new_row_button.value = 'Remove'; 

     // Delete function 
     new_row_button.onclick = function() { 
      // Remove the selected file from the formData map. 
      formDataMap.delete(this.id); 

      // Remove this row from the list 
      this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode); 

      // Re-enable file input element (if it's disabled) 
      fileInputElement.disabled = false; 

      // Appease Safari 
      // without it Safari wants to reload the browser window 
      // which nixes your already queued uploads 
      return false; 
     }; 

     // Add filename and button to row 
     contentsColumn.innerHTML = this.getOnlyFileName(fileObj.name); 
     new_row.appendChild(contentsColumn); 
     new_row_button.style.marginLeft = '20px'; 
     buttonColumn.appendChild(new_row_button); 
     new_row.appendChild(buttonColumn); 

     uploadContainer.appendChild(new_row); 
    }; 

    var submitButton = document.getElementById('submitUploads'); 
    var resetButton = document.getElementById('resetUploads'); 

    var success = function() {console.log('success!'); }; 
    var failure = function() {console.log('failure.'); }; 
    var complete = function() {console.log('Done.'); }; 

    submitButton.onclick = function() { 
     if(!formDataMap || formDataMap.size < 1) { 
      console.warn("No files selected, cancelled upload!"); 
      return; 
     } 

     // Convert the Map into a FormData object. 
     var formData = new FormData(); 
     formDataMap.forEach(function(value, key) { 
       console.log(key + ' = ' + value); 
       formData.append("uploads", value); 
     }); 

     // Send the FormData object to our Wicket app. 
     jQuery.ajax({ 
      url: callbackUrl, 
      type: 'POST', 
      data: formData, 
      context: self, 
      cache: false, 
      processData: false, 
      contentType: false, 
      success: [success], 
      error: [failure], 
      // complete: [complete] 
     }); 
    }; 

    resetButton.onclick = function() { 
     formDataMap.clear(); 
     fileInputElement.disabled = false; 
    }; 

    this.getOnlyFileName = function(file) { 
     var toEscape = { 
      "&" : "&amp;", 
      "<" : "&lt;", 
      ">" : "&gt;", 
      '"' : '&quot;', 
      "'" : '&#39;' 
     }; 

     function replaceChar(ch) { 
      return toEscape[ch] || ch; 
     } 

     function htmlEscape(fileName) { 
      return fileName.replace(/[&<>'"]/g, replaceChar); 
     } 

     var separatorIndex1 = file.lastIndexOf('\\'); 
     var separatorIndex2 = file.lastIndexOf('/'); 
     separatorIndex1 = Math.max(separatorIndex1, separatorIndex2); 
     var fileName = separatorIndex1 >= 0 ? file.slice(separatorIndex1 + 1, file.length) : file; 
     fileName = htmlEscape(fileName); 
     return fileName; 
    }; 
} 

JavaScript尚未完全測試。我會在發現問題時發佈腳本的更新。

您可能還想爲MultiFileUploadField添加一個HTML副本。

<wicket:panel xmlns:wicket="http://wicket.apache.org"> 
    <input wicket:id="upload" type="file" class="wicket-mfu-field" /> 
    <div wicket:id="container" class="wicket-mfu-container"> 
     <div wicket:id="caption" class="wicket-mfu-caption"></div> 
    </div> 
</wicket:panel> 

對於使用MyMultiFileUploadField類,你可以看看Wicket Examples(也由RobAU提到)。以下代碼和HTML基於Wicket示例。

// collection that will hold uploaded FileUpload objects 
private final Collection<FileUpload> uploads = new ArrayList<>(); 

public FileUploadForm(String formId, MultiUploadConfig multiUploadConfig) { 
     super(formId); 

     // set this form to multipart mode (always needed for uploads!) 
     setMultiPart(true); 

     // Add one multi-file upload field with this class attribute "uploads" as model 
     multiFileUploadField = new MyMultiFileUploadField("fileInput", 
         new PropertyModel<Collection<FileUpload>>(this, "uploads"), 
         multiUploadConfig.getMaxNumberOfFiles(), true); 
     add(multiFileUploadField); 

     // Set the maximum size for uploads 
     setMaxSize(Bytes.megabytes(multiUploadConfig.getMaxUploadSize())); 

     // Set maximum size of each file in upload request 
     setFileMaxSize(Bytes.megabytes(multiUploadConfig.getMaxFileSize())); 
    } 

    public static IUploadFileHandler getUploadFileHandler() { 
     return _uploadFileHandler; 
    } 

    public static void setUploadFileHandler(IUploadFileHandler uploadFileHandler) { 
     _uploadFileHandler = uploadFileHandler; 
    } 

我使用MyMultiFileUploadField在具有以下HTML的Wicket形式。

<fieldset> 
    <legend>Upload form</legend> 
    <p> 
     <div wicket:id="fileInput" class="mfuex" /> 
    </p> 
    <input wicket:id="submitUploads" type="submit" value="Upload"/> 
</fieldset> 
+0

你好,在表單的哪裏添加'submitUploads'按鈕?因爲我無法在表單的上述代碼中看到它。我使用wicket 7.5,當我在應用程序中運行上述代碼時,我得到一個「ServletRequest不包含多部分內容。一種可能的解決方案是顯式調用Form.setMultipart(true)」,即使我有setMultiPart(true);以我的形式。謝謝 – GeorgePap 2017-09-25 11:23:58

+0

@GeorgePap我有一個'公共類FileUploadForm擴展表單 {'在構造函數中,我創建了一個'新的AjaxButton(id){'方法'私人AjaxButton createSubmitAjaxButton(String id){'。我也將該按鈕設置爲'submitUploads = createSubmitAjaxButton(BUTTON_SUBMIT); submitUploads.setMarkupId(markupIdPrefix + BUTTON_SUBMIT); setDefaultButton(submitUploads);添加(submitUploads);'之後,我'setMultiPart(true);'(也在構造函數中)。我希望這可以幫助你解決你的問題。 – Vertongen 2017-09-27 07:46:44