10

My play app is in 2.4.2. In Developer Mode,I used to read files from public folder at back-end controllers using Source.fromFile("./public/files/abc.json")

When I converted the application to production mode, I am getting File Not Found Exceptions. I found that the public folder is packed in an assets jar in production mode.What can i do so that it works in both development and production mode??

user189107
  • 177
  • 2
  • 11
  • 1
    You could try reading it from the classpath: http://stackoverflow.com/a/1464366/1080523 – rethab Apr 28 '16 at 08:35
  • @user1869107 " In Production mode,Play's class loader can read files only from conf folder" -> This is not correct. Actually you can add other resource directories to the Play framework in distribution. I will edit my answer and add how. – Supun Wijerathne Jun 08 '16 at 03:59

5 Answers5

7

Have you tried out this Play Documentation https://www.playframework.com/documentation/2.5.x/AssetsOverview ? This is Ok with Play 2.4 and even with 2.3 also, I have tried out.

In there you can find this, you can simply do this in your conf/routes file.

GET  /assets/*file        controllers.Assets.at(path="/public", file)

file -> refers to the file name. Ex: myFile.json

To make this work in production mode you have to do some little more work. As explained in this answer, add these lines into your /build.sbt file.

import com.typesafe.sbt.packager.MappingsHelper._
    mappings in Universal ++= directory(baseDirectory.value / "public")

That would include your 'public' directory inside the dist file (You can include any directory like that way). Then your application would work in the production environment.

Supun Wijerathne
  • 11,964
  • 10
  • 61
  • 87
4

You can use this method:

Play.application().getFile("/public/foobar.baz");

Method Doc:

Get a file relative to the application root path.

jsonmurphy
  • 1,600
  • 1
  • 11
  • 19
1

Use Source.fromResource instead of Source.fromFile if you are using scala 2.12.

Example:

If you put the file in public folder, don't use the leading slash.

Source.fromResource(“public/files/abc.txt”)

If you put the file in conf folder, don't include conf in the path.

Source.fromResource(“files/abc.txt”)  // conf/files/abc.txt

If you are using scala < 2.12, you can fall back to Java. There are 2 ways.

Relative path(no leading slash)

scala.io.Source.fromInputStream(getClass.getClassLoader.getResourceAsStream(“public/test.txt”))

Absolute path (leading slash required)

scala.io.Source.fromInputStream(getClass.getResourceAsStream(“/public/test.txt”))

I guess you also have to exclude "conf" in the path if you put the file in conf folder.

Lastly, you can learn how Java's resource loading works in this blog.

ohkts11
  • 2,581
  • 2
  • 21
  • 17
0

Play comes with a built-in controller to serve public assets.

The controller is available in the default Play JAR as controllers.Assets and defines a single at action with two parameters:

Assets.at(path: String, file: String) The path parameter must be fixed and defines the directory managed by the action. The file parameter is usually dynamically extracted from the request path.

Here is the typical mapping of the Assets controller in your conf/routes file:

GET  /assets/*file        controllers.Assets.at(path="/public", file)

Refer here for more.

monica
  • 1,454
  • 14
  • 28
0

There are two ways to resolve this:- 1) Straight one is to use what Supun Wijerathne suggested in the comment above. 2) Second one is to use the following approach, if one does not want to add an extra public folder in the distribution version of the application:- a) Copy all files from public folder in conf folder. b) Get resource as stream using Play's classloader. c) Convert this inputstream to bufferedsource using Source.fromInputStream method. Now, this file can be used by the controller for processing.

user189107
  • 177
  • 2
  • 11