2015년 6월 15일 월요일

Jade script] Node.js의 jade방식으로 페이지 작성시 select box, radio 버튼을 만드는 script

Node.js의 jade방식으로 페이지 작성시 select box, radio, check 버튼을 만드는 script
1. select script
                        select#tel1(name="tel1")
                            - repeations = ['010', '011', '016', '017', '018', '019']
                            - for item in repeations
                                option #{item}

2. radio script
                        input#gender(type="radio", name="gender")
                        | 남
                        input#gender(type="radio", name="gender")
                        | 여

3. check script
input#JobType(type="checkbox", name="JobType" checked)
| 정규직
input#JobType(type="checkbox", name="JobType")
| 계약직
input#JobType(type="checkbox", name="JobType")
| 인턴직


% 아래와 같이 radio와 값을 한줄로 코딩시 아래와 같은 오류(input is self closing and should not have content.) 발생함.


이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

2015년 6월 4일 목요일

Mac, Node.js 학습 9일차] Express framework

Express framework은  Express 모듈로 만든 framework다. 프로젝트를 손쉽게 만들어주고 기본적인 뷰와 세션을 지원한다.

1. 설치 
  * 4. x 설치 명령어
  baesunghan:~/Documents/workspace/nodejs$sudo npm install -g express-generator
Password:
/usr/local/bin/express -> /usr/local/lib/node_modules/express-generator/bin/express
express-generator@4.12.1 /usr/local/lib/node_modules/express-generator
├── sorted-object@1.0.0
├── commander@2.6.0
└── mkdirp@0.5.0 (minimist@0.0.8)
baesunghan:~/Documents/workspace/nodejs$

2. HelloExpress Project 생성
현재 디렉토리에 HelloExpress 가 만들어지고 아래와 같이 구성된다.
baesunghan:~/Documents/workspace/nodejs$express HelloExpress

  
create : HelloExpress
  
create : HelloExpress/package.json
  
create : HelloExpress/app.js
  
create : HelloExpress/public
  
create : HelloExpress/public/javascripts
  
create : HelloExpress/public/images
  
create : HelloExpress/public/stylesheets
  
create : HelloExpress/public/stylesheets/style.css
  
create : HelloExpress/routes
  
create : HelloExpress/routes/index.js
  
create : HelloExpress/routes/users.js
  
create : HelloExpress/views
  
create : HelloExpress/views/index.jade
  
create : HelloExpress/views/layout.jade
  
create : HelloExpress/views/error.jade
  
create : HelloExpress/bin
  
create : HelloExpress/bin/www

   install dependencies:
     $ cd HelloExpress && npm install

   run the app:
     $ DEBUG=HelloExpress:* ./bin/www
baesunghan:~/Documents/workspace/nodejs$

3. Dependency를 가진 모듈 설치를 위해서 명령실행

baesunghan:~/Documents/workspace/nodejs$cd HelloExpress && npm install

4. 생성된 HelloExpress 실행

baesunghan:~/Documents/workspace/nodejs/HelloExpress$DEBUG=HelloExpress:* ./bin/www
or
baesunghan:~/Documents/workspace/nodejs/HelloExpress$npm start

5. 페이지 렌더링
jade, ejs 방식으로 페이지를 작성해서 표현할 수 있다.
- app.js : jade로 페이지를 렌드링 하도록 설정
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

- index.js : index.jade 파일을 읽어서 페이지를 렌드링한다. 이때 파라메타로 title과 query로 조회된 list를 rows변수로 넘겨준다.
var express = require('express');
var router = express.Router();

// load MySql
var mysql = require('mysql');
var pool = mysql.createPool({
    connectionLimit: 3,
    user: 'test',
    password: 'test',
    database: 'test'
});

/* GET 게시판 전체 리스트. */
router.get('/', function(req, res, next) {
  res.redirect('/board/list/1');
});

