2014-12-03 1 views
1

파일 형식의 필드 입력을 사용하여 여러 파일 목록을로드했습니다. 문제는 내가 양식을 게시하기 전에 원래 목록에서 일부를 삭제하고 싶습니다. Couse FileList js에 불변이고 재정의 된 FileList (js security reasons)로 게시 할 새 입력을 만들 수 없습니다. 제출하려는 파일로 배열을 만들어야합니다.wicket ajax 포스트를 사용하여 js에서 java로 파일 배열 보내기

하지만 난 게시하는 방법을 알고 그것을 Wicket.Ajax.post를 사용하여 수신하지 않습니다 (인해 더 - 위에서 언급 한 나는 양식을 게시 할 수 없습니다)

표준 fileUploadField 양식 IMultipartWebRequest의 인스턴스로 요청을받을 게시하다. Wicket.Ajax.post를 사용하여 동일한 작업을 수행하는 방법?

+0

안녕하세요 Mr Jedi 님, 여기에 설명 된 문제를 해결할 수 있었습니까? 나는 같은 상황에 있습니다 : 한 번에 여러 파일을 업로드하면 파일 목록에서 특정 파일을 삭제하고 싶습니다/한 파일 입력 필드에 있습니다. Wicket 6.x에서 제공되는 'MultiFileUploadField'는 모든 파일을 함께 선택했으면 삭제합니다. 이는 원하지 않는 것입니다. 기존 소프트웨어에 일종의 플러그인을 만들고 있기 때문에 Wicket을 최신 버전으로 업그레이드 할 수 없으며 Wicket 응용 프로그램에 리소스를 마운트 할 수 없습니다. – Vertongen

+0

@Vertongen 필자는 jQuery uploder plugin을 사용하여 숨겨진 입력 내용을 사용하여 이러한 파일을 양식과 함께 전송했다는 것을 기억한다. 그러나 나는 확신 할 수 없다. 그것은 얼마 전이었고 나는 프로젝트 소스를 가지고 있지 않다. –

+0

빠른 답장을 보내 주셔서 감사합니다. 나쁜 소식은 더 이상 소스가 없습니다. 내가 그것을 발견했을 때 나는 그것을 지키고 대답을 게시 할 것이다. – Vertongen

답변

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 파일을 업로드하면 목록에서 파일 하나를 삭제할 수 없습니다. 모든 파일을 삭제할 수 있지만 하나만 삭제할 수 있습니다. (함께 선택한 경우) –

0

내가 같은 상황에 있었다 :

이 개찰구 예제를 ​​참조하십시오 내가 하나 개의 파일 입력 필드에/한 번에 여러 파일을 업로드 할 때 파일 목록에서 특정 파일을 삭제하고 싶었다. Wicket 6.x에서 제공되는 'MultiFileUploadField'는 모든 파일을 함께 선택했으면 삭제합니다. 이는 원하지 않는 것입니다. 기존 소프트웨어에 일종의 플러그인을 만들고 있기 때문에 Wicket을 최신 버전으로 업그레이드 할 수 없으며 Wicket 애플리케이션에 리소스를 마운트 할 수 없습니다.

씨 제다이가 코멘트에 언급 :

지금까지 내가 형태로 해당 파일을 보내 숨겨진 입력 몇 가지 트릭을의 jQuery uploder 플러그인의 일종을 사용 할 기억한다. 그러나 나는 확신 할 수 없다. 그것은 얼마 전이었고 나는 프로젝트 소스를 가지고 있지 않다.

내 솔루션이 아직 완료되지 않았으며 업로드 플러그인을 사용하지 않았습니다 (아직?). JavaScript를 사용하여 Wicket 응용 프로그램에 파일을 업로드하는 수단으로 '기본'으로 사용할 수 있습니다.
임계 성분 jQuery.ajax()에 의해 제출 된 개체 FormData 를 수신 첨가 ajaxBehavior이다.

주의 사항 나는 대체 데이터없이 Wicket 응용 프로그램에 POST 데이터에 jQuery.ajax()을 사용합니다.
이전 브라우저에서는 작동하지 않을 수 있습니다. 자세한 내용은 jQuery browser support을 확인하십시오.
아직 모든 브라우저에서 FormData objects을 완전히 지원하지는 않습니다.

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 메소드를 오버라이드 (override) :

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를 추가 할 우리 자신의 생성자를 제공

먼저 나는 기존 MultiFileUploadField 확장 .
여기서 중요한 것은 스크립트에 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 클래스에 전달합니다.
그의 게시물 jQuery Wicket에서 이것을 설명 해주신 David Tanzer에게 감사드립니다.

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; 
    } 
} 

(또한 RobAU 언급)을 Wicket Examples에서와 같이 파일 같은 방식을 지속 할 수 있습니다.

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 사본을 추가 할 수도 있습니다. (또한 RobAU 언급)는 Wicket Examples에서 볼 수 있습니다 MyMultiFileUploadField 클래스를 사용하기 위해

<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> 

. 아래의 코드와 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; 
    } 

나는 다음과 같은 HTML을 가진 Wicket 형식으로 MyMultiFileUploadField을 사용합니다.

<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는 다중 컨텐츠를 포함하지 않는다. 한 가지 가능한 해결책은 setMultiPart (true)가 있더라도 명시 적으로 Form.setMultipart (true)를 호출하는 것이다. 내 양식에. 고맙습니다. – GeorgePap

+0

@GeorgePap'public 클래스 FileUploadForm이 양식 을 확장합니다. {'여기서, private private AjaxButton createSubmitAjaxButton (String id) {'메소드에서 새 AjaxButton (id) {'를 생성했습니다. 그 버튼을'submitUploads = createSubmitAjaxButton (BUTTON_SUBMIT);으로 설정했습니다. submitUploads.setMarkupId (markupIdPrefix + BUTTON_SUBMIT); setDefaultButton (submitUploads); add (submitUploads);'그 후에 setMultiPart (true); (또한 생성자에서). 이것이 귀하의 문제를 해결하는 데 도움이되기를 바랍니다. – Vertongen