Presentation is loading. Please wait.

Presentation is loading. Please wait.

데이터베이스 사용하기 6장 Do it! Node.js 프로그래밍 이지스퍼블리싱 제공 강의 교안 2017/03

Similar presentations


Presentation on theme: "데이터베이스 사용하기 6장 Do it! Node.js 프로그래밍 이지스퍼블리싱 제공 강의 교안 2017/03"— Presentation transcript:

1 데이터베이스 사용하기 6장 Do it! Node.js 프로그래밍 이지스퍼블리싱 제공 강의 교안 2017/03
○ 본 강의 자료는 이지스퍼블리싱에서 제공하는 강의 교안입니다. ○ 본 강의 교안은 아래 출판 서적의 내용을 기준으로 구성되었습니다. 또한 다수의 기타 서적이나 사이트를 참조하였습니다. 레퍼런스를 참조하십시오. 2017, 정재곤, “Do it! Node.js 프로그래밍 (개정판)”, 이지스퍼블리싱 - 강의 교안에 사용된 화면 캡처나 실습 자료의 경우에는 문서 업데이트에 따라 변경될 수 있습니다.

2 강의 주제 및 목차 데이터베이스 사용하기 강의 주제 목 차 몽고디비 시작하기 익스프레스에서 몽고디비 사용하기
목 차 1 몽고디비 시작하기 2 익스프레스에서 몽고디비 사용하기 3 몽구스로 데이터베이스 다루기 4 인덱스와 메소드 사용하기 5 비밀번호 암호화하여 사용하기 6 MySQL 데이터베이스 사용하기

3 1. 몽고디비 시작하기 난이도 소요시간 20분

4 몽고디비란? 노드에서는 Oracle, MySQL과 같은 관계형 데이터베이스를 사용할 수도 있고 NoSQL도 사용할 수 있음

5 몽고디비의 기본 구조 관계형 데이터베이스의 테이블  컬렉션(Collection), 레코드  문서 객체(Document)
하나의 컬렉션 안에 다양한 자료형의 데이터가 들어갈 수 있음 (스키마 없음)

6 몽고디비 설치 사이트에서 다운로드받아 설치

7 Path 시스템 변수에 추가 후 실행 Path 시스템 변수에 몽고디비 설치 폴더 아래의 bin 폴더 추가
윈도우 사용자 계정 폴더 아래에 database/local 폴더 생성 명령프롬프트 창에서 mongod 명령어로 실행 % mongod --dbpath /Users/user/database/local

8 몽고디비에 데이터 추가하고 조회하기 Mongo 명령어로 셸로 들어간 후 명령어 실행 가능 use 명령어로 DB 연결
% use local % db.users.insert({“name”:“소녀시대”,“age”:20}) % db.users.find().pretty()

9 몽고디비에 데이터 추가하고 조회하는 방식 insert 로 추가하고 find 로 조회

10 2. 익스프레스에서 몽고디비 사용하기 난이도 소요시간 30분

11 새로운 프로젝트 폴더 만들기 DatabaseExample 이라는 이름의 새로운 프로젝트 폴더 생성
브라켓에서 폴더 열기 메뉴를 이용해 프로젝트 폴더 지정하고 app.js 파일 생성 // Express 기본 모듈 불러오기 var express = require('express') , http = require('http') , path = require('path'); // Express의 미들웨어 불러오기 var bodyParser = require('body-parser') , cookieParser = require('cookie-parser') , static = require('serve-static') , errorHandler = require('errorhandler'); // 오류 핸들러 모듈 사용 var expressErrorHandler = require('express-error-handler'); // Session 미들웨어 불러오기 var expressSession = require('express-session'); // 익스프레스 객체 생성 var app = express(); …….

12 이전 장에서 입력했던 코드 실행 확인 app.js 파일이 동작하도록 코드 입력
package.json 파일 생성 및 외장 모듈 설치 후 실행하여 문제없는지 확인 % npm install express --save % npm install http --save % npm install path --save % npm install body-parser --save % npm install cookie-parser --save % npm install serve-static --save % npm install errorhandler --save % npm install express-error-handler --save % npm install express-session --save % npm install mongodb --save

