79
G* on GAE/J 挑戦編 2009/08/22 @Tokyo def speaker = new Cast(name:”T.Yamamoto”,version:”G*S-2009-08-22”)

G* on GAE/J 挑戦編

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: G* on GAE/J 挑戦編

G* on GAE/J 挑戦編

2009/08/22 @Tokyo

def speaker = new Cast(name:”T.Yamamoto”,version:”G*S-2009-08-22”)

Page 2: G* on GAE/J 挑戦編

自己紹介名前:山本 剛 (やまもとつよし)

所属:株式会社ニューキャストDTP、組版屋、印刷業界向けWebアプリ開発など。案件は90%Grailsを使ってます。

JGGUG(じぇいがぐ) 名古屋支部長です。「Grails徹底入門」9-11章を書きました。 Grails Acegi Plugin作った人。

ブログhttp://d.hatena.ne.jp/mottsnite/

Page 3: G* on GAE/J 挑戦編

第零幕

Grails!?

JavaEEで実績のあるSpringフレームワークやHibernateをベースに、Groovyを活用して効率よくJavaEE開発を行うことのできる、フルスタックフレームワークです。

Page 4: G* on GAE/J 挑戦編

Grails-1.2M2Spring3に更新@Transactionalでのメソッド単位のトランザクションの実装ダイナミックファインダでのBoolean値の機能を追加GORMにhasOneマッピングをサポート名前付き問合せ定義が可能GORM 厳密なバリデーションエラーWARデプロイでのGSPプリコンパイルマルチ組込コンテナサポート、デフォルトはTomcatに!i18nでのクラス名プロパティ名をハンドル名称付きURLマッピングプロジェクトドキュメントエンジンプラグインメタジェネレータ

Page 5: G* on GAE/J 挑戦編

では、Grailsを、

体験してみましょう。

Page 6: G* on GAE/J 挑戦編

第壱幕

GrailsでWebアプリ作ってみよう

Page 7: G* on GAE/J 挑戦編

準備どのようなWebアプリケーション開発を作るか?

今回のテーマ「イベント告知アプリ!?」を作ってみる

Page 8: G* on GAE/J 挑戦編

プラン「イベント告知アプリ!?」イベントの登録・配信がおこなえる

準備使いたい機能を持ったプラグインの現時点での候補Calendaryui-css •Tips

•必要機能に適したプラグインの有無を確認。•プラグインを活用!•無駄を無くす。•プラグインからアイデアをもらう。

Page 9: G* on GAE/J 挑戦編

Page 10: G* on GAE/J 挑戦編

設計必要項目ドメインクラスイベントを収納するテーブル

コントローラリスト表示 (list)作成・編集 (entry)editsave

詳細表示 (show)他ロゴレイアウト

Page 11: G* on GAE/J 挑戦編

プロジェクトを作成Grailsプロジェクトを作成

BuildConfig.groovy (オススメ) 作業ディレクトリやビルド時の環境指定が可能。grails-app/conf/BuildConfig.groovyファイルを作成

DBの設定 grails-app/conf/DataSource.groovyファイルを編集

$ grails create-app eventer$ cd eventer

grails.project.plugins.dir="work_tmp/plugins"grails.project.work.dir="work_tmp/work"

