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文字にして、ユニークキーに設定した。

 

 

対策については下記のエントリが参考になりました。

http://d.hatena.ne.jp/tanamon/20090930/1254332746

heroku で Grails + PostgreSQL を試してみる

GrailsアプリをHerokuで公開する の続きです。
今回はGrails2.1.1 で作成したCRUDアプリを heroku で動かしてみます。
ソースはGitHubにて公開しています。

 

大まかな手順
1.heroku のデータベース作成
2.ローカルで動作確認したアプリに heroku 用の設定を行う
3.デプロイ & 動作確認

 

以下、詳細。

 1.heroku のデータベース作成

  1. herokupostgres のページへ遷移。

    f:id:onBass_naga:20130105103952j:plain

    heroku dashboard > [ Resources] > [ Heroku Postgres Dev ]
  2. heroku のアカウントでログイン
  3. Your Databases ラベルの右横にある[ + ] ボタンを押下
  4. [ Dev Plan ] を押下後、表示された [ Add Database] を押下
  5. 追加されたDB名を押下して接続情報を確認
    (歯車ボタンで接続情報のフォーマットを変えられます)

    f:id:onBass_naga:20130105103955j:plain

 

 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.デプロイ & 動作確認

f:id:onBass_naga:20130105202653j:plain

普通に動きます。

 

◇ おまけ ◇
<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>

WEB+DB PRESS Vol.71

WEB+DB PRESS Vol.71

GrailsアプリをHerokuで公開する

Heroku とは何か?についての解説はGoogle先生に。
今日は アカウント登録から、サンプルアプリのデプロイまでをやってみます。
Grailsのバージョンは2.1.1を使用。(※1. 2012/01/03現在、ver.2.1.3はエラーとなる)

公式サイトの手順はこちら

  1. アカウントを取得する
  2. Heroku Toolbelt をインストールする
  3. アプリに Grails Heroku plugin をインストールし、BuildConfig.groovy を編集する
  4. Herokuに作成したリモートリポジトリにアプリをPush
  5. アプリを起動する

 

以下、詳細。

3.Grails プラグインインストール&設定

インストールはIDEAのGUIを使用してみた。

f:id:onBass_naga:20130102155503j:plain

この後表示される画面で 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

f:id:onBass_naga:20130103085142j:plain

ヒャッハー!!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://




WEB+DB PRESS Vol.71

WEB+DB PRESS Vol.71


Gitポケットリファレンス

Gitポケットリファレンス

Grails2.1 サンプル作成 其の一

今回作成したサンプル

・テキストボックスに入力した名前に挨拶文を付け加えて画面表示する。

・名前の入力必須チェックを行う。

・エラー時・正常時ともにテキストボックスの入力値をそのまま表示する。

 

コード抜粋 ( GitHub )

■ GreetingController.groovy
    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 のファイルに飛ばされる。
 
■ /greeting/index.gsp
<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']を押下する。

f:id:onBass_naga:20121230214903j:plain


プロジェクト内に必要なフォルダ・ファイルが作成される。

 

f:id:onBass_naga:20121230204435j:plain

[Run]ボタン押下後、ブラウザが立ち上がりデフォルトの画面が表示される。

 

Grails徹底入門

Grails徹底入門

  • 作者: 山田正樹,山本剛,上原潤二,永井昌子,杉山清美,杉浦孝博,笠原史郎,香月孝太,福岡竜一,伊堂寺北斗
  • 出版社/メーカー: 翔泳社
  • 発売日: 2008/08/26
  • メディア: 大型本
  • 購入: 3人 クリック: 42回
  • この商品を含むブログ (28件) を見る

プログラミングGROOVY

プログラミングGROOVY

The Definitive Guide to Grails 2 (Definitive Guide Apress)

The Definitive Guide to Grails 2 (Definitive Guide Apress)