13 mongodb 모듈 사용하기 mongodb 모듈을 사용하면 몽고디비 데이터베이스에 연결한 후 데이터 추가, 조회 등 가능
로그인 기능 만들어보기 위해 public 폴더 안에 login.html 파일 생성 <form method="post" action="/process/login"> <table> <tr> <td><label>아이디</label></td> <td><input type="text" name="id" /></td> </tr> <td><label>비밀번호</label></td> <td><input type="password" name="password" /></td> </table> <input type="submit" value="전송" name="" /> </form>

14 데이터베이스에 데이터 추가 서버 실행 node app.js insert 명령어를 이용해 데이터 추가 % cls
% use local % db.users.remove({"name":/소녀/}) % db.users.find().pretty() % db.users.insert({"id" : "test01" , "name" : "소녀시대", "password" : "123456"})

15 mongodb 모듈 설치하고 데이터베이스 연결
// 몽고디비 모듈 사용 var MongoClient = require('mongodb').MongoClient; var database; function connectDB() { // 데이터베이스 연결 정보 var databaseUrl = 'mongodb://localhost:27017/shopping'; // 데이터베이스 연결 MongoClient.connect(databaseUrl, function(err, db) { if(err) throw err; console.log('데이터베이스에 연결되었습니다. : ' + databaseUrl); // database 변수에 할당 database = db; }); } % npm install mongodb —save

16 웹 서버가 시작되면 데이터베이스 연결 웹 서버 시작 후 데이터베이스 연결하도록 코드 추가
//===== 서버 시작 =====// http.createServer(app).listen(app.get('port'), function() { console.log('서버가 시작되었습니다. 포트 : ' + app.get('port')); // 데이터베이스 연결 connectDB(); }); mongodb://%IP정보%:%포트정보%/%데이터베이스이름%

