使用额外的inputText上传多个文件

时间:2014-06-24 14:19:15

标签: jsf file-upload primefaces

我需要实现以下内容:

  1. 以ajax样式上传多个文件(不刷新整页)
  2. 每个文件的描述字段
  3. 必须使用JSF 2.0
  4. 完成

    任何组合中的3个要求中的2个都没有问题。多个fileUpload与JSF 2.0 = PrimeFaces,多个文件上传+描述是可能的JSF 2.2,因为它有本机上传元素(我想它可以是ajaxed但没有检查它,因为我不能使用它),但当我得到所有这三个要求一起被卡住了。 在PrimeFaces的p:fileUpload上没有描述字段,其简单模式不支持ajax。 JSF 2.0没有本机fileUpload组件。我可以使用PrimeFaces的p:fileUpload绑定描述字段,但是我无法阻止用户选择多个文件,这会导致少数文件与一个描述相关联。

    那么,是否可以使用PrimeFaces和JSF 2.0中的描述字段以ajax样式进行多个文件上传?

1 个答案:

答案 0 :(得分:7)

PrimeFaces上传基于blueimp/jQuery-File-Upload

调用.serializeArray()时,该表单中的所有数据都将被序列化。

在这种情况下,您可以覆盖add选项的PrimeFaces implementation,为每个文件附加一个额外的输入文本。

所以结果看起来像这样:

fileUpload with title

现在这将是一行额外的代码,正是here

.append('<td class="title"><label>Title: <input name="title['+ file.name +']"></label></td>') //the only modification we have to do

额外的输入文本称为title[fileName],在这种情况下,您将通过当前文件名获取请求参数的值。

public void handleFileUpload(FileUploadEvent event) {
    FacesContext context = FacesContext.getCurrentInstance();
    Map map = context.getExternalContext().getRequestParameterMap();
    String paramName = "title["+event.getFile().getFileName()+"]";
    String fileWithTitle = (String) map.get(paramName);            
}

以下是add选项的完整实施(假设您的widgetVarfileUpload

$(document).ready(function() {
   setTimeout(fileUpload, 1000);
})

function fileUpload() {

PF('fileUpload').jq.fileupload({
    add: function(e, data) {
        $this = PF('fileUpload');
        $this.chooseButton.removeClass('ui-state-hover ui-state-focus');
        if ($this.files.length === 0) {
            $this.enableButton($this.uploadButton);
            $this.enableButton($this.cancelButton);
        }

        if ($this.cfg.fileLimit && ($this.uploadedFileCount + $this.files.length + 1) > $this.cfg.fileLimit) {
            $this.clearMessages();
            $this.showMessage({
                summary: $this.cfg.fileLimitMessage
            });

            return;
        }

        var file = data.files ? data.files[0] : null;
        if (file) {
            var validMsg = $this.validate(file);

            if (validMsg) {
                $this.showMessage({
                    summary: validMsg,
                    filename: file.name,
                    filesize: file.size
                });
            }
            else {
                $this.clearMessages();                                                                               
                //the only modification we have to do
                var row = $('<tr></tr>').append('<td class="ui-fileupload-preview"></td>')
                        .append('<td>' + file.name + '</td>')
                        .append('<td class="title"><label>Title: <input name="title['+ file.name +']"></label></td>') 
                        .append('<td>' + $this.formatSize(file.size) + '</td>')
                        .append('<td class="ui-fileupload-progress"></td>')
                        .append('<td><button class="ui-fileupload-cancel ui-button ui-widget ui-state-default ui-corner-all ui-button-icon-only"><span class="ui-button-icon-left ui-icon ui-icon ui-icon-close"></span><span class="ui-button-text">ui-button</span></button></td>')
                        .appendTo($this.filesTbody);


                if ($this.isCanvasSupported() && window.File && window.FileReader && $this.IMAGE_TYPES.test(file.name)) {
                    var imageCanvas = $('<canvas></canvas')
                            .appendTo(row.children('td.ui-fileupload-preview')),
                            context = imageCanvas.get(0).getContext('2d'),
                            winURL = window.URL || window.webkitURL,
                            url = winURL.createObjectURL(file),
                            img = new Image();

                    img.onload = function() {
                        var imgWidth = null, imgHeight = null, scale = 1;

                        if ($this.cfg.previewWidth > this.width) {
                            imgWidth = this.width;
                        }
                        else {
                            imgWidth = $this.cfg.previewWidth;
                            scale = $this.cfg.previewWidth / this.width;
                        }

                        var imgHeight = parseInt(this.height * scale);

                        imageCanvas.attr({width: imgWidth, height: imgHeight});
                        context.drawImage(img, 0, 0, imgWidth, imgHeight);
                    }

                    img.src = url;
                }

                //progress
                row.children('td.ui-fileupload-progress').append('<div class="ui-progressbar ui-widget ui-widget-content ui-corner-all" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="ui-progressbar-value ui-widget-header ui-corner-left" style="display: none; width: 0%;"></div></div>');

                file.row = row;

                file.row.data('filedata', data);
                $this.files.push(file);

                if ($this.cfg.auto) {
                    $this.upload();
                }
            }
        }
    }});
}

只需将上述代码包含在某个js文件中,并在</h:body>

结尾之前将其包含在内

这是 online Demo

注意:此方法中唯一的拖动,如果用户选择了 具有相同名称和扩展名 的多个文件你会得到第一个标题两次!对于一些人来说这没关系,因为用户不应该上传相同的文件。

这是对PrimeFaces 5.0和Chrome的测试。