javascriptMVC入門 その1

 

javascriptMVCとはクライアントサイドでのMVC開発を強力にサポートしてくれるフレームワーク+ツールセットです。

http://javascriptmvc.com/

 

javascriptMVCの主な構成要素は以下5つ

 ・javascriptMVC本体

 ・StealJS:本家によると「A code manager」とのこと。依存性管理やコードクリーニング、デプロイなど

 ・jQueryMXjQueryの拡張

 ・FuncUnit Webテストフレームワーク

 ・DocumentJS ドキュメンテーションエンジン。javadocrdocみたいな感じ

 

なにぶん日本語の解説が少ない+本家のドキュメントが若干散らかっている部分があるんで、

チュートリアルαとして本家のTODOアプリみたいなのを作りながら解説します。

 

 

<作るアプリの概要>

 ・短い文章をメモとして登録/更新/削除/一覧ができる

 ・メモはセッションストレージに保存

 ・jQueryMobileを利用してモバイル用UIとして作成

 

実はCRUDをするだけならscaffold出来るんですが、、わかりやすさの為にあえて作ります。

また、javascriptMVCLESSCoffeeScriptもサポートしているんですが、

今回はシンプルにするために使いません。

 

<インストール&環境準備>

zipをダウンロードするか、gitで取得してくるか。

今回はお手軽にzipをダウンロードします。

http://javascriptmvc.com/

の画面右上の方のDownloadから取得します。

 

zipをダウンロードしたら展開し、そのディレクトリへ移動。

/jmvcに配置

ついでにApacheのドキュメントルートにシンボリックリンクを作成しておきます。

これで「http://localhost/jmvc/」でjavascriptMVCを配置したディレクトリが参照できる。

$ cd /var/www/

$ sudo ln -s /jmvc jmvc

 

 

<アプリ作成>

今回作るアプリの名前は「SimpleMemo」とします。

これにより、

 ・アプリのルートディレクトリ名は「simple_memo

 ・モデルやコントローラなどの属するルート名前空間は「SimpleMemo

となります。

この後使う「app」ジェネレータが「SimpleMemo」みたいな

キャメルケースを渡すことが出来ないため、注意が必要です、、

 

本家ドキュメントにもちょっとだけ注意事項が触れられていますが、

この現象、バグっぽいんですよね。

引用:本家ドキュメント

http://javascriptmvc.com/docs.html#!steal.generate

 

 

app

Creates a JavaScriptMVC application structure.

js jquery/generate/app path/to/app [OPTIONS]

  • path/to/app - The lowercase path you want your application in. Keep application names short because they are used as namespaces. The last part of the path will be taken to be your application's name.

 

この説明でキャメルケース渡す方が悪いっちゃ悪いと思いますが、、

うまいこと対応してほしいもんです。

 

という訳で、名前に気をつけつつアプリ作成に入ります。

 

1:アプリケーションのひな形作成

まずはappジェネレータを使ってひな形を作ります。

先ほども触れた通り、指定するアプリ名は「simple_memo」とし、以下のコマンドを実行します。

 

$./js jquery/generate/app simple_memo

 

出来上がるファイルは、、

simple_memo/             // アプリのディレクト

  simple_memo.css        // 当アプリのcssファイル

  simple_memo.html       // 当アプリのメインhtmlファイル

  simple_memo.js     // 当アプリのメインjsファイル。主に他のファイルの読み込みを行う

  docs/                  // APIドキュメントの生成先ディレクト

  fixtures/              // AJAXリクエストのシミュレーション用js

  funcunit.html          // FuncUnitを使ったテストの実行用ページ

  models/                // モデル&データレイヤ

  qunit.html             // qunitによるテスト実行用ページ

  scripts/               // コマンドラインスクリプト(中身の説明は省略)

  test/                  // テスト用js

 

 

 

確認のため「http://localhost/jvmc/simple_memo/simple_memo.html」をブラウザで確認。

念のためリンク切れなどないかFireBugなどで確認しておく。

 

まずはsimple_memo.htmlを開いて、不要なものを消しちゃいます。

今のところ重要なのは以下のscriptタグ。

<script type='text/javascript'

        src='../steal/steal.js?simple_memo'>

</script>

 

以外は消しちゃいましょう。こんな感じになってればOK

ちなみにlang="en"になってるんで"ja"に変更しましょう。ついでにcharsetも追加します。

<!DOCTYPE HTML>

<html lang="ja">

  <head>

    <meta charset="UTF-8" />

    <title>simple_memo</title>

  </head>

 

  <body>

    <div data-role="page"></div> <!--  -->

    <script type='text/javascriptpt'

            src='../steal/steal.js?simple_memo'>

    </script>

  </body>

 

 </html>

 

