MVC と ORM のサンプルプログラム†
import 文は省略
DBの設定 (memory 上のDBのため、再起動すると全て消える)†
conf/application.conf
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
ebean.default="models.*"
永続化したい場合は下記
conf/application.conf
db.default.url="jdbc:h2:file:play"
デバッグしたい
db.default.logStatements=true
logger.root=DEBUG
モデル†
- 基本的に1:1のテーブルが作成される
- public でフィールドを定義してあるが、自動的にソースに手が加えらえれ、 getter/setter が書き加えられてコンパイルされる
app/models/Country.java
package models;
(略)
@Entity
public class Country extends Model {
@Id
public Long id;
@Required
public String name;
@OneToMany(cascade = CascadeType.ALL)
public List<Holiday> holidays;
@CreatedTimestamp
public Date created_date;
@UpdatedTimestamp
public Date updated_date;
public static List<Country> all() {
return new Finder<Long, Country>(Long.class, Country.class).all();
}
}
app/models/Holiday.java
package models;
(略)
@Entity
public class Holiday extends Model {
@Id
public Long id;
@Required
public String name;
@ManyToOne
public Country country;
@Required
public Date date;
@CreatedTimestamp
public Date created_date;
@UpdatedTimestamp
public Date updated_date;
public static List<Holiday> all() {
return new Finder<Long, Holiday>(Long.class, Holiday.class).all();
}
}
ダミーデータの投入†
- package なしの Global.java#onStart はサーバ起動時に1回だけ呼ばれる
- 初期化処理などを入れる
- 毎回呼ばれるものは Global.java#filters に記述できる
Global.java
public class Global extends GlobalSettings {
@Override
public void onStart(final Application app) {
InitialData.insert(app);
}
public static class InitialData {
@SuppressWarnings("deprecation")
public static void insert(final Application app) {
if (Ebean.find(Country.class).findRowCount() == 0) {
Country country = new Country();
country.id = 1L;
country.name = "日本";
Holiday holiday = new Holiday();
holiday.id = 1L;
holiday.name = "元旦";
holiday.date = new Date("2000/01/01");
holiday.country = country;
country.save();
holiday.save();
}
}
}
}
コントローラー†
app/controllers/Countries.java
package controllers;
(略)
public class Countries extends Controller {
public static Result index() {
return ok(country.render(Country.all()));
}
}
app/controllers/Holidays.java
package controllers;
(略)
public class Holidays extends Controller {
public static Result index() {
return ok(holiday.render(Holiday.all()));
}
}
ビュー†
- app/views 以下に scala.html 置くとコンパイルされると、ファイル名=class名の .class ファイルとなる
app/views/country.scala.html
@(list: List[Country])
@main("") {
@for(i <- list){
@i.name
<br />
}
}
app/views/holiday.scala.html
@(list: List[Holiday])
@main("") {
@for(i <- list){
@i.name
<br />
}
}
route ファイル†
ブラウザで下記にアクセス
http://localhost:9000
Database 'default' needs evolution!
と表示されるので [Applly this script now! ] ボタンを押す~
(これはエラーではなく毎回でる)
下記にアクセス
http://localhost:9000/countries
配列のダンプがでれば成功
プリミティブ型と required の関係†
フィールドは型と required をちゃんと意識して選ばないとはまる。
- int vs Integer
primitive 型には必ず値が入るので @Required しているのと同等になるが、宣言時の初期値が入ることに注意。
例 : int a; の場合は 0
int a=10; の場合は 10 が入る|
3種類のリクエストがあることを意識すること
※ 特に、boolean を HTML の checkbox で表現する場合、false が?になるので注意
primitive vs Object
| | 制約なし | @Required 指定 |
int | ? | 初期値で値が上書きされる | 0 で値が上書きされる |
Integer | ? | 既存の値が残る | validation error でもう一度編集画面 |
int | ? | validation error | validation error でもう一度編集画面 |
Integer | ? | 既存の値が残る(nullに戻せない) | validation error でもう一度編集画面 |
boolean | ? | 初期値で上書き | 初期値で上書き |
Boolean | ? | 既存の値が残る | Validation Error でもう一度編集画面 |
boolean | ? | 初期値で上書き | 初期値で上書き |
Boolean | ? | 既存の値がのこる | Validation Error でもう一度編集画面 |
String | ? | 既存の値がのこる | Validation Error |
String | ? | 空文字が入る | Validation Error |
※ 結論というかおすすめ
- primitive 型は使わない
- Boolean を使う場合は checkbox を使わない
sample project†
http://caffeinecat.net/play2base.tgz