ふじやん雑記帳

「Slim3」の編集履歴(バックアップ)一覧はこちら

Slim3」の最新版変更点

追加された行はこの色になります。

削除された行はこの色になります。

-実験運用中…
-WebコミックLibrary
-http://web-comi.appspot.com/
-
 *参考サイト
 [[公式サイト>>http://sites.google.com/site/slim3appengine/Home]]
 [[公式サイト(Google Code)>>http://code.google.com/p/slim3/]] ダウンロードはコチラから
 [[ひがやすをblog>>http://d.hatena.ne.jp/higayasuo/]] 開発者ひがやすをさんのブログ
 
 ----
 -[[環境構築とプロジェクト作成>Slim3/環境構築とプロジェクト作成]]
 -[[Slim3でGWT>Slim3/Slim3でGWT]]
 -[[とりあえずSlim3アプリケーションを作ろう>Slim3/とりあえずSlim3アプリケーションを作ろう]]
 ----
 
 **Controller作成
 -基本的に、リクエストを受け取るアクション1つに対して1つのControllerを割り当てる
 --Controllerは、slim3.rootPackageの直下にcontrollerという名前のパッケージを作成し、その下にXxxxControllerという名前で作成する。build.xmlにあるgen-controllerターゲットを利用すれば、パッケージ作成からクラス作成まで面倒見てくれる(後述)
 --controller以下のパッケージ階層とXxxxControllerのXxxxの名前が、アクションのリクエストURLに対応する[[参考(URL Mapping)>>http://sites.google.com/site/slim3appengine/slim3-controller/url-mapping]]。
 slim3.rootPackageにjp.fujiyan.gae.example.slim3を指定している場合
 |リクエストのURL|必要なController|
 |/|jp.fujiyan.gae.example.slim3.controller.IndexController|
 |/show|jp.fujiyan.gae.example.slim3.controller.ShowController|
 |/sub/|jp.fujiyan.gae.example.slim3.controller.sub.IndexController|
 |/sub/show|jp.fujiyan.gae.example.slim3.controller.sub.ShowController|
 -gen-controllerターゲットでControllerを自動作成する。
 +build.xmlを開く(ダブルクリック等)。
 +Outlineビューからgen-controllerターゲットを選択し右クリック→[Run As]→[Ant Build]を選択する
 +[Ant Input Request]ダイアログの[Input a controller path.]に、作成したいアクションのリクエストURLを入力すると、リクエストURLに対応したパッケージとControllerが作成される。
 +また、Controllerの遷移先となるJSPも作成される。作成直後はwarディレクトリ直下に作成される&s(){が、外部にJSPが公開されるのも具合が悪いので、WEB-INFの下(WEB-INF/jsp等)に移動したほうがベター。その際は、Controller内のJSPのパスも移動先に修正する。}→そもそもGAE/JではJSPの直接参照が出来ないらしいので、war直下にあってもイイらしいです([[炸裂!情熱の右フック!!>>http://d.hatena.ne.jp/hageyahhoo/20100411/1270980051]])。
 **Service作成
 -Slim3では、ユースケース1つに対して1つのServiceを割り当てる、としている。「ユースケース」が何ぞや、というのもあるけど、難しい話はとりあえずすっ飛ばして、個人的には「Slim3に依存するフロー制御(画面遷移の実装等)はController」「ロジックのフロー制御はService」という棲み分けにしておく。
 --Serviceは、slim3.rootPackageの直下にserviceという名前のパッケージを作成し、その下にXxxxServiceという名前で作成する。やっぱり自動作成可能(後述)。
 -gen-serviceターゲットでServiceを自動作成する。
 +build.xmlを開く(ダブルクリック等)。
 +Outlineビューからgen-serviceターゲットを選択し右クリック→[Run As]→[Ant Build]を選択する
 +[Ant Input Request]ダイアログの[Input a service name.]に、サブパッケージ名+Service名を入力すると、パッケージとServiceが作成される。
 **Model作成
 -DatastoreのEntityをタイプセーフにしたもの。
 --Modelは、slim3.rootPackageの直下にmodelという名前のパッケージを作成し、その下任意の名前で作成する。例によって自動作成可能(後述)。
 -gen-modelターゲットでModelを自動作成する。
 +build.xmlを開く(ダブルクリック等)。
 +Outlineビューからgen-modelターゲットを選択し右クリック→[Run As]→[Ant Build]を選択する
 +[Ant Input Request]ダイアログの[Input a model name.]に、サブパッケージ名+Model名を入力すると、パッケージとModelが作成される。
 ***プロパティの定義
 -インスタンス変数とgetter/setterを定義する。特にAnnotationは不要
 #pre2(black){{
     private String name;
 
     public String getName() {
         return name;
     }
 
     public void setName(String name) {
         this.name = name;
     }
 }}
 -指定可能な型の一覧は、[[ここ>>http://sites.google.com/site/slim3appengine/slim3-datastore/defining-data-classes/core-value-types]]
 
 **リクエストのパラメータをControllerで取得する
 -Slim3のControllerには、リクエストのパラメータを取得するための簡易メソッドが用意されている。
 --asString()
 --asShort()
 --asInteger()
 --asLong()
 --asFloat()
 --asDouble()
 --asBoolean()
 --asDate()
 --asKey()
 
 **Controllerでの処理結果をJSPで出力
 -基本的には、各スコープ(Application/Session/Request)のattributeに値を設定し、Slim3のJSP Functions(特にh)で出力する。ループや条件分岐などの制御にはJSTLを利用する。
 -Slim3のControllerには、attributeに設定するための簡易メソッドが用意されている。
 --requestScope()
 --sessionScope()
 --applicationScope()
 -Serviceでデータを準備し、ControllerでServiceが準備したデータを上記メソッドでattributeに設定し、JSP FunctionsやJSTLを使って出力するのが定石か
 -Slim3のJSP Functionsのhは、Keyをパラメータとして用いる際に便利。引数にKeyのインスタンスを指定すれば、勝手にBase64にエンコードしてくれる。
 #pre2(black){{
 bookListの要素がEntity(プロパティkeyを持つ)であるとき、下記のコードで、アンカーをクリックした際に、そのEntityのKeyをリクエストのパラメータに渡せる。
 <c:forEach var="book" items="${bookList}">
 <a href="/showBook?bookKey=${f:h(book.key)}">${f:h(book.name)}</a>
 <hr/>
 </c:forEach>
 
 Controller側ではasKey()を使って、Keyに変換した状態で取得できる。
 Key bookKey = asKey("bookKey");
 }}
 
 ----
 
 *認証
 -GAE/Jの標準に準拠[[Google App Engine]]
 
 ----
 
 *前方一致検索
 -String型プロパティの前方一致検索が可能
 -Modelクラス(@Modelアノテーションを適用したクラス)を定義すると、ModelMetaクラスが自動的に定義される
 --Bookクラスを定義すると、BookMetaクラスが自動的に定義される。
 -Bookクラスのnameプロパティを前方一致検索するには、下記のように記述する。
 #pre2(black){{
 String value = "検索文字列";
 
 BookMeta meta = new BookMeta();
 StringAttributeMeta<Book> attrMeta = meta.name;
 List<Book> list = Datastore.query(Book.class).filter(attrMeta.startsWith(value)).asList();
 }}
 
 ----
 
 *ModelRefのLazy Load
 -ModelRefのsetKey()で参照先のKeyを設定すれば、getModel()でLoadされる。
 #pre2(black){{
 ModelRef<Foo> fooRef = new ModelRef<Foo>(Foo.class);
 
 とある場合、
 
 fooRef.setKey(fooKey);
 
 とすれば、
 
 Foo foo = fooRef.getModel();
 
 でfooKeyが指すFooをLoadする
 
 }}
 
 ----
 
 *ModelRefで問い合わせ
 -ModelRefAttributeMetaを使えば、ModelRefで問い合わせが可能
 -例えば、部署(1)対従業員(多)の場合、
 #pre2(black){{
 // 部署
 @Model(schemaVersion = 1)
 public class Dept implements Serializable {
 }
 
 // 従業員
 @Model(schemaVersion = 1)
 public class Employee implements Serializable {
     private ModelRef<Dept> deptRef = new ModelRef<Dept>(Dept.class);
     
     public ModelRef<Dept> getDeptRef() {
         return deptRef;
     }
 }
 }}
 とある場合に、「ある部署に所属する従業員全員」という問い合わせは下記のコードで可能。
 #pre2(black){{
 Key deptKey = [ある部署のKey];
 
 EmployeeMeta employeeMeta = new EmployeeMeta();
 ModelRefAttributeMeta<Employee, ModelRef<Dept>, Dept> refMeta = employeeMeta.deptRef;
 List<Employee> list = Datastore.query(Employee.class).filter(refMeta.equal(deptKey));
 }}
 -これを使えば、親子関連を持たせたい場合に、entityGroupを使わなくても良い。
 
 ----
 
 *ページング
 -DatastoreのCursorは、前にしか進むことができないため(多分)、「前ページ」とかの移動ができない。ましてや「nページ目」とかどうなの?
 -あと、Slim3のInMemoryFilterとModelQueryのlimit()/offset()を合わせて実行した場合、
 --先にlimit()/offset()が実行される
 --その結果に対してInMemoryFilterが実行される
 という順番なので(多分)、limit(1000)としても、1000件帰ってこない場合がある。例えば、総数2000件あって、InMemoryFilterにマッチするEntityが1001件目以降にしか存在しない場合、limit(1000)としても0件となる(っぽい)。
 -ということで、InMemoryFilterの結果に対して、任意のページに遷移可能なページ制御を考える。
 
 -&bold(){と、以前はここにソースがあったけど、どうも正常動作しないので取り下げ…}
 --&bold(){とりあえずの結論を[[文字列の部分一致検索とページング>Slim3/文字列の部分一致検索とページング]]にて}
 
 
 ----
 
 *InverseModelListRef(思いっきり想像なので、正確性は保証しません…)
 -InverseModelListRefは永続化の対象外(@Attribute(persistent = false))
 -InverseModelListRef#getModelList()によって、相手側Entityのクエリを実行する、プロキシ的な役割
 -InverseModelListRef#getModelList()を呼ぶ度にクエリが呼びだされ、新しいListのインスタンスが返されるので、それに相手側Entityを追加しても、データベースは変更されない
 
 ----
 
 *Slim3とFlex(BlazeDS)
 -Slim3とBlazeDSの組み合わせでは、/messagebroker/amfへのリクエストが大量発生して、GAEの上限に引っかかってしまうとの報告あり
 参考:[[ワタクシゴト>>http://blog.livedoor.jp/teruriot/archives/65211885.html]]
 -開発者のひがやすおサンも、BlazeDSの利用はあまり薦めておらず、HTTPServiceでやった方がラク、とおっしゃってます
 参考:[[ひがやすを blog>>http://d.hatena.ne.jp/higayasuo/20090522/1242978322]]
 -HTTPServiceのレスポンス形式については、下記2つの選択肢があるかと
 --XML
 ---E4Xを使えばFlex側の処理はラク。でもXMLフォーマットはやや冗長ですかねぇ
 --JSON
 ---ということで、こっちをサーバー側から返すようにしてみよう
 ---利用ライブラリは[[JSONIC]]を使うことに→[[Flex]]
 
 ----

間違いの御指摘は
コメントまでm(_ _)m

更新履歴




総数: 8827
本日: 4
昨日: 10