router.get('/list/:page', function(req, res, next) {
    pool.getConnection(function(err, conn) {
        var selectList = "SELECT  idx, creator_id, title, date_format(modidate, '%Y-%m-%d %H:%i:%s') modidate, hit from board";
        conn.query(selectList, function(err, rows) {
            if (err) console.error("err : " + err);

            console.log("rows : " + JSON.stringify(rows));
            res.render('index', {title: '게시판 전체 글 조회', rows:rows});
            conn.release();
        });
    });
});

- index.jade : jade 문법과 index.js에서 넘겨준 파라메타 값을 렌드링시에 출력한다. 참고로 extends  layout 을 통해서 layout.jade 를 같이 렌드링해서 페이지를 만든다.
extends layout

block content
  h1= title
  a(href="/board/write") 글쓰기로 이동
  br
  br
  table(border="1")
    tr
      td 번호
      td 작성자
      td 제목
      td 조회수
      td 변경일
    - for item in rows
      tr
        td= item.idx
        td= item.creator_id
        td
          a(href="/board/read/#{item.idx}")= item.title
        td= item.hit
        td= item.modidate

- layout.jade 
doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
    script(src="/javascripts/jquery-1.11.2.min.js")
  body
    block content

<수행 결과>
이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

Mac, Node.js 학습 8일차] MySql을 이용한 데이터 입력, 수정, 삭제 처리


1. MySQL에 products 테이블 생성 및 데이터 입력

create table products (
    id int not null auto_increment primary key,
    name varchar(50) not null,
    modelnumber varchar(15) not null,
    series varchar(30) not null
);


insert into products (name, modelnumber, series) values('Eric', '01123345', 'Artist');
insert into products (name, modelnumber, series) values('Tom', '01098271134', 'Architect');


2. 필요 Package 설치

baesunghan:~/Documents/workspace/nodejs/exam_mysql$npm install express && npm install ejs && npm install mysql
express@4.12.3 ../node_modules/express
├── merge-descriptors@1.0.0
├── utils-merge@1.0.0
├── cookie-signature@1.0.6
├── methods@1.1.1
├── fresh@0.2.4
├── cookie@0.1.2
├── escape-html@1.0.1
├── range-parser@1.0.2
├── content-type@1.0.1
├── finalhandler@0.3.4
├── vary@1.0.0
├── parseurl@1.3.0
├── content-disposition@0.5.0
├── path-to-regexp@0.1.3
├── depd@1.0.1
├── qs@2.4.1
├── on-finished@2.2.1 (ee-first@1.1.0)
├── debug@2.1.3 (ms@0.7.0)
├── etag@1.5.1 (crc@3.2.1)
├── send@0.12.2 (destroy@1.0.3, ms@0.7.0, mime@1.3.4)
├── proxy-addr@1.0.8 (forwarded@0.1.0, ipaddr.js@1.0.1)
├── serve-static@1.9.3 (send@0.12.3)
├── type-is@1.6.2 (media-typer@0.3.0, mime-types@2.0.11)
└── accepts@1.2.7 (negotiator@0.5.3, mime-types@2.0.11)
ejs@2.3.1 ../node_modules/ejs
mysql@2.6.2 ../node_modules/mysql
├── require-all@1.0.0
├── bignumber.js@2.0.7
└── readable-stream@1.1.13 (isarray@0.0.1, inherits@2.0.1, string_decoder@0.10.31, core-util-is@1.0.1)
baesunghan:~/Documents/workspace/nodejs/exam_mysql$ npm install body-parser


3. 리스트 표시를 위한 list.html 작성

<!DOCTYPE html>
<html>
<head>
    <title>List Page</title>
