【问题标题】:Sending file array from js to java using wicket ajax post使用wicket ajax post将文件数组从js发送到java
【发布时间】:2014-12-03 14:59:18
【问题描述】:

我正在使用文件类型的字段输入加载多个文件列表。问题是我想在表单发布之前从原始列表中删除其中一些。 Couse FileList 在 js 中是不可变的,我无法使用重写的 FileList 创建新输入来发布(出于 js 安全原因),我必须使用要提交的文件构建数组。

但我不知道如何使用 Wicket.Ajax.post 发布和接收它(由于上述我无法发布表单)

标准 fileUploadField 获取请求作为表单发布上的 IMultipartWebRequest 的实例。如何使用 Wicket.Ajax.post 做同样的事情?

【问题讨论】:

  • 您好绝地先生,您能解决这里描述的问题吗?我处于同样的情况:如果我一次上传多个文件/在一个文件输入字段中,我想从文件列表中删除特定文件。 Wicket 6.x 中提供的“MultiFileUploadField”会删除所有文件,如果它们被一起选择,这不是我想要的。因为我正在为现有软件制作一种插件,所以我无法将 Wicket 升级到更新版本,也无法在 Wicket 应用程序中挂载资源。
  • @Vertongen 据我所知,我使用了某种 jQuery uploder 插件,并使用隐藏输入做一些技巧来发送带有表单的文件。但我不确定,那是前一段时间了,我没有项目来源。
  • 非常感谢您的快速回复。可惜你没有资源了。当我找到它时,我会坚持并发布答案。

标签: javascript ajax wicket wicket-6


【解决方案1】:

Wicket.Ajax.post() 是 http://api.jquery.com/jquery.ajax/ 的包装器。 它只是为您提供了可以操纵请求或响应的钩子:onBefore、onPrecondition、onSuccess 等。 因此,如果您找到了一种使用普通 jQuery 完成所需操作的方法,那么只需在 onBeforeSend 钩子中添加此逻辑即可。

【讨论】:

    【解决方案2】:

    您已经可以使用 MultiFileUpload 执行此操作了吗?您不需要自己构建它。

    查看这个 Wicket 示例: http://www.wicket-library.com/wicket-examples/upload/multi

    【讨论】:

    • 如果我一次上传 X 个文件,我无法从列表中删除一个文件。它提供删除所有文件但不是一个(如果它们一起选择)
    【解决方案3】:

    我遇到了同样的情况:当我一次上传多个文件/在一个文件输入字段中时,我想从文件列表中删除一个特定文件。 Wicket 6.x 中提供的“MultiFileUploadField”会删除所有文件,如果它们被一起选择的话,这不是我想要的。因为我正在为现有软件制作一种插件,所以我无法将 Wicket 升级到更新版本,也无法在 Wicket 应用程序中安装资源。

    绝地先生在cmets中提到:

    据我所知,我使用了某种 jQuery uploder 插件,并使用隐藏输入做了一些技巧,以将这些文件与表单一起发送。但我不确定,那是前一段时间了,我没有项目来源。

    我的解决方案还没有完成,并且没有使用上传插件(还没有?)。它可以用作使用 JavaScript 将文件上传到 Wicket 应用程序的“基础”。
    关键组件是添加的 ajaxBehavior,它接收由 jQuery.ajax() 提交的 FormData 对象

    请注意我使用 jQuery.ajax() 将数据 POST 到 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;
        }
    

    我在具有以下 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>
    

    【讨论】:

    • 您好,您在表单的哪个位置添加了“提交上传”按钮?因为我在表格的上面代码中看不到它。我使用 wicket 7.5,当我在我的应用程序中运行上述内容时,我得到一个“ServletRequest 不包含多部分内容。一种可能的解决方案是显式调用 Form.setMultipart(true)”,即使我有 setMultiPart(true);到我的表格。谢谢
    • @GeorgePap 我有一个public class FileUploadForm extends Form&lt;Void&gt; {,在构造函数中,我在方法private AjaxButton createSubmitAjaxButton(String id) { 中创建了一个new AjaxButton(id) {。我还将该按钮设置为submitUploads = createSubmitAjaxButton(BUTTON_SUBMIT); submitUploads.setMarkupId(markupIdPrefix + BUTTON_SUBMIT); setDefaultButton(submitUploads); add(submitUploads); 之后我setMultiPart(true); (也在构造函数中)。我希望这可以帮助您解决问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-09
    • 2017-11-02
    相关资源
    最近更新 更多