3

Scala /Playgurusがあります。

Play 2.1(RC1)でAJAXを使用してファイルをアップロードしようとしています。クライアント部分では、eldarion / bootstrap-ajaxを使用していますが、アップロードされたファイルが空であることを除いて、すべて問題ないようです。

フロントエンドスニペット:

...
<form action="@routes.Campaigns.upload" method="post" class="form ajax replaceable" data-replace=".replaceable">
    <input type="file" name="picture">
    <p><input class="btn" type="submit"></p>
</form>
...

必要なcssクラス(data-replace)にダッシュが含まれているため、ヘルパーの代わりに明示的な<form>タグを使用@formする必要があり、したがって、として使用できないことに注意してSymbolください。とにかく。コントローラで呼び出されたアクションは次のようになります。

  def upload = Action(parse.temporaryFile) {
    request =>
      Logger.info("Trying to upload a file")
      val resultString = try {
        val file = new File("/tmp/picture")
        request.body.moveTo(file, true)
        "file has been uploaded"
      } catch {
        case e: Exception => "an error has occurred while uploading the file"
      }
      val jsonResponse = Json.toJson(
        Map("html" -> Json.toJson("<p>" + resultString + "</p>")
        )
      )
      Ok(jsonResponse)
  }

開発が進むにつれ、ファイル名をよりインテリジェントに設定する必要があることは承知していますが、現時点では、/ tmp/pictureは他の名前と同じくらい良い名前です。

JSON応答が生成され(「ファイルがアップロードされました」というメッセージが含まれます)、200応答のペイロードとしてブラウザーに返送されます。JSONが受信され、ページを変更するために正しく使用されます(この場合、アップロードフォームを削除するだけです)。

ただし、ファイルは適切なタイミングで適切な場所に表示されますが、常に空です。

larsson:tmp bruno$ ls -l /tmp/picture
-rw-r--r--  1 bruno  staff  0  7 Jan 03:07 /tmp/picture

私の意見では、これは特に奇妙なことです。なぜなら、multipart/form-dataAJAXをまったく使用せず、パラメータとしてActionwithを使用する代わりに、従来の形式を使用するアップロードコードは正常に機能するからです。parse.multipartFormDataparse.temporaryFile

どんな助けでも大歓迎です。前もって感謝します。

4

2 に答える 2

3

bootstrap-ajaxはわかりませんが、AJAXを介したファイルのアップロード専用のサポートがない場合(ファイルにその可能性に関する情報が見つからなかった場合readme)、AJAXでファイルを送信しません。

理由:標準のJavaScriptでは、セキュリティ制限のためにAJAXを使用してファイルをアップロードすることはできずiFrames、主にを使用してこれを回避するためのいくつかの手法がありますが、コードに類似したものが見当たらないbootstrap-ajaxため、おそらくそれを変更するか、他を使用する必要があります解決。

解決策:HTML5でうまく機能するAJAXファイルアップローダーがいくつかあります。jQuery File Uploadは、ajaxアップロード、複数ファイルアップロード、ファイルのドロップゾーンへのドラッグなどを提供します。

一般に、HTML5は以前のバージョンのHTMLよりも優れたファイルアップロードをサポートしているため、追加のプラグインを使用せずにアップローダーを簡単に構築できます。このトピックを参照してください。ご覧のとおり、アップロード前に一部のデータを検証する可能性があり、プログレスバーも提供されます。

于 2013-01-07T05:03:10.417 に答える
1

私は現在、このようなものを実装しようとしていますが、最初のバージョンが機能しています。これが私のやり方です:

私のコントローラーでは、ファイルをアップロードする方法を定義しています。私の場合、 reactivemongoを使用してMongoDBにデータを保存するため、Action.asyncを使用します。この例を複雑にしないように、そのコードを削除しました。

この例では、csvファイルをアップロードしてディスクに保存し、最初の行を文字列としてユーザーに返します。実際には、このメソッドはリストを生成し、ユーザーがどの列が何を表すかなどを選択できるようにします。