</head>
<body>
    <h1>List Page</h1>
    <a href="/insert">Insert Data</a>
    <hr />
    <table width="100%" border="1">
        <tr>
            <th>DELETE</th>
            <th>EDIT</th>
            <th>ID</th>
            <th>Name</th>
            <th>Model Number</th>
            <th>Series</th>
        </tr>
        <% data.forEach(function (item, index) { %>
        <tr>
            <td><a href="/delete/<%= item.id %>">DELETE</a></td>
            <td><a href="/edit/<%= item.id %>">EDIT</a></td>
            <td><%= item.name %></td>
            <td><%= item.modelnumber %></td>
            <td><%= item.series %></td>
        </tr>
        <%    }); %>
    </table>
</body>
</html>


4. 서비스 실행을 위한 app.js 모듈 작성

// 모듈을 추출
var fs = require('fs');
var ejs = require('ejs');
var http = require('http');
var mysql = require('mysql');
var express = require('express');
var bodyParser = require('body-parser');

// Mysql과 연결
var client = mysql.createConnection ({
    user : 'test',
    password : 'test',
    database : 'test'
});

// 서버 생성
var app = express();
// create application/json parser
var jsonParser = bodyParser.json()

// create application/x-www-form-urlencoded parser
var urlencodedParser = bodyParser.urlencoded({ extended: false })


// 서버 실행
http.createServer(app).listen(18585, function() {
    console.log('server running at http://localhost:18585');
});


5. 리스트 조회를 위한 app.js 모듈 작성

// router를 수행해서 페이지 분기
// 리스트 조회
app.route('/')
    .get(function(req, res, next) {
        getList(req,res,next);
    })
    .post(function(req, res, next) {
        getList(req,res,next);
    });

function getList(req, res, next) {
    // list.html을 읽음
    fs.readFile('list.html', 'utf-8', function(error, data){
        // mysql 에서 데이터 query
        client.query('SELECT * FROM products', function (error, results) {
            // 결과 리턴
            res.send(ejs.render(data, {
                data : results
            }));
        });
    });
};


  - list.html 작성
<!DOCTYPE html>
<html>
<head>
    <title>List Page</title>
</head>
<body>
    <h1>List Page</h1>
    <a href="/insert">Insert Data</a>
    <hr />
    <table width="100%" border="1">
        <tr>
            <th>DELETE</th>
            <th>EDIT</th>
            <th>ID</th>
            <th>Name</th>
            <th>Model Number</th>
            <th>Series</th>
        </tr>
        <% data.forEach(function (item, index) { %>
        <tr>
            <td><a href="/delete/<%= item.id %>">DELETE</a></td>
            <td><a href="/edit/<%= item.id %>">EDIT</a></td>
            <td><%= item.id %></td>
            <td><%= item.name %></td>
            <td><%= item.modelnumber %></td>
            <td><%= item.series %></td>
        </tr>
        <%    }); %>
    </table>
</body>
</html>


  - list 페이지

2. Insert/update/delete 를 위한  app.js 모듈 작성


app.route('/edit/:id')
    .get(function(req, res, next) {
        console.log('id : %s', req.param('id'));
        fs.readFile('edit.html', 'utf-8', function(error, data){
            client.query('SELECT * FROM products WHERE id = ?', [req.param('id')], function(error, result) {
                // 응답
                res.send(ejs.render(data, { data : result[0]}));
            });
        });
    })
    .post(urlencodedParser, function(req, res, next) {
        var body = req.body;
        // body.id is undefined. Then use req.param('id')
        console.log('id : %s, %s', body.id, req.param('id'));

        client.query('UPDATE products SET name = ?, modelnumber = ?, series = ? WHERE id = ?', 
            [body.name, body.modelnumber, body.series, req.param('id')], function() {
            res.redirect('/');
        });
    });

app.route('/insert')
    .get(function(req, res, next) {
        fs.readFile('insert.html', 'utf-8', function(error, data) {
            res.send(data);
        })
    })
    .post(urlencodedParser, function(req, res, next) {
        console.log('insert post');
        var body = req.body;
        console.log('body : ' + req.body.name);
        client.query('INSERT INTO products (name, modelnumber, series) VALUES (?, ?, ?)', [
            body.name, body.modelnumber, body.series], function() {
                res.redirect('/');
            });
    });


  - insert.html 작성
