使用 Dropzone 和 Laravel 上传产品

Posted

技术标签:

【中文标题】使用 Dropzone 和 Laravel 上传产品【英文标题】:Product upload with Dropzone and Laravel 【发布时间】:2020-03-28 23:43:01 【问题描述】:

我想使用 Dropzone 上传包含多个图像的产品,我有一个包含价格、名称等其他字段的表单。我看过其他教程,但他们只上传图像而不是其他字段(价格、名称)的图像一次。我已经设置了显示预览的 Dropzone,但如果我提交按钮,我会得到验证 Please enter product image。如何使用 Dropzone 将图像传递给控制器​​?

控制器

 public function store(Request $request)
 
  $formInput=$request->except('filename');

    $product = product::create(array_merge($formInput, [
        'user_id' => Auth::user()->id
    ]));
    foreach ($request->file as $photo) 
        $filename = $photo->store('public/photos');
        ProductsPhoto::create([
            'product_id' => $product->id,
            'filename' => $filename
        ]);
     
 

刀片

//The form

 <div class="panel-body">
   <form>
    @csrf
     <input type="hidden" value="csrf_token()" id="token"/>
  <label for="pro_name">Name</label>
  <input type="text" class="form-control" name="pro_name" id="pro_name" placeholder="Enter product name">

    <label for="pro_price">Price</label>
     <input type="text" class="form-control" name="pro_price" id="pro_price" placeholder="Enter price">

 <label for="photos">Choose 5 Images</label>
 <div class="needsclick dropzone" id="document-dropzone">  // Display images preview

  </div>

 <input type="submit" class="btn btn-primary" value="Submit" id="btn"/>

</div>

阿贾克斯

   //This is how I submit the form
   <script>

    var token = $("#token").val();
    $(document).ready(function()
        $("#btn").click(function (e) 
            e.preventDefault();
            $("#loading").show();
            var url = ' route('product.store') ';
            var form = $('form')[0]; // You need to use standard javascript object here
            var formData = new FormData(form);
            formData.append('_token', token); // adding token
            $.ajax(
                url: url,
                data: formData, //just that without variables
                type: 'POST',
                cache: false,
                contentType: false, // NEEDED, DON'T OMIT THIS (requires jQuery 1.6+)
                processData: false, // NEEDED, DON'T OMIT THIS
                success:function(data)
                if($.isEmptyObject(data.error))
                $("#msg").html("Product has been added successfull");
                $("#msg").fadeOut(3000);
                 window.location.href =  "<?php echo url('seller/product') ?>";
                 $("#loading").hide();
                 
                 else

                        printErrorMsg(data.error);

                        
                
            );
            function printErrorMsg (msg) 
            $("#loading").hide();
            $(".print-error-msg").find("ul").html('');
            $(".print-error-msg").css('display','block');
            $.each( msg, function( key, value ) 
                $(".print-error-msg").find("ul").append('<li>'+value+'</li>');
            );
            
        );

    );

    var uploadedDocumentMap = 
Dropzone.options.documentDropzone = 
  url: ' route('product.store') ',
  maxFilesize: 10, // MB
  addRemoveLinks: true,
  headers: 
    'X-CSRF-TOKEN': " csrf_token() "
  ,
  success: function (file, response) 
    $('form').append('<input type="hidden" name="document[]" value="' + file.name + '">')
    uploadedDocumentMap[file.name] = response.name
  ,
  removedfile: function (file) 
    file.previewElement.remove()
    var name = ''
    if (typeof file.file_name !== 'undefined') 
      name = file.file_name
     else 
      name = uploadedDocumentMap[file.name]
    
    $('form').find('input[name="document[]"][value="' + name +  '"]').remove()
  ,
  init: function () 
    @if(isset($project) && $project->document)
      var files =
        !! json_encode($project->document) !!
      for (var i in files) 
        var file = files[i]
        this.options.addedfile.call(this, file)
        file.previewElement.classList.add('dz-complete')
        $('form').append('<input type="hidden" name="document[]"  value="' + file.file_name + '">')
      
    @endif
  
  
</script>

【问题讨论】:

你为什么要设置contentType: false 提交表单时是否会导致问题?@Johannes 在这里你可以找到一个最小的工作示例:***.com/questions/41981922/… 我还注意到你在刀片模板中缺少@csrf 注释,否则 Laravel 将拒绝你的请求(参见laravel.com/docs/5.7/csrf ) 更改后,将console.log(data) 添加到success 回调。 是的,但据我所知,您还需要一个 name 属性。 @csrf 隐含地这样做了。 Here is an answer describing how to upload your form fields with a Dropzone image,当您单击一个按钮时。正如 Johannes 指出的那样,您的 CSRF 代码无效,只需使用 @csrf。至于后端,Please enter product image 不在您向我们展示的代码中的任何位置,因此我们只能猜测那里可能存在问题。 【参考方案1】:

在你的代码和你的概念中有些事情是不对的(至少在我看来):

    您需要阻止#btn 的默认行为,因为您需要拦截表单提交。否则,表单只会作为GET 请求提交(默认行为是什么)。
$("#btn").click(function (e) 
  e.preventDefault();
  // ...

    &lt;form&gt; 元素未关闭。此外,不要在 JavaScript 中覆盖 _ token,而只需将 @csrf 添加到表单中。 Larvel 和 jQuery 将为您处理一切。
<form>
  @csrf
    我想我理解您现在想要达到的目标。 Dropzone 正在直接上传(= POST 请求)文件,因此您需要一个单独的路由(或另一个代码分支)来处理文件上传。然后,您可以获取之前上传文件的文件名并将其附加为hidden 输入字段,如下所示:
success: function (file, response) 
  $('form').append('<input type="hidden" name="document[]" value="' + file.name + '">')
,

您将在控制器的方法中收到pro_namepro_price 和一个数组document,其中包含已上传文件的名称。按照您的逻辑,该文件必须已经存在于存储中,因为它是由 Dropzone 操作上传的。然后,您可以将filename 保存到数据库或其他任何内容中,并将其用作稍后访问文件的参考。 无论如何,我不建议使用客户端提供的文件名进行存储,因为它可能不是唯一的。 Laravel 为这种场景提供了很多有用的工具:https://laravel.com/docs/5.7/filesystem#file-uploads

【讨论】:

以上是关于使用 Dropzone 和 Laravel 上传产品的主要内容,如果未能解决你的问题,请参考以下文章

如何克服 Laravel dropzone 文件上传中的 getClientOriginalName() 错误?

使用 dropzone.js 和 laravel 5 验证 CsrfToken

Dropzone CSRF令牌不匹配Laravel 5

Dropzone多个文件上传不适用于Excel文件

在 laravel 中解码和移动 base64 编码的图像

如何在 Dropzone 上传请求的标头中包含 CSRF 令牌?