본문 바로가기

웹/Node.js

4. (Node.js) express로 웹 서버 만들기(2/2)

이전 (Node.js) express로 웹 서버 만들기(1/2) 에서 Express를 사용하여 웹 서버를 만들기 위한 html (메인, 로그인, 회원가입, id 찾기, password 찾기)과 미들웨어 사용법을 살펴봤습니다.


이번 포스트에서는 라우터, 데이터베이스 연동 (mongoose)을 통한 로그인, 회원가입, id 찾기, 비밀번호 찾기 기능을 구현하겠습니다.


이전 포스트의 main.js에 내용을 추가하며 작성하겠습니다.

데이터베이스 연동


main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//mongoose 모듈 사용
var mongoose = require('mongoose');
 
var database;
var UserSchema;
var UserModel;
 
http.createServer(app).listen(3000function(){
    console.log('Express server start....');
    
    connectDB();
});
 
var connectDB = function(){
    var databaseUrl = 'mongodb://localhost:27017/local';
     
    // 데이터베이스 연결
    console.log('데이터베이스 연결을 시도합니다.');
    mongoose.set('useCreateIndex'true);
    mongoose.Promise = global.Promise;
    mongoose.connect(databaseUrl, {useNewUrlParser:true});
    database = mongoose.connection;
 
    database.on('error'console.error.bind(console'mongoose connection error.'));
    database.on('open'function () {
        console.log('데이터베이스에 연결되었습니다. : ' + databaseUrl);
 
        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}
        });
 
        // 스키마에 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 정의함.');
 
        // User 모델 정의
        UserModel = mongoose.model('users', UserSchema); // 2번 문제
        console.log('users 정의함.');
    });
};
cs


데이터베이스 연결을 위한 connectDB 함수를 만들어 줍니다.

15 ~ 22 : mongoose 모듈을 이용해 먼저 데이터베이스에 연결해줍니다.

※ mongoose는 event 발생 방식으로 사용합니다. (mongoDB는 callback 방식으로 사용함)

25 : open 이벤트가 정상적으로 발생하면 database에 연결이 됩니다.

28 ~ 35 : Schema() 메소드로 스키마를 정의합니다.

37 ~ 44 : static 메소드를 사용하여 모델 객체에서 사용할 수 있는 함수(findById, findAll)를 등록합니다.

49 : shcema를 model로 정의합니다.


회원가입 함수


main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var addUser = function(database, id, password, name, age, callback){
    console.log('addUser 호출됨.');
 
    // UserModel의 인스턴스 생성
    var user = new UserModel({"id" : id, "password" : password, "name" : name"age" : age});
    // save()로 저장
    user.save(function(err) {
        if(err) {
            callback(err, null);
            return;
        }
        
        console.log("사용자 데이터 추가함.");
        callback(null, user);     
    });
};
cs

5 : 전달인자로 받은 변수를 통해 UserModel의 인스턴트를 생성합니다.
7 : 생성된 user를 save()로 저장합니다.


로그인 함수


main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var authUser = function(database, id, password, callback) {
     console.log('authUser 호출됨.');
     var failcode = -1// 추가됨. 1인 경우 id 못찾음. 2인 경우 password 틀림
    
    // 1. 아이디를 사용해 검색
    UserModel.findById(id, function(err, results) {
        if(err) {
            callback(err, null);
            return;
        }
        
        if(results.length > 0) {
            console.log('아이디와 일치하는 사용자 찾음.');
 
            // 2. 비밀번호 확인
            if(results[0]._doc.password === password) {
                console.log('비밀번호 일치함');
                callback(null, results, failcode);
            } else {
                console.log('비밀번호 일치하지 않음');
                failcode = 2;
                callback(nullnull, failcode);
            }
 
        } else {
            console.log("아이디와 일치하는 사용자를 찾지 못함.");
            failcode = 1;
            callback(nullnull, failcode);
        }
    });
};
cs

아이디를 사용해서 검색한다.
results는 결과물인 객체들이 들어있는 배열이다.
배열의 각 원소 안에는 _doc 속성이 있어 그 안에서 각 속성을 접근할 수 있다.
12 : 검색하는 id와 일치하는 id가 있으면 results의 length가 0보다 크다.
16 ~ 23 : 데이터베이스에서 가져온 비밀번호와 내가 입력한 비밀번호가 같은지 확인한다.

라우터


main.js

1
2
var router1 = express.Router();
var router2 = express.Router();
cs

