職場実習16日目

Grailsでアプリの雛型を作る(半自動)

ホームに適当なワークフォルダを作って、その中に移動した後、grailsのコマンドを実行する

~$ mkdir projects
~$ cd projects
projects$ grails create-app

アプリ名の入力を求められるので、適当な名前を入れてEnter

Application name not specified. Please enter:
test[ENTER]

これでアプリが出来上がるので、フォルダの中に移動し、アプリを起動する。

projects$ cd test
test$ grails run-app

ただし、この状態ではまだ何も無いので、ドメインクラスを作成する。

grails create-domain-class

クラス名の入力を求められるので、名前を入れてEnter

Domain class name not specified. Please enter:
person[ENTER]

この後、ドメインクラスのフィールドを作成するため、ドメインクラスファイルを編集
人物(名前、年齢、備考)というクラスを作る。

~/projects/test/grails-app/domain/Person.groovy
class Person {
	String name
	Integer age
	String memo
	
    static constraints = {
        name ()
        age ()
        memo (maxSize:300)
    }
}

また、コントローラーを作成

test$ grails create-controller person

コントローラークラスファイルを編集

~/projects/test/grails-app/controllers/PersonController.groovy
class PersonController {

    def scaffold = true;
}

アプリを起動(コマンドを実行すると下記のようなメッセージが表示され、一番下のURLへアクセスするとページを見ることができる。)

test$ grails run-app
Welcome to Grails 1.1.1 - http://grails.org/
(中略)
Server running. Browse to http://localhost:8080/test

アプリを起動した状態で、ブラウザでページを確認すると、こんな感じのデータグリッドが出てくる。(表中のデータはあくまで例であり、最初は何も入ってない)
Person List

id name age memo
1 M.I 30 研修生

この状態で既にCRUD(作成、表示、更新、削除)全て可能だが、アプリを再起動するとデータは全部消えてしまうので、データソース設定を弄ってみる。

~/projects/test/grails-app/conf/DataSource.groovy
dataSource {
	pooled = true
	driverClassName = "org.hsqldb.jdbcDriver"
	username = "sa"
	password = ""
}
hibernate {
    cache.use_second_level_cache=true
    cache.use_query_cache=true
    cache.provider_class='com.opensymphony.oscache.hibernate.OSCacheProvider'
}
// environment specific settings
environments {
	development {
		dataSource {
			dbCreate = "create-drop" // one of 'create', 'create-drop','update'
			url = "jdbc:hsqldb:mem:devDB"
		}
	}
	test {
		dataSource {
			dbCreate = "update"
			url = "jdbc:hsqldb:mem:testDb"
		}
	}
	production {
		dataSource {
			dbCreate = "update"
			url = "jdbc:hsqldb:file:prodDb;shutdown=true"
		}
	}
}

初期状態では、JBDCドライバを通してhsqldbが使われているが、environmentsのdevelopment(開発環境)とtest(テスト環境)ではメモリ上に保存される設定になっているので、アプリを再起動してもデータを保持するのなら、一番下のproduction(製品環境)のパラメータをコピーすると、データベースのファイルが作られるようになるらしい。

ビューの生成とカスタマイズ

ドメインとコントローラーを生成するだけでは、アプリの外観を変える事ができないので、ビューを決めるgspファイルを次のコマンドで生成する。(「user」はドメインクラス名)

test$ grails generate-views user

そして、次のビューが作られるので、それぞれのファイルを編集する。

~/projects/test/grails-app/views/user/*.gsp
  • list.gsp (リスト表示画面)
  • create.gsp (新規作成画面)
  • show.gsp (表示画面)
  • edit.gsp (編集画面)
日付表示のフォーマットをgspファイルで弄る

Date型のデータを画面表示する際、普通に表示すると"yyyy-MM-dd hh:mm:ss.ss"のような形式になり、日付として表示したくても思うようにできない不便さがある。そこで、どうにかして表示形式を弄れないかと調べた所、次のサイトを見付け、早速実行してみた。
Grails をマスターする: Grails アプリケーションの見栄えを良くする
(「Date TagLib の作成」のリストを参照)
上のサイトに掲載されたソースを少し変えてみた。

grails-app/taglib/DateTagLib.groovy
import java.text.SimpleDateFormat

class DateTagLib {
  def longDate = {attrs, body ->
    //parse the incoming date
    def b = attrs.body ?: body()
    def d = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(b)
        
    //if no format attribute is supplied, use this
    def pattern = attrs["format"] ?: "yyyy年M月d日(E)"
    out << new SimpleDateFormat(pattern).format(d)
  }
}

タグの使用箇所はこうなる。

<g:longDate>${fieldValue(bean:userInstance, field:'since')}</g:longDate>

仕組みは、userドメインインスタンスフィールドsince(Date型)を文字列として出力したデータを、g:longDateタグで囲む事で、DateTagLibクラスで読み込んで、日付形式に戻した後、指定したフォーマットで出力し直すというもの。
TagLibでこんな真似ができるなんて・・・以前からTagLibの存在は知っていたが、もっと早くから学んでおくべきだった。

これでようやく解決したかと思ったその時、社員の金村さんから遠回り過ぎると言われ、他にもっといい方法があると教えてもらい、その方法が掲載されたブログを見せてもらったところ、それは私が今実習を行っている会社の社長である川原さんのブログだった・・・。
mkawa.xmldo: 第13.8回Grailsコードリーディング(その4) Grails本気の入門〜2時間でいけるところまでライブコーディング!?をまとめてみました
このブログ記事に載っているソースを元に、金村さんと色々試行錯誤してみた結果、次の方法で偶然成功した。

<g:formatDate date="${userInstance?.since}" format="yyyy年M月d日(E)" />

日付フォーマットを指定できるg:formatDateタグというのが既にあるらしく、userドメインインスタンスフィールドは、「userInstance?.since」でも指定できるらしい。
まさかヒントが以前から知ってるブログの中に書かれていたとは・・・今ならGrails/Groovyも少し理解してきたところなので、記事にあるソースの内容も理解できるだろうし、関連記事を読んでおいて損は無いだろう。

今日はとても長い一日だった。Grails/Groovy初日からこんなに飛ばして大丈夫だろうか。
もう寝ようと思う。