지난번에 웹소켓을 사용하여 구현된 채팅 프로그램에 데이터 베이스를 활용하여 이전 채팅을 보관하고 사용자에게 출력해서 보여줄 것이다. 먼저 mysql을 사용할 수 있도록 패키지를 설치해 주어야 한다.

1
> npm install mysql

이후 테스트를 위해서 데이터 베이스에 다음과 같은 테이블을 생성했다. 이 글에서는 데이터 베이스의 기초적인 설치와 설정 방법에 대해서는 다루지 않는다.

1
2
3
4
5
CREATE TABLE CHAT(
  PK INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  USER VARCHAR(15) NOT NULL,
  CONTENT VARCHAR(400)
);

데이터 베이스와 정상적으로 연동도되며 값의 출력이 어떻게 이뤄지는지 알기 위해서 데이터 베이스에 값을 삽입해 놓았다.

1
INSERT INTO CHAT(USER, CONTENT) VALUES('감자탕', '안녕하세요!');

이제 테스트를 위헤서 아래 코드를 활용해 보도록 하자. 아래 코드에서 중괄호과 표시된 부분의 자신의 정보를 삽입하면 된다. 잘 이해가 가지 않는다면 그 아래에 예시를 주석으로 작성하였다.

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
var mysql = require('mysql');
var connection = mysql.createConnection({
	host: 'localhost',
	user: '{USER_NAME}',
	password: '{USER_PASSWORD}',
	port: {PORT_NUMBER},
	database: '{DB_NAME}'
});

/* EXAMPLE //
host: 'localhost',
user: 'baealex',
password: '1234',
port: 3306,
database: 'testcase'
*/

connection.connect();

connection.query('SELECT * FROM CHAT', (err, rows, filds)=> {
	if(!err) {
		console.log(rows);
	} else {
		console.log(err);
	}
});

connection.end();

이후 node index.js를 실행하면 다음과 같은 결과가 발생한다.

1
[ RowDataPacket { PK: 1, USER: '감자탕', CONTENT: '안녕하세요!' } ]




값의 삽입 역시 쿼리만 잘 날리면 정상적으로 수행된다.

1
2
3
4
5
6
7
8
9
10
let name = '그라탕';
let content = '그래요 반가워요';

connection.query('INSERT INTO CHAT(USER, CONTENT) VALUES(\''+name+'\',\''+content+'\')', (err, rows, filds) => {
    if(!err) {
        console.log(rows);
    } else {
        console.log(err);
    }
});

단 전달할 때 문자열인 만큼 따옴표도 함께 보내줘야한다. 아래는 삽입 후 전체 출력한 결과다.

1
2
3
4
5
6
[ RowDataPacket { PK: 1, USER: '감자탕', CONTENT: '안녕하세요!' } ]
OkPacket { ... }
[
    RowDataPacket { PK: 1, USER: '감자탕', CONTENT: '안녕하세요!' },
    RowDataPacket { PK: 2, USER: '그라탕', CONTENT: '그래요 반가워요' }
]

이제 웹소켓에서 채팅이 진행되면 채팅을 데이터 베이스에 삽입하고 사용자가 입장했을때 이전에 기록되어있던 데이터를 출력할 것이다.

채팅 삽입

1
2
3
4
5
6
insertChat = (name, chat) => {
	connection.query('INSERT INTO CHAT(USER, CONTENT) VALUES(\''+name+'\',\''+chat+'\');', (err, rows, filds) => {
		if(err)
			console.log(err);
	});
};

필자는 위와같이 insertChat 이라는 메서드를 생성하여 사용자의 이름과 채팅을 넘겨주어 데이터 베이스에 삽입할 것이다. 에러가 발생할 경우에만 콘솔에 에러를 띄우도록 하였다.

1
2
3
4
5
6
socket.on('send message', (name, text) => {
	massage = name + ' : ' + text;
	console.log(socket.id + '(' + name + ') : ' + text);
	io.emit('receive message', massage);
	insertChat(name, text);
});

소켓 부분에서 사용에게 send message 신호를 받은경우 사용자에게 메세지를 리시브하면서 이후에 이름과 텍스트를 데이터 베이스에 삽입한다.

사용자 입장

이번에는 사용자가 입장했을 때 사용자에게 이전에 데이터 베이스에 기록된 메세지를 보여줄 것이다. NodeJS에서 데이터 베이스의 결과 값(rows)는 JSON 형식으로 출력된다.

1
2
3
4
5
6
7
8
9
getChatHistory = (num) => {
	connection.query('SELECT PK, USER, CONTENT FROM CHAT ORDER BY PK DESC LIMIT ' + num + ';', (err, rows, filds)=> {
		if(!err) {
			return rows;
		}
		else
			console.log(err);
	});
};

처음에 필자는 위와같이 rows를 리턴하도록 하였는데 값이 리턴되지 않았다. 노드가 비동기식으로 실행되어서 발생하는 문제라고하는데 해결방법은 아직 잘 모르겠다. 그래서 임시적으로 인라인으로 작성하였다.

1
2
3
4
5
6
7
8
9
io.on('connection', socket => {
	var randomNick = ['감자탕', '조개탕', '온탕', '냉탕', '맛탕', '새우탕', '그라탕', '갈비탕', '백설탕', '쌍화탕', '탕탕탕'];
	console.log('USER CONNECTED : ', socket.id);

    connection.query('SELECT PK, USER, CONTENT FROM CHAT ORDER BY PK DESC LIMIT 10;', (err, rows, filds)=> {
		if(!err) for(let i=rows.length-1; i>=0; i--) io.to(socket.id).emit('receive message', rows[i].USER, rows[i].CONTENT);
		else console.log(err);
	});
	...

사용자가 입장했을 때 쿼리를 돌린다. DESC를 이용하여 하위에 있는 채팅이면서 10개만 가져오도록 하였다. 결과값인 rows에서는 rows[x].USER와 같이 컬럼의 값을 거져올 수 있다.

for문을 거꾸로 돌리는 이유는 저렇게 하지 않으면 결과가 반대로 출력됐기 때문이다. 그 외 다른 이유는 없었다. 또한 rows.length를 활용하여 10개보다 적은 경우에도 오류없이 실행하도록 하였다.

WRITTEN BY

배진오

소비적인 일보단 생산적인 일을 추구하며, 좋아하는 일을 잘하고 싶어합니다 :D
im@baejino.com