1

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

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

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

4

3 回答 3

0

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

于 2014-12-04T08:50:19.903 回答
0

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

请参阅此 Wicket 示例: http: //www.wicket-library.com/wicket-examples/upload/multi

于 2014-12-04T13:00:47.547 回答
0

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

绝地先生在评论中提到:

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

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

请注意, 我使用jQuery.ajax()将数据 POST 到 Wicket 应用程序,没有回退。
这可能不适用于旧版浏览器。检查jQuery 浏览器支持以获取更多信息。
另请注意,并非所有浏览器都完全支持FormData 对象。

首先我扩展了现有的 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 示例(RobAU 也提到)中所示的相同方式保存文件。

至于 JavaScript,我自己基于 Stickman 制作的 Wicket 6.x 附带的脚本。请注意,这个脚本仍然非常基础。有关将 wicket abstractajaxbehavior 与 jquery ajax 一起使用的
更多详细信息。有关使用 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 示例(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>
于 2017-05-22T15:54:57.040 回答