javascriptMVC入門 その1
javascriptMVCとはクライアントサイドでのMVC開発を強力にサポートしてくれるフレームワーク+ツールセットです。
javascriptMVCの主な構成要素は以下5つ
・javascriptMVC本体
・StealJS:本家によると「A code manager」とのこと。依存性管理やコードクリーニング、デプロイなど
・jQueryMX:jQueryの拡張
・FuncUnit :Webテストフレームワーク
・DocumentJS :ドキュメンテーションエンジン。javadocやrdocみたいな感じ
なにぶん日本語の解説が少ない+本家のドキュメントが若干散らかっている部分があるんで、
チュートリアル+αとして本家のTODOアプリみたいなのを作りながら解説します。
<作るアプリの概要>
・短い文章をメモとして登録/更新/削除/一覧ができる
・メモはセッションストレージに保存
・jQueryMobileを利用してモバイル用UIとして作成
実はCRUDをするだけならscaffold出来るんですが、、わかりやすさの為にあえて作ります。
また、javascriptMVCはLESSやCoffeeScriptもサポートしているんですが、
今回はシンプルにするために使いません。
<インストール&環境準備>
zipをダウンロードするか、gitで取得してくるか。
今回はお手軽にzipをダウンロードします。
の画面右上の方の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ファイル。主に他のファイルの読み込みを行う
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> <!-- ※1 -->
<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をブラウザで開いて、cssやjsが読み込めているか確認しておきます。
<余談>
なお、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側。
まずは手順の再確認。
- Write Your Web API App
- Declare Gem Dependencies With Bundler
- Declare Process Types With Foreman/Procfile
- Store Your App in Git
- Deploy to Heroku/Cedar
- Create Your iOS Client App
- Declare iOS Dependencies with CocoaPods
- Write A Table View Controller
- Configure AppDelegate
- Build & Run
昨日の時点で5まで終わっているので6から。
単純に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。
実行結果はこんな感じ。
日本語もバッチリ。
以上です。
次回は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
元ネタの環境構築やらトラブルシューティングをのぞいた手順。
- Write Your Web API App
- Declare Gem Dependencies With Bundler
- Declare Process Types With Foreman/Procfile
- Store Your App in Git
- Deploy to Heroku/Cedar
- Create Your iOS Client App
- Declare iOS Dependencies with CocoaPods
- Write A Table View Controller
- Configure AppDelegate
- Build & Run
Heroku側は前回までと同様SAStrutsを使う+今回はDB使わないので、
今回のHeroku側に上げるアプリ作成手順は、
となります。
元ネタではSinatraを使ってJSONを返していますので、
4.「JSONを返すメソッドの実装」にてSAStrutsでJSONを生成して返す処理だけ実装します。
それ以外は前回までと同様です。
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が出ました。
Heroku/Cedar上でSAStruts+S2JDBCを動かす その1
元ネタはこちら。
Getting Started with Spring MVC Hibernate on Heroku/Cedar
Heroku上でSpring MVC Hibernateが動くなら、SAStruts+S2JDBCも動くはず。
ということで実験。
まずは元ネタから手順を確認。
- Create a Java App That Uses Spring MVC and Hibernate
- Modify Database Configuration
- Add Jetty Runner
- Declare Process Types in a Procfile
- Run Your App Locally
- Deploy to Heroku/Cedar
- Doltengでプロジェクト作成
- データベース設定変更
- Jetty Runner追加
- Procfileの作成
- ローカルでの動作確認
- Heroku/Cedarへのアップロード
主な違いは
といったところ。詳細は各項目ごとの説明を参照。
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>
続きは次回へ。