Edited at

Play Framework(v2.2.3)からMongoDBを使う

More than 5 years have passed since last update.

Play初心者がMongoDBを使えるようになるまでのメモ。


環境

Mac OS X - 10.9.2

play(java) - 2.2.3

MongoDB - 2.6.1

Eclipse - 4.3.2


ソースコード

https://github.com/brly/play-morphia-sample


Morphia

https://github.com/mongodb/morphia

"Morphia is a lightweight type-safe library for mapping Java objects to/from MongoDB."

どうやらこれを使えばよさそうなのでこれを使うことにします。


play-morphia

http://www.playframework.com/modules/morphia

playへmorphiaを組み込むための公式っぽいモジュールがあったっぽいですが

適用可能なplayのバージョンが1.xのみ、ということで使えません。


playMongoDemo

公式ドキュメントにMongoDB関連のドキュメントがあんまり無い気がしたので適当に検索してたら

https://github.com/czihong/playMongoDemo

playでしかもmorphiaを使っているデモを見つけられたのでcloneしてplayしようとしたら色々エラーが出て動きませんでした。

どうやらplay自体のバージョンが異なる事が原因でした。

"play migration"とかで検索するとなんだかバージョン間の移行に関するページが沢山出てきて、とりあえずそれに従って進めていましたがうまく行かないため挫折。

2.0, 2.1, 2.2でかなり変わっているようですね。playバージョン管理ツールが欲しくなりましたが存在してませんよね?


play new myapp

というわけでplayMongoDemoを参考にしつつ、自分で手探りで作っていくことにしました。


Global.java

playMongoDemoにあったのものをまるまるコピーします。

GlobalSettingsオブジェクトでアプリケーションの起動時にMongoDBに接続しているっぽいですね。

GlobalSettings

- http://www.playframework-ja.org/documentation/2.0.8/JavaGlobal


Global.java

import java.net.UnknownHostException;

import com.google.code.morphia.Morphia;
import com.mongodb.Mongo;

import controllers.MorphiaObject;
import play.GlobalSettings;
import play.Logger;

public class Global extends GlobalSettings {
@Override
public void onStart(play.Application arg0) {
super.beforeStart(arg0);
Logger.debug("** onStart **");
try {
MorphiaObject.mongo = new Mongo("127.0.0.1", 27017);
} catch (UnknownHostException e) {
e.printStackTrace();
}
MorphiaObject.morphia = new Morphia();
MorphiaObject.datastore = MorphiaObject.morphia.createDatastore(MorphiaObject.mongo, "test");
MorphiaObject.datastore.ensureIndexes();
MorphiaObject.datastore.ensureCaps();

Logger.debug("** Morphia datastore: " + MorphiaObject.datastore.getDB());
}
}


Global.javaで使われているMorphiaObjectもplayMongoDemoで以下のように定義されてるのでコピー。


MorphiaObject.java

package controllers;

import com.google.code.morphia.Datastore;
import com.google.code.morphia.Morphia;
import com.mongodb.Mongo;

public class MorphiaObject {
static public Mongo mongo;
static public Morphia morphia;
static public Datastore datastore;
}



build.sbt

import文で使われてる"com.google.code.morphia"とか"com.mongodb.Mongo"とかを使うためには、build.sbtに色々追記する必要があります。

libraryDependencies ++= Seq(

javaJdbc,
javaEbean,
cache,
"com.google.code.morphia" % "morphia" % "0.99",
"org.mongodb" % "mongo-java-driver" % "2.7.3",
"de.flapdoodle.embed" % "de.flapdoodle.embed.mongo" % "1.36" % "test"
)

libraryDependenciesに追記します。

デフォルトだとjavaJdbc,javaEbean,cacheのみが書かれていますが、以下の3個を追加します。一番下のやつはテストを書く時に使います。

その後、追加したライブラリを.classpathとかに反映させるためにplayコンソールに入って

eclipse with-source=trueとかしたりします。うまく行かない時はplay cleanしてもう一度やったりして、今のところはうまく行きました。


モデル

https://github.com/brly/play-morphia-sample/blob/master/app/models/TestModel.java

playMongoDemoに沿って定義します。このソース例ではメンバ数を減らして、

{

name: String,
value: Int
}

こんな感じの簡単なやつです。

あとソースを見れば分かりますがRequiredアノテーションとかも使えます。


コントローラとルーティング

https://github.com/brly/play-morphia-sample/blob/master/conf/routes

https://github.com/brly/play-morphia-sample/blob/master/app/controllers/Application.java

playMongoDemoに沿って変更。play.data.Formあたりの仕様が変わってるので調整する。


ビュー

https://github.com/brly/play-morphia-sample/blob/master/app/views/index.scala.html

これはplayMongoDemoのままでも大丈夫だったような気がします。


実行

スクリーンショット 2014-05-18 18.39.58.png

5個程要素を追加後の画面です。


テスト

テストを書かないと色々言われるご時世なので書かないといけませんが、環境を整えなければなりません。

MySQLの場合だとplayのfakeApplicationとかinMemoryDatabaseを使えば良かったのですが、それは使えないので用意する必要があります。

という訳でまたぐぐったところ、以下の記事を見つけます。

http://www.cubeia.com/2012/03/using-mongodb-for-your-game-data/

見慣れたMorphiaという単語が安心感を与えてくれますが、新たな"EmbedMongo"という単語が出てきます。


EmbedMongo

というわけで"embedded mongo unit test"とかで検索するといかにもなページがあります。

http://quillbytes.com/display/JAVA/Setting+Up+An+Embedded+MongoDB+Database+for+Unit+Tests

でサンプル例があるのですが、サンプルのテストが書きたい感じとちょっと違います。

例ではDBCollectionとかいうオブジェクトを使ってread/writeをしてます。

TestModel.javaではそんな感じに書いてなかったので、どうしたら良いのかよくわかりませんでしたがとりあえず以下のようにしたらfakeぽく動作するようになりました。


TestModelTest.java

@Before

public void beforeTest() {
MorphiaObject.mongo = getMongoClient();
MorphiaObject.datastore = new Morphia().createDatastore(getMongoClient(), "test");
}

@Beforeで毎回MorphiaObjectのmongoとdatastoreを初期化して書きたかった感じにテストを書きます。


TestModelTest.java

 @Test

public void 初期値は空リスト() {
assertThat(TestModel.all()).isEmpty();
}

@Test
public void addしたものが順番に取り出せる() {
TestModel ts0 = new TestModel();
ts0.name = "ほとココア";
ts0.value = 15;
TestModel.create(ts0);

TestModel ts1 = new TestModel();
ts1.name = "かふうチノ";
ts1.value = 13;
TestModel.create(ts1);

TestModel ts2 = new TestModel();
ts2.name = "てでざリゼ";
ts2.value = 16;
TestModel.create(ts2);

TestModel ts3 = new TestModel();
ts3.name = "うじまつチヤ";
ts3.value = 15;
TestModel.create(ts3);

TestModel ts4 = new TestModel();
ts4.name = "きりまシャロ";
ts4.value = 15;
TestModel.create(ts4);

assertThat(TestModel.all()).hasSize(5);
assertThat(TestModel.all().get(0).name).isEqualTo("ほとココア");
assertThat(TestModel.all().get(1).name).isEqualTo("かふうチノ");
assertThat(TestModel.all().get(2).name).isEqualTo("てでざリゼ");
assertThat(TestModel.all().get(3).name).isEqualTo("うじまつチヤ");
assertThat(TestModel.all().get(4).name).isEqualTo("きりまシャロ");
}


という訳で、なんとか環境が出来ました。