【问题标题】:PlayFramework 2.3.x: Access public folder using URL with Play and ScalaPlayFramework 2.3.x:使用带有 Play 和 Scala 的 URL 访问公共文件夹
【发布时间】:2015-03-17 22:12:55
【问题描述】:

我正在使用网络服务上传视频和图像并将图像保存在我们的应用程序中。当我保存文件时,文件保存在应用程序文件夹的根目录中。我想使用localhost url 访问这些图像和视频,例如:我上传文件并保存在app-root/upload/image.jpg 下。在我的路由映射文件中,我声明路由如下:

GET     /uploads/                                   staticDir:/upload 

Play Documentation 中定义的那样。但仍然出现编译时错误:Controller method call expected。我想访问这样的图像http://localhost:9999/uploads/image.jpg

【问题讨论】:

  • GET /uploads/*file controllers.Assets.at(path="/uploads", file)
  • 不,@SarveshKumarSingh 这不是办法。由此,我得到了另一个编译错误。请加入聊天根进行讨论。 stackoverflow.com/questions/11937335/…

标签: scala playframework-2.3


【解决方案1】:

嗯...一种方法是添加以下路线,

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 文件夹肯定不是其中之一。所以...我们可以通过将uploads 添加到类路径来让play 的Assets.at 工作。

但是...再想一想...如果我记得类路径中的所有文件夹都应该打包在要部署的包中,以防打包构建部署。上传的东西将由用户创建,这意味着它们不应该是包的一部分。这再次意味着......我们不应该尝试使用 Play 的 Assets.at thingy 访问我们上传的内容。

所以...我认为我们最好使用我们自己的更简单的基本实现 serveUploadedFiles

现在在路由文件中添加一个路由,

GET         /uploads/*file                        controllers.FileServer.serveUploadedFiles( file:String )

另外...请记住,您不应考虑使用 play 来提供上传的资产。请使用 nginx 或类似的东西。

【讨论】:

  • 从 URL The image http://localhost:9999/uploads/test.jpg cannot be displayed because it contains error 访问图片时出现以下浏览器错误
  • @Sarvesh 我有完全相同的想法并尝试了同样的事情,尽管它在尝试加载资源时返回 404。我尝试在target/web 内部和根目录下复制uploads 目录,但它仍然不起作用。
  • 努力@SarveshKumarSingh,但使用第二个代码,我的文件已下载,未在浏览器中打开。
  • 是的...因为我们仍然缺少文件的mime-types。添加正确的mime 信息将使浏览器能够理解传入的文件类型,并且浏览器将尝试找出处理它的方法。
  • @HarmeetSinghTaara 我已经做出了启用浏览器渲染文件所需的更改(给定浏览器知道如何处理它们,所以应该渲染 png、jpeg、pdf 等...其他将被下载)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-24
相关资源
最近更新 更多