<!DOCTYPE html>
<html>
<head>
    <title> Insert Page</title>
</head>
<body>
    <h1>Insert Page</h1>
    <hr />
    <form method="post">
        <fieldset>
            <legend>Insert Data</legend>
            <table>
                <tr>
                    <td><label>Name</label></td>
                    <td><input type="text" name="name" /></td>
                </tr>
                <tr>
                    <td><label>ModelNumber</label></td>
                    <td><input type="text" name="modelnumber" /></td>
                </tr>
                <tr>
                    <td><label>Series</label></td>
                    <td><input type="text" name="series" /></td>
                </tr>
            </table>
            <input type="submit" />
        </fieldset>
    </form>
</body>
</html>

  - edit.html 작성

<!DOCTYPE html>
<html>
<head>
    <title> Edit Page</title>
</head>
<body>
    <h1>Edit Page</h1>
    <hr />
    <form method="post">
        <fieldset>
            <legend>Edit Data</legend>
            <table>
                <tr>
                    <td><label>ID</label></td>
                    <td><input type="text" name="id" value="<%= data.id %>" disabled/></td>
                </tr>
                <tr>
                    <td><label>Name</label></td>
                    <td><input type="text" name="name" value="<%= data.name %>"/></td>
                </tr>
                <tr>
                    <td><label>ModelNumber</label></td>
                    <td><input type="text" name="modelnumber"  value="<%= data.modelnumber %>"/></td>
                </tr>
                <tr>
                    <td><label>Series</label></td>
                    <td><input type="text" name="series"  value="<%= data.series %>"/></td>
                </tr>
            </table>
            <input type="submit" />
        </fieldset>
    </form>
</body>
</html>




* 참고하는 책에서는 express의 router에 대한 로직을  3.x로 작성되어 서비스 실행시 "app.router" is deprecated오류가 발생함

이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

Mac, Node.js 학습 7일차] 서버 실행 모듈

* 전역 모듈 - 서버 실행 모듈 
  - supervisor : js 파일의 변경을 자동으로 인식해서 실행중인 서비스를 종료 후 다시 실행한다.
  - forever : exception으로 서비스가 중단되는 것을 다시 실행한다.
  - express : http 모듈을 쉽게 사용하도록 지원하는 모듈 

1. supervisor 모듈
js 파일의 변경을 자동으로 인식해서 실행중인 서비스를 종료 후 다시 실행한다.

- 모듈 설치 방법

baesunghan:~/Documents/workspace/nodejs$sudo npm install -g supervisor
Password:
/usr/local/bin/node-supervisor -> /usr/local/lib/node_modules/supervisor/lib/cli-wrapper.js
/usr/local/bin/supervisor -> /usr/local/lib/node_modules/supervisor/lib/cli-wrapper.js
supervisor@0.6.0 /usr/local/lib/node_modules/supervisor
baesunghan:~/Documents/workspace/nodejs$

- 사용 방법

baesunghan:~/Documents/workspace/nodejs$supervisor test.supervisor.js

Running node-supervisor with
  program 'test.supervisor.js'
  --watch '.'
  --extensions 'node,js'
  --exec 'node'

Starting child process with 'node test.supervisor.js'
Watching directory '/Users/baesunghan/Documents/workspace/nodejs' for changes.
Server running at http://127.0.0.1:52273/

   ==> test.supervisor.js 가 변경된 것을 감지하여 자동으로 재 시작한다.
crashing child
Starting child process with 'node test.supervisor.js'
Server running at http://127.0.0.1:52273/


* 주의사항 
  서비스의 오류로 인해 서비스가 다운되도 계속 다시 수행하므로 주의해야 한다.