気になる'steal.js?simple_memo'ですが、?以降をアプリケーション名として解釈し、

メインのjsファイルを読み込んでくれます。

読み込み対象はアプリケーション名.jsファイルです。

今回読み込まれるのは「simple_memo.js」となります。

 

ではsimple_memo.jsをのぞいてみましょう。

steal(

    './simple_memo.css',           // application CSS file

    './models/models.js',       // steals all your models

    './fixtures/fixtures.js',   // sets up fixtures for your models

    function(){                 // configure your application

 

})

 

steal関数にファイルパスと関数を渡しています。

このsteal関数は単純に、渡されたパスのファイル読み込み+渡された関数処理を行うだけです。

読み込み順序なんかがある場合は以下のように書きます。

steal(

// ファイルパスや関数・・・(1)

).then(

    // (1)が完了した後に実行される。

    // (1)と同じくファイルパスや関数を渡す ・・・(2)

).then(

    // (2)が完了した後に実行される。

    // (1)と同じくファイルパスや関数を渡す 

)

 

 

現状のsimple_memo.jsではCSSファイルやその他のJSファイルなんかを読み込んでいますね。

今回jQueryMobileを使うため、必要ファイルを追記します。

jQueryMobileのグローバル設定の為に、

1:jQuery本体の読み込み

2:jQueryMobileのグローバル設定用イベントを登録

3:jQueryMobileの読み込み

となるようにします。

 

steal(

    './simple_memo.css',           // application CSS file

    './models/models.js',       // steals all your models

    './fixtures/fixtures.js',   // sets up fixtures for your models

    'http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css',   // jQueyMobile用CSS

    'http://code.jquery.com/jquery-1.7.2.min.js',                        // jQuery本体

    function(){                 // configure your application

    }

).then(                                                                  // グローバル設定用イベント

    function(){

        $(document).bind("mobileinit", function(){

            $.mobile.loadingMessage = '読み込み中';

            $.mobile.pageLoadErrorMessage = '読み込みに失敗しました';

            $.mobile.dialog.prototype.options.closeBtnText = '閉じる';

            $.mobile.selectmenu.prototype.options.closeText= '閉じる';

            $.mobile.listview.prototype.options.filterPlaceholder = '検索文字列';

            $.mobile.page.prototype.options.backBtnText = '戻る';        

        });

    }

).then(

    'http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css',   // jQueryMobile本体

)

 

 

確認のためsimple_memo.htmlをブラウザで開いて、cssjsが読み込めているか確認しておきます。

 

<余談>

なお、simple_memo.html中の※1の部分ですが、これがないとdev.jsの読み込みエラーが発生します。

 

このエラーについてgoogle先生に聞いてみると、、、

http://forum.javascriptmvc.com/topic/integration-jquery-mobile-js-mvc

http://forum.javascriptmvc.com/topic/jquery-mobile-or-zeptojs

こんなのが。おんなじ症状っぽいですね。

何らかの条件下でjqueryMobileの初期化処理が行われるとエラーになるっぽい。

とりあえずdata-role="page"のエレメントを追加しておけば大丈夫だったんで、後で調査してみます。

 

長くなりそうなんで、続きは次回。

 

Heroku/Cedar上でSAStruts + iOSアプリしてみる その2

昨日の続き。

今日は問題ありありだったiOS側。

まずは手順の再確認。

  1. Write Your Web API App
  2. Declare Gem Dependencies With Bundler
  3. Declare Process Types With Foreman/Procfile
  4. Store Your App in Git
  5. Deploy to Heroku/Cedar
  6. Create Your iOS Client App
  7. Declare iOS Dependencies with CocoaPods
  8. Write A Table View Controller
  9. Configure AppDelegate
  10. Build & Run

昨日の時点で5まで終わっているので6から。

 

6. Create Your iOS Client App

単純にXCodeで新規プロジェクトを作成するだけの部分。

元ネタに従って進めましょう。

 

7.Declare iOS Dependencies with CocoaPods

MacRuby入れて、macgemでcocoapods入れろとのこと。

でもLionの場合エラーが出て進めない。

 

調べてみるとデフォルトで入っているruby使えばいいとのこと。

gem install cocoapods

pod setup

すればOK。

Podfileの作成とpod installは元ネタのままでOK。

 

8.Write A Table View Controller

XCodeでファイルを追加すればいいのね♪

じゃあご指定の“UIViewController subclass”を選んで、、、、ないじゃない。

実はXCode4.3で変わってる部分。

慌てずに「Objective-C class」テンプレートを選択しましょう。

ここからUITableViewのサブクラスと出来るように選択肢が出てきます。

 

 

9.Configure AppDelegate
10.Build & Run

