MVC 모델

api 서버를 구축하기 위해 mvc 모델을 구축해보았다.
db는 mongodb를 이용하였고 연동시켜 보았다.

routes에서 요청을 받고 controllers로 요청을 하는 그림을 보고 https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes 링크를 참조하며 공부한 결과 아래와 같은 mvc 패턴을 구현하였다.

app.js

var express = require('express');
var http = require('http');
var bodyParser = require('body-parser');
 
var app = express();
 
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
 
app.listen(8888);
 
console.log("Server is Running...");
 
var catalog = require('./api/routes/catalog');
 
app.use('/', catalog);
 

userController.js

(function() {
  'use strict';
})();
 
var User = require('../models/userModel.js');
 
exports.get_dummy = function (req, res) {
  res.end('get_dummy');
};
 
exports.put_dummy = function (req, res) {
  res.end('put_dummy');
};
 
exports.post_dummy = function (req, res) {
  var userIns = User();
  userIns.name = 'jung';
  res.end(userIns.name);
};
 
exports.delete_dummy = function (req, res) {
  res.end('delete_dummy');
};

catalog.js(route)

catalog.js 에서 각 controllers를 추가하여 라우팅을 해준다.

(function() {
  'use strict';
})();
 
var express = require('express');
var router = express.Router();
 
var userController = require('../controllers/userController');
 
router.get('/', function (req, res) {
  res.redirect('user router');
});
 
//user router
router.get('/user', userController.get_dummy);
router.post('/user', userController.post_dummy);
router.put('/user', userController.put_dummy);
router.delete('/user', userController.delete_dummy);
 
 
module.exports = router;

userModel.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
 
mongoose.createConnection('mongodb://localhost:27017/test');
 
var UserSchema = new Schema({
    name: String,
    address: String,
    phone: String,
    email: String
});
 
module.exports = mongoose.model('User', UserSchema);


'Framework > Nodejs' 카테고리의 다른 글

node js, mongodb 연동 with mongoose  (0) 2017.08.16
이메일 발송  (0) 2017.07.13
mocha  (0) 2017.07.05
미들웨어(1):cookieParser, bodyParser, limit, query  (0) 2017.04.05
connect  (0) 2017.04.04

mocha

mocha는 Javascript Testing Tool이다.

Installation

$ npm install mocha --global

테스트 코드는 .spec.js로 관리하여 -w를 추가하여 실행하여 파일 변경시 자동으로 테스트 러너가 실행된다

$ mocha

test

describe()으로 테스트 suite을 만들고 그 안에 it()으로 테스트 코드를 작성한다. descirbe()은 중첩해서 사용할 수 있다.

Asynchronous

it()에 사용하는 함수에 파라미터로 done을 전달하면 자동으로 비동기 테스트로 인식하고 비동기 로직이 완료된 시점에서 파라미터로 받은 done()을 실행해 주면 테스트가 완료된다. assertion은 done()을 실행하기 전에 작성하면 됩니다. done()을 실행하지 않으면 기본 타임아웃인 2000ms후에 타임아웃 실패로 간주합니다.

done() 이라는 콜백 함수를 비동기 코드가 정상적으로 완료되었을 때 호출하면 된다. done()이 호출되지 않는다면 설정된 기본 timeout 시간으로 2ms 후에 실패로 간주된다.

before(function(){
  console.log('before');
});
 
it('test spec', function(done){
  // do the test
  console.log(1);
  done();
});
 
after(function(){
  console.log('after');
});

mocha --timeout 3000 처럼 timeout 값을 변경할 수 있다.

Hooks

테스트 케이스의 상황에 따라 실행되어야 하는 부분을 설정할 때 사용

describe('Hooks example', function() {
  before(function() {
    // 테스터들을 실행하기 전에 한번 실행하는 부분
    console.log('before');
  });
 
  after(function() {
    // 테스터들을 모두 실행하고 나서 한번 실행하는 부분
    console.log('after');
  });
 
  beforeEach(function() {
    // 각 테스터들이 실행되기 전에 실행하는 부분
    console.log('beforeEach');
  });
 
  afterEach(function() {
    // 각 테스터들이 실행된 후에 실행하는 부분
    console.log('afterEach');
  });
 
  // test case
  it('test1', function() {
    // write test logic
    console.log('1');
  });
 
  it('test2', function() {
    // write test logic
    console.log('2');
  });
});
 

결과 화면

Hooks example
before
beforeEach
1
    ✓ test1
afterEach
beforeEach
2
    ✓ test2
afterEach
after
 
 
  2 passing (8ms)


'Framework > Nodejs' 카테고리의 다른 글

