/* user2.js 파일에서 exports 객체를 할당하였으므로,
require()를 호출할 때 자바스크립트에서 새로운 변수로 처리한다.
결국 아무 속성도 없는 {}가 반환된다. */
var user = require('./user2');
console.dir(user);
function showUser(){
return user.getUser().name + ','+user.group.name;
}
console.log(showUser);
노드는 모듈을 처리할 때 exports를 속성으로 인식한다. 이 속성에 함수나 객체를 속성으로 추가하면 모듈을 불러들인 쪽에서 exports에 추가된 속성들을 참조할 수 있다. 그러나 exports에 객체를 할당하면 모듈 파일 안에서 선언한 exports는 모듈 시스템에서 처리할 수 있ㄴ는 전역변수가 아닌 단순 변수로 인식된다. 이때문에 참조할 수 없게된다.
module.exports를 사용해 객체를 그대로 할당하기
//module.exports에는 객체를 그대로 할당할 수 있다.
var user = {
getUser : function(){
return {id: 'test01',name: '박우진'};
},
group : {id: 'group1',name:'친구'}
}
module.exports = user;
// require()메소드는 객체를 반환
var user = require('./user3');
function showUser(){
return user.getUser().name + ',' + user.group.name;
}
console.log(showUser());
module.exports에 객체를 그대로 할당하면 모둘파일 안에서 할당한 객체를 참조할 수 있다.
module.exports에 함수만 할당하기
//인터페이스(함수 객체)를 그대로 할당할 수 있다.
module.exports = function(){
return {id: 'test01',name: '박우진'}
};
//require()메소드는 함수를 반환
var user = require('./user4');
function showUser(){
return user().name+','+'No group';
}
console.log(showUser());
반환된 함수에 소괄호만 붙여주면 함수를 그대로 실행할 수 있다.
exports와 module.exports 함께 사용하기
module.exports가 우섡으로 적용된다. 즉, 모듈을 불러오는 쪽에서는 module.exports에 할당된 객체나 속성을 참조할 수 있으며 exports 전역 변수는 무시된다.
//require()메소드는 exports가 아닌 module.exports로 설정된 속성 반환
var user = require('./user5');
function showUser(){
return user.getUser().name + user.group.name;
}
console.log(showUser());
require() 메소드의 동작 방식 이해하기
//가상으로 require()함수를 정의해 보면 require()함수가 내부적으로 처리되는 방식을 이해할 수 있따.
var require = function(path){
var exports = {
getUser : function(){
return {id:'test01',name:'박우진'};
},
group: {id:'group01',name:'친구'}
}
return exports;
}
var user = require('...');
function showUser(){
return user.getUser().name + user.group.name;
}
console.log(showUser());
모듈을 분리할 때 사용하는 전형적인 코드 패턴
코드패턴
설명
함수를 할당하는 경우
모듈 안에서 함수를 만들어 할당한다.
모듈을 불러온 후 소괄호를 붙여 모듈을 실행한다.
인스턴스 객체를 할당하는 경우
모듈 안에서 인스턴스 객체를 만들어 할당한다.
모듈을 불러온 후 해당 객체의 메소드를 호출하거나 속성을 사용할 수 있다.
프로토타입 객체를 할당하는 경우
모듈 안에서 프로토타입 객체를 만들어 할당한다.
모듈을 불러온 후 new연산자로 인스턴스 객체를 만들어 사용할 수 있다.
1. 함수를 할당하는 코드 패턴
//사용패턴 : exports에 속성으로 추가된 함수 객체를 그대로 참조한 후 호출
exports.printUser = function(){
console.log('user이름은 박우진');
};
//exports에 속성으로 추가된 함수 객체를 그대로 참조한 후 호출
var printUser = require('./user7').printUser;
printUser();
2.인스턴스 객체를 할당하는 코드 패턴
// module.exports에 인스턴스 객체를 만들어 할당
// 생성자 함수
function User(id,name){
this.id = id;
this.name = name;
}
User.prototype.getUser = function(){
return {id:this.id,name:this.name};
}
User.prototype.group = {id: 'group1',name:'친구'};
User.prototype.printUser = function(){
console.log(this.name + this.group.name);
}
module.exports = new User('test01','박우진');
// new연산자로 만든 인스턴스 객체를 할당한 후 인스턴스 객체 호출
var user = require('./user8');
user.printUser();
// exports에 인스턴스 객체를 할당할 경우
exports.user = new User('test01','박우진');
// new연산자로 만든 인스턴스 객체를 할당한 후 인스턴스 객체 호출
var user = require('./user9').user;
user.printUser();
3.프로토타입 객체를 할당하는 코드 패턴
//user.js
...
exports.user = User;
//module_test.js
var User = require('./user10');
var user = new User('test01','박우진');
user.printUser();
07-2 사용자 정보 관련 기능을 모듈화하기
스키마 파일을 별도의 모듈 파일로 분리하기
스키마는 컬렉션의 구조를 결정하는 것으로 데이터베이스와 분리해서 독립적으로 정의할 수 있다.
var crypto = require('crypto');
var Schema={ };
Schema.createSchema= function(mongoose){
// 스키마 정의
// password를 hashed_password로 변경, 각 칼럼에 default 속성 모두 추가, salt 속성 추가
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}
});
// password를 virtual 메소드로 정의 : MongoDB에 저장되지 않는 가상 속성임.
// 특정 속성을 지정하고 set, get 메소드를 정의함
UserSchema
.virtual('password')
.set(function(password) {
this._password = password;
this.salt = this.makeSalt();
this.hashed_password = this.encryptPassword(password);
console.log('virtual password의 set 호출됨 : ' + this.hashed_password);
})
.get(function() {
console.log('virtual password의 get 호출됨.');
return this._password;
});
// 스키마에 모델 인스턴스에서 사용할 수 있는 메소드 추가
// 비밀번호 암호화 메소드
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())) + '';
});
// 인증 메소드 - 입력된 비밀번호와 비교 (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 {
console.log('authenticate 호출됨 : %s -> %s : %s', plainText, this.encryptPassword(plainText), this.hashed_password);
return this.encryptPassword(plainText) === this.hashed_password;
}
});
// 값이 유효한지 확인하는 함수 정의
var validatePresenceOf = function(value) {
return value && value.length;
};
// 저장 시의 트리거 함수 정의 (password 필드가 유효하지 않으면 에러 발생)
UserSchema.pre('save', function(next) {
if (!this.isNew) return next();
if (!validatePresenceOf(this.password)) {
next(new Error('유효하지 않은 password 필드입니다.'));
} else {
next();
}
})
// 필수 속성에 대한 유효성 확인 (길이값 체크)
UserSchema.path('id').validate(function (id) {
return id.length;
}, 'id 칼럼의 값이 없습니다.');
UserSchema.path('name').validate(function (name) {
return name.length;
}, 'name 칼럼의 값이 없습니다.');
UserSchema.path('hashed_password').validate(function (hashed_password) {
return hashed_password.length;
}, 'hashed_password 칼럼의 값이 없습니다.');
// 스키마에 static으로 findById 메소드 추가
UserSchema.static('findById', function(id, callback) {
return this.find({id:id}, callback);
});
// 스키마에 static으로 findAll 메소드 추가
UserSchema.static('findAll', function(callback) {
return this.find({}, callback);
});
console.log('UserSchema 정의함.');
return UserSchema;
}
//module.exports에 UserSchema 객체 직접할당
module.exports = Schema;
//app.js
// user 스키마 및 모델 객체 생성
function createUserSchema() {
//user_schema.js 모듈 불러오기
UserSchema = require('./database/user_schema').createSchema(mongoose);
// User 모델 정의
UserModel = mongoose.model("users3", UserSchema);
console.log('users3 정의함.');
}