元ネタのままでOK。

実行結果はこんな感じ。

 

f:id:febc_yamamoto:20120306222353j:plain

日本語もバッチリ。

以上です。

 

次回はHeroku/Cedar上のSAStrutsを利用した

簡易ステージング環境構築を書きたいな〜。

 

Heroku/Cedar上でSAStruts + iOSアプリしてみる その1

前回までに引き続き、Heroku/Cedar上でSAStrutsを動かしてみる。

今回はmacbook proの環境をLion+XCode4.3にしたので、せっかくなのでiOSアプリと連携してみる。

 

元ネタはこちら

Getting Started with iOS Development using Sinatra on Heroku / Cedar

元ネタの環境構築やらトラブルシューティングをのぞいた手順。

  1. Write Your Web API App
  2. Declare Gem Dependencies With Bundler
  3. Declare Process Types With Foreman/Procfile
  4. Store Your App in Git
  5. Deploy to Heroku/Cedar
  6. Create Your iOS Client App
  7. Declare iOS Dependencies with CocoaPods
  8. Write A Table View Controller
  9. Configure AppDelegate
  10. Build & Run

 

Heroku側は前回までと同様SAStrutsを使う+今回はDB使わないので、

今回のHeroku側に上げるアプリ作成手順は、

  1. Doltengでプロジェクト作成
  2. Jetty Runner追加
  3. Procfileの作成
  4. JSONを返すメソッドの実装
  5. ローカルでの動作確認
  6. Heroku/Cedarへのアップロード

となります。

元ネタではSinatraを使ってJSONを返していますので、

4.「JSONを返すメソッドの実装」にてSAStrutsJSONを生成して返す処理だけ実装します。

それ以外は前回までと同様です。

 

4.「JSONを返すメソッドの実装」

単純にJSON文字列を返すメソッドを実装します。

今回実装する機能はこれだけなので、index/IndexActionに実装してしまいます。

package com.febc.action;

import org.seasar.struts.annotation.Execute;
import org.seasar.struts.util.ResponseUtil;

public class IndexAction {
    
    @Execute(validator = false)
    public String index() {
    	ResponseUtil.write("{\"sushi\":[\"鮪\",\"鰤\",\"雲丹\",\"鯖\",\"海老\",\"鮭\",\"鯛\"]}", "text/json");
    	return null;
    }
}

元ネタではローマ字表記の寿司ネタですが、

本場日本ですから当然漢字表記します。

※おとなしくオブジェクトをJSON変換すればよかったんですが、

楽しようと思って手書きでJSONを書いた結果、フォーマットが正しくなく、

iOS側で読み込めないという事態が発生しました。

ダブルクォートをシングルクォートにしてたのがよくなかったらしい。

これで2時間くらい飛びました。

 

後はローカルでforeman startして動作確認できたらHeroku側にpush。

この辺は前回までと全く一緒です。

そしてここからが問題のiOS側。

基本的に元ネタをたどればいいはずなのにちょいちょいコケるポイントがありました。

 

 

続きはまた次回。

 

Heroku/Cedar上でSAStruts+S2JDBCを動かす その2

前回の続き。

4.Procfileの作成

これも元ネタのままでOK。以下の内容で「Procfile」という名前でファイル作成。プロジェクトのルートディレクトリにおいておく。

