Mirage を Grails で使う
Mirage(※1)というORMをGrailsで使えるようにするための方法を記します。
(GORMと同一のConnectionを使用する方法はコチラ)
作成したサンプルはGithubに公開しています。
コードレビューしていただけると、泣いて喜びます。
■ Mirageのダウンロード
BuildConfig.groovyに下記の設定を行う。
・repositories に 「mavenRepo "http://amateras.sourceforge.jp/mvn/"」を追記
・dependencies に 「compile 'jp.sf.amateras.mirage:mirage:1.1.6'」を追記
■ DIのための設定
resources.groovyを下記のように編集。
// -------------------------------------------------------------------
beans = {
dataSource(org.apache.commons.dbcp.BasicDataSource) { bean ->
bean.destroyMethod = 'close'
driverClassName = '${dataSource.driverClassName}'
url = '${dataSource.url}'
username = '${dataSource.username}'
password = '${dataSource.password}'
}
transactionManager(org.springframework.jdbc.datasource.DataSourceTransactionManager) {
dataSource = dataSource
}
connectionProvider(jp.sf.amateras.mirage.integration.spring.SpringConnectionProvider) {
transactionManager = transactionManager
}
dialect(jp.sf.amateras.mirage.dialect.MySQLDialect)
sqlManager(jp.sf.amateras.mirage.SqlManagerImpl) {
connectionProvider = connectionProvider
dialect = dialect
}
}
// -------------------------------------------------------------------
上記設定により、Grails でDI可能になります。また、トランザクション管理はGrailsが行ってくれるようになります。(デフォルトはServiceがトランザクション境界となります)
■ Serviceでの使用方法
以下のように使用できます。
// -------------------------------------------------------------------
class CustomerService {
SqlManager sqlManager
def list() {
return sqlManager.getResultList(
Customer.class, "com/area_b/samples/select.sql");
}
}
// -------------------------------------------------------------------
SQLファイルは ProjectRoot/src/java 下にパッケージを切って配備しています。
以上でMirageが使用可能となります。
Mirageかわいいよ Mirage
※1.Mirage とは
JavaのO/Rマッパ。2WaySQLの記述方法を用いた外部SQLを読み込み、実行可能。もちろん、Entityにアノテーションベースのメタ情報を設定することによりSQLレスでCRUDも可能。
Spring Security Core plugin をMySQLで試した時のエラー
Grails Spring Security Core Plugin をMySQL5.5.27 で試したところ、下記のエラーが発生。
| Error 2013-04-29 11:11:59,426 [localhost-startStop-1] ERROR hbm2ddl.SchemaUpdate - Unsuccessful: create table authority (id bigint not null auto_increment, version bigint not null, authority varchar(255) not null unique, primary key (id))
| Error 2013-04-29 11:11:59,427 [localhost-startStop-1] ERROR hbm2ddl.SchemaUpdate - Specified key was too long; max key length is 767 bytes
原因:ユニークキーに指定したカラムの桁数オーバー
データ型がvarchar(255)、照合順序がutf8mb4_general_ci のカラムをユニークキーにしようとしたため、255×4=1020byteとなり桁あふれ。
対策:初期テーブル生成時はunique制約をドメインから外してテーブルを作成。後からDBとソースを修正。フィールドの文字コードを2byte文字にして、ユニークキーに設定した。
対策については下記のエントリが参考になりました。
heroku で Grails + PostgreSQL を試してみる
GrailsアプリをHerokuで公開する の続きです。
今回はGrails2.1.1 で作成したCRUDアプリを heroku で動かしてみます。
ソースはGitHubにて公開しています。
大まかな手順
1.heroku のデータベース作成
2.ローカルで動作確認したアプリに heroku 用の設定を行う
3.デプロイ & 動作確認
以下、詳細。
1.heroku のデータベース作成
- herokupostgres のページへ遷移。
heroku dashboard > [ Resources] > [ Heroku Postgres Dev ]
- heroku のアカウントでログイン
- Your Databases ラベルの右横にある[ + ] ボタンを押下
- [ Dev Plan ] を押下後、表示された [ Add Database] を押下
- 追加されたDB名を押下して接続情報を確認
(歯車ボタンで接続情報のフォーマットを変えられます)
2.ローカルで動作確認したアプリに heroku 用の設定を行う
DataSource.groovy の本番用接続情報に 1-5 で確認した情報を設定する。
「sslfactory = org.postgresql.ssl.NonValidatingFactory」を忘れないよう注意!
上記設定を行っていない場合、下記エラーが発生。
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
3.デプロイ & 動作確認
普通に動きます。
◇ おまけ ◇
<g:form>の使い方を誤っていたために、下記エラーが発生。
ローカル環境では動いていたが、heroku上でエラーになった。
URI /todo/index
Class java.lang.IllegalArgumentException
Message Method name must not be null
Error 500: Internal Server Error
Line | Method ->> 41 | retrieveAction in grails.plugin.cache.web.ProxyAwareMixedGrailsControllerHelper - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 547 | handle in org.eclipse.jetty.servlet.ServletHolder | 1359 | doFilter . . . . in org.eclipse.jetty.servlet.ServletHandler$CachedChain | 186 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter | 63 | doFilter . . . . in grails.plugin.cache.web.filter.AbstractFilter | 1330 | doFilter in org.eclipse.jetty.servlet.ServletHandler$CachedChain | 478 | doHandle . . . . in org.eclipse.jetty.servlet.ServletHandler | 119 | handle in org.eclipse.jetty.server.handler.ScopedHandler | 520 | handle . . . . . in org.eclipse.jetty.security.SecurityHandler | 227 | doHandle in org.eclipse.jetty.server.session.SessionHandler | 941 | doHandle . . . . in org.eclipse.jetty.server.handler.ContextHandler | 409 | doScope in org.eclipse.jetty.servlet.ServletHandler | 186 | doScope . . . . in org.eclipse.jetty.server.session.SessionHandler | 875 | doScope in org.eclipse.jetty.server.handler.ContextHandler | 117 | handle . . . . . in org.eclipse.jetty.server.handler.ScopedHandler | 288 | forward in org.eclipse.jetty.server.Dispatcher | 115 | forward . . . . in '' | 1330 | doFilter in org.eclipse.jetty.servlet.ServletHandler$CachedChain | 51 | doFilterInternal in grails.plugin.databasesession.SessionProxyFilter | 1330 | doFilter in org.eclipse.jetty.servlet.ServletHandler$CachedChain | 478 | doHandle . . . . in org.eclipse.jetty.servlet.ServletHandler | 119 | handle in org.eclipse.jetty.server.handler.ScopedHandler | 520 | handle . . . . . in org.eclipse.jetty.security.SecurityHandler | 227 | doHandle in org.eclipse.jetty.server.session.SessionHandler | 941 | doHandle . . . . in org.eclipse.jetty.server.handler.ContextHandler | 409 | doScope in org.eclipse.jetty.servlet.ServletHandler | 186 | doScope . . . . in org.eclipse.jetty.server.session.SessionHandler | 875 | doScope in org.eclipse.jetty.server.handler.ContextHandler | 117 | handle . . . . . in org.eclipse.jetty.server.handler.ScopedHandler | 250 | handle in org.eclipse.jetty.server.handler.ContextHandlerCollection | 149 | handle . . . . . in org.eclipse.jetty.server.handler.HandlerCollection | 110 | handle in org.eclipse.jetty.server.handler.HandlerWrapper | 345 | handle . . . . . in org.eclipse.jetty.server.Server | 441 | handleRequest in org.eclipse.jetty.server.HttpConnection | 936 | content . . . . in org.eclipse.jetty.server.HttpConnection$RequestHandler | 801 | parseNext in org.eclipse.jetty.http.HttpParser | 224 | parseAvailable . in '' | 51 | handle in org.eclipse.jetty.server.AsyncHttpConnection | 586 | handle . . . . . in org.eclipse.jetty.io.nio.SelectChannelEndPoint | 44 | run in org.eclipse.jetty.io.nio.SelectChannelEndPoint$1 | 598 | runJob . . . . . in org.eclipse.jetty.util.thread.QueuedThreadPool | 533 | run in org.eclipse.jetty.util.thread.QueuedThreadPool$3 ^ 636 | run . . . . . . in java.lang.Thread
原因:formタグに controller 属性を記述していなかったためエラー
【駄目なソース】
<g:form method="post"> <g:actionSubmit value="add" action="/create"/> </g:form>
【正しいソース】
<g:form controller="todo" method="post"> <g:actionSubmit value="add" action="create"/> </g:form>
- 作者: 竹迫良範,Jxck,じょさん,後藤秀宣,藤原俊一郎,奥野幹也,堤智代,森田創,中島聡,A-Listers,はまちや2,相澤歩,柴田博志,池田尚史,梅澤雄一郎,九岡佑介,近藤宇智朗,佐藤鉄平,mala,WEB+DB PRESS編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2012/10/24
- メディア: 大型本
- 購入: 12人 クリック: 157回
- この商品を含むブログ (10件) を見る
GrailsアプリをHerokuで公開する
Heroku とは何か?についての解説はGoogle先生に。
今日は アカウント登録から、サンプルアプリのデプロイまでをやってみます。
Grailsのバージョンは2.1.1を使用。(※1. 2012/01/03現在、ver.2.1.3はエラーとなる)
公式サイトの手順はこちら
- アカウントを取得する
- Heroku Toolbelt をインストールする
- アプリに Grails Heroku plugin をインストールし、BuildConfig.groovy を編集する
- Herokuに作成したリモートリポジトリにアプリをPush
- アプリを起動する
以下、詳細。
3.Grails プラグインインストール&設定
インストールはIDEAのGUIを使用してみた。
この後表示される画面で Heroku Integration の [ Enable ] にチェックをいれ、[ Apply changes ] を押下する。
しばらくするとインストールが完了する。
BuidConfig.groovy の plugins に下記を追記する
(※2. 下3つを記述していなかった場合、エラーが発生した)
compile ':heroku:1.0.1'
compile ':cloud-support:1.0.8'
compile ":webxml:1.4.1"
compile ":database-session:1.1.2"
また、同ファイルの dependencies に下記を追記する
(※3. DBに接続しない場合も記述が必要)
runtime 'postgresql:postgresql:8.4-702.jdbc3'
詳しくは公式サイトを参照
修正後、ローカルのGitに commit する。
4.Deploy
コマンドプロンプトを立ち上げ、下記コマンドを実行
(Heroku Toolbelt をインストールすると heroku コマンドが使用できる)
$ heroku login
メールアドレスとパスワードを入力後、public key を作成するか聞かれるので、yを入力し作成する。
$ heroku keys:add
作成したキーを適用します。
(Herokuの公開鍵についてはこちらのサイトが詳しいです。)
$ git push heroku master
作成したHerokuのリポジトリへPush
(※4. .gitignoreを作成する際、
公式手順の tailored for Grails リンク先のソースをまるまるコピペするとエラーになるので注意!)
5. アプリ起動
$ heroku open
ヒャッハー!!Grailsアプリが起動したぜぃっ♪
(※5. 設定をしくじっているときは503エラーが発生する)
$ heroku logs
エラー時は上記コマンドでログを確認する
※1. 2012/1/3現在、Ver.2.1.3には未対応のため下記エラーが発生した。
-----> Grails 2.1.3 app detected
WARNING: The Grails buildpack is currently in Beta.
-----> Installing Grails 2.1.3.....
-----> Error installing Grails framework or unsupported Grails framework version
specified. Please review Dev Center for a list of supported versions.
! Heroku push rejected, failed to compile Grails app
※2. herokuプラグイン以外を記述していない場合、下記エラーが発生
2013-01-02T23:28:25+00:00 app[web.1]: Caused by:
2013-01-02T23:28:25+00:00 app[web.1]: java.lang.IllegalStateException: The datab
ase-session plugin requires that the webxml plugin be installed
※3. DB接続を行わないアプリでも、jdbcがないと怒られる。
2013-01-02T23:40:08+00:00 app[web.1]: org.springframework.jdbc.support.MetaDataA
ccessException: Error while extracting DatabaseMetaData; nested exception is org
.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class 'org.post
gresql.Driver'
※4. applicationContext.xml がアップロードされていないと怒られる。.gitignore の
/web-app/WEB-INF をコメントアウトすればOK!
※5. 設定をしくじっている場合、503エラーとなる。
HTTP ERROR: 503
Problem accessing /. Reason:
Service Unavailable
Powered by Jetty://
- 作者: 竹迫良範,Jxck,じょさん,後藤秀宣,藤原俊一郎,奥野幹也,堤智代,森田創,中島聡,A-Listers,はまちや2,相澤歩,柴田博志,池田尚史,梅澤雄一郎,九岡佑介,近藤宇智朗,佐藤鉄平,mala,WEB+DB PRESS編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2012/10/24
- メディア: 大型本
- 購入: 12人 クリック: 157回
- この商品を含むブログ (10件) を見る
- 作者: 岡本隆史,武田健太郎,相良幸範
- 出版社/メーカー: 技術評論社
- 発売日: 2012/07/10
- メディア: 単行本(ソフトカバー)
- 購入: 6人 クリック: 92回
- この商品を含むブログ (17件) を見る
Grails2.1 サンプル作成 其の一
今回作成したサンプル
・テキストボックスに入力した名前に挨拶文を付け加えて画面表示する。
・名前の入力必須チェックを行う。
・エラー時・正常時ともにテキストボックスの入力値をそのまま表示する。
コード抜粋 ( GitHub )
def greet(GreetingCommand cmd) { if (cmd.hasErrors()) { render(view: "/greeting/index", model: ['cmd':cmd]) return } def name = cmd['name'] def message = "Hello ${name} !!" // return new ModelAndView("/greeting/index", [ 'message' : message, 'cmd' : cmd ]) render(view: "/greeting/index", model: [ 'message' : message, 'cmd' : cmd ]) } @grails.validation.Validateable static class GreetingCommand { String name static constraints = { name(blank: false, maxSize: 12) } }
- フォームの値をDomainではなく、Commad クラスを用意して受け取る。Domainパッケージ下のクラスは永続化対象となってしまうため、今回はControllerのインナークラスとして定義している。
- 遷移先の指定方法はreturn・renderのどちらでもOK。
遷移先 を記載しない場合、メソッド名.gsp or .jsp のファイルに飛ばされる。
<g:hasErrors bean="${cmd}"> <ul> <g:eachError bean="${cmd}"> <li><g:message error="${it}" /></li> </g:eachError> </ul> </g:hasErrors> <g:form action="greet"method="get"> <g:textField name="name"size="12"value="${fieldValue(bean: cmd, field: 'name')}"/> <g:submitButton name="submit"value="say" /> <p>${message}</p> </g:form>
- <g:message>タグを使用しないと、プロパティファイルのメッセージは表示されない。
- Beanの値を参照する場合、#fieldValue を使用しなければならない。
※ ${cmd.name}ではNPEが発生。 Cannot get property 'name' on null object というメッセージが表示される。
IDEA から Githubに公開する
1. プロジェクトをローカルリポジトリに登録
[ VSC ] > [ Import into Version Control ] > [ Create Git Repository ]
2. GitHub にリモートリポジトリを作成し、公開
[ VSC ] > [ Import into Version Control ] > [ Share project on GitHub ]
New repositoryname と Description を記入し、Shareを押下。
※ すでに同名のリポジトリがgithub上に存在する場合、作成できない。
3. ソース変更後、コミットすると「リモートにPushするか?」という画面が表示される。PushすればGitHubに反映できる。
IDEA12 で Grails2.1 のプロジェクトを作成する
1. [File] > [New Project] を押下。
2. [Grails Module] を選択し、Project name を入力後 [Next]を押下する。
3. Use library にて使用したいバージョンのgrailsを選択し、[Finish]を押下する。
プルダウンに表示されていない場合、[Create...]にて使用するgrailsのホームディレクトリを選択し、[OK]を押下するとプルダウンに表示される。
4. Grails標準ディレクトリ構成に従ってフォルダ等を作成するか、のダイアログが表示される。作成する場合、[Run 'create-app']を押下する。
プロジェクト内に必要なフォルダ・ファイルが作成される。
[Run]ボタン押下後、ブラウザが立ち上がりデフォルトの画面が表示される。
- 作者: 山田正樹,山本剛,上原潤二,永井昌子,杉山清美,杉浦孝博,笠原史郎,香月孝太,福岡竜一,伊堂寺北斗
- 出版社/メーカー: 翔泳社
- 発売日: 2008/08/26
- メディア: 大型本
- 購入: 3人 クリック: 42回
- この商品を含むブログ (28件) を見る
- 作者: 関谷和愛,上原潤二,須江信洋,中野靖治
- 出版社/メーカー: 技術評論社
- 発売日: 2011/07/06
- メディア: 単行本(ソフトカバー)
- 購入: 6人 クリック: 381回
- この商品を含むブログ (146件) を見る
The Definitive Guide to Grails 2 (Definitive Guide Apress)
- 作者: Jeff Scott Brown,Graeme Rocher
- 出版社/メーカー: Apress
- 発売日: 2012/12/26
- メディア: ペーパーバック
- クリック: 2回
- この商品を含むブログを見る