17 아이디, 비밀번호 조회 함수 추가 authUser라는 이름의 함수를 만들고 데이터베이스에서 조회하도록 코드 작성
var authUser = function(database, id, password, callback) { console.log('authUser 호출됨.'); var users = database.collection('users'); users.find({"id" : id, "password" : password}).toArray(function(err, docs) { if(err) { callback(err, null); return; } if(docs.length > 0) { console.log('아이디 [%s], 비밀번호 [%s]가 일치하는 사용자 찾음.', id, password); callback(null, docs); } else { console.log("일치하는 사용자를 찾지 못함."); callback(null, null);

18 라우팅 함수 추가 클라이언트가 보내온 파라미터를 데이터베이스에서 조회한 값과 비교 // 라우터 객체 참조
var router = express.Router(); ……. router.route('/process/login').post(function(req, res) { console.log('/process/login 호출됨.'); var paramId = req.body.id || req.query.id; var paramPassword = req.body.password || req.query.password; if(database) { authUser(database, paramId, paramPassword, function(err, docs) { if(err) {throw err;} if(docs) { console.dir(docs); // 라우터 객체 등록 app.use('/', router);

19 몽고디비에 연결한 후 문서 객체를 찾아내는 과정
데이터베이스 연결  컬렉션 참조  문서 객체 찾기

20 웹브라우저에서 요청 후 서버쪽에 출력된 내용 확인
웹브라우저에서 요청하면 데이터베이스에서 조회한 결과 출력됨

21 사용자 추가 기능 만들기 사용자 인증 기능을 만드는 과정과 동일한 순서로 만들 수 있음
app.js 파일 복사하여 app2.js 파일 만들고 addUser 함수 추가 var addUser = function(database, id, password, name, callback) { console.log('addUser 호출됨.'); var users = database.collection('users'); // id, password, username을 사용해 사용자 추가 users.insertMany([{"id":id, "password":password, "name":name}], function(err, result) { if (err) { // 오류가 발생했을 때 콜백 함수를 호출하면서 오류 객체 전달 callback(err, null); return; } if (result.insertedCount > 0) { console.log("사용자 레코드 추가됨 : " + result.insertedCount); } else { console.log("추가된 레코드가 없음."); callback(null, result);

22 라우팅 함수 추가 사용자를 추가하기 위한 라우팅 함수추가
router.route('/process/adduser').post(function(req, res) { console.log('/process/adduser 호출됨.'); var paramId = req.body.id || req.query.id; var paramPassword = req.body.password || req.query.password; var paramName = req.body.name || req.query.name; if(database) { addUser(database, paramId, paramPassword, paramName, function(err, result) { if(err) {throw err;} // 결과 객체 확인하여 추가된 데이터 있으면 성공 응답 전송 if (result && result.insertedCount > 0) { console.dir(result); res.writeHead('200', {'Content-Type':'text/html;charset=utf8'}); res.write('<h2>사용자 추가 성공</h2>'); res.end();

23 웹페이지 작성 public 폴더 안에 adduser.html 파일 작성
<form method="post" action="/process/adduser"> <table> <tr> <td><label>아이디</label></td> <td><input type="text" name="id" ></td> </tr> <td><label>비밀번호</label></td> <td><input type="password" name="password" ></td> <td><label>사용자명</label></td> <td><input type="text" name="name" ></td> </table> <input type="submit" value="전송" name="" > </form>

24 웹브라우저에서 요청 후 서버쪽에 출력된 내용 확인
웹브라우저에서 요청하면 데이터베이스에서 사용자 추가한 결과 출력됨

25 데이터베이스 관리도구 사용하기 로보몽고(robomongo)를 설치하여 사용

26 3. 몽구스로 데이터베이스 다루기 난이도 소요시간 30분

27 스키마를 지원하는 mongoose 모듈 var mongoose = require('mongoose');
컬렉션 안에 같은 자료형의 객체를 넣는 방법 제공 var mongoose = require('mongoose'); % npm install mongoose --save 메소드 이름 설명 connect(uri(s), [options], [callback]) mongoose를 사용해 데이터베이스에 연결합니다. 연결 후에는 mongoose.connection 객체를 사용해 연결 관련 이벤트를 처리할 수 있습니다. Schema( ) 스키마를 정의하는 생성자입니다. model(name, [schema], [collection], [skipInit]) 모델을 정의합니다. [collection]이 지정되면 이 컬렉션을 사용하며, 지정하지 않으면 name으로 유추한 컬렉션을 사용합니다.

28 몽구스를 이용한 데이터베이스 연결 mongoose 모듈을 이용해 먼저 데이터베이스에 연결
connect() 메소드로 연결하고 on() 메소드를 이용해 연결되었는지 여부 확인 var database; var UserSchema; var UserModel; function connectDB() { var databaseUrl = 'mongodb://localhost:27017/local'; // 데이터베이스 연결 console.log('데이터베이스 연결을 시도합니다.'); mongoose.Promise = global.Promise; mongoose.connect(databaseUrl); database = mongoose.connection; database.on('error', console.error.bind(console, 'mongoose connection error.')); database.on('open', function () { console.log('데이터베이스에 연결되었습니다. : ' + databaseUrl);

29 데이터베이스 연결 후 스키마와 모델 정의 Schema() 메소드로 스키마를 정의하고 model() 메소드로 모델 정의
database.on('open', function() { console.log('데이터베이스에 연결되었습니다. : ' + databaseUrl); // 스키마 정의 UserSchema = mongoose.Schema({ id: String, name: String, password: String }); console.log('UserSchema 정의함.'); // User 모델 정의 UserModel = mongoose.model("users", UserSchema); console.log('users 정의함.');

30 데이터베이스의 이벤트와 스키마 타입 데이터베이스의 이벤트는 open, error, disconnected 등 있음.
스키마 타입에는 String, Number, Array, Date 등이 있음 스키마 타입 설명 String 문자열 타입 Number 숫자 타입 Boolean 이진 타입 Array 배열 타입 Buffer 버퍼 타입 바이너리 데이터를 저장할 수 있습니다. Date 날짜 타입 ObjectId 각 문서(Document)마다 만들어지는 ObjectId를 저장할 수 있는 타입 Mixed 혼합 타입

31 스키마 정의 Schema() 메소드를 이용해 스키마 정의하고 UserSchema 라는 이름의 변수에 할당 속성 이름 설명
var UserSchema = new mongoose.Schema({ id: {type: String, required: true, unique: true}, password: {type: String, required: true}, name: String, age: Number, created_at: Date, updated_at: Date }); 속성 이름 설명 - type 자료형을 지정합니다. - required 값이 true이면 반드시 들어가야 하는 속성이 됩니다. - unique 값이 true이면 이 속성에 고유한 값이 들어가야 합니다.

32 몽구스 스키마와 모델과의 관계 모델은 컬렉션과 스키마를 연결하는 역할이며, 모델 객체가 컬렉션이라고 생각하면 쉬움

33 몽구스의 데이터 조회 및 업데이트 메소드 find(), save(), update(), remove() 등의 메소드가 있음
UserModel.where({id : ‘test01’}).update({name: '애프터스쿨'}, function(err...) {...}) 메소드 이름 설명 find([criteria], [callback]) 조회 조건을 사용해 컬렉션의 데이터를 조회합니다. 조회 결과는 콜백 함수로 전달됩니다. save([options], [callback]) 모델 인스턴스 객체의 데이터를 저장합니다. 저장 결과는 콜백 함수로 전달됩니다. update([criteria], [doc], [options], [callback]) 컬렉션의 데이터를 조회한 후 업데이트합니다. where( ) 메소드와 함께 사용됩니다. remove([criteria], [callback]) 컬렉션의 데이터를 삭제합니다.

34 사용자 인증 함수 추가 모델 객체의 find() 메소드를 이용해 데이터 조회
var authUser = function(database, id, password, callback) { console.log('authUser 호출됨.'); UserModel.find({"id" : id, "password" : password}, function(err, results) { if(err) { callback(err, null); return; } console.log('아이디 [%s], 비밀번호 [%s]로 사용자 검색결과', id, password); console.dir(results); if(results.length > 0) { console.log('일치하는 사용자 찾음.', id, password); callback(null, results); } else { console.log("일치하는 사용자를 찾지 못함."); callback(null, null); }); };

35 사용자 추가 함수 추가 새로운 모델 인스턴스 객체를 만들고 save() 메소드를 이용해 저장
var addUser = function(database, id, password, name, callback) { console.log('addUser 호출됨.'); // UserModel의 인스턴스 생성 var user = new UserModel({"id" : id, "password" : password, "name" : name}); // save()로 저장 user.save(function(err) { if(err) { callback(err, null); return; } console.log("사용자 데이터 추가함."); callback(null, user); }); };

36 사용자 추가 웹페이지에서 요청 login.html 페이지에서 사용자 추가
콘솔 창에서 정상 처리 확인 후 로보몽고를 이용해 추가된 데이터 확인

37 4. 인덱스와 메소드 사용하기 난이도 소요시간 30분

38 빠른 성능을 위한 인덱스와 편리함을 위한 메소드 추가
스키마를 만들 때 인덱스를 추가할 수 있으며 스키마 객체에 메소드 추가 가능 var UserSchema = mongoose.Schema({ id: {type: String, required: true, unique: true}, password: {type: String, required: true}, name: {type: String, index: ‘hashed’}, age: Number, created_at: {type: Date, index: {unique: false, expires: ‘1d’}}, updated_at: Date }); 메소드 이름 설명 static(name, fn) 모델 객체에서 사용할 수 있는 함수를 등록합니다. 함수의 이름과 함수 객체를 파라미터로 전달합니다. method(name, fn) 모델 인스턴스 객체에서 사용할 수 있는 함수를 등록합니다.

39 사용자 리스트 조회 기능 추가 스키마 수정 UserSchema = mongoose.Schema({
id: {type : String, required : true, unique: true}, password : {type : String, required: true}, name: {type : String, index : 'hashed'}, age: {type : Number, 'default' : -1}, created_at : {type : Date, index : {unique : false}, 'default' : Date.now}, updated_at : {type : Date, index : {unique : false}, 'default' : Date.now} });

40 스키마에 메소드 추가 static() 메소드를 사용하여 스키마에 메소드 추가 // 스키마에 static 메소드 추가
UserSchema.static('findById', function(id, callback) { return this.find({id : id}, callback); }); UserSchema.static('findAll', function(callback) { return this.find({ }, callback); console.log('UserSchema 정의함.'); // UserModel 모델 정의 UserModel = mongoose.model("users2", UserSchema); console.log('UserModel 정의함.');

41 스키마에 추가한 메소드의 사용 예 static() 으로 추가하면 모델 객체, method() 로 추가하면 모델 인스턴스 객체에서 사용

42 authUser() 메소드 안에서 새로 추가한 메소드 사용
authUser() 메소드 안에서 findById() 메소드를 사용하도록 수정 var authUser = function(database, id, password, callback) { console.log('authUser 호출됨.'); // 1. 아이디를 사용해 검색 UserModel.findById(id, function(err, results) { if(err) { callback(err, null); return; } console.log('아이디 [%s]로 사용자 검색 결과', id); console.dir(results); if(results.length > 0) { console.log('아이디와 일치하는 사용자 찾음.');

43 results 결과물의 구조 results는 결과물인 문서 객체들이 들어있는 배열임
배열의 각 원소 안에는 _doc 속성이 있어 그 안에서 각 속성을 접근할 수 있음 if(results.length > 0) { console.log('아이디와 일치하는 사용자 찾음.'); // 2. 비밀번호 확인 if(results[0]._doc.password === password) { console.log('비밀번호 일치함'); callback(null, results); } else { console.log('비밀번호 일치하지 않음'); callback(null, null); } console.log("아이디와 일치하는 사용자를 찾지 못함.");

44 사용자 리스트 조회를 위한 라우팅 함수 추가 /process/listuser 요청 패스에 대해서는 모델 객체의 findAll() 메소드 직접 사용 router.route('/process/listuser’).post(function(req, res) { console.log(‘/process/listuser 호출됨.'); if(database) { // 1. 모든 사용자 검색 UserModel.findAll(function(err, results) { if (err) { console.error('사용자 리스트 조회 중 오류 발생 : ' + err.stack); res.writeHead('200', {'Content-Type':'text/html;charset=utf8'}); res.write('<h2>사용자 리스트 조회 중 오류 발생</h2>'); res.write('<p>' + err.stack + '</p>'); res.end(); return; }

45 사용자 리스트 조회를 위한 라우팅 함수 추가 /process/listuser 요청 패스에 대해서는 모델 객체의 findAll() 메소드 직접 사용 if (results) { // 결과 객체 있으면 리스트 전송 console.dir(results); res.writeHead('200', {'Content-Type':'text/html;charset=utf8'}); res.write('<h2>사용자 리스트</h2>'); res.write('<div><ul>'); for (var i = 0; i < results.length; i++) { var curId = results[i]._doc.id; var curName = results[i]._doc.name; res.write(' <li>#' + i + ' : ' + curId + ', ' + curName + '</li>'); } res.write('</ul></div>'); res.end(); } else { // 결과 객체가 없으면 실패 응답 전송

46 사용자 리스트 조회를 위한 웹 페이지 작성 public 폴더 안에 listuser.html 페이지 작성
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>사용자 리스트 테스트</title> </head> <body> <h1>사용자 리스트</h1> <br> <form method="post" action="/process/listuser"> <table> <tr> <td><label>아래 [전송] 버튼을 누르세요.</label></td> </tr> </table> <input type="submit" value="전송" name="" /> </form> </body> </html>

47 5. 비밀번호 암호화하여 저장하기 난이도 소요시간 30분

48 비밀번호 암호화 비밀번호를 단방향 암호화하여 저장할 수 있음
사용자 인증 과정에서 클라이언트가 보내온 비밀번호를 암호화한 후 비교함

49 virtual 함수 사용하기 virtual() 함수를 사용하면 문서 객체에 저장되는 속성이 아닌 가상 속성을 지정할 수 있음
문서 객체를 저장할 때 set(), 조회할 때 get() 메소드 사용

50 virtual 함수 사용법 테스트 database.on('open', function() {
스키마 만든 후 doTest() 함수 안에서 테스트 database.on('open', function() { console.log('데이터베이스에 연결되었습니다. : ' + databaseUrl); // user 스키마 및 모델 객체 생성 createUserSchema(); // test 진행함 doTest(); });

51 스키마 생성 부분 수정 스키마 생성 후 virtual() 메소드 호출하여 가상 속성 추가
공백으로 구분된 id, password 값을 분리하여 저장하고 조회할 때는 붙여서 조회하도록 함 function createUserSchema() { // 스키마 정의 // info를 virtual 메소드로 정의 UserSchema .virtual('info') .set(function(info) { var splitted = info.split(' '); this.id = splitted[0]; this.name = splitted[1]; console.log('virtual info 설정함 : %s, %s', this.id, this.name); }) .get(function() {return this.id + ' ' + this.name}); console.log('UserSchema 정의함.');

52 테스트 함수 추가 doTest() 함수 안에서 테스트
일반적인 문서 객체 추가하듯이 추가할 수 있으며, info 속성만 추가해도 id, name 추가됨. function doTest() { // UserModel 인스턴스 생성 // id, name 속성은 할당하지 않고 info 속성만 할당함 var user = new UserModel({"info" : 'test01 소녀시대'}); // save()로 저장 user.save(function(err) { if(err) {throw err;} console.log("사용자 데이터 추가함."); findAll(); }); console.log('info 속성에 값 할당함.'); console.log('id : %s, name : %s', user.id, user.name); }

53 테스트 함수 추가 findAll() 함수 안에서 id, name 속성 조회 function findAll() {
UserModel.find({}, function(err, results) { if(err) {throw err;} if(results) { console.log('조회된 user 문서 객체 #0 -> id : %s, name : %s', results[0]._doc.id, results[0]._doc.name); } });

54 데이터 저장한 후 조회 virtual() 함수로 지정한 info 속성으로 데이터 저장한 결과 확인

55 비밀번호 암호화하여 저장하는 코드 적용 var crypto = require('crypto'); …
crypto 모듈을 이용해 암호화한 후 hashed_password 속성에 저장 var crypto = require('crypto'); UserSchema = mongoose.Schema({ id : {type : String, required : true, unique : true, 'default' : ' '}, hashed_password : {type : String, required : true, 'default' : ' '}, salt : {type : String, required : true}, name : {type : String, index : 'hashed', 'default' : ' '}, age : {type : Number, 'default' : -1}, created_at : {type : Date, index : {unique : false}, 'default' : Date.now}, updated_at : {type : Date, index : {unique : false}, 'default' : Date.now} }); % npm install crypto -- save

56 암호화를 위한 virtual 함수 추가 password 속성을 virtual 함수로 추가 UserSchema
.set(function(password) { this._password = password; this.salt = this.makeSalt(); this.hashed_password = this.encryptPassword(password); console.log('virtual password 호출됨 : ' + this.hashed_password); }) .get(function() {return this._password});

57 스키마에 메소드 추가 모델 인스턴스 객체에서 사용할 수 있도록 method() 메소드를 호출하여 추가
UserSchema.method('encryptPassword', function(plainText, inSalt) { if(inSalt) { return crypto.createHmac('sha1', inSalt).update(plainText).digest('hex'); } else { return crypto.createHmac('sha1', this.salt).update(plainText).digest('hex'); } }); // salt 값 만들기 메소드 UserSchema.method('makeSalt', function() { return Math.round((new Date().valueOf() * Math.random())) + '';

58 스키마에 메소드 추가 모델 인스턴스 객체에서 사용할 수 있도록 method() 메소드를 호출하여 추가
// 인증 메소드 - 입력된 비밀번호와 비교 (true/false 리턴) UserSchema.method('authenticate', function(plainText, inSalt, hashed_password) { if(inSalt) { console.log('authenticate 호출됨 : %s -> %s : %s', plainText, this.encryptPassword(plainText, inSalt), hashed_password); return this.encryptPassword(plainText, inSalt) === hashed_password; } else { this.encryptPassword(plainText), this.hashed_password); return this.encryptPassword(plainText) === this.hashed_password; } });

59 속성값의 유효성 확인 path()와 validate() 메소드를 이용해 속성 값이 있는지 확인
// 필수 속성에 대한 유효성 확인 (길이 값 체크) UserSchema.path('id').validate(function(id) { return id.length; }, 'id 칼럼의 값이 없습니다.'); UserSchema.path('name').validate(function(name) { return name.length; }, 'name 칼럼의 값이 없습니다.');

60 사용자 추가 함수 작성 addUser 메소드 안에서 사용자 데이터 추가 // 사용자를 등록하는 함수
var addUser = function(database, id, password, name, callback) { console.log('addUser 호출됨.'); // UserModel 인스턴스 생성 var user = new UserModel({"id" : id, "password" : password, "name" : name}); // save()로 저장 user.save(function(err) { if(err) { callback(err, null); return; } console.log("사용자 데이터 추가함."); callback(null, user); });

61 사용자 인증 함수 작성 authUser 함수 안에서 모델 인스턴스 객체의 authenticate() 메소드 사용
var authUser = function(database, id, password, callback) { console.log('authUser 호출됨.'); UserModel.findById(id, function(err, results) { ……. if(results.length > 0) { console.log('아이디와 일치하는 사용자 찾음.'); var user = new UserModel({id : id}); var authenticated = user.authenticate(password, results[0]._doc.salt, results[0]._doc.hashed_password); if(authenticated) { console.log('비밀번호 일치함'); callback(null, results); } else { console.log('비밀번호 일치하지 않음'); callback(null, null); }

62 사용자 추가 및 로그인 테스트 adduser.html 페이지에서 사용자 추가, login.html 페이지에서 로그인

63 6. MySQL 데이터베이스 사용하기 난이도 소요시간 30분

64 노드에서 관계형 데이터베이스 사용하기 기존에 사용하던 관계형 데이터베이스를 연결하는 경우 많음
모듈을 설치하면 MySQL, Oracle 등 연결하여 사용 가능

65 관계형 데이터베이스를 사용하는 4단계 4단계만 알면 SQL을 이용해 데이터를 조회하거나 추가하는 것이 가능 단계 설명 1단계:
데이터베이스 연결 어떤 데이터베이스에 연결할지 지정하는 정보와 보안 정보를 입력합니다. 예) connectionLimit: 10, host: 'localhost', user: 'root', password: 'OOOOO', database: 'users', debug: false 2단계: 테이블 생성 테이블을 만들어 어떤 칼럼에 어떤 타입의 데이터가 들어가는지 정의합니다. 예) CREATE TABLE users(id text, name text, age int, password text) 3단계: 레코드 추가 레코드를 한 줄 추가합니다. 예) INSERT INTO users(id, name, age, password) VALUES (‘101’, ‘김진수’, 20, ‘123456’) 4단계: 데이터 조회 원하는 조건을 넣어 데이터를 조회합니다. 예) SELECT id, name, age, password FROM users WHERE age > 10

66 MySQL 설치하기 사이트에서 커뮤니티 서버 다운로드받아 설치

67 화면이 있는 관리도구 설치하고 데이터베이스 연결
관리도구는 여러 가지가 있지만 여기에서는 HeidiSQL 설치하여 사용

68 데이터베이스 생성과 테이블 추가 HeidiSQL을 이용해 데이터베이스를 생성하고 테이블 추가

69 데이터베이스 생성과 테이블 추가 테이블에 칼럼 정보 추가

70 mysql 모듈을 이용해 데이터베이스 연결 노드에서는 mysql 모듈을 설치하고 Pool을 이용해 데이터베이스 연결
var mysql = require('mysql'); //===== MySQL 데이터베이스 연결 설정 =====// var pool = mysql.createPool({ connectionLimit : 10, host : 'localhost', user : 'root', password : 'OOOOO', database : 'test', debug : false }); % npm install mysql --save

71 Pool을 만들 때 사용할 수 있는 속성 host, port 정보 외에 최대 연결 개수 등 설정 가능 단계 설명
connectionLimit 커넥션 풀에서 만들 수 있는 최대 연결 개수를 설정합니다. host 연결할 호스트 이름을 설정합니다. 내 컴퓨터인 경우 localhost 또는 을 입력할 수 있습니다. port 데이터베이스가 사용하는 포트 번호를 설정합니다. MySQL의 디폴트 포트는 3306입니다. user 데이터베이스 사용자 아이디를 설정합니다. MySQL에서 루트 권한을 가진 디폴트 사용자 아이디는 root입니다. password 데이터베이스 사용자의 비밀번호를 설정합니다. database 데이터베이스 이름을 설정합니다. debug 데이터베이스 처리 과정을 로그로 남길 것인지 설정합니다.

72 사용자 추가 함수 작성 getConnection() 메소드로 연결 객체를 참조한 후 query() 메소드로 SQL 실행
var addUser = function(id, name, age, password, callback) { console.log('addUser 호출됨.'); // 커넥션 풀에서 연결 객체를 가져옵니다. pool.getConnection(function(err, conn) { if (err) { if (conn) { conn.release(); // 반드시 해제해야 합니다. } callback(err, null); return; console.log('데이터베이스 연결 스레드 아이디 : ' + conn.threadId); insert into users set id=’test01‘, name=’김준수‘, age=20, password=’123456’

73 사용자 추가 함수 작성 getConnection() 메소드로 연결 객체를 참조한 후 query() 메소드로 SQL 실행 ……
var data = {id:id, name:name, age:age, password:password}; // SQL문을 실행합니다. var exec = conn.query('insert into users set ?', data, function(err, result) { conn.release(); // 반드시 해제해야 합니다. console.log('실행 대상 SQL : ' + exec.sql); if(err) { console.log('SQL 실행 시 오류 발생함.'); console.dir(err); callback(err, null); return; } callback(null, result); }); …….

74 라우팅 함수 추가 사용자를 추가하기 위한 라우팅 함수추가
router.route('/process/adduser').post(function(req, res) { console.log('/process/adduser 호출됨.'); var paramId = req.body.id || req.query.id; var paramPassword = req.body.password || req.query.password; var paramName = req.body.name || req.query.name; var paramAge = req.body.age || req.query.age; if(pool) { addUser(paramId, paramName, paramAge, paramPassword, function(err, addedUser) { // 동일한 id로 추가할 때 오류 발생 - 클라이언트로 오류 전송 if (err) { console.error('사용자 추가 중 오류 발생 : ' + err.stack);

75 라우팅 함수 추가 사용자를 추가하기 위한 라우팅 함수추가
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'}); res.write('<h2>사용자 추가 중 오류 발생</h2>'); res.write('<p>' + err.stack + '</p>'); res.end(); return; } if (addedUser) { console.dir(addedUser); console.log('inserted ' + result.affectedRows + ' rows'); var insertId = result.insertId; console.log('추가한 레코드의 아이디 : ' + insertId); res.write('<h2>사용자 추가 성공</h2>');

76 웹페이지 작성 adduser2.html 페이지 작성
<form method="post" action="/process/adduser"> <table> <tr> <td><label>아이디</label></td> <td><input type="text" name="id" ></td> </tr> <td><label>사용자명</label></td> <td><input type="text" name="name" ></td> <td><label>나이</label></td> <td><input type="text" name="age" ></td> <td><label>비밀번호</label></td> <td><input type="password" name="password" ></td> </table> <input type="submit" value="전송" > </form>

77 사용자 추가 여부 확인 웹페이지에서 요청 후 HeidiSQL을 이용해 데이터 추가되었는지 확인

78 로그인 기능을 위한 함수 추가 로그인 기능을 테스트하기 위해 authUser 함수 추가
var authUser = function(id, password, callback) { console.log('authUser 호출됨.'); // 커넥션 풀에서 연결 객체를 가져옵니다. pool.getConnection(function(err, conn) { if (err) { if (conn) { conn.release(); // 반드시 해제해야 합니다. } callback(err, null); return; console.log('데이터베이스 연결 스레드 아이디 : ' + conn.threadId);

79 로그인 기능을 위한 함수 추가 로그인 기능을 테스트하기 위해 authUser 함수 추가
var columns = ['id', 'name', 'age']; var tablename = 'users'; // SQL문을 실행합니다. var exec = conn.query("select ?? from ?? where id = ? and password = ?", [columns, tablename, id, password], function(err, rows) { conn.release(); // 반드시 해제해야 합니다. console.log('실행 대상 SQL : ' + exec.sql); if(rows.length > 0) { console.log('아이디 [%s], 패스워드 [%s] 가 일치하는 사용자 찾음.', id, password); callback(null, rows); } else { console.log("일치하는 사용자를 찾지 못함."); callback(null, null); } }); select id, name, age from users where id = ‘test01’ and password = ‘123456’

80 라우팅 함수 추가 사용자 로그인을 위한 라우팅 함수추가
router.route('/process/login').post(function(req, res) { console.log('/process/login 호출됨.'); var paramId = req.body.id || req.query.id; var paramPassword = req.body.password || req.query.password; if(pool) { authUser(paramId, paramPassword, function(err, rows) { if(err) …. if(rows) { console.dir(rows); var username = rows[0].name; res.writeHead('200', {'Content-Type':'text/html;charset=utf8'}); res.write('<h1>로그인 성공</h1>'); res.write('<div><p>사용자 아이디 : ' + paramId + '</p></div>'); res.write('<div><p>사용자 이름 : ' + username + '</p></div>'); res.write("<br><br><a href='/public/login2.html'>다시 로그인하기</a>"); res.end();

81 실행 확인 웹페이지에서 접속하여 확인

82 참고 문헌 [ References] 기본 서적
2017, 정재곤, “Do it! Node.js 프로그래밍 (개정판)”, 이지스퍼블리싱 Node.js Site


Download ppt "데이터베이스 사용하기 6장 Do it! Node.js 프로그래밍 이지스퍼블리싱 제공 강의 교안 2017/03"

Similar presentations


Ads by Google