web: java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --port $PORT target/*.war

 

5.ローカルでの動作確認

これも元ネタのままでOK。 

 

6.Heroku/Cedarへのアップロード

元ネタに加えてDBのインポートを行う。

インポートはこちらを参考に。

 

後はお決まりのgit addからpushまで。

git init
git add .
git commit -m 'init'
# --stack cedarをつけること。
heroku create  --stack cedar
git push heroku master
# プロセスが起動しているか確認
heroku ps
# ログの確認
heroku logs    
 
以上です。
 

 ※実際にデプロイすると、いくつかの画面でExceptionが出ました。

その場合、web.xmlからrequestDumpFilterをコメントアウトしておくとよさそうです。後で調べる。

Heroku/Cedar上でSAStruts+S2JDBCを動かす その1

元ネタはこちら。

Getting Started with Spring MVC Hibernate on Heroku/Cedar

Heroku上でSpring MVC Hibernateが動くなら、SAStruts+S2JDBCも動くはず。

ということで実験。

事前の環境構築についてはこちらこちらを参照。

 

まずは元ネタから手順を確認。

  1. Create a Java App That Uses Spring MVC and Hibernate
  2. Modify Database Configuration
  3. Add Jetty Runner
  4. Declare Process Types in a Procfile
  5. Run Your App Locally
  6. Deploy to Heroku/Cedar

 SAStruts+S2JDBCの場合はこんな感じ。

  1. Doltengでプロジェクト作成
  2. データベース設定変更
  3. Jetty Runner追加
  4. Procfileの作成
  5. ローカルでの動作確認
  6. Heroku/Cedarへのアップロード

主な違いは

  • Spring RooではなくDoltengを使う
  • データベース設定に環境変数読み取りの仕組みを追加
  • Heroku/Cedarへのアップロードの際にローカルのDBをインポートする

といったところ。詳細は各項目ごとの説明を参照。

 

1.Doltengでプロジェクト作成

このあたりを参考にプロジェクト作成。もちろんSAStruts+S2JDBCにしておく。

今回はDB上にテーブルを作成し、Doltengのscaffoldを利用する。

まずはPostgreSQL上でCREATE TABLEしておく。

今回作ったのは以下のシンプルなテーブル。

CREATE TABLE users
(
  id serial NOT NULL,
  first_name character varying(100),
  last_name character varying(100),
  CONSTRAINT pk_users PRIMARY KEY (id )
)

 このテーブルを元にscaffoldします。

scaffoldについてはこのあたりを参照。

※もちろんjdbc.diconとs2jdbc.diconにURLやユーザー名、パスワードなどの設定が必要。あらかじめ設定しておきましょう。

 

2.データベース設定変更

Heroku上ではDatabase接続情報は環境変数「DATABASE_URL」に格納されている。

フォーマットは以下のとおり。

postgres://user:password@hostname/path

元ネタでは

<bean class="java.net.URI" id="dbUrl">
    <constructor-arg value="${DATABASE_URL}"/>
</bean>

 として環境変数を利用してURIインスタンス(dbUrl)を生成し、

データベース接続設定ファイルにて

<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
    <property name="driverClassName" value="${database.driverClassName}"/>
    <property name="url" value="#{ 'jdbc:postgresql://' + @dbUrl.getHost() + @dbUrl.getPath() }"/>
    <property name="username" value="#{ @dbUrl.getUserInfo().split(':')[0] }"/>
    <property name="password" value="#{ @dbUrl.getUserInfo().split(':')[1] }"/>
    ...

という形で利用している。

これをS2JDBC用に置き換えるため、以下のヘルパークラスを作成する。

package com.febc.heroku.util;

import java.net.URI;
import java.net.URISyntaxException;

public class HerokuEnvironmentHelper {

    private static HerokuEnvironmentHelper instance;

	public static HerokuEnvironmentHelper getInstance()
			throws URISyntaxException {
		if (instance == null) {
			instance = new HerokuEnvironmentHelper();
		}
		return instance;
	}

	private URI DB_URI;
	private static final String DB_URI_ENV_NAME = "DATABASE_URL";

	private HerokuEnvironmentHelper() throws URISyntaxException {
		DB_URI = new URI(System.getenv(DB_URI_ENV_NAME));
	}

	public String getUrl() {
		return "jdbc:postgresql://" + DB_URI.getHost() + DB_URI.getPath();
	}

	public String getUsername() {
		return DB_URI.getUserInfo().split(":")[0];
	}

	public String getPassword() {
		return DB_URI.getUserInfo().split(":")[1];
	}

}
    
    

これでdiconファイル中に環境変数からのDB接続情報を設定できる。

jdbc.diconはこんな感じ。

<component name="xaDataSource"
    	class="org.seasar.extension.dbcp.impl.XADataSourceImpl">
	<property name="driverClassName">
		"org.postgresql.Driver"
        </property>
        <property name="URL">
	        @com.febc.heroku.util.HerokuEnvironmentHelper@getInstance().url
        </property>
        <property name="user">
		@com.febc.heroku.util.HerokuEnvironmentHelper@getInstance().username
	</property>
        <property name="password">
		@com.febc.heroku.util.HerokuEnvironmentHelper@getInstance().password
	</property>
</component>

 ローカルで動かす場合にも環境変数「DATABASE_URL」が必要となるので設定しておく。

 

3.Jetty Runner追加

 これは元ネタのままでOK。Doltengでプロジェクトを作成しているためpom.xmlも生成されているはず。plugins配下に以下を追記。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.3</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals><goal>copy</goal></goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>org.mortbay.jetty</groupId>
                        <artifactId>jetty-runner</artifactId>
                        <version>7.4.5.v20110725</version>
                        <destFileName>jetty-runner.jar</destFileName>
                    </artifactItem>
                </artifactItems>
            </configuration>
        </execution>
    </executions>
</plugin>

 

ついでに、依存jarについてもここで記載しておく。

dependencies配下に以下を追加。

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
</dependency>
<dependency>
    <groupId>postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>9.1-901.jdbc3</version>
</dependency>

続きは次回へ。