1
votes

The goal is to be able to both download and render (e.g. profile pic) images that are either a public asset or a private one.

In the Play Framework docs (ScalaStream), it says:

Play provides easy-to-use helpers for common task of serving a local file:

def index = Action {
  Ok.sendFile(new java.io.File("/tmp/fileToServe.pdf"))
}

If you want to serve this file inline:

def index = Action {
  Ok.sendFile(
    content = new java.io.File("/tmp/fileToServe.pdf"),
    inline = true
  )
}

This looks like what is needed to achieve the goal.

Now, I have a directory structure as shown below, and would like to serve the files 1.png and 2.png

MyApp
|_ app
|_ conf
|_ public (all public assets)
   |_ images
      |_ 1.png
|_ private (more assets, not public)
   |_ images
      |_ 2.png
|_ ...

I have defined a controller function as follows:

def sendImage() = Action {
  // Ok.sendFile(new java.io.File("/public/images/1.png"))
  // Ok.sendFile(new java.io.File("assets/images/1.png"))
  Ok.sendFile(new java.io.File("/private/images/1.png"))
}

Tried various different paths, absolute, relative, but when I call this controller function from the front-end (React / Axios), it only returns "NoSuchFileException".

However, I am able to render public assets from the front-end simply using:

<img src='/assets/images/1.png' />   // from the public dir

The same path does not work from within the controller. Could not figure out how Play expects its paths.

Currently using Play 2.5

Any ideas? Thanks

3
When you use / before the file name, this expects the full path of the file and not a relative one. You need to change from "/private/images/1.png" to "private/images/1.png" so that it will be relative to your application. But, if these private files are uploaded by the user, have them inside the application directory would be considered a bad practice. What will happen when you deploy a new version of the application? You will either lose the files or you will need to copy/move them while deploying. So, have an directory that is external to the application to store uploaded files.marcospereira

3 Answers

0
votes

inject play.api.Application object in your controller and use the getFile method defined in the application object as shown below.

class JobInstanceController @Inject()(protected val app: Application) extends Controller {
  def test = Action {
    Ok.sendFile(app.getFile("public/images/1.png"))
  }
}
0
votes

the private folder isn't in the classpath. I think you need to add it to the build.sbt file

unmanagedResourceDirectories in Compile += baseDirectory.value / "private"

see here http://www.scala-sbt.org/0.13/docs/Howto-Customizing-Paths.html

0
votes

The comment by @marcospereira is what helped resolve the path, thanks!

When you use / before the file name, this expects the full path of the file and not a relative one. You need to change from /private/images/1.png to private/images/1.png so that it will be relative to your application.

But, if these private files are uploaded by the user, have them inside the application directory would be considered a bad practice. What will happen when you deploy a new version of the application? You will either lose the files or you will need to copy/move them while deploying. So, have an directory that is external to the application to store uploaded files.