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

Posted

技术标签:

【中文标题】使用额外的 inputText 上传多个文件【英文标题】:Multiple file upload with extra inputText 【发布时间】:2014-08-14 20:34:31 【问题描述】:

我需要实现以下内容:

    ajax方式多文件上传(不刷新整页) 每个文件的描述字段 必须使用 JSF 2.0 完成

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

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

【问题讨论】:

您使用的是 PrimeFaces 2.0 吗? 不,我只对 JSF 版本有限制。如果 Primeface 与 JSF 2.0 兼容,我可以使用它 在我的情况下,我使用 3.5,但考虑继续前进 5.0 【参考方案1】:

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

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

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

所以结果应该是这样的:

现在这将是额外的一行代码,确切地说是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文件中,并在&lt;/h:body&gt;结束之前包含它

这是一个online Demo。

注意:如果用户选择了具有完全相同的名称和扩展名的多个文件,您可能会在此方法中遇到唯一的拖累。你会得到第一个标题两次!对于某些人来说这是可以的,因为用户不应该上传相同的文件。

这是在 PrimeFaces 5.0 和 Chrome 上进行的测试。

【讨论】:

有效!我的启动脚本有一些问题,但总的来说它可以工作!非常感谢! 什么样的问题? 当我在覆盖窗口中使用它时它不起作用,当我在主页上使用它时它工作得很好。我认为我需要编写 js 函数,它会在渲染覆盖时调用你的代码,在此之前它只是找不到这个小部件。 你需要确保widgetVar已经初始化并且可以使用了,这是我在document.ready中使用setTimeout的主要原因。我想您的叠加层正在即时或部分渲染,在这种情况下,正如您所说,您应该确保在正确的时间调用代码。 PF('fileUpload') 是组件的 javascript 对象,jq 是 jquery 对象,fileupload 是文件上传 javascript 插件对象......你应该看看 javascript 原型。 @Anatoly

以上是关于使用额外的 inputText 上传多个文件的主要内容,如果未能解决你的问题,请参考以下文章

afnetworking 多文件上传

使用 vuetify 2 v-file-input 和 axios 上传文件

使用请求上传文件并发送额外数据

使用 Alamofire(多部分数据)上传带有额外参数的 .PDF 文件时出错

如何向 ajax 文件上传添加额外的 POST 参数?

使用 Post 方法的 PHP 上传