development { dataSource { dbCreate = "update" url = "jdbc:hsqldb:file:work_tmp/devDB;shutdown=true"

Page 12: G* on GAE/J 挑戦編

試し起動$ grails run-app

Page 13: G* on GAE/J 挑戦編

ドメインクラスモデル → 詳細(ドメインモデル) → ドメイン設計1. 必要な項目

イベントタイトル - eventName開催日 - eventDate開催時間など - eventDesc場所 - place主催団体名 - groupName内容 - content

2. 実際にドメインクラスを作る

3. コントローラを作成

$ grails create-controller org.jggug.Event

$ grails create-domain-class org.jggug.Event

Page 14: G* on GAE/J 挑戦編

Event.groovypackage org.jggug

class Event {

/** イベントタイトル */ String eventName /** 開催日 */ Date eventDate /** 開催時間など */ String eventDesc /** 場所 */ String place /** 主催団体名 */ String groupName /** 内容 */ String content Date dateCreated Date lastUpdated

static constraints = { }}

EventController.groovypackage org.jggug

class EventController { def scaffold = true}

Page 15: G* on GAE/J 挑戦編

起動してみましょう!$ grails run-app

Page 16: G* on GAE/J 挑戦編

調整!idをuuid.hexにする。

バリデーション全て null不許可、空白不許可contentに4000文字制限

Event.groovyclass Event implements Serializable {

static mapping = { id generator:'uuid.hex', params:[type:'string'] } String id...

static constraints = { eventName nullable:false,blank:false eventDate nullable:false,blank:false eventDesc nullable:false,blank:false place nullable:false,blank:false groupName nullable:false,blank:false content nullable:false, blank:false,maxSize:4000 dateCreated display:false lastUpdated display:false }

Page 17: G* on GAE/J 挑戦編

調整! i18n (1.2M2の新機能)i18n (1.2M2の新機能)messages_ja.propertiesにフィールド名称を定義

コマンドとか有れば良いのに....無いのでテキストエディタで置換!

/** イベントタイトル */String eventName

/** 開催日 */Date eventDate

/** 開催時間など */String eventDesc

event.label = イベントevent.eventName.label = イベントタイトル

適当だけど/\*\*(.*)\*/\n(.*) (.*)

event.$3.label = $1

event.eventName.label = イベントタイトル event.eventDate.label = 開催日 event.eventDesc.label = 開催時間など

Page 18: G* on GAE/J 挑戦編
Page 19: G* on GAE/J 挑戦編

ドメインが完成

Page 20: G* on GAE/J 挑戦編

STEP.4 コントローラとビューgenerate-all して各ソースファイルを編集します。

起動します。

$ grails generate-all org.jggug.Event

$ grails run-app

Page 21: G* on GAE/J 挑戦編

調整ポイント!カレンダープラグインで日付フォームをかっこよくリスト調整必要な部分だけ残して見た目調整。詳細表示デザイン調整!レイアウト調整

Page 22: G* on GAE/J 挑戦編

カレンダープラグイン開催日のフォーム調整

★<head>タグの中に<calendar:resources lang="en" theme="tiger"/>

★対象の場所に<calendar:datePicker name="eventDate" defaultValue="${eventInstance?.eventDate}" dateFormat="%Y/%m/%d" />

★カレンダープラグインをインストール$ grails install-plugin calendar

Page 23: G* on GAE/J 挑戦編

リスト調整

こんな感じに。タイトルはリンクに

Page 24: G* on GAE/J 挑戦編

詳細表示調整

Page 25: G* on GAE/J 挑戦編

レイアウト調整横にメニューのあるレイアウトに調整yui-cssを使う!

http://grails.jp/sample/grails-yui-css-2.7.0-M2.zip

コマンドを実行

★yui-cssのプラグイン(非公式)をインストールgrails install-plugin http://grails.jp/sample/grails-yui-css-2.7.0-M2.zipgrails yui-css

<head>内の以下の部分 content=”main”を “yui-t1”に変更<meta name="layout" content="main" />

<meta name="layout" content="yui-t1" />

Page 26: G* on GAE/J 挑戦編

メニュー調整・・・・・

Page 27: G* on GAE/J 挑戦編

STEP.5 完成いろいろやり残しは有りますが・・

デプロイするとTomcat等のアプリケーションサーバーで運用可能です。$ grails wareventer-0.1.war が生成されます。

Page 28: G* on GAE/J 挑戦編

第弐幕

GrailsでGAE/J

Page 30: G* on GAE/J 挑戦編

GAE登録Googleのアカウントでログイン。アカウントが無い場合は作成。

Page 31: G* on GAE/J 挑戦編

GoogleアカウントGoogleアカウントが無い場合は登録してください。

Page 32: G* on GAE/J 挑戦編

ログインするとログイン

Page 33: G* on GAE/J 挑戦編

App Engineのトップページアプリケーション作成画面。Create an Applicationをクリック

Page 34: G* on GAE/J 挑戦編

認証メール携帯電話のメールアドレスを登録携帯メールに認証コードが送られてくるので、次の画面でコードを入力

Page 35: G* on GAE/J 挑戦編

GAEアプリ作成アプリケーション作成画面

Page 36: G* on GAE/J 挑戦編

GrailsをGAEに!

Grailsには、GAEに対応させるためのプラグインが用意されています。

Page 37: G* on GAE/J 挑戦編

AppEngine

Plugin

Page 38: G* on GAE/J 挑戦編

AppEngine PluginGrailsをGAE/Jに対応させるプラグイン機能

インストール時にGAEに必要なファイル生成デプロイ用のコマンドスカッフォルドテンプレートJDOとJPAに対応認証設定 → Config.groovyに設定

Page 39: G* on GAE/J 挑戦編

AppEngine Pluginインストール前に必要な設定

Google App Engine SDK設定ダウンロード&解凍http://code.google.com/appengine/

AppEngineSDKの場所を指定。環境変数 APPENGINE_HOME 又は、config/BuildConfig.groovyにgoogle.appengine.sdkで指定

export APPENGINE_HOME=/opt/appengine-java-sdk-1.2.2

google.appengine.sdk='/opt/appengine-java-sdk-1.2.2'

Page 40: G* on GAE/J 挑戦編

インストールと設定インストール!$ grails install-plugin app-engine

インストール途中で質問に答えます。Do you want to use JPA or JDO for persistence? (jpa, jdo)jpa

インストールされるとgrails-app/conf/以下にそれぞれのファイルが追加されます。datastore-indexes.xmlpersistence.xml

★grails-app/conf/Config.groovyにGAEのアプリケーション名を記述google.appengine.application="jggugv4"

★Grailsプロジェクトのバージョンをセット

Page 41: G* on GAE/J 挑戦編

GORM-JPA

Page 42: G* on GAE/J 挑戦編

GORM-JPA PluginJPAプラグインは3種類ある…

Hibernate JPA Provider PluginJPA PluginGORM-JPA Plugin ← これを使います。

できることGORMと同じsave(),list()等のメソッドが利用できる(※一部未対応、)

できないことドメインクラスと同じmapping定義ドメインの定義には、JPAアノテーションを利用Criteria (※JPA1.0で未対応なため)

Page 43: G* on GAE/J 挑戦編

GORM-JPAインストールインストール! $ grails install-plugin gorm-jpa

resources.groovyにentityManagerFactoryとtransactionManagerを追記entityManagerFactory(org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean) { beanClassLoader = ref("classLoader")}

transactionManager(org.springframework.orm.jpa.JpaTransactionManager) { entityManagerFactory = entityManagerFactory }

何故かdatanucleus-enhancer*.jarが入っていないのでコピーcp $APPENGINE_HOME/lib/tools/orm/datanucleus-enhancer-1.1.4.jar lib

Page 44: G* on GAE/J 挑戦編

起動!ちょっとまった!起動したいのですが、そのままだと色々と問題が。JPA用にドメインクラスの調整が必要コントローラも若干調整が必要

Page 45: G* on GAE/J 挑戦編

ドメインクラスの調整通常のGrailsドメインクラスでは、JPAで使うことはできません。若干の修正が必要です。JPA用のアノテーションを追記

import org.datanucleus.jpa.annotations.Extensionimport javax.persistence.*;

@Entityclass Event implements Serializable {

@Id @GeneratedValue (strategy = GenerationType.IDENTITY) @Extension (vendorName = "datanucleus",

key = "gae.encoded-pk", value = "true") String id /** イベントタイトル */ @Column //全てのフィールドに付加 String eventName

Page 46: G* on GAE/J 挑戦編

コントローラの調整これが正解なのかは検証中ですが。アクションクロージャsaveだけ編集。

def save = { def eventInstance = new Event(params) Event.withTransaction{ if(eventInstance.save(flush:true)) { flash.message = "Event ${eventInstance.id} created" redirect action:"show", id:eventInstance.id } else { render view:'create', model:[eventInstance:eventInstance] } }}

Page 47: G* on GAE/J 挑戦編

起動テスト起動してみましょう!

準備$ grails set-version 1

起動$ grails app-engine run

Page 48: G* on GAE/J 挑戦編

動いた!

Page 49: G* on GAE/J 挑戦編

だが、

ローカル

Page 50: G* on GAE/J 挑戦編

反省点・まとめ まあ、どうにかローカルで動きました。が・・

Stringは500文字までなので・・・対応方法は有るのだけど、よく分からなかったので放置。GORM-JPAプラグインで完全サポートされると思うので待ちます。

GAEにアップデート・・・動作しない。1.2-M2だと、ログ関係があやしい・・たしかに、1.1.1では動いていた・・・早急に対応期待

もう少しGAE/Jを勉強しないと。

Page 51: G* on GAE/J 挑戦編

くやしいです!

Page 52: G* on GAE/J 挑戦編

ホントにムリ?

Page 53: G* on GAE/J 挑戦編

1.2-M2だと、ログ関係があやしい問題を探ってみた。

どうやらこれが問題点

Page 54: G* on GAE/J 挑戦編

1.2-M2だと、ログ関係があやしい回避方法。該当部分を修正して、grailsをビルドする。LoggingGrailsPlugin.groovyを修正単純に該当箇所コメントアウトバージョンが、1.2-SNAPSHOTになる。application.propertiesのGrailsバージョン変えるGRAILS_HOMEも変更そして実行。

$ grails app-engine package$ rm target/war/WEB-INF/lib/jul-to-slf4j-1.5.6.jar$ appcfg.sh update ./target/war

Page 55: G* on GAE/J 挑戦編

動きました!

Page 56: G* on GAE/J 挑戦編

まとめGAE/J・・・ローカルとサーバで違いがあるね。どうなんですかね???

Grails自体にバグがあると対応は大変です。まだ、一般向けでは無いと思う。

でも、これ完成したらスゴイと思います。

Page 57: G* on GAE/J 挑戦編

もっとライトな

Groovy on GAE/J

Page 58: G* on GAE/J 挑戦編

第参幕

Gaelyk(GroovyでGAE/J)

Page 59: G* on GAE/J 挑戦編

 ※ここでは、Google App Engineのコマンドを使用します。App Engine SDKの設定が必要です。

export APPENGINE_HOME=/opt/appengine-java-sdk-1.2.2export PATH=$PATH:$APPENGINE_HOME/bin

動作確認$ dev_appserver.sh -h$ appcfg.sh -h

※Windowsでは、.sh→.cmd

Page 60: G* on GAE/J 挑戦編

Gaelyk - ゲーリックGaelykとは、

GAE/J用の軽量Groovy開発ツールキットです。GroovyテンプレートとGroovyletで構成されています。ビューとコントローラGroovletsとTemplateServletを拡張したクラスで実現ビュー:GaelykTemplateServlet拡張子gtplのプレゼンテーション層

コントローラ:GaelykServletGaelykTemplateServletとGaelykServletにGAE/Jで使用するサービスなどがServletBindingにバインドされています。GAE/JのサービスにもCategoryを使用してメソッドが拡張追加されています。

Page 61: G* on GAE/J 挑戦編

セットアップGaelykテンプレートプロジェクトをダウンロードhttp://gaelyk.appspot.com/download/

テンプレートプロジェクトです。そのまま解凍して仕様します。gaelyk-template-project-0.1.zipを解凍。

Page 62: G* on GAE/J 挑戦編

内容 プロジェクトbuild.groovy & srcAntBuilderで実装されてる簡単なビルド用プログラム。srcフォルダに配置した、GroovyとJavaのソースのコンパイルに使用。

warこのディレクトリがデプロイされます。

Page 63: G* on GAE/J 挑戦編

内容 warディレクトリこのディレクトリに、ビューの*.gtplと、css、images等のファイルを配置します。WEB-INFappengine-web.xmlGAEの定義ファイル

web.xml/groovy/ここに*.groovy配置

/includes/ - インクルードファイル//lib/ - *.jar/classes/

Page 64: G* on GAE/J 挑戦編

設定appengine-web.xml<application>タグの中身を自分のアプリケーション名称に変更<version>を指定<static-files> 拡張子を変えるときはここも変更

Page 65: G* on GAE/J 挑戦編

設定web.xml拡張子など変更したい場合や、色々追記したい場合は、そのまま追記でOK。

Page 66: G* on GAE/J 挑戦編

起動してみましょう

http://localhost:8080/をブラウザで表示

ローカルで起動テンプレートプロジェクトのルートで、$ dev_appserver.sh ./war

※Windowsでは、.sh→.cmd

Page 67: G* on GAE/J 挑戦編

さわってみよう

Page 68: G* on GAE/J 挑戦編

テンプレートJSPやGSPと同じようなもの。Groovyコードが書けます。<% /* some code */ %>${value}でGString書けます。<%=hoge %>も使えます。printとprintlnもOK。

Page 69: G* on GAE/J 挑戦編

GaelykTemplateServletソース

Page 70: G* on GAE/J 挑戦編

GaelykのGroovletsGroovyServletを拡張したGroovyスクリプト

Viewテンプレートへのデリゲートrequest.setAttribute 'list', [1, 2, 3, 4]request.setAttribute 'date', new Date() forward 'display.gtpl'

Page 71: G* on GAE/J 挑戦編

GaelykServletソース

Page 72: G* on GAE/J 挑戦編

Eager変数request : HttpServletRequestresponse : HttpServletResponsecontext : ServletContextapplication : contextと同じsession : HttpSessionを返します。 request.getSession(false) と同じです。params : フォームパラメータのマップheaders : 全てのリクエストヘッダのマップ

Page 73: G* on GAE/J 挑戦編

Lazy変数out : PrintWriterを返す。   response.getWriter()への速記sout : ServletOutputStreamを返す。 response.getOutputStream() への速記html : MarkupBuilderを返す。   new MarkupBuilder(response.getWriter()) への速記

Page 74: G* on GAE/J 挑戦編

注入済みGAEのサービスdatastoreService : DatastoreサービスmemcacheService : MemcacheサービスurlFetchService : URLFetchサービスmailService : メールサービスimagesService : ImagesサービスuserService : ユーザサービスuser : ログイン中のユーザ (ログインしていない場合は null )

Page 75: G* on GAE/J 挑戦編

low-levelデータストアAPIEntityクラスを使ってサクサクデータストアimport com.google.appengine.api.datastore.Entity

def person = new Entity("person")

person['name'] = "やまもとつよし"println person['name']

person.age = 31println person.age

//保存person.save()

//削除person.delete()

//リストdef q = new Query('person')def list = datastoreService.prepare(q).asList(

    Builder.withLimit(20).offset(0) )

Page 76: G* on GAE/J 挑戦編

Demo/デモ

Page 77: G* on GAE/J 挑戦編

注意点・ゲーリックまとめ*.gtplの文字化け回避

file.encodingのみではだめっぽい。groovy.source.encodingも指定してね。

意外と楽しいので、ゲーリック中毒注意! 

<system-properties> <property name="file.encoding" value="UTF-8"/> <property name="groovy.source.encoding" value="UTF-8"/></system-properties>

Page 78: G* on GAE/J 挑戦編

まとめG*なGAE/J開発では、どれを選択するべき?ものすごく単純なWebアプリを作る場合は、Gaelyk

様々なプラグインを活用して高度なWebアプリを作りたい場合は、Grails/AppEngine

Grailsをそのままクラウドへの場合はCloudFoundry/EC2

Page 79: G* on GAE/J 挑戦編

Thank you.

日本 Grails/Groovy ユーザーグループhttp://www.jggug.org/