Upload
shunsuke-watanabe
View
2.829
Download
2
Embed Size (px)
DESCRIPTION
Citation preview
大阪Node学園八時限目
node.jsみちしるべ
expressで作るWebアプリ
2013/10/26
スライド内のリンクはクリックできます
リンクは ですこの色
express
expressとは
Webアプリケーションフレームワーク
現状node.jsでのデファクトスタンダード
sinatraライクなシンプルな構成
デフォルトテンプレートエンジンはjade
http://expressjs.com/
最新バージョンは 3.4.2大阪Node学園で取り上げるのも4回目になりました
express 2.x 系とはいろいろ変わってます
過去の情報を参照する際はバージョンに注意してく さい
私のブログとかヹヹヹ
expressのインスール
$ npm install -g express1
2
プロジェクトの初期化
expressコボンドでプロジェクトを初期化します
expressの依存モジュールをインストール
これでexpressが立ち上がるようになっているので動かしてみる。
ブラウザで http://localhost:3000 にアクセスする。
"Error: listen EADDRINUSE" エラーで動かない場合は p.ecstacy app.jsをテキストエディタで開き 15行目のホート番号を3000な に変
更します。
$ express handson1
$ cd handson
$ npm install
1
2
$ node app.js1
サーバ側の処理の追加
ブラウザから
サーバ側の処理の追加
Ctrl+C でサーバを停止し、サーバを再起動する。
ブラウザで http://localhost:3000/hello にアクセスしてみる。
"hello"と表示されます。
$ node app.js1
2
パスとイベントハンドラの追加の仕方
パスの追加
イベントハンドラの書き方
jQueryで
と書くのと比較すると覚えやすいかと思います。
app.HTTPメソッ 名('ルー か のURLパス', イベン ハン );1
function(req, res){
//ここでユーザか の入力値を け 、
//ユーザに返す ータを作る
}
1
2
3
4
5
$('#top').on('click', function(){
//イベン ハン ング
});
1
2
3
テンプレートで値を表示
先ほ の app.get('/hello', ...); では直接文字列を返していましたが テンプレ
ートを使ってHTMLを返すように変更してみます。
handson/views/ ディレクトリに hello.jade という新しいファイルを作って テキ
ストエディタで開きます。
内容を次のように書いてく さい。
ここで作成したファイルは jade というテンプレートエンジン用のテンプレートファ
イルです。
h1 こんにちは
p #{message} へようこそ
1
2
3
テンプレートで値を表示
app.js の res.send('Hello', ...); の部分を次のように変更します。
サーバを再起動してブラウザを再読み込みします。
こんにちは expressハンズオンへようこそ と表示されます。
app.get('/hello', function (req, res) {
// res.send('Hello'); この行は削除する
res.locals.message = 'expressハンズオン';
res.render('hello');
});
1
2
3
4
5
6
アプリケーションの自動リロード
スクリプトを変更するたびに手動でサーバの再起動をしてきました。
開発中は変更後に自動で再起動されたほうが便利なので、ツールを使って自
動化します。
nodemonというモジュールを使います
app.jsファイルを保存し直すと、サーバが自動で再起動されます
$ npm install -g nodemon
$ nodemon app.js
1
2
入力値の け取り クエリ引数編
ブラウザで http://localhost:3000/hello?greeting=hoge を開きます。
hoge という文字列はま こにも表示されていません。
この hoge という文字列をページに表示してみます。
app.get('/hello', ...); を次のように変更します。
サーバを再起動して 再度ブラウザでアクセスします。
こんにちは hogeへようこそ と表示されます。
app.get('/hello', function(req, res){
res.locals.message = req.query.greeting;
res.render('hello');
});
1
2
3
4
入力値の け取り URLパラメータ編
次に app.get('/hello') を次のように変更します
サーバを再起動し ブラウザで
http://localhost:3000/hello/fugaを開くと fugaへようこそ と と表示されます。
app.get('/hello/:greeting', function (req, res) {
res.locals.message = req.params.greeting;
res.render('hello');
});
1
2
3
4
5
入力値の け取り URLパラメータ編
この状態で http://localhost:3000/hello や http://localhost:3000/hello/ にアクセスするとエラーになるので
空のパラメータも け付けるようにするには :greeting? のようにパラメータの最
後に?をつけます。
:greeting がないときにデフォルトの値を表示するには
のようにします。
res.locals.message = req.params.greeting || ' フォル メッセージ';1
2
入力値の け取り POSTデータ編
hello.jade にフォームを追加します
ブラウザをリロードするとフォームが表示されるので
テキストフィールドに moga と入力して送信ボタンを押します。
Cannot POST /hello というエラーになります。
form(action="/hello", method="post")
input(type="text", name="greeting")
input(type="submit", value="送信")
1
2
3
入力値の け取り POSTデータ編
app.get('/hello'); は変更せ 、その後に次のように書きます。
サーバを再起動し 再度 フォームから値を送信してみます。
今度はエラーになら に mogaへようこそ 表示されます。
app.post('/hello', function(req, res){
res.locals.message = req.body.greeting;
res.render('hello');
});
1
2
3
4
5
GETとPOSTapp.get と app.post は同じURLパスでも別の処理として記述します。
GET データの取得に使われるHTTPメソッド
POST サーバにデータを送るときに使われるメソッド
HTTPメソッドの種類に関係なく常に処理を実行したい場合は app.all() が使え
ます
jadeでテンプレートを継承する
HTMLタグやHEADタグをすべてのテンプレートファイルに書くのは面倒なの
で
ひとつのファイルに書いた内容を他のファイルでも使うように変更します。
views/layout.jade ファイルがすでにあるので これを使ってみます。
テキストエディタで layout.jadeを開き block contentの行の後に一行追加し
ます。
block content
イアウ フォル コンテンツ
1
2
jadeでテンプレートを継承する
hello.jade をテキストエディタで開き いったんすべての内容を削除してから、
次のように変更します。
ブラウザをリロードすると
レイアウトデフォルトコンテンツ と表示されます。
extends layoutのあとに2行追加します
layout.jade にある block content の内容を上書きしています。
ブラウザでアクセスすると helloコンテンツ と表示されます。
extends layout1
2
extends layout
block content
h1 helloコンテンツ
1
2
3
4
アプリケーションワイドな値とブルパ
全てのビューで表示する値はあらかじめ設定しておくことができます。
app.js のルート設定の前に次の一行を追加します。
ブラウザをリロードして、ページのタイトルが変わっていることを確認します。
テンプレートで表示はしないが アプリケーション全体で共有したい設定値な
は app.set() で設定し app.get() で参照します。
app.locals.title = 'アプ ケーションワイ なサイ タイ ル';1
2
app.set('some_setting', 'some value');
app.get('some_setting'); // some value が返る
1
2
3
アプリケーションワイドな値とブルパ
app.locals には次のように関数を設定することもできます。
設定した関数はテンプレート内でブルパメソッドとして呼び出すことができま
す。
hello.jade でこのブルパを使ってみます。
app.locals.braced = function(str){
return '[' + str + ']';
}
1
2
3
p #{braced('カッコつき文字列')}1
2
セッション
セッションを使うには app.js に設定を追加します。
20行目の
の後に二行設定を追加します。
これでセッションが使えるようになりました。
express.sessionはデフォルトでメモリ上にセッション情報を保存するので実運
用には向きません
app.use(express.bodyParser());1
app.use(express.cookieParser());
app.use(express.session({key: 'sess_id', secret: 'salt'}));
1
2
3
セッション
セッションが使えることを確認するために
ダミーのログイン画面を作ってみましょう。
app.js にログイン画面用のルートを追加します。
views/login.jade を新規作成します。
app.get('/login', function(req, res){
res.render('login');
});
1
2
3
4
extends layout
block content
form(action="/login", method="post")
label ユーザ名
input(type="text", name="username")
input(type="submit", value="ログイン")
1
2
3
4
5
6
セッション
app.js にダミーのログイン処理を追加します。
http://localhost:3000/hello でログイン名を表示できるようにします。
app.post('/login', function(req, res){
req.session.username = req.body.username;
res.redirect('/hello');
});
1
2
3
4
5
app.get('/hello', function(req, res){
res.locals.username = req.session.username;
res.render('hello');
});
1
2
3
4
5
セッション
hello.jade にヤーザ名表示を表示します。
ブラウザで http://localhost:3000/login にアクセスします。
ヤーザ名を入力してログインボタンをクリックすると /hello にリダイレクトされ
入力したヤーザ名としてログインしています と表示されます。
p としてログインしています。1
2
イベントハンドラの分離
これまでにたくさんルートを追加して app.js が少し長くなったので
イベントハンドラを別ファイルに分離してすっきりさせます。
新しいファイル routes/handson.js をつくります。
app.js で今作成したファイルを読み込みます。
場所は app.get('/hello', ...); の前にします。
var handson = require('./routes/handson');
app.get('/hello', ...);
1
2
3
イベントハンドラの分離
次に app.js と routes/handson.js をつなげるため
いま handson.js に貼りつけたイベントハンドラに名前をつけます。
routes/handson.js
最後に 今名前をつけた関数を app.js で呼び出します。
app.js
exports.index = function(req, res){
res.locals.username = req.session.username;
res.render('hello');
}
1
2
3
4
5
app.get('/hello', handson.index);1
実行時の環境変数
サーバ実行時に環境変数を渡すことができます。
nodemonを使っている場合も同じです。
スクリプト内では process.env で環境変数を参照できます。
app.js の最後に以下の一行を追加してみます。
コンソールの最後にproduction と表示されます。
process.env の代わりに app.get('env') でも同じ結果を得られます。
$ NODE_ENV=production node app.js1
$ NODE_ENV=production nodemon app.js1
2
console.log(process.env.NODE_ENV);1
console.log(app.get('env'));1
入力値のエスケープ
express-validatorというexpress用のミドルウェアがあるのでそれを使います
インストール
--saveオプションをつけておくとインストールしたパッケージがpackage.jsonに
自動で追加されます
ミドルウェアの組み込み
app.jsの先頭でモジュールを読み込んで、
bodyParserの後でミドルウェアを有効にします。
https://github.com/ctavan/express-validator
$ npm install express-validator --save1
var validator = require('express-validator');
(略)
app.use(express.bodyParser());
app.use(validator());
(略)
1
2
3
4
5
lessのコンパイル
less.js-middlewareをインストールします
ミドルウェアを有効にします
app.use(express.static)の前に入れる必要があります
https://github.com/emberfeather/less.js-middlewarenpm install less-middleware
var lessMiddleware = require('less-middleware');
(略)
app.use(lessMiddleware({
dest: __dirname + '/public/css',
src: __dirname + '/public/less',
//force: true,
compress: true
}));
app.use(express.static(__dirname + '/public'));
(略)
データを保存する
今回はMongoDBを使います
MongoDBとは
ドキュメント指向データベース
node.jsでは最初期からモジュールがある
いまやIBM御用達
MongoDB用モジュール
MongoDB用のモジュールは大量に有ります
一番有名なのはmongooseですが、
私には使いにくいので今回はmongo-native-driverを紹 します
非公式モジュールから公式モジュールに格上げされました
mongo-native-driver
MongoDBのshellと同じような文法で書ける
多数のライブラリから利用されている
インストール
https://github.com/mongodb/node-mongodb-native
$ npm install mongodb --save1
モジュールの読み込みと初期化
MongoDBではDBとコレクション(テーブル)は自動で作成されます。
ファイルの前の方、モジュールのrequireをしている部分に以下のコードを追加
します。
続いて、ミドルウェア内でコネクションを初期化します
var mongoClient = require('mongodb').MongoClient;
var mongo = null;
1
2
3
app.use(function(req, res, next){
mongoClient.connect('mongodb://127.0.0.1:27017/handson',
function(err, db) {
if(err) throw err;
mongo = db;
next();
}
);
});
1
2
3
4
5
6
7
8
9
データの書き込み
\/helloにPOSTされたmessageをMongoDBに書き込んでみます。
hello.jade に次の二行を付け足すと、 (入力したメッセージ)が保存されました
と表示されます。
app.post('/hello', function(req, res){
var user_message = req.body.greeting;
var messages = mongo.collection('messages');
messages.insert({message: user_message}, function (err, doc) {
res.locals.message = doc[0].message;
res.render('hello');
});
});
1
2
3
4
5
6
7
8
if message
p が保存されました。
データの読み出し
/hello/list にアクセスした時に保存されたメッセージをすべて表示します
app.jsに以下のコードを追加します。
hello.jadeに以下のコードを追加します
ブラウザで http://localhost:3000/hello/list にアクセスすると保存したメッセ
ージの一覧が表示されます。
app.get('/hello/list', function (req, res) {
var messages = mongo.collection('messages');
messages.find().toArray(function (err, data) {
res.locals.data = data;
res.render('hello');
});
});
1
2
3
4
5
6
7
h2 保存されたメッセージ
ul
each datum in data
li= datum.message
1
2
3
4
asyncを使ったフローコントロール
フロー制御モジュール async
フローコントロールもたくさんモジュールがありますが、asyncが一番有名です。
並列実行、逐次処理、非同期処理の終了待ちな ができます。
フロー制御のほか、コレクションのイテレーションもできます。
https://github.com/caolan/async
asyncのインストール
インストール
他のモジュールと同じように、app.jsの先頭でrequireしておきます。
app.js
$ npm install async --save1
var async = require('async');1
asyncの例
MongoDBで登録されたメッセージの総数と一覧を取得してみます。
app.get('/hello/list', function (req, res) {
var messages = mongo.collection('messages');
async.parallel({
total: function (callback) {
messages.count(function (err, count) {
callback(err, count);
});
},
list: function (callback) {
messages.find().toArray(function (err, data) {
callback(err, data);
});
}
}, function (err, results) {
res.locals.data = results.list;
res.locals.total = results.total;
res.render('hello');
});
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
asyncの例
3行目でasyncのパラレル処理を開始しています
3行目から14行目のparallelメソッドの第一引数がオブジェクトになっていま
す
第一引数はオブジェクトか配列になります
この第一引数に並列処理したい関数を渡します
第一引数内に置く関数にはデフォルトで関数が渡されます
処理が終了したらこの関数を呼び出して、明示的に終了を知らせます
全ての関数が終了すると14行目から18行目にある関数が呼び出されるの
で、ここで結果を け取ります
その他のフロー制御の方法
Promiseライブラリを使う方法Qが有名です(た し遅い)BlueBirdという速いのが出ている
generatorベースのライブラリを使う方法node 0.12.xから
で取り上げました第六回のスライドの後半
Q?
宣伝
半年ほ 前に本を書きました
HTML5とJavaScriptによるiPhone/Android両対応アプリ開発ガイド(DESIGN & WEB TECHNOLOGY)