Goalist Developers Blog

Play Frameworkで画像・アセットをユーザーに届ける

Play Frameworkが非常に便利ですので、Apiサーバーとして使ってます。この度、自分のサーバーに持ってる画像などなアセットをそのまま返したい場合(例え、アンギュラーのフロントで表示したいなど)にどうすればいいかを説明します。 それぞれの状況に合わせて、二つの方法を説明します。

とりあえず、…image.jpgに画像を出したい!

つまり、誰でもそのurlにいくとその画像がみれるような場合です。 この方法は割と簡単です。

conf/routesのファイルに

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

これで、/public/images/のディレクトリーをベースにして、「ファイル」というパス変数に当てはまるファイルをそのまま出せます。

www.example.com/assets/cats/myCat.png/public/images/cats/myCat.pngにあるファイルを出します。(なかったら、404エラーが出ます)

ちなみに、Idea使ってる方々はこのようなdeprecatedという知らせを見ることもあると思いますが、Ideaのバグらしいです。(link: https://github.com/playframework/playframework/issues/7521)

このように、Angularのクライアントで、<img src="www.example.com/assets/cats/myCat.png" />

このイメージのアクセスを制限したいですが…

アクセス制限、何かのトラッキング・編集などのことがやりたい場合もあると思います。その場合は直接routesから返したらできなくなるかと思いますが、別な方法もあります!

では、routesにこう追加しましょう

 GET       /getImage                controllers.HomeController.getImage

getImageの中でバリデーションやアナリティクスなど、でもできます。 欲しいイメージや、アクセス権限の情報がGET変数で送られてるとしますと、FormFactoryとDynamicForm を使って、コントローラーからその変数のアクセスができます。

public class MyController extends Controller {

@Inject
private FormFactory formFactory;

public Result getImage() {
...
}

}

まずは、FormFactoryをInjectionで使えるようになる。そして、getImageの書き方は...

DynamicForm dynamicForm = formFactory.form.bindFromRequest();
// 適切なログインチェックを行う
if(!isLoggedIn(dynamicForm)) {
    // もしユーザーがログインしてない場合には、対応する。
        return ....; //アクセス制限する。
}

まずは、バリデーションができる、そしてアクセス制限したい場合にはふさわしい風に行える。 その後、ユーザーが頼んでるイメージの正式なパスを作成し、Resultを返す。

// ユーザーが送ってるファイル名的なパスと実際のサーバーのパスが違うのはず。
String path = getRealImagePath(dynamicForm.get("")); 
java.nio.file.Path deliveryPath = Paths.get(path);
// これはPlayFrameworkに存在する、ファイルをだす方法:
return new Result(
          new ResponseHeader(200, Collections.emptyMap()),
          new HttpEntity.Streamed(FileIO.fromPath(deliveryPath), Optional.empty(), Optional.of("image/png"))
);

こんな風に、画像や他のアセットのアクセスを制限することもできます。