오늘은 드디어 MVC에 MySQL을 연결하는 것을 배웠습니다...
파일이 너무 많아서 왔다갔다하는데 너무 헷갈렸고.. 복잡하고.. 그래서 미뤘다가는 큰일 날 것 같다는 생각이 들어서 호다닥 정리를 해보도록 하겠습니다.
우선 파일 구조는
이렇게 만들면 됩니다.. 아직은 어색하기만 한 복잡한 구조의 파일들..
일단 먼저 해주어야 할 것은 npm i express ejs는 설치했으니, MySQL을 연동하려면 터미널에 npm i mysql을 해주어야 합니다!!
mysql이 설치된 것을 확인해주시구요,,,
항시적으로 이걸 잊지말고 내가 지금 어떤 폴더에서 어떤 코드를 작성하고 있는지 잊으면 안됩니다.. 오늘은 폴더도 많고 파일도 매우 많기 때문에...
1. app.js
const express = require('express');
const app = express();
const PORT = 8004;
app.set('view engine', 'ejs');
app.use('/views', express.static(__dirname + '/views'));
app.use('/static', express.static(__dirname + '/static'));
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const indexRouter = require('./routes/index');
app.use('/', indexRouter);
app.get('*', (req, res) => {
res.render('404');
});
app.listen(PORT, () => {
console.log(`${PORT} is opening!`);
});
2. controller/Cvisitor.js
이 코드를 보면 [before]/[after]로 나눠어져있는데요! db연결 전 후로 보면 됩니다!
우리는 앞으로 db에 연결해서 쓰는 경우가 많으니 [after]를 위주로 참고해서 공부하면 되겠죠?
const Visitor = require('../model/Visitor');
exports.main = (req, res) => {
res.render('index');
};
exports.getVisitors = (req, res) => {
// [before]
// res.render('visitor', { data: Visitor.getVisitors() });
// [after]
// console.log(Visitor.getVisitors())
Visitor.getVisitors((result) => {
console.log('controller >>', result);
res.render('visitor', { data: result });
});
};
exports.postVisitor = (req, res) => {
console.log(req.body); // { name: xx, comment: yy }
const { name, comment } = req.body;
Visitor.postVisitor(req.body, (insertId) => {
console.log('controller >> ', insertId);
res.send({ id: insertId, name: name, comment: comment });
});
};
exports.deleteVisitor = (req, res) => {
console.log(req.body); // { id: xx }
const { id } = req.body;
Visitor.deleteVisitor(id, (result) => {
console.log('controller >>', result); // true
res.send(result); // res.send(true)
});
};
3. model/Visitor.js
const mysql = require('mysql');
// db연결 설정
const conn = mysql.createConnection({
host: 'localhost',
//user: 'root',//root계정은 비밀번호 접근을 허용하지 않아서 이렇게만 하면 에러가 뜬다...--> 해결방법: 새로운 사용자를 만들고 그 사용자로 접근해야한다.
user: 'user', //mysql에서 ddl을 사용해서 user라는 사용자를 추가하고, dcl을 통해서 user에 권한을 부여한다..
password: '1234',
database: 'sesac',
});
exports.getVisitors = (callback) => {
conn.query(`select * from visitor`, (err, rows) => {
//`select * from visitor`:webserver에서 database로 query를 날리는 것!!
//visitor의 모든 행을 선택해서
if (err) {
throw err; //에러가 뜨면 에러를 던지고
}
console.log('model>>', rows);
callback(rows); //아니면 rows를 넘긴다(database에서 webserver로 응답하는데 그게 rows라는 말임)
});
};
exports.postVisitor = (data, callback) => {
//매개변수
//data:프론트엔드에서 유저가 입력한 값(req.body)
//callback:query실행 후 호출할 함수
conn.query(
`insert into visitor values(null, "${data.name}","${data.comment}")`,
(err, rows) => {
if (err) {
throw err;
}
console.log('model>>', rows);
4.routes/index.js
const express = require('express');
const controller = require('../controller/Cvisitor');
const router = express.Router();
// 기본주소: localhost:PORT
router.get('/', controller.main);
router.get('/visitors', controller.getVisitors);
router.post('/visitor', controller.postVisitor);
router.delete('/visitor', controller.deleteVisitor);
module.exports = router;
5.static/js/visitor.js
// front js
// tbody 요소, button-group 요소를 선택
const tbody = document.querySelector('tbody'); // $('tbody')
const buttonGroup = document.querySelector('#button-group'); // $('#button-group')
// 폼의 [등록] 버튼 클릭시 테이블에 방문데이터 추가
// = 버튼 클릭시 axios로 POST /visitor 요청 날려서 db에 데이터 insert 하기
function createVisitor() {
const form = document.forms['visitor-form'];
axios({
method: 'POST',
url: '/visitor',
data: {
name: form.name.value,
comment: form.comment.value,
},
}).then((res) => {
console.log('post /visitor 요청에 대한 응답', res.data);
const { id, name, comment } = res.data;
// 방금 추가한 방명록 정보를 보이기
// : newVisitor 변수에 tr 요소를 생성하고, tbody의 맨마지막 요소로 추가
const newVisitor = `
<tr id="tr_${id}">
<td>${id}</td>
<td>${name}</td>
<td>${comment}</td>
<td><button type="button">수정</button></td>
<td><button type="button" onclick="deleteVisitor(this, ${id})>삭제</button></td>
</tr>
`;
tbody.insertAdjacentHTML('beforeend', newVisitor); // / $('tbody').append(newVisitor);
});
}
function deleteVisitor(obj, id) {
console.log(obj, id);
// confirm 창에서 [취소] 누르면 아무일도 일어나지 않음
if (!confirm('정말로 삭제하나요?')) {
// !false => true
return;
}
// confirm 창에서 [확인] 누르면 visitor 데이터 삭제
// : axios로 DELETE /visitor 요청 날려서 db에 데이터 delete 하기
axios({
method: 'delete',
url: '/visitor',
data: {
id: id,
},
}).then((res) => {
console.log('delete /visitor 요청에 대한 응답', res.data);
alert('삭제성공!');
obj.parentElement.parentElement.remove();
});
}
자 전체적인 구조와 코드는 이렇게 되는데 각 라우트별로 하나하나씩 어떻게 기능들이 작동하는지 한번 자세하게 알아보도록 하겠습니다.
우선 위의 도표가 있었죠? 그거 잘 생각해주셔야 백에서의 코드들이 어떤 순서로 요청이 오고 가는지 이해할 수 있어요..!
1.Read
원래 우리가 라우트들을 app.js라는 파일에다가 싹다 정리를 했었잖아요? 그걸 mvc패턴을 이용해서 route파일들에 정의를 했었죠...
그래서 app.js 파일에서 routes/index.js에 라우트들을 연결해줘야하니까
const indexRouter = require('./routes/index');
app.use('/', indexRouter);
이런 코드가 필요했습니다..
이렇게 라우트와 연결해주면
routes/index.js에서도 express모듈을 사용하고 express의 라우트기능을 사용하니
const express = require('express');
const router = express.Router();
이 두줄이 필요한거죠.
또, 라우트는 controller와도 연결되어 있어야 하죠?
그래서
const controller = require('../controller/Cvisitor');
이렇게 컨트롤러의 Cvisitor.js파일을 불러오는 코드가 필요합니다.
그럼 이제 라우트에서 기본 경로를 정해주어야겠죠?
routes/index.js에서
router.get('/', controller.main);
기본경로로 이렇게 설정해주면 컨트롤러의 controller/Cvisitor.js와 연결되어
exports.main = (req, res) => {
res.render('index');
};
localhost:8004로 접속했을 때, index.ejs로 접속하게 됩니다.
이렇게요...
views/index.ejs는
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>홈</title>
</head>
<body>
<h1>MVC패턴과 MYSQL 연결</h1>
<a href="/visitors">방명록 남기기</a>
</body>
</html>
이렇게 구성되어 있는데요...
a태그에 걸려있는 /visitors라는거 보이죠? 이걸누르면 views/visitor.ejs로 이동해야겠죠?
그래서 routes/index.js파일에서 라우트를 '/visitors'에 대한 라우트를 정의해주어야 합니다.
router.get('/visitors', controller.getVisitors);
그럼 컨트롤러로 getVisitors에서 어떻게 작동하는지 봐야겠죠?
exports.getVisitors = (req, res) => {
// [before]
// res.render('visitor', { data: Visitor.getVisitors() });
// [after]
// console.log(Visitor.getVisitors())
Visitor.getVisitors((result) => {
console.log('controller >>', result);
res.render('visitor', { data: result });
});
};
그런데 여기에 처음보는게 하나있지 않나요? 저 Visitor뭘까요? 컨트롤러와 연결되어야 하는 것들 중에 아직 우리가 연결 안한걸 생각을 해보면...네.. model입니다..
const Visitor = require('../model/Visitor');
이렇게 모델을 불러와서 Visitor라는 변수에 저장해주었어요.
그래서 Visitor라는 변수를 사용할 수 있었던거죠.
그럼 Visitor.getVisitors()라는건 결국엔 model에게 어떤 정보를 보내는거겠죠..?
그럼 model/Visitor로 들어가서 getVisitor가 어떤 역할을 하고 있는지 보겠습니다. (아 그전에 model은 db와 연결되어있답니다 ㅎㅎ다들알고계시겠지만...)
exports.getVisitors = (callback) => {
conn.query(`select * from visitor order by id desc`, (err, rows) => {
//`select * from visitor`:webserver에서 database로 query를 날리는 것!!
//visitor의 모든 행을 선택해서
if (err) {
throw err; //에러가 뜨면 에러를 던지고
}
console.log('model>>', rows);
callback(rows); //아니면 rows를 넘긴다(database에서 webserver로 응답하는데 그게 rows라는 말임)
});
};
네.. 여기에서 callback으로 넘겨준 rows가 컨트롤러에서 보면 result로 받아서 views/visitor로 넘겨주고있었겠네요.. data객체로 묶어서요...그 결과
이런 화면을 볼 수 있게 됩니다... 밑에 표에서 데이터베이스의 정보를 볼 수 있는 이유도 이제 아시겠죠?
여기까지가 Read라고 보면 됩니다!
2. Create
다음으로 방명록을 등록하는 Create기능을 살펴보도록 하겠습니다.
먼저, visitor.ejs에서 [등록]버튼을 눌렀을 때에 해당하는 기능이니 button에 onclick="createVisitor()"이라는 함수를 걸어두고 함수를 정의해야겠죠?
이 함수에 대한 정의는 front.js에 해당하는 static/js/visitor.js에 정의해주면 됩니다.
뭐 당연히 visitor.ejs에서 script를 걸어서 정의해도 상관은 없겠죠? 그런데 모듈을 분리하기로 했으니까...ㅎ
아 참... 그런데 우리가 방명록을 등록하면 등록버튼을 누름과 동시에 프론트에서 바로 보이길 원하는 거잖아요? 그러려면 dom으로 연결을 해주어야 겠죠?
const tbody = document.querySelector('tbody');
이렇게 연결을해서 tbody라는 변수에 저장을하고
createVisitor()함수를 살펴보도록 합시다.
// 폼의 [등록] 버튼 클릭시 테이블에 방문데이터 추가
// = 버튼 클릭시 axios로 POST /visitor 요청 날려서 db에 데이터 insert 하기
function createVisitor() {
const form = document.forms['visitor-form'];
axios({
method: 'POST',
url: '/visitor',
data: {
name: form.name.value,
comment: form.comment.value,
},
}).then((res) => {
console.log('post /visitor 요청에 대한 응답', res.data);
const { id, name, comment } = res.data;
// 방금 추가한 방명록 정보를 보이기
// : newVisitor 변수에 tr 요소를 생성하고, tbody의 맨마지막 요소로 추가
const newVisitor = `
<tr id="tr_${id}">
<td>${id}</td>
<td>${name}</td>
<td>${comment}</td>
<td><button type="button" onclick='editVisitor(${id})'>수정</button></td>
<td><button type="button" onclick="deleteVisitor(this, ${id})">삭제</button></td>
</tr>
`;
tbody.insertAdjacentHTML('beforeend', newVisitor); // / $('tbody').append(newVisitor);
});
}
복잡하죠? 하나하나 뜯어볼까요? 우선 입력받은 정보를 백으로 넘겨야 하잖아요? axios를 이용해서 post요청을 날립니다. 다. data객체에 묶어서 이름과 comment를 각각 폼에 입
아 작성하다가 날라갔습니다... 안녕...DELETE까지 다 했는데... 사진첨부하다가....
눈물납니다..어쨌든 저는 이해를 다 했으니
나중에 시간될때 이어서 작성을 해볼게요ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ
'[새싹X코딩온]웹 풀스택' 카테고리의 다른 글
[새싹X코딩온]웹 풀스택 7주차(9/1)회고록|Rest API & DB응용 & cookie (1) | 2023.09.03 |
---|---|
[새싹X코딩온]웹 풀스택 7주차(8/30)회고록|Sequelize (0) | 2023.09.02 |
[새싹X코딩온]웹 풀스택 6주차(8/25)회고록|MYSQL+MVC패턴 (0) | 2023.08.30 |
[새싹X코딩온]웹 풀스택 6주차(8/23)회고록|데이터베이스, MYSQL, SQL문법 (0) | 2023.08.24 |
[새싹X코딩온]웹 풀스택 4주차(8/21)회고록|폼 유효성검사, 파일전송하기 (0) | 2023.08.23 |