이메일 발송  (0) 2017.07.13
MVC model  (0) 2017.07.07
미들웨어(1):cookieParser, bodyParser, limit, query  (0) 2017.04.05
connect  (0) 2017.04.04
FileUpload  (0) 2017.03.26

[더블릿] fac


N!의 끝에서 연속하는 0의 개수를 출력하는문제이다. 단, N! = N * (N-1) * (N-2) . . . * 3 * 2 * 1


예를들어 10! = 3628800 임으로 끝에서 연속하는0의 개수는 2이다.


입력


N이 주어진다. ( 1 <= N <= 1,000,000,000,000,000,000 )

출력


끝에서 연속하는 0의 개수를 출력한다. 단, 숫자가 너무커질수 있으므로 500,000,000,000,000,007로 나눈 나머지 값을 출력한다.

입출력 예



입력 


1


출력


0


입력


10


출력


2



입력


100


출력


24


입력


1422534662


출력


355633660


[풀이]

1! = 1

2! = 2

3! = 6

4! = 24

5! = 120    <--- 1개

6! = 720

7! = 5040

8! = 40320

9! =362880

10! = 3628800   <--- 2개

15! = 1307...000 <--- 3개

20! = 243...0000 <--- 4개

25! =1551..000000 <--- 6개


n!에서 n이 5로 나누어지면 0이 1씩 증가함을 알 수 있다.

n이 25이면 n/5 로 나누어져 5개의 0을 가지고, 추가적으로 25로 또 나누어지기 때문에 한개의 0을 가진다는 점근법을 세울 수 있다.

n이 50이면 50/5로 나누어져 10개의 0을, 추가적으로 50/25로 또 나누어지기 때문에 2개의 0을 가진다고 예측할 수 있다.


for (int i = 1; i <= 25; ++i) {

      cnt += (long long)(num / pow(5, i)) % 500000000000000007;

 }

'IT > Algorithm' 카테고리의 다른 글

[1562] 계단수  (0) 2017.09.10
[더블릿] koi 수열/series  (0) 2017.04.08

[더블릿] koi 수열/series 


우리는 양의 정수들이 나열된 수열 을 < a1 ,a2 , a3,..,an >을 구하는 다음과 같은 두 문제를 풀려고 한다.

수열의 길이는 < a1 ,a2 , a3,..,an >수열에 포함된 정수들의 개수 n 이라고 정의한다.


문제 A: 양의 정수 M 이 주어질 때, a1 + a2 + .. + an = M 을 만족하면서 a1 * a2 ...* an 의 값이 가장 크게 되는 수열 을 구하시오. 단, a1 * a2 * a3 .. * an 의 값이 가장 크게 되는 서로 다른 길이의 수열이 두 개 이상 존재할 경우, 수열의 길이 n 이 최대인 수열을 구한다.


문제 B: 양의 정수 M 이 주어질 때, a1 * a2 * ... * am = M 을 만족하면서 a1 + a2 + .. + am 의 값이 가장 작게 되는 수열 을 구하시오. 단, a1 + a2 + ... + am 의 값이 가장 작게 되는 서로 다른 길이의 수열이 두 개 이상 존재할 경우, 수열의 길이 m 이 최소인 수열을 구한다.


문제 A에서 구한 수열의 길이 n 과 문제 B에서 구한 수열의 길이 m 을 출력하는 프로그램을 작성하시오.


예를 들어, M = 6 이면, 문제 A에서 구한 수열은 < 3, 3 >이므로 이 수열의 길이는 2이고, 문제 B에서 구한 수열은 < 2, 3> 이므로 이 수열의 길이는 2이다.


입력


첫째 줄에 정수 M 이 주어진다. 1 <= M <= 1,000,000 이다.


출력


첫째 줄에 문제 A에서 구한 수열의 길이 n 과 문제 B에서 구한 수열의 길이 m 을 한 개의 빈칸을 사이에 두고 차례대로 출력한다.

입출력 예


입력


6


출력


2 2



<풀이 중>

문제 A


아직 제대로 이해가 안됬지만 3을 최대로 집어넣고 나머지를 2로 채우는 것이 최적이라고 한다..


증명을 위해 2^n 과 n^2을 비교하면


n : 1 -> 2 > 1 

n : 2 -> 4 = 4 

n : 3 -> 8 < 9             <-- 3이 2보다 효율이 좋다

n : 4 -> 16 = 16 

n : 5 -> 32 > 25 


그 다음으로, n이 4보다 크면 항상 2^n > n^2 라는 것을 알 수 있다.


---> 결국 N/3 올림값이 결과값이 된다.


경우수를 나눠 보면 


N = 3n의 경우 : 3*n -> 답은 n 

