我正在使用网络服务上传视频和图片,并将图片保存在我们的应用程序中。保存文件时,文件保存在应用程序文件夹的根目录下。我想使用localhost
网址访问这些图片和视频,例如:我上传文件并保存在app-root/upload/image.jpg
下。在我的路由映射文件中,我声明路由如下:
GET /uploads/ staticDir:/upload
在Play Documentation中定义。但仍然遇到编译时错误:Controller method call expected
。我想访问像http://localhost:9999/uploads/image.jpg
答案 0 :(得分:0)
嗯......这样做的一种方法是添加以下路线,
GET /uploads/*file controllers.Assets.at(path="/uploads", file)
但是,它会干扰现有路线的反向路由,即
GET /assets/*file controllers.Assets.at(path="/public", file)
然后,您必须将这两条资产路线用作 - @route.Assets.at("public", filename)
和@route.Assets.at("uploads", filename)
,这意味着您使用公共资产路线的所有模板 - @route.Assets.at(filename)
必须是改变。在现有的大项目中,这可能是一件麻烦事。
您可以使用以下方法来避免这种情况,
创建另一个控制器, 包控制器
object FileServer extends Controller {
def serveUploadedFiles1 = controllers.Assets.at( dicrectoryPath, file, false )
// Or... following is same as above
def serveUploadedFiles2( file: String ) = Action.async {
implicit request => {
val dicrectoryPath = "/uploads"
controllers.Assets.at( dicrectoryPath, file, false ).apply( request )
}
}
}
上面的内容应该有效......但是看起来好像Play对所请求的"资产"进行了大量的元数据检查。以某种方式导致所有/uploads/filename
个请求的空结果。我试着查看播放源代码进行检查,但似乎可能需要一段时间来弄明白。
所以我认为我们可以使用以下更简单的方法(它可以在很多方面进一步完善。)。
object FileServer extends Controller {
import play.api.http.ContentTypes
import play.api.libs.MimeTypes
import play.api.libs.iteratee.Enumerator
import play.api.libs.concurrent.Execution.Implicits.defaultContext
def serveUploadedFiles(file: String) = Action { implicit request =>
val fileResUri = "uploads/"+file
val mimeType: String = MimeTypes.forFileName( fileResUri ).fold(ContentTypes.BINARY)(addCharsetIfNeeded)
val serveFile = new java.io.File(fileResUri)
if( serveFile.exists() ){
val fileContent: Enumerator[Array[Byte]] = Enumerator.fromFile( serveFile )
//Ok.sendFile(serveFile).as( mimeType )
val response = Result(
ResponseHeader(
OK,
Map(
CONTENT_LENGTH -> serveFile.length.toString,
CONTENT_TYPE -> mimeType
)
),
fileContent
)
response
}
else {
NotFound
}
}
def addCharsetIfNeeded(mimeType: String): String =
if (MimeTypes.isText(mimeType)) s"$mimeType; charset=$defaultCharSet" else mimeType
lazy val defaultCharSet = config(_.getString("default.charset")).getOrElse("utf-8")
def config[T](lookup: Configuration => Option[T]): Option[T] = for {
app <- Play.maybeApplication
value <- lookup(app.configuration)
} yield value
}
但是这种方法会在打包构建部署的情况下造成一些麻烦。
这意味着,使用Play的Asset
内容将是更明智的选择。再看一遍,controllers.Assets.at
实际上controllers.Assets.assetAt
在一个地方使用此方法,
def resource(name: String): Option[URL] = for {
app <- Play.maybeApplication
resource <- app.resource(name)
} yield resource
这意味着,它会尝试在属于应用程序classpath
的目录中找到资源,而我们的uploads
文件夹肯定不是其中之一。所以...我们可以通过将Assets.at
添加到类路径来制作游戏的uploads
功能。
但是......再想一想......如果我记得类路径中的所有文件夹都应该打包在要打包的包中,以便打包 - 构建部署。上传的内容将由用户创建,这意味着他们不应该成为包的一部分。这又意味着......我们不应该尝试使用Play的Assets.at
内容来访问我们上传的内容。
所以......我认为我们最好使用我们自己更简单的基本实现serveUploadedFiles
。
现在在路径文件中添加路由为
GET /uploads/*file controllers.FileServer.serveUploadedFiles( file:String )
另外......请记住,您不应该考虑使用Play来提供上传的资源。请使用nginx或类似的东西。