我是在同樣的情況:我想從文件列表中刪除特定的文件時,我上傳多個文件一次/在一個文件中輸入字段。 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 = {
"&" : "&",
"<" : "<",
">" : ">",
'"' : '"',
"'" : '''
};
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>
嗨Jedi先生,你能解決這裏描述的問題嗎?我處於同樣的情況:如果我一次上載多個文件/在一個文件輸入字段中,我想從文件列表中刪除特定文件。 Wicket 6.x中提供的'MultiFileUploadField'刪除所有文件,如果它們一起被選中,這不是我想要的。 因爲我正在爲現有軟件製作一種插件,所以我無法將Wicket升級到更新的版本,也無法在Wicket應用程序中安裝資源。 – Vertongen 2017-05-17 16:57:19
@Vertongen據我所知,我使用了某種jQuery uploder插件,並用隱藏的輸入做一些技巧來發送這些帶有形式的文件。但我不確定,這是前一段時間,我沒有項目來源。 – 2017-05-18 07:16:07
非常感謝您的快速回復。爲了不好,你再也沒有消息來源。當我找到它的時候,我會堅持併發佈一個答案。 – Vertongen 2017-05-18 12:10:54