SlideShare a Scribd company logo
+
MEAN 스택을 사용한 IoT 개발
박재호(jrogue@gmail.com)
+
MEAN이란?
+
+
TESSEL 모듈 유형
+
TESSEL 스펙
+
Beagle Bone Black
+
bonescript
n  Beagle Bone에서 아두이노 스타일의 프로그램이 가능하게 만들어
주는 자바스크립트 라이브러리
+
AWS Lambda(1)
+
AWS Lambda(2)
+
AWS Lambda(3)
+
heimcontrol.js(1)
Raspberry PI and Arduino using Node.js
+
heimcontrol.js(2)
Socket.io(for Websockets)
Requirejs
HTML5/CSS3
Jade(for
templating)
+
Node.js인 이유는?(1)
+
Node.js인 이유는?(2)
n  개발 시간과 성능의 조화
n  아무리 성능이 좋더라도 개발 시간이 오래 걸릴 경우 생산성이 떨어진다
n  주의: 1행을 작성하는 시간은 어셈블리나 SQL이나 비슷하다
n  스크립트 언어의 경우 빨리 개발은 가능하지만 성능이 떨어진다
n  자바스크립트를 사용한 Node.js는 개발과 성능 양쪽 모두 뛰어나다
n  스타트업 vs 기업
n  스타트업은 빨리 변화하는 생태계에서 살아남기 위해 필연적으로 오픈
소스에 매진한다
n  대기업은 유지보수와 안정성, 그리고 성능에 관심이 많다
n  Node.js는 양쪽 모두를 만족시킨다(오픈 소스 기반, 자바와 같은 강력한
생태계)
+
Node.js인 이유는?(3)
n  뛰어난 성능
n  월마트는 블랙 프라이데이에 Node.js로 전제 모바일 사이트 오픈
n  초당 두 배 요청을 받아들이고 응답시간을 35%(200ms) 줄임
n  서버 CPU 사용량이 2%, 200만 명 온라인 접속 방어
n  이벤트 아키텍처
n  스레드가 아닌 단일 프로세스
n  대신 동기식 차단이 아닌 비동기식 I/O
n  웹 브라우저 특성상 이미 자바스크립트는 콜백을 사용하는 이벤트 구
동 방식을 지원(비동기식 코드에 대한 표현력이 강함)
+
동기식 입출력 vs 비동기식 입출력
+
멀티 스레드 vs 단일 스레드
+
LAMP vs MEAN
+
자기 조직화
+
MEAN stack 아키텍처
+
선행조건
n  MEAN 기본 스택 준비
n  Node.js 설치: http://nodejs.org/
n  MongoDB 설치: http://www.mongodb.org/
n  자바스크립트 편집기는 brackets 추천: http://brackets.io/
n  예제 소스 코드 저장소 위치
n  Node.js용 node-collector: https://bitbucket.org/jrogue/node-
collector
n  AngularJS용 angular-lamp-app: https://bitbucket.org/jrogue/
angular-lamp-app
+
무엇을 만들어볼까?
lamp 관리 시스템
+
기본 아키텍처
+
첫 Node.js 프로그램: /
server_plain_vanilla.js
/*jslint node: true */
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello Worldn');
}).listen(3000, '127.0.0.1');
console.log('Server running at http://127.0.0.1:3000/');
+
Node.js 프로그램을 위한 패키지 설
정: /package.json
{
"name": "node-collector",
"private": true,
"version": "0.1.0",
"description": "A starter project for Node.js",
"license": "MIT",
"devDependencies": {
"express": "4.x",
"body-parser": "1.4.x“,
"mongoose": "^3.8.20"
}
}
+
의존성 설치와 목록
+
Node.js를 사용한 첫 RESTful 프로그
램: /server.js
var express = require('express');
var app = express();
app.get('/lamps', function(req, res) {
res.send([{name: 'lamp1'}, {name: ‘lamp2'}]);
});
app.get('/lamps/:id', function(req, res) {
res.send({id:req.params.id, name: "lamp" + req.params.id, status: "lamp
ready"});
});
app.listen(3000);
console.log('Listening on port 3000...');
+
실행과 테스트 방법
+
Node.js 모듈 사용: /routes/lamps.js
exports.findAll = function (req, res) {
res.send([{name: 'lamp1'}, {name: 'lamp2'}, {name: ‘lamp3'}]);
};
exports.findById = function (req, res) {
res.send({id: req.params.id, name: "lamp" + req.params.id, status: "lamp
ready"});
};
var express = require('express'),
bodyParser = require('body-parser'),
lamps = require('./routes/lamps.js');
var app = express();
app.get('/lamps', lamps.findAll);
app.get('/lamps/:id', lamps.findById);
app.listen(3000);
console.log('Listening on port 3000...');
+
몽고DB 연동을 위한 준비: /db.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/lamps', function () {
console.log('mongodb connected')
});
module.exports = mongoose;
+
몽고DB 모델 생성: /models/lamp.js
var db = require('../db');
var Lamp = db.model('Lamp', {
lampname: { type: String, required: true },
status: { type: String, required: true },
date: { type: Date, required: true, default: Date.now }
});
module.exports = Lamp;
+
Node.js 모듈 내용 변경(1): /routes/
lamps.js
var Lamp = require('../models/lamp');
exports.addLamp = function (req, res, next) {
var lamp = new Lamp({
lampname: req.body.lampname,
status: req.body.status
});
lamp.save(function (err, lamp) {
if (err) { return next(err); }
res.status(201).json(lamp);
});
};
+
Node.js 모듈 내용 변경(2): /routes/
lamps.js
exports.updateLamp = function (req, res, next) {
Lamp.findOne({ _id: req.params.id }, function (err, lamp) {
if (err) { return next(err); }
lamp.status = req.body.status;
lamp.save(function (err, lamp) {
if (err) { return next(err); }
res.status(201).json(lamp);
});
});
};
exports.deleteLamp = function (req, res, next) {
Lamp.remove({ _id: req.params.id }, function (err, lamp) {
if (err) { return next(err); }
res.status(201).json(lamp);
});
};
+
Node.js 모듈 내용 변경(3): /routes/
lamps.js
exports.findAll = function (req, res, next) {
Lamp.find(function (err, lamps) {
if (err) { return next(err); }
res.status(201).json(lamps);
});
};
exports.findById = function (req, res, next) {
Lamp.findOne({ _id: req.params.id }, function (err, lamp)
{
if (err) { return next(err); }
res.status(201).json(lamp);
});
};
+
CRUD 전체 정의를 위한 변경: /
server.js
var express = require('express'),
bodyParser = require('body-parser'),
lamps = require('./routes/lamps.js');
var app = express();
app.use(bodyParser.json());
app.post('/lamps', lamps.addLamp);
app.get('/lamps', lamps.findAll);
app.get('/lamps/:id', lamps.findById);
app.put('/lamps/:id', lamps.updateLamp);
app.delete('/lamps/:id', lamps.deleteLamp);
app.listen(3000);
console.log('Listening on port 3000...');
+
서버 시작
n  서버 시작
n  $ node server
n  주의: 서버 시작에 앞서 지역 호스트(localhost)에 몽고DB를 설치
하고 시작했는지 반드시 확인하자!
+
단말 쪽 프로그래밍
n  REST 방식으로 API를 호출하면 된다
n  단말 조건: TCP/IP 스택이 설치되어 있으며, REST 클라이언트 라이브러
리를 사용할 수 있어야 한다.
n  만일 리눅스 기반으로 동작하는 단말인 경우 뒤에 테스트 예제에서
설명하는 curl을 system으로 호출하면 아주 쉽게 구현 가능하다.
n  C 언어로 개발할 경우 libcurl을 사용할 수도 있다.
n  스크립트 언어로 개발할 경우 스크립트 언어의 REST 클라이언트 패
키지를 사용하면 몇 줄로 서버 쪽에 자신의 상태를 전달할 수 있다.
n  이어지는 테스트 예제를 보며 CRUD 전달 방식을 확인하자.
+
CRUD 테스트: POSTMAN vs curl
크롬 확장: REST 클라이언트
http://curl.haxx.se/ (홈페이지)
http://www.confusedbycode.com/curl/ (윈도우 32비트/64비트)
참고: 여기서는 설명의 편의를 위해 cURL을 사용한다!
+
서버 구동 후 생성 테스트(curl 사용)
+
몽고DB 셸을 사용한 확인
+
(전체) 읽기 테스트
+
변경 테스트
+
(변경 내역 반영 검증을 위한) 읽기 테
스트
+
삭제 테스트
+
최종 확인
+
Single Page Application
+
MVC vs MVVM
+
AngularJS 샘플 앱의 디렉터리 구조
+
/index.html
<!DOCTYPE html>
<html ng-app="LampApp">
<head>
<link href="styles/main.css" rel="stylesheet">
<link rel="stylesheet" ref="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
</head>
<body>
<ul class="menu">
<li><a href="#/notice">notice</a></li>
<li><a href="#/list">list</a></li>
</ul>
<div class="container" ng-view=""></div>
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular-resource.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular-route.min.js"></script>
<script src="scripts/app.js"></script>
<script src="scripts/services/services.js"></script>
<script src="scripts/controllers/controllers.js"></script>
</body>
</html>
+
views/list.html
<div class="span6">
<table class="table table-striped table-condensed">
<thead>
<tr>
<th style="min-width: 300px;">Lamp ID</th>
<th style="min-width: 120px;">Name</th>
<th style="min-width: 120px;">Status</th>
<th style="min-width: 120px;">Action</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="lamp in lamps">
<td>{{ lamp._id }}</td>
<td>{{ lamp.lampname }}</td>
<td>{{ lamp.status }}</td>
<td><input type="radio" value="on"> on <input type="radio" value="off"> off</td>
</tr>
</tbody>
</table>
</div>
+
views/notice.html
<div>
<p>환영합니다.</p>
<p>{{ message }}</p>
</div>
+
scripts/services/services.js
'use strict';
var services = angular.module('lampApp.services', ['ngResource']);
var baseUrl = 'http://localhost:3000';
services.factory('NoticeFactory', function ($resource) {
return $resource(baseUrl + '/notice', {}, {
query: { method: 'GET', params: {} }
});
});
services.factory('LampsFactory', function ($resource) {
return $resource(baseUrl + '/lamps', {}, {
query: { method: 'GET', isArray: true }
});
});
services.factory('LampFactory', function ($resource) {
return $resource(baseUrl + '/lamps/:id', {}, {
show: { method: 'GET' }
});
});
+
scripts/controller/controller.js
'use strict';
var app = angular.module('lampApp.controllers', []);
// Clear browser cache (in development mode)
//
// http://stackoverflow.com/questions/14718826/angularjs-disable-partial-caching-on-
dev-machine
app.run(function ($rootScope, $templateCache) {
$rootScope.$on('$viewContentLoaded', function () {
$templateCache.removeAll();
});
});
app.controller('NoticeCtrl', ['$scope', 'NoticeFactory', function ($scope, NoticeFactory) {
$scope.message = '간단한 AngularJS 테스트 프로그램입니다. Lamp 상태를 보여줍니다. 아
직 Lamp 조작 기능은 구현되어 있지 않습니다.';
}]);
app.controller('ListCtrl', ['$scope', 'LampsFactory', function ($scope, LampsFactory) {
$scope.lamps = LampsFactory.query();
}]);
+
scripts/app.js
"use strict";
// Declare app level module which depends on views, and components
angular.module('LampApp', [
'ngResource',
'ngRoute',
'lampApp.services',
'lampApp.controllers'
]).
config(['$routeProvider', function ($routeProvider, $httpProvider) {
$routeProvider.when('/notice', { templateUrl: 'views/notice.html', controller: 'NoticeCtrl'});
$routeProvider.when('/list', { templateUrl: 'views/list.html', controller: 'ListCtrl'});
$routeProvider.otherwise({redirectTo: '/notice'});
}]);
+
HTTP 서버 사용하기
n  Node용 간이 http 서버 설치
n  npm install http-server –g
n  AngularJS를 서비스 하기 위한 HTTP 서버 시작
n  cd angular-app
n  http-server
실시간 미
리 보기
또는 Brackets에서
+
앱 결과 화면(index.html)
+
앱 결과 화면(index.html에서 list)
+
도전 과제
n  socket.io를 사용해 polling하지 않고서 추가/변경/삭제되는 Lamp
목록을 보여준다.
n  hard coded된 notice 문구 대신, 특정 Lamp에 문제가 생겼을 경
우 서버에서 경고를 받아 출력한다.
n  Action을 추가해, Lamp를 켜고/끄게 만든다.
n  bower를 사용해 AngularJS 개발 과정에서 복잡한 프론트엔드 의
존성을 자동으로 관리하게 만든다.
+
실제 사례
+
참고 자료
n  http://docs.aws.amazon.com/lambda/latest/dg/
walkthrough-custom-events.html
n  http://ni-c.github.io/heimcontrol.js/
n  http://coenraets.org/blog/2012/10/creating-a-rest-api-
using-node-js-express-and-mongodb/
n  https://blog.codecentric.de/en/2013/03/home-automation-
with-angularjs-and-node-js-on-a-raspberry-pi/
n  http://mean.io/
n  http://bcho.tistory.com/881
+
참고 서적(팩트 서적은 번역 진행 중)
+

More Related Content

PDF
MEAN Stack 기반 모바일 서비스 개발 overview
PDF
웹 Front-End 실무 이야기
PPTX
XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기
PDF
Front end dev 2016 & beyond
PDF
Node.js 기본
PDF
React를 이용하여 멀티플랫폼에서 개발하기
PDF
Resource Handling in Spring MVC
PDF
Vue SSR vs Prerender
MEAN Stack 기반 모바일 서비스 개발 overview
웹 Front-End 실무 이야기
XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기
Front end dev 2016 & beyond
Node.js 기본
React를 이용하여 멀티플랫폼에서 개발하기
Resource Handling in Spring MVC
Vue SSR vs Prerender

What's hot (20)

PDF
Universal Rendering
PPTX
Deview2013 track1 session7
PPTX
[114]angularvs react 김훈민손찬욱
PDF
서버리스 기반의 프론트엔드 서버 구축(Serverless frontend web server)
KEY
Meteor 0.3.6 Preview
PPTX
Node.js
PPTX
[123] electron 김성훈
PDF
Isomorphicspring Isomorphic - spring web seminar 2015
PDF
Javascript everywhere - Node.js | Devon 2012
PPTX
Nodejs 발표자료
PDF
Facebook은 React를 왜 만들었을까?
PDF
프론트엔드 개발자를 위한 크롬 렌더링 성능인자 이해하기
PDF
[213]monitoringwithscouter 이건희
PDF
20131217 html5
PPTX
AngularJS의 개발방식에 대하여
PDF
역시 Redux
PDF
AngularJS 2, version 1 and ReactJS
PDF
Front-end Development Process - 어디까지 개선할 수 있나
PDF
React Native를 사용한
 초간단 커뮤니티 앱 제작
PDF
막하는 스터디 네 번째 만남 AngularJs (20151108)
Universal Rendering
Deview2013 track1 session7
[114]angularvs react 김훈민손찬욱
서버리스 기반의 프론트엔드 서버 구축(Serverless frontend web server)
Meteor 0.3.6 Preview
Node.js
[123] electron 김성훈
Isomorphicspring Isomorphic - spring web seminar 2015
Javascript everywhere - Node.js | Devon 2012
Nodejs 발표자료
Facebook은 React를 왜 만들었을까?
프론트엔드 개발자를 위한 크롬 렌더링 성능인자 이해하기
[213]monitoringwithscouter 이건희
20131217 html5
AngularJS의 개발방식에 대하여
역시 Redux
AngularJS 2, version 1 and ReactJS
Front-end Development Process - 어디까지 개선할 수 있나
React Native를 사용한
 초간단 커뮤니티 앱 제작
막하는 스터디 네 번째 만남 AngularJs (20151108)
Ad

Similar to Mean 스택을 사용한 IoT 개발 (20)

PPTX
Node.js의 도입과 활용
PPTX
One-day-codelab
PPTX
리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API
PPTX
Startup JavaScript 8 - NPM, Express.JS
PDF
CoreDot TechSeminar 2018 - Session2 Ji Donghyun
PDF
Internship backend
PDF
NODE.JS 글로벌 기업 적용 사례 그리고, real-time 어플리케이션 개발하기
PDF
막하는스터디 두번째만남 Express(20151025)
PDF
진짜기초 Node.js
PPTX
Nodejs, PhantomJS, casperJs, YSlow, expressjs
PDF
Meteor IoT
PDF
세션3 node.js의 의미와 자바의 대안
PDF
[Play.node] node.js 를 사용한 대규모 글로벌(+중국) 서비스
PPTX
Startup JavaScript 9 - Socket.IO 실시간 통신
PDF
Node.js intro
PDF
막하는 스터디 첫 번째 만남 Node.js
PDF
Node.js 기본과정
PDF
Why javaScript?
PDF
[Korea Linux Forum] Implementing web based online multiplayer tetris with Ope...
PDF
『풀스택 개발자를 위한 MEAN 스택 입문』 - 미리보기
Node.js의 도입과 활용
One-day-codelab
리스펙토링 세미나 - 웹 브라우저 동작 개념, Node.js를 통한 서버 이해, REST API
Startup JavaScript 8 - NPM, Express.JS
CoreDot TechSeminar 2018 - Session2 Ji Donghyun
Internship backend
NODE.JS 글로벌 기업 적용 사례 그리고, real-time 어플리케이션 개발하기
막하는스터디 두번째만남 Express(20151025)
진짜기초 Node.js
Nodejs, PhantomJS, casperJs, YSlow, expressjs
Meteor IoT
세션3 node.js의 의미와 자바의 대안
[Play.node] node.js 를 사용한 대규모 글로벌(+중국) 서비스
Startup JavaScript 9 - Socket.IO 실시간 통신
Node.js intro
막하는 스터디 첫 번째 만남 Node.js
Node.js 기본과정
Why javaScript?
[Korea Linux Forum] Implementing web based online multiplayer tetris with Ope...
『풀스택 개발자를 위한 MEAN 스택 입문』 - 미리보기
Ad

More from Jay Park (20)

PDF
[독서광] 코드 넘어 회사보다 오래 남을 개발자
PDF
(독서광) 윌 라슨의 엔지니어링 리더십 - 테크 리더를 위한 성공 전략
PDF
[독서광] 모던 소프트웨어 엔지니어링 - 소프트웨어 개발의 복잡함과 난해함 속에서 길을 찾으려는 엔지니어를 위한...
PDF
(독서광) Azure OpenAI로 ChatGPT와 LLM 시스템 쉽고 빠르게 구축하기
PDF
(독서광) 이펙티브 소프트웨어 설계 - 실수와 트레이드오프로부터 배우는 현명한 소프트웨어 설계 가이드
PDF
(독서광) 지능의 기원 - 우리의 뇌 그리고 AI를 만든 다섯 번의 혁신
PDF
(독서광) 린 프로덕트 플레이북: 시장에서 살아남는 프로덕트를 개발하는 6단계 프로세스
PDF
(OkdevTV) 2025년 1월 8일 개발 이야기
PDF
(독서광) 2024년 12월 모두를 위한 소프트웨어 보안 설계와 구현
PDF
(OkdevTV) 2024년 12월 18일 개발 이야기
PDF
(OKdevTV) 2024년 12월 5일 개발 이야기
PDF
(독서광) 2024년 11월 선택 설계자들 - 어떻게 함정을 피하고 탁월한 결정을 내릴 것인가
PDF
(OkdevTV) 2024년 10월 30일 개발 이야기
PDF
(OkdevTV) 2024년 10월 16일 개발 이야기
PDF
(독서광) 갈대 속의 영원 - 저항하고 꿈꾸고 연결하는 발명품, 책의 모험
PDF
(OkdevTV) 2024년 10월 2일 개발 이야기
PDF
(OkdevTV) 2024년 9월 2일 개발 이야기 - 좋은 리팩토링 vs 나쁜 리팩토링
PDF
[OkdevTV] 2024년 9월 2일 개발 이야기
PDF
[독서광] 프리세일즈 (Technical Presales) - 고객과 기업을 잇는 기술 대표
PDF
[OKdevTV] 2024년 8월 21일 개발 이야기
[독서광] 코드 넘어 회사보다 오래 남을 개발자
(독서광) 윌 라슨의 엔지니어링 리더십 - 테크 리더를 위한 성공 전략
[독서광] 모던 소프트웨어 엔지니어링 - 소프트웨어 개발의 복잡함과 난해함 속에서 길을 찾으려는 엔지니어를 위한...
(독서광) Azure OpenAI로 ChatGPT와 LLM 시스템 쉽고 빠르게 구축하기
(독서광) 이펙티브 소프트웨어 설계 - 실수와 트레이드오프로부터 배우는 현명한 소프트웨어 설계 가이드
(독서광) 지능의 기원 - 우리의 뇌 그리고 AI를 만든 다섯 번의 혁신
(독서광) 린 프로덕트 플레이북: 시장에서 살아남는 프로덕트를 개발하는 6단계 프로세스
(OkdevTV) 2025년 1월 8일 개발 이야기
(독서광) 2024년 12월 모두를 위한 소프트웨어 보안 설계와 구현
(OkdevTV) 2024년 12월 18일 개발 이야기
(OKdevTV) 2024년 12월 5일 개발 이야기
(독서광) 2024년 11월 선택 설계자들 - 어떻게 함정을 피하고 탁월한 결정을 내릴 것인가
(OkdevTV) 2024년 10월 30일 개발 이야기
(OkdevTV) 2024년 10월 16일 개발 이야기
(독서광) 갈대 속의 영원 - 저항하고 꿈꾸고 연결하는 발명품, 책의 모험
(OkdevTV) 2024년 10월 2일 개발 이야기
(OkdevTV) 2024년 9월 2일 개발 이야기 - 좋은 리팩토링 vs 나쁜 리팩토링
[OkdevTV] 2024년 9월 2일 개발 이야기
[독서광] 프리세일즈 (Technical Presales) - 고객과 기업을 잇는 기술 대표
[OKdevTV] 2024년 8월 21일 개발 이야기

Mean 스택을 사용한 IoT 개발

  • 1. + MEAN 스택을 사용한 IoT 개발 박재호(jrogue@gmail.com)
  • 3. +
  • 7. + bonescript n  Beagle Bone에서 아두이노 스타일의 프로그램이 가능하게 만들어 주는 자바스크립트 라이브러리
  • 11. + heimcontrol.js(1) Raspberry PI and Arduino using Node.js
  • 14. + Node.js인 이유는?(2) n  개발 시간과 성능의 조화 n  아무리 성능이 좋더라도 개발 시간이 오래 걸릴 경우 생산성이 떨어진다 n  주의: 1행을 작성하는 시간은 어셈블리나 SQL이나 비슷하다 n  스크립트 언어의 경우 빨리 개발은 가능하지만 성능이 떨어진다 n  자바스크립트를 사용한 Node.js는 개발과 성능 양쪽 모두 뛰어나다 n  스타트업 vs 기업 n  스타트업은 빨리 변화하는 생태계에서 살아남기 위해 필연적으로 오픈 소스에 매진한다 n  대기업은 유지보수와 안정성, 그리고 성능에 관심이 많다 n  Node.js는 양쪽 모두를 만족시킨다(오픈 소스 기반, 자바와 같은 강력한 생태계)
  • 15. + Node.js인 이유는?(3) n  뛰어난 성능 n  월마트는 블랙 프라이데이에 Node.js로 전제 모바일 사이트 오픈 n  초당 두 배 요청을 받아들이고 응답시간을 35%(200ms) 줄임 n  서버 CPU 사용량이 2%, 200만 명 온라인 접속 방어 n  이벤트 아키텍처 n  스레드가 아닌 단일 프로세스 n  대신 동기식 차단이 아닌 비동기식 I/O n  웹 브라우저 특성상 이미 자바스크립트는 콜백을 사용하는 이벤트 구 동 방식을 지원(비동기식 코드에 대한 표현력이 강함)
  • 16. + 동기식 입출력 vs 비동기식 입출력
  • 17. + 멀티 스레드 vs 단일 스레드
  • 21. + 선행조건 n  MEAN 기본 스택 준비 n  Node.js 설치: http://nodejs.org/ n  MongoDB 설치: http://www.mongodb.org/ n  자바스크립트 편집기는 brackets 추천: http://brackets.io/ n  예제 소스 코드 저장소 위치 n  Node.js용 node-collector: https://bitbucket.org/jrogue/node- collector n  AngularJS용 angular-lamp-app: https://bitbucket.org/jrogue/ angular-lamp-app
  • 24. + 첫 Node.js 프로그램: / server_plain_vanilla.js /*jslint node: true */ var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello Worldn'); }).listen(3000, '127.0.0.1'); console.log('Server running at http://127.0.0.1:3000/');
  • 25. + Node.js 프로그램을 위한 패키지 설 정: /package.json { "name": "node-collector", "private": true, "version": "0.1.0", "description": "A starter project for Node.js", "license": "MIT", "devDependencies": { "express": "4.x", "body-parser": "1.4.x“, "mongoose": "^3.8.20" } }
  • 27. + Node.js를 사용한 첫 RESTful 프로그 램: /server.js var express = require('express'); var app = express(); app.get('/lamps', function(req, res) { res.send([{name: 'lamp1'}, {name: ‘lamp2'}]); }); app.get('/lamps/:id', function(req, res) { res.send({id:req.params.id, name: "lamp" + req.params.id, status: "lamp ready"}); }); app.listen(3000); console.log('Listening on port 3000...');
  • 29. + Node.js 모듈 사용: /routes/lamps.js exports.findAll = function (req, res) { res.send([{name: 'lamp1'}, {name: 'lamp2'}, {name: ‘lamp3'}]); }; exports.findById = function (req, res) { res.send({id: req.params.id, name: "lamp" + req.params.id, status: "lamp ready"}); }; var express = require('express'), bodyParser = require('body-parser'), lamps = require('./routes/lamps.js'); var app = express(); app.get('/lamps', lamps.findAll); app.get('/lamps/:id', lamps.findById); app.listen(3000); console.log('Listening on port 3000...');
  • 30. + 몽고DB 연동을 위한 준비: /db.js var mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/lamps', function () { console.log('mongodb connected') }); module.exports = mongoose;
  • 31. + 몽고DB 모델 생성: /models/lamp.js var db = require('../db'); var Lamp = db.model('Lamp', { lampname: { type: String, required: true }, status: { type: String, required: true }, date: { type: Date, required: true, default: Date.now } }); module.exports = Lamp;
  • 32. + Node.js 모듈 내용 변경(1): /routes/ lamps.js var Lamp = require('../models/lamp'); exports.addLamp = function (req, res, next) { var lamp = new Lamp({ lampname: req.body.lampname, status: req.body.status }); lamp.save(function (err, lamp) { if (err) { return next(err); } res.status(201).json(lamp); }); };
  • 33. + Node.js 모듈 내용 변경(2): /routes/ lamps.js exports.updateLamp = function (req, res, next) { Lamp.findOne({ _id: req.params.id }, function (err, lamp) { if (err) { return next(err); } lamp.status = req.body.status; lamp.save(function (err, lamp) { if (err) { return next(err); } res.status(201).json(lamp); }); }); }; exports.deleteLamp = function (req, res, next) { Lamp.remove({ _id: req.params.id }, function (err, lamp) { if (err) { return next(err); } res.status(201).json(lamp); }); };
  • 34. + Node.js 모듈 내용 변경(3): /routes/ lamps.js exports.findAll = function (req, res, next) { Lamp.find(function (err, lamps) { if (err) { return next(err); } res.status(201).json(lamps); }); }; exports.findById = function (req, res, next) { Lamp.findOne({ _id: req.params.id }, function (err, lamp) { if (err) { return next(err); } res.status(201).json(lamp); }); };
  • 35. + CRUD 전체 정의를 위한 변경: / server.js var express = require('express'), bodyParser = require('body-parser'), lamps = require('./routes/lamps.js'); var app = express(); app.use(bodyParser.json()); app.post('/lamps', lamps.addLamp); app.get('/lamps', lamps.findAll); app.get('/lamps/:id', lamps.findById); app.put('/lamps/:id', lamps.updateLamp); app.delete('/lamps/:id', lamps.deleteLamp); app.listen(3000); console.log('Listening on port 3000...');
  • 36. + 서버 시작 n  서버 시작 n  $ node server n  주의: 서버 시작에 앞서 지역 호스트(localhost)에 몽고DB를 설치 하고 시작했는지 반드시 확인하자!
  • 37. + 단말 쪽 프로그래밍 n  REST 방식으로 API를 호출하면 된다 n  단말 조건: TCP/IP 스택이 설치되어 있으며, REST 클라이언트 라이브러 리를 사용할 수 있어야 한다. n  만일 리눅스 기반으로 동작하는 단말인 경우 뒤에 테스트 예제에서 설명하는 curl을 system으로 호출하면 아주 쉽게 구현 가능하다. n  C 언어로 개발할 경우 libcurl을 사용할 수도 있다. n  스크립트 언어로 개발할 경우 스크립트 언어의 REST 클라이언트 패 키지를 사용하면 몇 줄로 서버 쪽에 자신의 상태를 전달할 수 있다. n  이어지는 테스트 예제를 보며 CRUD 전달 방식을 확인하자.
  • 38. + CRUD 테스트: POSTMAN vs curl 크롬 확장: REST 클라이언트 http://curl.haxx.se/ (홈페이지) http://www.confusedbycode.com/curl/ (윈도우 32비트/64비트) 참고: 여기서는 설명의 편의를 위해 cURL을 사용한다!
  • 39. + 서버 구동 후 생성 테스트(curl 사용)
  • 43. + (변경 내역 반영 검증을 위한) 읽기 테 스트
  • 48. + AngularJS 샘플 앱의 디렉터리 구조
  • 49. + /index.html <!DOCTYPE html> <html ng-app="LampApp"> <head> <link href="styles/main.css" rel="stylesheet"> <link rel="stylesheet" ref="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"> </head> <body> <ul class="menu"> <li><a href="#/notice">notice</a></li> <li><a href="#/list">list</a></li> </ul> <div class="container" ng-view=""></div> <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular-resource.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular-route.min.js"></script> <script src="scripts/app.js"></script> <script src="scripts/services/services.js"></script> <script src="scripts/controllers/controllers.js"></script> </body> </html>
  • 50. + views/list.html <div class="span6"> <table class="table table-striped table-condensed"> <thead> <tr> <th style="min-width: 300px;">Lamp ID</th> <th style="min-width: 120px;">Name</th> <th style="min-width: 120px;">Status</th> <th style="min-width: 120px;">Action</th> </tr> </thead> <tbody> <tr ng-repeat="lamp in lamps"> <td>{{ lamp._id }}</td> <td>{{ lamp.lampname }}</td> <td>{{ lamp.status }}</td> <td><input type="radio" value="on"> on <input type="radio" value="off"> off</td> </tr> </tbody> </table> </div>
  • 52. + scripts/services/services.js 'use strict'; var services = angular.module('lampApp.services', ['ngResource']); var baseUrl = 'http://localhost:3000'; services.factory('NoticeFactory', function ($resource) { return $resource(baseUrl + '/notice', {}, { query: { method: 'GET', params: {} } }); }); services.factory('LampsFactory', function ($resource) { return $resource(baseUrl + '/lamps', {}, { query: { method: 'GET', isArray: true } }); }); services.factory('LampFactory', function ($resource) { return $resource(baseUrl + '/lamps/:id', {}, { show: { method: 'GET' } }); });
  • 53. + scripts/controller/controller.js 'use strict'; var app = angular.module('lampApp.controllers', []); // Clear browser cache (in development mode) // // http://stackoverflow.com/questions/14718826/angularjs-disable-partial-caching-on- dev-machine app.run(function ($rootScope, $templateCache) { $rootScope.$on('$viewContentLoaded', function () { $templateCache.removeAll(); }); }); app.controller('NoticeCtrl', ['$scope', 'NoticeFactory', function ($scope, NoticeFactory) { $scope.message = '간단한 AngularJS 테스트 프로그램입니다. Lamp 상태를 보여줍니다. 아 직 Lamp 조작 기능은 구현되어 있지 않습니다.'; }]); app.controller('ListCtrl', ['$scope', 'LampsFactory', function ($scope, LampsFactory) { $scope.lamps = LampsFactory.query(); }]);
  • 54. + scripts/app.js "use strict"; // Declare app level module which depends on views, and components angular.module('LampApp', [ 'ngResource', 'ngRoute', 'lampApp.services', 'lampApp.controllers' ]). config(['$routeProvider', function ($routeProvider, $httpProvider) { $routeProvider.when('/notice', { templateUrl: 'views/notice.html', controller: 'NoticeCtrl'}); $routeProvider.when('/list', { templateUrl: 'views/list.html', controller: 'ListCtrl'}); $routeProvider.otherwise({redirectTo: '/notice'}); }]);
  • 55. + HTTP 서버 사용하기 n  Node용 간이 http 서버 설치 n  npm install http-server –g n  AngularJS를 서비스 하기 위한 HTTP 서버 시작 n  cd angular-app n  http-server 실시간 미 리 보기 또는 Brackets에서
  • 58. + 도전 과제 n  socket.io를 사용해 polling하지 않고서 추가/변경/삭제되는 Lamp 목록을 보여준다. n  hard coded된 notice 문구 대신, 특정 Lamp에 문제가 생겼을 경 우 서버에서 경고를 받아 출력한다. n  Action을 추가해, Lamp를 켜고/끄게 만든다. n  bower를 사용해 AngularJS 개발 과정에서 복잡한 프론트엔드 의 존성을 자동으로 관리하게 만든다.
  • 60. + 참고 자료 n  http://docs.aws.amazon.com/lambda/latest/dg/ walkthrough-custom-events.html n  http://ni-c.github.io/heimcontrol.js/ n  http://coenraets.org/blog/2012/10/creating-a-rest-api- using-node-js-express-and-mongodb/ n  https://blog.codecentric.de/en/2013/03/home-automation- with-angularjs-and-node-js-on-a-raspberry-pi/ n  http://mean.io/ n  http://bcho.tistory.com/881
  • 61. + 참고 서적(팩트 서적은 번역 진행 중)
  • 62. +