1. Nodejs 프로그래밍
6. 경량 웹 프레임워크 익스프레스
아키텍트를 꿈꾸는 사람들 오전반 스터디
전효성( itmentor@gmail.com )
1
2. 이번 발표에서 다룰 내용
1. Express 프로젝트 셋팅
2. app.js 소스 살펴보기
3. Jade 뷰 템플릿 엔진
4. 폼 전송 웹사이트 예제
5. 데이터베이스 연동
6. 비동기 패턴의 의존성 문제
2
3. 1. Express 프로젝트 셋팅
아래의 명령어를 순차적으로 입력합니다.
$ npm install express -g
$ express simpleweb
$ cd simpleweb
$ npm install
$ npm install express jade
3
4. Simpleweb 웹페이지 server-side구성
• node_modules
– 해당 웹프로젝트에서 사용하는 모듈들이 위치함.
• Public
– 정적 리소스 파일 저장 ( css, 이미지 등 )
• Route
– url에 따라 호출될 함수를 모아두는 디렉토리.
• Views
– 클라이언트에 보여줄 화면의 템플릿이 위치함.
• App.js
– main()함수 개념
• Package.json
– npm으로 설치하면 여기에 설치된 모듈의 정보( 버전 )가 들어간다.
4
6. 2. app.js 소스 살펴보기
// 모듈 종속성
var express = require('express')
, routes = require('./routes');
var app = module.exports = express.createServer();
현재 파일의 절대 경로
// configuration
app.configure( function() {
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
6
7. 2. app.js 소스 살펴보기
// 모듈 종속성
var express = require('express')
, routes = require('./routes');
var app = module.exports = express.createServer();
// configuration
app.configure( function() {
app.set('views', __dirname + '/views'); • View template엔진과 view tempalte위치 지정
app.set('view engine', 'jade'); • app.set() 특정 키에 값을 지정
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
7
8. 2. app.js 소스 살펴보기
// 모듈 종속성
var express = require('express')
, routes = require('./routes');
var app = module.exports = express.createServer();
// configuration
app.configure( function() {
app.set('views', __dirname + '/views'); • View template엔진과 view tempalte위치 지정
app.set('view engine', 'jade'); • app.set() 특정 키에 값을 지정
app.use(express.bodyParser()); • app.use() 사용할 미들웨어 결정
app.use(express.methodOverride()); • express.static 리소스파일 위치 지정
app.use(app.router); • express.bodyParser() application/x-www-form-
app.use(express.static(__dirname + '/public')); urlencoded나 application/json의 바디를 파싱하여
}); req.body변수에 할당
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
8
9. 2. app.js 소스 살펴보기
// 모듈 종속성
var express = require('express')
, routes = require('./routes');
var app = module.exports = express.createServer();
// configuration
app.configure( function() {
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser()); • app.router 요청 url을 라우팅한다.
app.use(express.methodOverride());
app.use(app.router); 예, http://localhost:3000/id에 따라 페이지를 다르게 구성하고 싶
app.use(express.static(__dirname + '/public')); 을 경우
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
9
10. 2. app.js 소스 살펴보기
// 모듈 종속성
var express = require('express')
, routes = require('./routes');
var app = module.exports = express.createServer();
// configuration
app.configure( function() {
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser()); • express.methodOverride()
app.use(express.methodOverride()); • <input>태그의 method를 오버라이드하여 브라우저
app.use(app.router); 에서 지원 못하는 PUT, DELETE를 처리
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, HTTP명령어 })); 클라이언트의 의도
showStack: true
});
GET 서버에서 정보를 얻어온다.
app.configure('production', function(){
POST 정보를 서버에 보낸다.
app.use(express.errorHandler());
}); PUT 기존에 존재하는 정보를 갱신한다.
DELETE 특정 항목을 제거한다?!
• 참고 : http://code.google.com/intl/ko-KR/apis/gdata/docs/2.0/basics.html
10
12. 2. app.js 소스 살펴보기
// Routes – HTTP 명령어( get, put, post, delete )에 대한 이벤트 핸들러 연결
app.get('/', routes.index);
// 3000번 포트 오픈
app.listen(3000);
// 서버 콘솔에 메시지 출력
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
simpleweb/route/index.js
/*
* GET home page.
*/
exports.index = function(req, res){
res.render('index', { title: 'Express' })
};
12
17. 5. 데이터베이스 연동 - mysql
설치 및 테이블 생성
// install
$ npm install mysql
// TABLE생성
CREATE TABLE members (name VARCHAR(20), email VARCHAR(30));
route/index.js repository.js
var repo = require( ‘../repository’ ); insertUser: function(user,res) {
...
exports.index = function(req, res){ }
… , hasNameAndEmail: function(user, res) {
client.query(
exports.join = function(req,res) { 'SELECT * FROM ' + TABLE + 'WHERE name = ? OR email = ?'
// repo.insertUser( req.body, res ); , [user.name, user.email]
repo. hasNameAndEmail( req.body, res ); , function(err, results, fields) {
}; if (err) {
throw err;
}
if( results.length > 0 ) {
res.render('join-fail', { title: 'Express' } );
} else {
mysqlUtil.insertUser( user, res );
}
});
} 17
18. 5. 데이터베이스 연동 - mongodb
Repository.js
외부 인터페이스
DB접근 로직
코드
가시화 로직
구조
뷰 렌더링 / DB접근 로직을 분리하자.
18
19. 6. 비동기 패턴의 의존성 문제
• 비동기로 수행된다 수행시점을 알 수 없
다.
• 해당 시점에 실행될 함수를 function
parameter로 전달
var result = db.query(‘SELECT …’ ); //동기 방식 function call
db.query(‘SELECT … ‘, 처리하는 함수) //비동기 방식 function call
19
20. 6. 비동기 패턴의 의존성 문제 – 해결책
방법1. callback을 이용하여 의존성 분리
// a.js
var b = require( './b' );
b.funcA( function( err, result1 ) {
b.funcB( result1, function( err, result2 ) {
//result를 사용하는 코드 : 렌더링 로직
});
});
// b.js
var B = module.exports = {
funcA: function( callback ) {
db.query( 'SELECT ... ', callback );
},
funcB: function( callbck ) {
db.query( 'SELECT ... ', callback );
}
}
20
21. 6. 비동기 패턴의 의존성 문제 – 해결책
방법2. event를 이용하여 의존성 분리
// b.js // a.js
var b = require( './b' );
var EventEmitter = require('events').EventEmitter; var resultA = b.funcA();
var B = module.exports = {
resultA.on( 'end', function( err, result ) {
funcA: function() {
var resultB = b.funcB(result);
var evt = new EventEmitter();
db.query( 'SELECT ... ', function( err,result ) { resultB.om( 'end', function( err, result ) {
evt.emit('end', err, result ); //result사용하는코드
}); });
return evt; });
},
funcA: function() {
var evt = new EventEmitter();
db.query( 'SELECT ... ', function( err,result ) {
evt.emit('end', err, result );
});
return evt;
}
}
21
22. 6. 비동기 패턴의 의존성 문제 – 해결책
비동기 호출 순서를 보장하는 방법
func repeater(i)
{
if( i < length )
{
requestAsyncWork ( function() {
repeater(i+1)
})
}
}
repeater(0)
• 0번 요청 끝 1번 요청 1번 요청 끝 2번 요청 …
• 결국 동기와 동일한 방식을 비동기로 구현한 것.
22
23. 7. 정리
• 웹서버 생성
– express.createServer()
• 서버 설정
– express.createServer().configure( callback )
– Callback에서 express.createServer().set()과
express.createServer().use()사용
• GET/POST의 라우팅
– express.createServer().get()
– express.createServer().post()
• HTML노가다 하지 말고 jade로 작성하자.
– 디자이너와 소통이 어려울수도 있음.
23
24. 질문 받겠습니다.
Express에 대한 자세한 설명은 생략한
다.
http://firejune.io/express/guide를 참조 한다.
24