express router 생성

1 : router1은 회원가입, 로그인 관련 router이다.

2 : router2는 id, password 찾기 관련 router이다.


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
router1.route('/adduser').post(function(req,res){
    console.log('/process/adduser called.....');
 
    var paramId = req.body.id;
    var paramPassword = req.body.password;
    var paramName = req.body.name;
    var paramAge = req.body.age;
 
      if(database) {
          addUser(database, paramId, paramPassword, paramName, paramAge, function(err, result) {
              if(err) {throw err;}
            
              // 결과 객체 확인하여 추가된 데이터 있으면 성공 응답 전송
              if (result) {                  
                  res.writeHead('200', {'Content-Type':'text/html;charset=utf-8'});
                  res.write('<h2>Success registration.....</h2>');
                  res.write('<div><h2><a href=/public/index.html>Goto Main Page</a></h2></div>');
                  res.end();
              } else {
                  res.writeHead('200', {'Content-Type':'text/html;charset=utf-8'});
                  res.write('<h2>Fail to registration....</h2>');
                  res.write('<div><h2><a href=/public/index.html>Goto Main Page</a></h2></div>');
                  res.end();
              }
            });
        } else  {
            res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
            res.write('<h2>database connection...fail</h2>');
            res.write('<div><h2><a href=/public/index.html>Goto Main page</a></h2></div>');
            res.end();
        }
});
 
 
router1.route('/login').post(function(req, res){ 
    console.log('/process/login 호출됨.....');
 
    var paramId = req.body.id;
    var paramPassword = req.body.password;
 
    if(database) {
        authUser(database, paramId, paramPassword, function(err, docs, failcode) {        
            console.log("callback run.....");
            if(err) {throw err;}
            
            if(docs) {
                console.log('....to client...');
                var username = docs[0]._doc.name;
                res.writeHead('200', {'Content-Type':'text/html;charset=utf-8'});
                res.write('<h1>login success...</h1>');
                res.write('<h1>hello ' + username + '</h1>');
                res.write('<div><h2><a href=/public/index.html>Goto Main Page</a></h2></div>');
                res.end();
            }
            else {
                res.writeHead('200', {'Content-Type':'text/html;charset=utf-8'});
                res.write('<h1>login fail...</h1>');
                if(failcode == 1) {
                    res.write('<div><h2>cannot find ID</h2></div>');
                    res.write('<h2><a href=/public/findid.html>Find ID</a></h2>');
                } else if(failcode == 2) {
                    res.write('<div><h2>mismatch password</h2></div>');
                    res.write('<h2><a href=/public/findpass.html>Find ID</a></h2>');
                }
                res.write('<div><h2><a href=/public/index.html>Goto Main Page</a></h2></div>');
                res.end();
            }
        });
    } else {
        res.writeHead('200', {'Content-Type':'text/html;charset=utf-8'});
        res.write('<h1>connection error....</h1>');
        res.end();
    }
});
cs


1 ~ 32 : 회원가입에 관련된 router이다.

4 ~ 7 : sign.html의 form에서 입력한 값을 받아온다.

10 ~ 31 : addUser 함수를 통해 데이터베이스에 새롭게 추가하고 추가된 데이터가 있으면 result로 성공 응답


35 ~ 74 : 로그인에 관련된 router이다.

38 ~ 39 : login.html의 form에서 입력한 값을 받아온다.

41 ~ 73 : authUser 함수를 통해 입력된 값과 데이터베이스에 저장된 값이 일치하는지 확인한다.


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
router2.route('/findid').post(function(req, res){
    console.log("/user/findid called......");
    
    var Pname = req.body.name;
 
    UserModel.findById(Pname, function(err, results) {
        if(err) {
            console.log('error')
            res.write('<h1> error <h1>')
            return;
        }
        
        if(results.length > 0) {
            console.log('find');
            if(results[0]._doc.name === Pname) {
                res.write('<h1> 이름: ' + Pname + '</h1>');
                res.write('<h1> id: ' + results[0]._doc.id + '</h1>');
                res.end();
            }
        } else {
            res.write('<h1> 아이디: ' + Pname + '</h1>');
            res.end();
        }
    });
});
 
