play2/sample の変更点   

  • 追加された行はこの色です。
  • 削除された行はこの色です。
  • play2/sample へ行く。

* MVC と ORM のサンプルプログラム [#o3ddd1f0]
import 文は省略

*** DBの設定 (memory 上のDBのため、再起動すると全て消える) [#r00ae663]
''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

*** モデル [#fa30ea1e]
- 基本的に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();
	}
 } 
*** ダミーデータの投入 [#d7af4d46]
- 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();
			}
		}
	}
 }

*** コントローラー [#re049dbc]
''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()));
   }
 } 

*** ビュー [#i923c563]
- 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 ファイル [#a6c07d91]
- ここに記載した URLでアクセスされると、コントローラーに渡される
''conf/routes''
 GET     /countries                  controllers.Countries.index()
 GET     /holidays                   controllers.Holidays.index()

ブラウザで下記にアクセス
 http://localhost:9000

 Database 'default' needs evolution!

 と表示されるので [Applly this script now! ] ボタンを押す~
(これはエラーではなく毎回でる)

下記にアクセス
 http://localhost:9000/countries

配列のダンプがでれば成功

*** プリミティブ型と required の関係 [#v6a9de38]
フィールドは型と required をちゃんと意識して選ばないとはまる。~
- int vs Integer
primitive 型には必ず値が入るので @Required しているのと同等になるが、宣言時の初期値が入ることに注意。~
例 : int a; の場合は 0 ~
int a=10; の場合は 10 が入る|

3種類のリクエストがあることを意識すること
 
|?|http://example.com/?             | key すらない |
|?|http://example.com/?hoge=        | key はあるが、値がない |
|?|http://example.com/?hoge=""      | key はあるが、空文字   |

※ 特に、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 [#ie06789b]
http://caffeinecat.net/play2base.tgz