Scala / Play专家。
我试图在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>
...
请注意,我必须使用显式<form>
标记而不是@form
帮助程序,因为所需的css类(数据替换)包含破折号,因此不能用作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响应(&#34;文件已上传&#34;消息在内),并作为200响应的有效负载发送回浏览器。收到JSON并正确用于修改页面(在这种情况下,仅删除上传表单)。
但该文件虽然出现在正确的时刻和正确的位置,但始终是空的:
larsson:tmp bruno$ ls -l /tmp/picture
-rw-r--r-- 1 bruno staff 0 7 Jan 03:07 /tmp/picture
在我看来,这是特别奇怪的,因为上传代码使用传统的multipart/form-data
形式,没有任何AJAX,而Action
使用parse.multipartFormData
作为参数,而不是parse.temporaryFile
,可以很好地工作。
任何帮助将非常感谢。提前谢谢。
答案 0 :(得分:3)
我不知道bootstrap-ajax,无论如何它没有专门支持通过AJAX上传文件(我在readme
文件中没有找到任何关于这种可能性的信息)它不会发送使用AJAX的文件。
原因:在标准JavaScript上传文件时,使用AJAX 是不可能的由于安全限制而且有一些技巧可以解决这个问题,主要是使用iFrames
,但我什么也看不见在bootstrap-ajax
的代码中类似,所以可能需要修改它或使用其他解决方案。
解决方案:有一些AJAX文件上传器,适用于HTML5即。 jQuery File Upload,提供ajax上传,多文件上传,拖放文件到放置区等。
通常,HTML5支持文件上传比早期版本的HTML更好,因此您可以轻松构建上传器而无需使用其他插件,请查看this topic。正如您所看到的,它提供了在上传之前验证某些数据的可能性,并且还提供了进度条。
答案 1 :(得分:1)
我正在尝试实现这样的东西,我得到了第一个版本。我就是这样做的:
在我的Controller中,我定义了一种上传文件的方法。在我的情况下,我使用Action.async,因为我使用reactivemongo将东西保存到我的MongoDB。我已删除该代码,因此不会使此示例复杂化。
我在这个例子中做的是上传一个csv文件,将其保存到磁盘然后将第一行作为字符串返回给用户。在现实生活中,该方法生成一个列表,以便用户能够选择哪个列代表什么等等。
我使用mighty csv进行csv解析。伟大的LIB!
<强>应用强>
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
我在控制器之前使用@,因为我使用DI和guice作为我的服务类。 由于我们将使用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内容作为进度条和其他处理程序,在besiors link中有所描述。 我使用常规的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);
}
});
});
我已经删除了很多代码来简化这个例子,我希望我没有忘记任何事情。希望这有帮助!