router2.route('/findpass').post(function(req, res){
    console.log("/user/findpass called......");
    
    var pid = req.body.id;
    var pname = req.body.name;
    
    UserModel.findById(pid, function(err, results) {
        if(err) {
            console.log('error')
            res.write('<h1> error <h1>')
            return;
        }
        
        if(results.length > 0) {
            console.log('find');
            if(results[0]._doc.id === pid && results[0]._doc.name === pname) {
                res.write('<h1> 아이디: ' + pid + '</h1>');
                res.write('<h1> 이름: ' + pname + '</h1>');
                res.write('<h1> 비밀번호: ' + results[0]._doc.password + '</h1>');
                res.end();
            }
        } else {
            res.write('<h1> 아이디: ' + pid + '</h1>');
            res.write('<h1> 비밀번호를 찾지 못했습니다.</h1>');
            res.end();
        }
    });
});
cs

1 ~ 25 : 이름을 이용하여 id를 찾는 router이다.
6 ~ 24 : 데이터베이스에서 입력된 이름과 일치하는 결과가 있는지 찾는다.

27 ~ 55 : id와 이름을 이용하여 password를 찾는 router이다

40 ~ 53 : 데이터베이스에서 입력된 id와 일치하는 결과를 찾은 후 그 결과의 이름이 입력된 이름과 같으면 비밀번호를 알려준다.


1
2
app.use('/process', router1); // 회원가입, 로그인
app.use('/user', router2);   // id, password 찾기
cs

1 : /process의 path는 router1
2 : /user의 path는 router2

전체 코드


main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
var express = require('express'), http = require('http'), path = require('path');
// Express의 미들웨어 불러오기
var bodyParser = require('body-parser'), cookieParser = require('cookie-parser'), serveStatic = require('serve-static');
// Session 미들웨어 불러오기
var expressSession = require('express-session');
// 익스프레스 객체 생성
var app = express();
 
 
app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());
 
 
app.use('/public', serveStatic(path.join(__dirname, 'HTML')));
 
app.use(cookieParser());
app.use(expressSession({
    secret:'my key',
    resave: true,
    saveUninitialized:true
}));
 
http.createServer(app).listen(3000function(){
    console.log("express server start......");
 
    connectDB();
});
 
// 몽고디비 모듈 사용
var MongoClient = require('mongodb').MongoClient;
var mongoose = require('mongoose');
 
var database;
var UserSchema;
var UserModel;
 
var connectDB = function() {
    
    var databaseUrl = 'mongodb://localhost:27017/local';
     
    // 데이터베이스 연결
    console.log('데이터베이스 연결을 시도합니다.');
    mongoose.set('useCreateIndex'true);
    mongoose.Promise = global.Promise;
    mongoose.connect(databaseUrl, {useNewUrlParser:true});
    database = mongoose.connection;
 
    database.on('error'console.error.bind(console'mongoose connection error.'));
    database.on('open'function () {
        console.log('데이터베이스에 연결되었습니다. : ' + databaseUrl);
 
        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}
        });
 
        // 스키마에 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 정의함.');
 
        // User 모델 정의
        UserModel = mongoose.model('users', UserSchema); // 2번 문제
        console.log('users 정의함.');
    });
};
 
 
var authUser = function(database, id, password, callback) {
     console.log('authUser 호출됨.');
     var failcode = -1// 추가됨. 1인 경우 id 못찾음. 2인 경우 password 틀림
    
    // 1. 아이디를 사용해 검색
    UserModel.findById(id, function(err, results) {
        if(err) {
            callback(err, null);
            return;
        }
        
        if(results.length > 0) {
            console.log('아이디와 일치하는 사용자 찾음.');
 
            // 2. 비밀번호 확인
            if(results[0]._doc.password === password) {
                console.log('비밀번호 일치함');
                callback(null, results, failcode);
            } else {
                console.log('비밀번호 일치하지 않음');
                failcode = 2;
                callback(nullnull, failcode);
            }
 
        } else {
            console.log("아이디와 일치하는 사용자를 찾지 못함.");
            failcode = 1;
            callback(nullnull, failcode);
        }
    });
};
 
var addUser = function(database, id, password, name, age, callback){
    console.log('addUser 호출됨.');
 
    // UserModel의 인스턴스 생성
    var user = new UserModel({"id" : id, "password" : password, "name" : name"age" : age});
    // save()로 저장
    user.save(function(err) {
        if(err) {
            callback(err, null);
            return;
        }
        
        console.log("사용자 데이터 추가함.");
        callback(null, user);     
    });
 
};
 
var router1 = express.Router();
var router2 = express.Router();
 