N = 3n+1의 경우 : 3*(n-1) + 2*2 -> 답은 n+1 

N = 3n+2의 경우 : 3*n + 2*1 -> 답은 n+1 



문제 B


소인수분해하면 합이 최소가 된다. 주의해야 할점은 '최단' 길이이므로 2*2=4 의 경우를 생각해줘야 한다.


예를 들어 12는 {2, 2, 3}과 {4, 3}의 선택지가 생기는데 최단 길이이므로 {4,3}의 길이인 2가 출력되야 한다.

이 이유는 2^n과 n^2가 같은 수가 유일하게(?) 2이기 때문이다. 이 경우만 예외로 처리해주면 올바른 출력값을 얻을 수 있다.


32같은 경우는 {2, 2, 2, 2, 2} 와 {4, 4, 2}가 될 수 있고 최단길이 이므로 3이 출력되야 한다.


소스

#include <stdio.h>

#pragma warning(disable:4996)


int n;

int num1;

int num2;


int main() {

int temp;


scanf("%d", &n);


//문제 A

if (n % 3 == 0) {

num1 = n/3;

}

else if (n % 3 == 1) {

num1 = n / 3 + 1;

}

else {

num1 = n / 3 + 1;

}

//문제 B

temp = n;

  

  // 2*2 = 4인 경우를 처리해주기 위해 먼저 4로 나누어줄 수 있는 만큼 나누어준다.

while (temp % 4 == 0) {

temp = temp / 4;

num2++;

}


for (int i = 2; i < n; i++) {

while (temp%i == 0) {

temp = temp / i;

num2++;

}

if (temp == 1)

break;

}

printf("%d %d", num1, num2);


return 0;

}


'IT > Algorithm' 카테고리의 다른 글

[1562] 계단수  (0) 2017.09.10
[더블릿] fac  (0) 2017.04.08

쿠키와 요청본문, 쿼리 스트링을 해석하는 미들웨어

cookieParser()

웹 브라우저의 쿠키를 해석해 req.cookies에 넣는다.

var express = require('express');
var cookieParser = require('cookie-parser');
 
var app = express();
app.use(cookieParser());
 
app.get('/', function (req, res) {
  // Cookies that have not been signed
  console.log('Cookies: ', req.cookies);
 
  // Cookies that have been signed
  console.log('Signed Cookies: ', req.signedCookies);
})
 
app.listen(3000, function(req, res) {
  console.log("running on 3000 port");
});

cookie response setting

res.setHeader('Set-Cookie', 'foo=bar');
res.setHeader('Set-Cookie', 'tobi=feert');
res.end();

req.signedCookies(서명된 쿠키)

//req.signedCookies에 {name : value} 추가
res.cookie('name', 'value', {signed:true});
 
//req.cookies에 {name : value} 추가
res.cookie('name', 'value', {signed:false});

bodyParser()

요청 본문을 받아서 해석해 req.body에 넣는다.

var express = require('express')
var bodyParser = require('body-parser')
 
var app = express()
 
// create application/json parser
var jsonParser = bodyParser.json()
 
// create application/x-www-form-urlencoded parser
var urlencodedParser = bodyParser.urlencoded({ extended: false })

bodyParser.urlencodeed :
url 인코딩된 본문만을 parse하는 미들웨어를 반환, x-www-form-urlencoded parser 임을 명시
기본값은 true이지만 더이상 사용되지 않는다.

app.use(bodyParser.urlencoded({ extended: false }))

top-level middleware(모든 요청에 body 구문을 parse한다)

var express = require('express')
var bodyParser = require('body-parser')
 
var app = express()
 
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
 
// parse application/json
app.use(bodyParser.json())
 
app.use(function (req, res) {
  res.setHeader('Content-Type', 'text/plain')
  res.write('you posted:\n')
  res.end(JSON.stringify(req.body, null, 2))
})
 
app.listen(3000);

express4.x부터 body-parser 미들웨어의 multipart 기능 불가능해짐
connect-multipart 등 미들웨어 사용

limit()

bodyParser()와 같이 사용해서 요청이 커지지 않게 제한한다.

예시를 위해 bodyPaser 미들웨어에 multipart(업로드 및 form-data파싱)을 추가하가 위해 connect-multiparty 미들웨어를 사용

var fs = require('fs');
var express = require('express');
var multiparty = require('connect-multiparty');
var multipartMiddleware = multiparty();
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
 
var app = express();
 
app.use(cookieParser());
app.use(bodyParser.json({limit: '1mb'}));
//업로드하여 저장할 디렉토리 지정(디렉토리가 존재하여야 한다.)
app.use(multiparty({uploadDir : __dirname + '/multipart'}));
 
