嗯...一种方法是添加以下路线,
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 或类似的东西。