router1.route('/adduser').post(function(req,res){
    console.log('/process/adduser called.....');
 
    var paramId = req.body.id;
    var paramPassword = req.body.password;
    var paramName = req.body.name;
    var paramAge = req.body.age;
 
      if(database) {
          addUser(database, paramId, paramPassword, paramName, paramAge, function(err, result) {
              if(err) {throw err;}
            
              // 결과 객체 확인하여 추가된 데이터 있으면 성공 응답 전송
              if (result) {                  
                  res.writeHead('200', {'Content-Type':'text/html;charset=utf-8'});
                  res.write('<h2>Success registration.....</h2>');
                  res.write('<div><h2><a href=/public/index.html>Goto Main Page</a></h2></div>');
                  res.end();
              } else {
                  res.writeHead('200', {'Content-Type':'text/html;charset=utf-8'});
                  res.write('<h2>Fail to registration....</h2>');
                  res.write('<div><h2><a href=/public/index.html>Goto Main Page</a></h2></div>');
                  res.end();
              }
            });
        } else  {
            res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
            res.write('<h2>database connection...fail</h2>');
            res.write('<div><h2><a href=/public/index.html>Goto Main page</a></h2></div>');
            res.end();
        }
});
 
 
router1.route('/login').post(function(req, res){ 
    console.log('/process/login 호출됨.....');
 
    var paramId = req.body.id;
    var paramPassword = req.body.password;
 
    if(database) {
        authUser(database, paramId, paramPassword, function(err, docs, failcode) {        
            console.log("callback run.....");
            if(err) {throw err;}
            
            if(docs) {
                console.log('....to client...');
                var username = docs[0]._doc.name;
                res.writeHead('200', {'Content-Type':'text/html;charset=utf-8'});
                res.write('<h1>login success...</h1>');
                res.write('<h1>hello ' + username + '</h1>');
                res.write('<div><h2><a href=/public/index.html>Goto Main Page</a></h2></div>');
                res.end();
            }
            else {
                res.writeHead('200', {'Content-Type':'text/html;charset=utf-8'});
                res.write('<h1>login fail...</h1>');
                if(failcode == 1) {
                    res.write('<div><h2>cannot find ID</h2></div>');
                    res.write('<h2><a href=/public/findid.html>Find ID</a></h2>');
                } else if(failcode == 2) {
                    res.write('<div><h2>mismatch password</h2></div>');
                    res.write('<h2><a href=/public/findpass.html>Find ID</a></h2>');
                }
                res.write('<div><h2><a href=/public/index.html>Goto Main Page</a></h2></div>');
                res.end();
            }
        });
    } else {
        res.writeHead('200', {'Content-Type':'text/html;charset=utf-8'});
        res.write('<h1>connection error....</h1>');
        res.end();
    }
});
 
router2.route('/findid').post(function(req, res){
    console.log("/user/findid called......");
    
    var Pname = req.body.name;
 
    UserModel.findById(Pname, function(err, results) {
        if(err) {
            console.log('error')
            res.write('<h1> error <h1>')
            return;
        }
        
        if(results.length > 0) {
            console.log('find');
            if(results[0]._doc.name === Pname) {
                res.write('<h1> 이름: ' + Pname + '</h1>');
                res.write('<h1> id: ' + results[0]._doc.id + '</h1>');
                res.end();
            }
        } else {
            res.write('<h1> 아이디: ' + Pname + '</h1>');
            res.end();
        }
    });
});
 
router2.route('/findpass').post(function(req, res){
    console.log("/user/findpass called......");
    
    var pid = req.body.id;
    var pname = req.body.name;
    
    UserModel.findById(pid, function(err, results) {
        if(err) {
            console.log('error')
            res.write('<h1> error <h1>')
            return;
        }
        
        if(results.length > 0) {
            console.log('find');
            if(results[0]._doc.id === pid && results[0]._doc.name === pname) {
                res.write('<h1> 아이디: ' + pid + '</h1>');
                res.write('<h1> 이름: ' + pname + '</h1>');
                res.write('<h1> 비밀번호: ' + results[0]._doc.password + '</h1>');
                res.end();
            }
        } else {
            res.write('<h1> 아이디: ' + pid + '</h1>');
            res.write('<h1> 비밀번호를 찾지 못했습니다.</h1>');
            res.end();
        }
    });
});
 
app.use('/process', router1); // 회원가입, 로그인
app.use('/user', router2);   // id, password 찾기 
cs