2. forever  모듈
Exception으로 서비스가 중지되어도 다시 시작하도록 하는 예외처리 모듈

- 모듈 설치

baesunghan:~/Documents/workspace/nodejs/exam_mysql$sudo npm instal -g forever
Password:
/usr/local/bin/forever -> /usr/local/lib/node_modules/forever/bin/forever

- 사용 방법

baesunghan:~/Documents/workspace/nodejs/exam_mysql$forever stat app.js
baesunghan:~/Documents/workspace/nodejs/exam_mysql$forever listinfo:    No forever processes running
baesunghan:~/Documents/workspace/nodejs/exam_mysql$
baesunghan:~/Documents/workspace/nodejs/exam_mysql$forever stop 0

3. Express 모듈
http 모듈을 쉽게 사용하도록 지원하는 모듈 
- Express 모듈의 미들웨어
  • logger : 로그 정보 출력
  • csrf : CSRF 보안 수행
  • basicAuth : 기본 인증 수행
  • bodyParser : POST 요청 매개변수 추출
  • cookieParser : Cookie 분해
  • session : 세션 처리
  • methodOverride : 다양한 요청 방식 수행
  • responseTime : 응답시간 계산
  • router : 페이지 라우트 수행
  • staticCache : static 미들웨어를 위한 메모리 캐시 
  • static : 특정 폴더를 서버의 루트 폴더로 올려서 path 지정이 간편하게 함.
  • directory : 서버의 디렉토리 구조를 보여줌
  • vhost : 가상 호스트 설정
  • favicon : 파비콘 생성
  • limit : POST  요청 데이터 제한
  • errorHandler : 예외처리 수행

위와 같이 다양한 미들웨어가 있지만, 많이 사용하게 되는 것은 router, static, bodyParser 이 있다.

<사용 예제>
- app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);
app.use('/join', join);


- index.js
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

module.exports = router;




이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

2015년 6월 3일 수요일

Jade  오류 : Failed to lookup view "error" in views directory "/Users/baesunghan/git/dentalJobs/views"

- 발생현상
node.js에서 .jade render시 발생 오류

Error: Failed to lookup view "error" in views directory "/Users/baesunghan/git/dentalJobs/views"
   at EventEmitter.app.render (/Users/baesunghan/git/dentalJobs/node_modules/express/lib/application.js:555:17)
   at ServerResponse.res.render (/Users/baesunghan/git/dentalJobs/node_modules/express/lib/response.js:938:7)
   at /Users/baesunghan/git/dentalJobs/app.js:55:7
   at Layer.handle_error (/Users/baesunghan/git/dentalJobs/node_modules/express/lib/router/layer.js:58:5)
   at trim_prefix (/Users/baesunghan/git/dentalJobs/node_modules/express/lib/router/index.js:300:13)
   at /Users/baesunghan/git/dentalJobs/node_modules/express/lib/router/index.js:270:7
   at Function.proto.process_params (/Users/baesunghan/git/dentalJobs/node_modules/express/lib/router/index.js:321:12)
   at IncomingMessage.next (/Users/baesunghan/git/dentalJobs/node_modules/express/lib/router/index.js:261:10)
   at fn (/Users/baesunghan/git/dentalJobs/node_modules/express/lib/response.js:933:25)
   at EventEmitter.app.render (/Users/baesunghan/git/dentalJobs/node_modules/express/lib/application.js:557:14)

.jade 파일
  => jade 문법에는 이상이 없어 보임
doctype html
html
    head
        title #{title}
    body
        h1 #{title}
        form#joinForm
            div
                table(width="400px", border="1")    
            input#id(type="text", size="12" maxlength="12") 


- 발생원인
아래와 같이 table에서 뒤에 탭이 있어 발생한 오류임. 공백은 오류가 발생하지 않음.

- 해결방법
뒤에 있는 탭을 없앤다.



이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.