csv解析には強力なcsvを使用します。グレートリブ!

応用:

def upload = Action.async(parse.multipartFormData) {
    implicit request =>
      val result = uploadForm.bindFromRequest().fold(
        errorForm => Future(BadRequest(views.html.index(errorForm))),
        form => {
          import java.io.File
          request.body.file("csvFile").map {
            csv =>
              val path = current.configuration.getString("csv.job.new.file.path").getOrElse("")
              val name = DateTime.now().getMillis + ".csv"
              csv.ref.moveTo(new File(path + name))
              val settings = CSVReaderSettings.Standard(linesToSkip = form.linesToSkip)
              val rows: Iterator[Array[String]] = CSVReader(path + name)(settings)
              val firstRow = rows.next()
              val test = firstRow match {
                case xs if xs.size == 0 || xs.size == 1 => xs.mkString
                case xs if xs.size > 1 => xs.mkString(", ")
              }
              Future(Ok(test))           
          }.getOrElse(Future(BadRequest("ahadasda")))
        }
      )
      result
  }

ルート:

POST          /upload        @controllers.Application.upload

サービスクラスにguiceを使用してDIを使用するため、コントローラーの前に@を使用します。アップロードにはJavaScriptを使用するため、jsRoutesを定義する必要があります。

jsRoutes:

def javascriptRoutes = Action {
    implicit request =>
      import routes.javascript._
      Ok(
        Routes.javascriptRouter("jsRoutes")(
          Application.upload
        )
      ).as("text/javascript")
  }

ルートを使用するテンプレートにインポートすることを忘れないでください。

<script type="text/javascript" src="@routes.Application.javascriptRoutes"></script>
<script src="@routes.Assets.at("javascripts/app.js")@Messages("js.version")" type="text/javascript" ></script>

ビューテンプレートには、通常のヘルパーフォームがあります。アップロードボタンとファイルチューザーのルックアンドフィールを変更するために私が行うCSSスタイルのものがいくつかあります。しかし、入力フィールドはそこにあります。

index.scala.html:

<div class="csvContainer">

    @helper.form(action = routes.Application.upload, 'enctype -> "multipart/form-data", 'id -> "csvUpload") {
        @Messages("upload.row.skip")
        @inputText(uploadForm("linesToSkip"), 'class -> "hidden")

        <div style="position:relative;">
            <div id="csvFile" style="position:absolute;">
                @Messages("upload.choose")
            </div>
            <input id="uploadFile" type="file" name="csvFile" style="opacity:0; z-index:1;" onchange="document.getElementById('csvFile').innerHTML = this.value;" />
        </div>
        <p>
            <input type="submit" value="@Messages("upload.submit")">
        </p>
    }
    </div>

app.jsでは、ajaxの魔法が発生します。ベシオールのリンクで説明されているように、プログレスバーやその他のハンドラーとして、検証やクールなhtml5のものをまだ実装していないことを忘れないでください。私は通常のJQueryを使用しています。

app.js:

$('#uploadFile').change(function(){
        var name = $(this).val().split("\\");
        console.log(name[2]);
        $('#csvFile').text(name[2]);
    });

    $('#csvFile').click(function(){
        $('#uploadFile').click();
    });

$("#csvUpload").submit(function(e) {
        e.preventDefault();
        var formData = new FormData();
        formData.append('csvFile',  $( '#uploadFile' )[0].files[0]);
        formData.append('linesToSkip', $( "#linesToSkip").val());
        jsRoutes.controllers.Application.upload().ajax({
            data: formData,
            processData: false,
            contentType: false,
            cache: false,
            type: 'POST',
            success: function(data){
                alert(data);
            }
        });
    });

この例を単純化するために多くのコードを削除しました。何も忘れていないことを願っています。お役に立てれば!

于 2013-11-20T10:49:07.883 に答える