app.get('/', function(req, res) {
  fs.readFile('index.html', function(err, data) {
    res.send(data.toString());
  })
});
 
app.post('/', function(req, res) {
  console.log(req.body);
  console.log(req.files);
 
  res.redirect('/');
});
 
app.listen(3000, function() {
  console.log('server running on 3000 port');
})

limit가 필요한 이유 :
악의적인 사용자가 HTTP 클라이언트를 사용해 대량의 파일 데이터를 만들어서 공격하는 것을 방지

var express = require('express');
var http = require('http');
var app = express();
 
var req = http.request({
  method: 'POST',
  port:3000,
  headers: {
    'Content-Type': 'application/json'
  }
});
 
req.write('[');
var n = 30000000;
while(n--) {
  req.write('"foo",');
}
req.write('"bar"]');
 
req.end();

query()

요청 URL 쿼리 스트링을 req.query에 넣는다.

app.use(function (req, res) {
  res.setHeader('Content-Type', 'text/plain')
  res.write('you posted:\n')
  res.end(JSON.stringify(req.query));
})

localhost:3000?query=query_data 로 url 호출시 {"query":"query_data"}가 출력된다.

'Framework > Nodejs' 카테고리의 다른 글

이메일 발송  (0) 2017.07.13
MVC model  (0) 2017.07.07
mocha  (0) 2017.07.05
connect  (0) 2017.04.04
FileUpload  (0) 2017.03.26

커넥트

노드는 기본적으로 HTTP 모듈을 가지고 있고, Connect는 HTTP 모듈에 여러 플러그인을 추가할 수 있는 미들웨어 프레임워크이다. Express는 Connect를 내장하고 있는 웹 프레임워크이다.

  • 커넥트 애플리케이션 준비

    var connect = require('connect');
    var app = connect();
    app.listen(3000);
  • 커넥트 미들웨어 동작방식
    커넥트에서 미들웨어 컴포넌트는 req, res, next() 세 인자를 가진다.

    function logger(req, res, next) {
      consloe.log('%s %s', req.method, req.url);
      next();
    }

    next()를 실행해 디스패처에 제어를 넘겨준다.

    var connect = require('connect');
    var app = connect();
    app.use(logger);
    app.listen(3000);
  • 미들웨어 순서의 중요성

    function logger(req, res, next) {
      consloe.log('%s %s', req.method, req.url);
      next();
    }
    function hello(req, res) {
      res.setHeader('Content-Type', 'text/plain');
      res.end('hello world');
    }
    connect().use(logger).use(hello).listen(3000);

    미들웨어 순서는 인증과 같은 경우에 사용하면 좋다

    connect()
      .use(looger)
      .use(restrictFileAccess)
      .use(serveStaticFiles)
      .use(hello)

'Framework > Nodejs' 카테고리의 다른 글

이메일 발송  (0) 2017.07.13
MVC model  (0) 2017.07.07
mocha  (0) 2017.07.05
미들웨어(1):cookieParser, bodyParser, limit, query  (0) 2017.04.05
FileUpload  (0) 2017.03.26

FileUpload

body-parser는 파일을 업로드하는 경우에 json과 urlencoded 양식 제출만 처리한다. multi-part를 처리하기 위해서 connect-busboy 모듈을 사용하였다.

주의해야 할 점은 이미지를 저장하고자 하는 폴더가 경로에 있어야한다.

var express = require('express');
var fs = require('fs');
// var bodyParser = require('body-parser');
var busboy = require('connect-busboy');
var app = express();
 
// app.use(bodyParser.urlencoded({extended: false}));
app.use(busboy());
 
app.listen(3303, function() {
  console.log("Server Start");
});
 
app.get('/', function(req, res) {
  fs.readFile('index.html', function(err, data) {
    res.writeHead(200, { 'Content-Type': 'text/html'});
    res.end(data, function(error) {
      console.log(error);
    })
  })
})
 
app.post('/upload', function(req, res) {
  var fstream;
  req.pipe(req.busboy);
  req.busboy.on('file', function(fieldname, file, filename) {
    console.log("Uploading: " + filename);
    fstream = fs.createWriteStream(__dirname + '/files/' + filename);
    file.pipe(fstream);
    fstream.on('close', function() {
      res.redirect('back');
    });
  });
});


'Framework > Nodejs' 카테고리의 다른 글

이메일 발송  (0) 2017.07.13
MVC model  (0) 2017.07.07
mocha  (0) 2017.07.05
미들웨어(1):cookieParser, bodyParser, limit, query  (0) 2017.04.05
connect  (0) 2017.04.04

+ Recent posts