2012年2月1日水曜日

Slim3 Source Code Reading #6

今日はSlim3 Source Code Reading #6でした。

今日は、FileUploadの辺りを読む予定でしたが、
最近Slim3で開発を始めたので、それに対する疑問を聞いてみたり、BlobstoreAPIの
使い方を説明したりしました。

あとは、最近Google App EngineのアプリケーションをSlim3を使って
開発しているので、その時に疑問に思ったことを聞いてみたりしました。
先週と同じく、言いだしっぺの2人だったので、すぐ脱線してしまいました。

ちゃんと、FileUploadの部分も読みました。

が、HTTPのリクエストに対する知識がないと、意味不明な部分もあったりして、
Chromeのデベロッパーツールでhttp headerの中身をみたりしました。
個人的には十分な内容だったと思います。

では、一つ目のBlobstoreAPIを利用したファイルのアップロードについては、
以下の手順でファイルをBlobstoreに格納します。

  1. アプリケーションのファイル選択画面を表示する。
    1. ここで、POST先のURLはBlobstoreService#createUploadURL(url)を呼び出して、BlobstoreAPIで利用するURLを指定する。
    2. 引数のURLはBlobstoreにデータを格納後にリクエストされるURLを指定する。
  2. アップロード後に呼び出されるURLで、BlobstoreService#getUploadsを呼び出し、Blobstoreに格納したデータのBlobkeyを取得する。(複数ファイルに対応しているため、戻り値がMap<String, List<BlobKey>>の型になっている。)
    1. この時取得したBlobKeyは忘れてはいけない。(BlobKeyで格納しているデータにアクセスするため、BlobKeyを参照できないとデータを参照する事も、削除することもできなくなる。※ただし、admin consoleからなら削除可能)
  3. BlobKeyを引数にBlobstoreService#serve()を呼び出すことで、HttpResponseにBlobstoreに格納されているデータを書きこんでくれる。
    1. 画像であれば、<img>タグのsrcに指定することで、画像が表示される。
    2. 動画であれば、<video>タグのsrc
    3. 音声であれば、<audio>タグのsrc
  4. 同じく、Blobkeyを引数にBlobstoreService#delete()を呼び出すことで、Blobstoreのデータを削除する。ただし、Entityに格納している場合は、Entityの中身(BlobKey)を読みだした後に削除しないと、BlobKeyが参照できないのでdeleteできなくなる。
ちなみに、私のGoの本を参考にサンプルプログラムを作りましたが、(私だけかもしれませんが)意外と作れます。(Go→Javaができたという事は、その逆もまた可能なはず)

BlobstoreAPIはファイルサイズが最大32Mバイトまでとなっていますので、
大きなデータは格納できません。

脱線した話として、

  1. 自作のControllerに親クラスを作ったりするかどうか。
    1. これはやる。Sessionなど、全体に渡って取得する場合はやる。
  2. データストアから読みだした後、表示用に編集した値を保持するクラスをどこに作るか。
    1. 特にルールはないので、どこでもいいんじゃないか。
    2. Modelで編集用のデータを返すメソッドを定義する
  3. Keyのnameに名前を格納しておくと結構いい感じ。
    1. エンティティを読み出すのとKeyのみ読み出すのとでは、コスト的に7分の1
  4. とりあえず、良く使うデータはmemcacheに突っ込んどけば良いんじゃないかな?
    1. 更新頻度の問題がある。
      1. インスタンスが停止する場合。→所詮その程度なので安く収まるのでは?
      2. 結局は運用してみないとわからない。
  5. 課金設定にしたら、9ドル/月
    1. 最大9ドル/日と勘違いしていた。(1日9ドルだと月2万以上…)
    2. 無料枠を使い切る→9ドルの枠でがんばる→枠を越えたら…。
  6. Javaで作ったアプリケーションの最初の起動は遅い…
    1. Javaは初回のアクセス(インスタンスを起動する)時は一呼吸あるけど、Goだとそれはない。
最後にFileUploadの話題

  1. FrontControllerで、Content-Typeを確認して、"multipart/"で始まるかどうかをチェック。
    1. "multipart/"の場合、ファイルがアップロードされてきた判定。
      1. この場合、MultipartRequestHandlerのインスタンスが生成される。
    2. その他は、普通の(?)リクエスト
  2. MultipartRequestHandler#handleで、FileUploadクラスのインスタンスを生成する。
    1. FileUploadクラスで、ファイルのサイズの制限設定を読み込む。
      1. 現時点のblankプロジェクトの設定はコメントアウトされているので初期値が使われる。
      2. 初期値は-1なので、「制限なし」
    2. この中で、いろいろな処理をして、FileItemクラスのインスタンスを生成する。
      1. MultipartRequestHandlerはかなり頑張ってます。
      2. ちなみに、ファイルを読み込む時のバッファは8 * 1024(8192)バイトです。ファイルが大きいと実行されるステップ数も増えます。
    3. 最終的にControllerでFileItem item = requestScope("formFile")の1行でファイルが取得できる。
  3. Serviceでアップロードされたデータを格納する処理を実行すれば、Datastoreにファイルが格納される。
個人的に思うこと。

  1. BlobstoreAPIを利用したほうが良い。
  2. ただし、BlobstoreAPIはファイルの中身をチェックできない
    1. UploadはAPI用のリンクへのリクエスト
    2. downloadは直接HttpResponseに書きこまれる
  3. したがって、中身をチェックしたい場合は、Slim3のFileUploadを使うほうが良い。
  4. あと、課金状況で判断するのも必要かもしれない。
  5. 32Mバイトを超えるファイルを格納する可能性があれば、BlobstoreAPIは使えないのでSlim3のFileUpload一択。(※ただし、そんなに大きなファイルを格納しようと思うと、30秒の時間制限を考える必要がある)

次回の#7は2/7(火)19:00〜の予定です。
少人数で行っているので制限が厳しいですが、ご参加をお待ちしております。