[๐ฑ๋ชฉ์ฐจ๐ฑ]
- mysql ์ฐ๋ํ๊ธฐ
- ๋ฐฉ๋ช ๋ก ์ถ๊ฐํ๊ธฐ
- '๋ฑ๋ก'๋ ๋ด์ฉ์ด ์๋ Table์ ๋ฐ๋ก ๋ณด์ด๊ธฐ
- ๋ฐฉ๋ช ๋ก ์ง์ฐ๊ธฐ
- ์ญ์ ๋ฐ๋ก๋ณด์ด๊ธฐ
+) Rest API
+) insertAdjacentHTML?
์ด๋ฒ ์์
๋๋ ๋งจ๋ ์์๋ก DB์์ ๋ฐ์์๋ค๊ณ ๊ฐ์ ์ ํ์๋๋ฐ ์ด๋ฒ์ ์ง์ DB์์ ๋ฐ์์ค๊ธฐ๋ฅผ ํด๋ณด๊ฒ ์ต๋๋ค.
01. mysql ์ฐ๋ํ๊ธฐ
๋จผ์ mysql ์ฐ๊ฒฐ์ ์ํ mvc ํ๋ก์ ํธ ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํด์ค๋๋ค. ๊ทธ ๋ค์ DB ํ
์ด๋ธ์ ์์ฑํฉ๋๋ค. npm install mysql ๋ก mysql ๋ชจ๋์ ์ค์นํด์ค๋๋ค.
-- user ๋ผ๋ ์๋ก์ด ๊ณ์ ์์ฑ - mysql ์ฌ์ฉ์ ์ถ๊ฐํ๊ธฐ
CREATE USER 'user'@'%' IDENTIFIED WITH mysql_native_password by '1234';
--user ๊ณ์ ์ DB ๊ถํ ๋ถ์ฌ (๋ชจ๋ DB์ ์ ๊ทผ ๊ฐ๋ฅํ๋๋ก)// *.* -> ๋ชจ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ชจ๋ ํ
์ด๋ธ ์๋ฏธ
GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' WITH GRANT OPTION;
-- ํ์ฌ ์ฌ์ฉ์ค์ธ mysql ์บ์๋ฅผ ์ง์ฐ๊ณ ์๋ก์ด ์ค์ ์ ์ฉ
FLUSH PRIVILEGES;
๊ทธ ๋ค์ sql ํ์ผ์์ user ๋ผ๋ ์๋ก์ด ๊ณ์ ์ ์ถ๊ฐํด์ค๋๋ค.
๊ทธ ๋ค์ model ๋๋ ํ ๋ฆฌ์ Visitor.js๋ฅผ ์ถ๊ฐํ๊ณ Visitor.js ํ์ผ์ require ํจ์๋ก mysql ์ ๋ฐ์์์ค๋๋ค.
[/model/Visitor.js]
const mysql = require('mysql');
const conn = mysql.createConnection({
//db ์ฐ๊ฒฐ ์ค์
host: 'localhost',
user: 'user',
password: '1234',
database: 'mvc',
});
db ์ฐ๊ฒฐ ๊ฐ์ฒด ์์ฑํ๊ธฐ (mysql ์ createConnection ์ด์ฉ )
user ๊ณ์ ์์ ์ค์ ํด์ค password์ ์ฐ๊ฒฐํ๋ ค๋ database๋ฅผ ์ฐ๊ฒฐํด์ฃผ๊ณ
create database mvc character set utf8mb4 collate utf8mb4_unicode_ci;
use mvc;
CREATE TABLE VISITOR (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
name VARCHAR(10) NOT NULL,
comment MEDIUMTEXT
);
INSERT INTO VISITOR
VALUES ('1','ํ๊ธธ๋','๋ด๊ฐ ์๋ค.'),
('2','์ด์ฐฌํ','์ผ๋ผ์ฐจ์ฐจ');
sql ํ์ผ์์ ์ด๋ชจํฐ์ฝ๋ ์ธ์ฝ๋ฉํด์ค ์ ์๋ ์ธ์ฝ๋ฉ ์กฐํฉ์ ๋ถ๋ฌ์ ์ค๋๋ค.
[model/Visitor.js]
const mysql = require('mysql');
const conn = mysql.createConnection({
//db ์ฐ๊ฒฐ ์ค์
host: 'localhost',
user: 'user',
password: '1234',
database: 'mvc',
});
exports.getVisitors = (callback) => {
//db์ฐ๊ฒฐ ๊ฐ์ฒด์๋ค๊ฐ query๋ฅผ ๋ ๋ฆด๊ฑฐ์
conn.query('SELECT * FROM VISITOR', (err, rows) => {
if (err) {
//๋ง์ฝ์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด ์๋ฌ๋ฅผ ๋์ง๊ณ
throw err;
}
//๊ทธ๊ฒ ์๋๋ผ๋ฉด
console.log('model >>', rows);
callback(rows); //callback์ผ๋ก rows๋ฅผ ๋๊ธธ๊ฑฐ์
//์ด callback์ ์ปจํธ๋กค๋ฌ๊ฐ ๋ฐ์์ฌ ์ ์์
});
};
getVisitors ๋ผ๋ ํจ์๋ฅผ ์์ฑํด์ค๋๋ค. db๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด ์ฝ๋ฐฑ์ ์ฌ์ฉํด์ค๋๋ค. db ์ฐ๊ฒฐ ๊ฐ์ฒด์ query ๋ฅผ ๋ ๋ฆด ํจ์๋ฅผ ์กฐ๊ฑด๋ฌธ์ผ๋ก ๋ฌ์์ ์์ฑํด์ค๋๋ค.
๋ง์ฝ์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด ์๋ฌ๋ฅผ ๋์ง๊ณ ๊ทธ๊ฒ ์๋๋ผ๋ฉด callback์ผ๋ก rows๋ฅผ ๋๊น๋๋ค.
[controller/Cvisitor.js]
const Visitor = require('../model/Visitor');
exports.main = (req, res) => {
res.render('index');
};
exports.getVisitors = (req, res) => {
//[before]
//res.render('visitor', { data: Visitor.getVisitors() });
//[after]
Visitor.getVisitors((result) => {
console.log('controller >>', result);
res.render('visitor', { data: result }); //model์์ ๋ฐ์์จ result๋ฅผ ๋๊ธธ๊ฑฐ์
});
};
getVisitors ์์ visitor.ejsํ์ผ์ ๋ ๋ํ๊ณ ์ model/Visitor.js์ ์๋ ์ฝ๋ฐฑ์ ๋ฐ์์ rows๋ฅผ ๋ณด๋ด์ค๋๋ค. ๋ฐ๋ผ์ controllerํ์ผ์ ํจ์์ ํ๋ผ๋ฏธํฐ๊ฐ ํ์ํฉ๋๋ค. (rows -> result) model์์ callback์ ๋ฐ์์์ ๋ฐ์์จ result๋ฅผ data๋ก ๋๊ธฐ๊ฒ ์ต๋๋ค. ๋์ค์ ์ด result๊ฐ์ ejsํ์ผ์์ ์ฌ์ฉ์ data๋ผ๋ ๋ณ์๋ช
์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ฉด ์ฝ์์์ RowDataPacket { id: 1, name: 'ํ๊ธธ๋', comment: '๋ด๊ฐ ์๋ค.' }, ์์ผ๋ก result๊ฐ ์ฐํ๊ฒ ๋ฉ๋๋ค.
์ ๋ง ์์๋ณผ ๊ฒ๊ฐ์ง๋ง ํ์ผ๋ค ์๋ค๊ฐ๋ค ๋ณด๊ธฐ์ข๊ฒ ํด๋ดค์ต๋๋ค. ํํ ;;
02. ๋ฐฉ๋ช ๋ก ์ถ๊ฐํ๊ธฐ
์์ฑ ํ "๋ฑ๋ก"์ ๋๋ฅด๋ฉด DB์ ์ ์ฅ๋๋๋ก ํด๋ณด๊ฒ ์ต๋๋ค.
[/views/visitor.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>
<!-- axios cdn -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- jquery cdn -->
<script
src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"
></script>
<script defer src="/static/js/visitor.js"></script>
<style>
body {
background-color: rgb(231, 255, 240);
}
</style>
</head>
<body>
<form name="visitor-form">
<fieldset>
<legend>๋ฐฉ๋ช
๋ก ๋ฑ๋ก</legend>
<input type="text" id="name" placeholder="์ฌ์ฉ์ ์ด๋ฆ" /> <br />
<input type="text" id="comment" placeholder="๋ฐฉ๋ช
๋ก" /> <br />
<div id="button-group">
<button type="button" onclick="createVisitor()">๋ฑ๋ก</button>
</div>
</fieldset>
</form>
<br />
<table border="1" cellspacing="0">
<thead>
<tr>
<th>ID</th>
<th>์์ฑ์</th>
<th>๋ฐฉ๋ช
๋ก</th>
<th>์์ </th>
<th>์ญ์ </th>
</tr>
</thead>
<tbody>
<% for (let d of data) { %>
<tr id="tr_<%= d.id %>">
<td><%= d.id %></td>
<td><%= d.name %></td>
<td><%= d.comment %></td>
<td>
<button type="button">์์ </button>
</td>
<td>
<button type="button">์ญ์ </button>
</td>
</tr>
<% } %>
</tbody>
</table>
</body>
</html>
tbody ์์ ์์ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋๊ฒ์ ๋ณด๋ฉด controller์์ data๋ผ๋ ํค๊ฐ์ผ๋ก result๊ฐ๋ค์ ๊ฐ์ ธ์๊ธฐ ๋๋ฌธ์ data ๋ณ์๋ฅผ ์ด์ฉํด์ id, name,comment๊ฐ์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
๋์ ํผ ์ ์ก์ ์ํด axios์ ์ ์ด์ฟผ๋ฆฌ๋ฅผ ๊ฐ์ ธ์ค๋ CDN์ ์
๋ ฅํด์ค๋๋ค.
๋ฑ๋ก์ด๋ผ๋ ๋ฒํผ์ ๋๋ฅด๋ฉด onclick์ผ๋ก createVisitorํจ์๋ฅผ ์คํ๋๊ฒ ์์ฑํด์ค๋ค์ ์ด ํจ์๋ฅผ ์คํํ script๋ฅผ ํค๋ ์คํฌ๋ฆฝํธ์ ์ฐ๊ฒฐํด์ค๋๋ค.
static ๋๋ ํ ๋ฆฌ์์ ํ์๋ก js ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํ๊ณ ๊ทธ ํ์์ index.js ํ์ผ์ ์์ฑํด๋ณด๊ฒ ์ต๋๋ค.
/views/visitor.ejs ์์ ์คํ๋ js ํ์ผ์ ๋ฐ๋ก static ๋๋ ํ ๋ฆฌ์์ ๋ง๋ค์ด์ค ๊ฒ์
๋๋ค.
[static/js/index.js]
//front js
const tbody = document.querySelector('tbody');
const buttonGroup = document.querySelector('#button-group');
// ํผ์ [๋ฑ๋ก] ๋ฒํผ ํด๋ฆญ์ ํ
์ด๋ธ์ ๋ฐฉ๋ฌธ๋ฐ์ดํฐ ์ถ๊ฐ
// : ๋ฒํผ ํด๋ฆญ์ axios ๋ก POST/visitor ์์ฒญ ๋ ๋ ค์ db์ ๋ฐ์ดํฐ insert ํ๊ธฐ
function createVisitor() {
const form = document.forms['visitor-form']; //form ์ ํ
axios({
//axios๋ก ์์ฒญ ๋ ๋ฆฌ๊ธฐ
method: 'POST',
url: '/visitor',
data: {
name: form.name.value,
comment: form.comment.value,
},
}).then((res) => {
console.log('post/visitor ์์ฒญ์ ๋ํ ์๋ต', res);
});
}
querySelector๋ก tbody๋ buttonGroup ๋ถ๋ฌ์ค๊ณ createVisitorํจ์ ์ ์ํด์ค๋๋ค. visitor.ejsํ์ผ์์ ๋ฑ๋ก button์ด ๋๋ฆฌ๋ฉด onclick ์ด๋ฒคํธ๋ก createVisitor ํจ์ ์คํ๋๊ฒ ๋ง๋ค์์ต๋๋ค. createVisitorํจ์์์๋ 'visitor-form'์ด๋ผ๋ ํผ์ ๋ฐ์์จ๋ค์ axios ๋ก ์์ฒญ์ ๋ ๋ ค์ค๋๋ค. ์ฐธ๊ณ ๋ก ์์ data์๋ id๊ฐ ์๋๋ฐ ์ด ์ด์ ๋ ์ฐ๋ฆฌ๊ฐ ๋ฐ๋ก id๋ฅผ ์ ์ด์ฃผ์ง ์์๋ ๋ฑ๋กํ๋๋ก ์ซ์๊ฐ ์นด์ดํ
๋์ด ์ฌ๋ผ๊ฐ ์ ์๋ ๊ฒ์ mysql์์ auto_increment๋ฅผ ์ค์ ํด์ฃผ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๋ฐ๋ผ์ name๊ณผ comment๋ง ์ ์ด์ฃผ์์ต๋๋ค.
์ฌ๊ธฐ์ ๋ณด๋ด๋ ๋ฐ์ดํฐ๊ฐ์ name๊ณผ comment ๊ฐ์
๋๋ค. ์ด ๊ฐ๋ค์ ๋ณด๋ด์ฃผ๊ธฐ ์ ์ router์์ ๊ฒฝ๋ก๋ฅผ ๋ง๋ค์ด ์ฃผ์ด์ผ ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ผ์ฐํฐ ํด๋๋ก ๊ฐ์
[/routes/index.js]
const express = require('express');
const controller = require('../controller/Cvisitor');
const router = express.Router();
router.get('/', controller.main);
router.get('/visitors', controller.getVisitors); //๋ฐฉ๋ช
๋ก ์ ์ฒด๋ณด์ด๊ธฐ
//๋ฐฉ๋ช
๋ก ํ๋ ์ถ๊ฐ
//visitor.ejs์์ ๋ฒํผ ํด๋ฆญ์ createVisitor ํจ์ ์คํ๋๊ณ
router.post('/visitor', controller.postVisitor);
module.exports = router;
axios ๋ฅผ ๋ณด๋ด์ post๋ก ๋ฐ๋ ๋ผ์ฐํฐ๋ฅผ ์์ฑํด์ค๋๋ค. router.post ์์ ๊ฒฝ๋ก๋ฅผ ์ ์ด์ฃผ๊ณ controller ์์ ์คํ๋ ํจ์๋ฅผ ์์ฑํด์ค๋๋ค.
router์์ controller์์ ์ด๋ค ํจ์๋ฅผ ์คํํ ๊ฑด์ง ์ ํด์ค๋๋ค.
[controller/Cvisitor.js]
const Visitor = require('../model/Visitor');
exports.main = (req, res) => {
res.render('index');
};
exports.getVisitors = (req, res) => {
//[before]
//res.render('visitor', { data: Visitor.getVisitors() });
//[after]
Visitor.getVisitors((result) => {
console.log('controller >>', result);
res.render('visitor', { data: result }); //model์์ ๋ฐ์์จ result๋ฅผ ๋๊ธธ๊ฑฐ์
});
};
// controller >> [
// RowDataPacket { id: 1, name: 'ํ๊ธธ๋', comment: '๋ด๊ฐ ์๋ค.' },
// RowDataPacket { id: 2, name: '์ด์ฐฌํ', comment: '์ผ๋ผ์ฐจ์ฐจ' }
// ]
exports.postVisitor = (req, res) => {
console.log('controller postVisitor ํจ์ ์คํ~~');
console.log('axios์ data', req.body); //axios์ data ๋ ๋ผ์ด
const { name, comment } = req.body;
Visitor.postVisitor(req.body, (insertId) => {
//model/visitor์ ์ฝ๋ฐฑํจ์๋ก ๋ฐ์์ค๋ ๊ฐ
console.log('controller >>', insertId);
// res.send('ํ๋ก ํธ๋ก ๋ณด๋ผ ๋ฐ์ดํฐ ');
res.send({ id: insertId, name: name, comment: comment });
});
};
postVisitor ํจ์์์ req.body๋ฅผ ๊ฐ์ฒด ๋ถํด ํ๊ณ [/model/Visitor.js] ์์ ์ฝ๋ฐฑํจ์๋ก ๋ฐ์์ค๋ ๊ฐ์ ์ธ์๋ก ๋ฃ์ด์ฃผ๊ณ ํ๋ก ํธ๋ก ๋ณด๋ผ ๋ฐ์ดํฐ๋ฅผ ์์ฑํด์ค๋๋ค. controller์์ Model Visitor์๊ฒ id,name,comment ์ธ๊ฐ์ง์ ๊ฐ์ ๋ณด๋
๋๋ค. ์ด ๊ฐ๋ค์ views ๋๋ ํ ๋ฆฌ์ ejs ํ์ผ๋ก ๋์ด๊ฐ๋๋ค. ์ฐ๋ฆฌ๋ ์๋ฐ์คํฌ๋ฆฝํธํ์ผ์ ๋ฐ๋ก ์ฐ๊ฒฐํด์ฃผ์๊ธฐ ๋๋ถ์ ์ด ๊ฐ๋ค์ static/index.js ํ์ผ๋ก ๋์ด๊ฐ์
//front js
const tbody = document.querySelector('tbody');
const buttonGroup = document.querySelector('#button-group');
// ํผ์ [๋ฑ๋ก] ๋ฒํผ ํด๋ฆญ์ ํ
์ด๋ธ์ ๋ฐฉ๋ฌธ๋ฐ์ดํฐ ์ถ๊ฐ
// : ๋ฒํผ ํด๋ฆญ์ axios ๋ก POST/visitor ์์ฒญ ๋ ๋ ค์ db์ ๋ฐ์ดํฐ insert ํ๊ธฐ
function createVisitor() {
const form = document.forms['visitor-form']; //form ์ ํ
axios({
//axios๋ก ์์ฒญ ๋ ๋ฆฌ๊ธฐ
method: 'POST',
url: '/visitor',
data: {
name: form.name.value,
comment: form.comment.value,
},
}).then((res) => {
console.log('post/visitor ์์ฒญ์ ๋ํ ์๋ต', res);
});
}
controller์์ ๋์ด์จ send ๊ฐ์ res.data๋ก ๋ค์ด๊ฐ๊ฒ ๋ฉ๋๋ค.
[/model/Visitor.js]
const mysql = require('mysql');
const conn = mysql.createConnection({
//db ์ฐ๊ฒฐ ์ค์
host: 'localhost',
user: 'user',
password: '1234',
database: 'mvc',
});
exports.getVisitors = (callback) => {
//db์ฐ๊ฒฐ ๊ฐ์ฒด์๋ค๊ฐ query๋ฅผ ๋ ๋ฆด๊ฑฐ์
conn.query('SELECT * FROM VISITOR', (err, rows) => {
if (err) {
//๋ง์ฝ์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด ์๋ฌ๋ฅผ ๋์ง๊ณ
throw err;
}
//๊ทธ๊ฒ ์๋๋ผ๋ฉด
console.log('model >>', rows);
callback(rows); //callback์ผ๋ก rows๋ฅผ ๋๊ธธ๊ฑฐ์
//์ด callback์ ์ปจํธ๋กค๋ฌ๊ฐ ๋ฐ์์ฌ ์ ์์
});
};
// model >> [
// RowDataPacket { id: 1, name: 'ํ๊ธธ๋', comment: '๋ด๊ฐ ์๋ค.' },
// RowDataPacket { id: 2, name: '์ด์ฐฌํ', comment: '์ผ๋ผ์ฐจ์ฐจ' }
// ]
//๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ถ๊ฐํ๋ ํจ์
exports.postVisitor = (data, callback) => {
console.log('model postVisitor ํจ์ ์คํ~');
//๋งค๊ฐ๋ณ์
//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);
callback(rows.insertId);
}
);
};
Visitor์์ ๋ฐ์์จ ๊ฐ์ ์ด๋ป๊ฒ ๋ํ๋ผ์ง ์ค์ ํด์ค๋๋ค. ๋ฑ๋ก์ ๋๋ฅด๋ฉด DB์ INSERT ๋์ด์ผ ํ๊ธฐ ๋๋ฌธ์ model ๋๋ ํ ๋ฆฌ์ Visitor.js ํ์ผ๋ก ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ถ๊ฐํ๋ ํจ์๋ฅผ ์์ฑํด์ค๋๋ค. db ๊ฐ์ฒด์ ๋ ๋ฆด ์ฟผ๋ฆฌ๋ฅผ ์์ฑํด์ค๋๋ค. callback์์๋ rows์ insertId๋ฅผ ์ธ์๋ก ๋ฐ๊ฒ ํฉ๋๋ค. (rows(data) ->inserId๋ฅผ ํค๊ฐ์ผ๋ก ๊ฐ์ง๊ณ ์๋ ๊ฐ์ฒด) ์ ์ฝ๋ฐฑํจ์๋ controller์ ์๋ ํจ์๋ก ๋ณด๋ด์ง๊ฒ ๋ฉ๋๋ค.
๊ทธ๋ฐ๋ฐ ์ด๋ ๊ฒ๋๋ฉด ๋ฑ๋ก์ ๋๋ ์ ๋ ๋ฐ๋ก ๋ฑ๋ก์ด ์๋๊ณ ์๋ก๊ณ ์นจ์ ํด์ผ ์ถ๊ฐ๊ฐ ๋ฉ๋๋ค.
03. '๋ฑ๋ก'๋ ๋ด์ฉ์ด ์๋ Table ์ ๋ฐ๋ก ๋ณด์ด๊ธฐ
[controller/Cvisitor.js] ์์ res.send๋ก ๋ณด๋ด์ฃผ๊ณ ์์ผ๋๊น visitor.js์์ ์ถ๊ฐํ ๋ฐฉ๋ช
๋ก ์ ๋ณด๋ฅผ ๋ณด์ด๊ธฐ๋ฅผ ํ๋ฉด ๋ฉ๋๋น.
๋ฑ๋ก์ <tr>์์๊ฐ ํ์ค์ด ์ถ๊ฐ๋๋ฉด ๋๋๊น
[static/js/visitor.js]
//front js
const tbody = document.querySelector('tbody');
const buttonGroup = document.querySelector('#button-group');
// ํผ์ [๋ฑ๋ก] ๋ฒํผ ํด๋ฆญ์ ํ
์ด๋ธ์ ๋ฐฉ๋ฌธ๋ฐ์ดํฐ ์ถ๊ฐ
// : ๋ฒํผ ํด๋ฆญ์ axios ๋ก POST/visitor ์์ฒญ ๋ ๋ ค์ db์ ๋ฐ์ดํฐ insert ํ๊ธฐ
function createVisitor() {
const form = document.forms['visitor-form']; //form ์ ํ
axios({
//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">์ญ์ </button>
</td>
</tr>
`;
//jquery
// $('tbody').append(newVisitor);
//js
tbody.insertAdjacentHTML('beforeend', newVisitor);
});
}
createVisitor ํจ์์ then ๋ถ๋ถ์ res.data ๊ฐ์ฒด๋ถํดํ ๋ค์ ์๋กญ๊ฒ ์ถ๊ฐํ ๋ด์ฉ์ ์์ฑํ๊ณ ์ ์ด์ฟผ๋ฆฌ๋ฒ์ ๊ณผ ์๋ฐ์คํฌ๋ฆฝํธ ๋ฒ์ ์ผ๋ก ์์ฑํด์ฃผ์์ต๋๋ค.
ํ ์ด๊ฒ๋ ๋๋ฆ ๋ณด๊ธฐ์ข๊ฒ ์ ๋ฆฌํด๋ดค์ต๋๋ค..
04. ๋ฐฉ๋ช ๋ก ์ง์ฐ๊ธฐ
[/views/visitor.ejs]์์ ์ญ์ ๋ฒํผ์ onclick์ผ๋ก deleteVisitorํจ์๋ฅผ ๊ฑธ์ด์ค๋๋ค.
<!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>
<!-- axios cdn -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- jquery cdn -->
<script
src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"
></script>
<script defer src="/static/js/visitor.js"></script>
<style>
body {
background-color: rgb(231, 255, 240);
}
</style>
</head>
<body>
<form name="visitor-form">
<fieldset>
<legend>๋ฐฉ๋ช
๋ก ๋ฑ๋ก</legend>
<input type="text" id="name" placeholder="์ฌ์ฉ์ ์ด๋ฆ" /> <br />
<input type="text" id="comment" placeholder="๋ฐฉ๋ช
๋ก" /> <br />
<div id="button-group">
<button type="button" onclick="createVisitor()">๋ฑ๋ก</button>
</div>
</fieldset>
</form>
<br />
<table border="1" cellspacing="0">
<thead>
<tr>
<th>ID</th>
<th>์์ฑ์</th>
<th>๋ฐฉ๋ช
๋ก</th>
<th>์์ </th>
<th>์ญ์ </th>
</tr>
</thead>
<tbody>
<% for (let d of data) { %>
<tr id="tr_<%= d.id %>">
<td><%= d.id %></td>
<td><%= d.name %></td>
<td><%= d.comment %></td>
<td>
<button type="button">์์ </button>
</td>
<td>
<button type="button" onclick="deleteVisitor(this,'<%= d.id%>')">
์ญ์
</button>
</td>
</tr>
<% } %>
</tbody>
</table>
</body>
</html>
๊ทธ๋ค์
[/static/js/visitor.js]
์๋ deleteVisitor onclick์ผ๋ก ๊ฑธ์ด์ค๋๋ค.
//front js
const tbody = document.querySelector('tbody');
const buttonGroup = document.querySelector('#button-group');
// ํผ์ [๋ฑ๋ก] ๋ฒํผ ํด๋ฆญ์ ํ
์ด๋ธ์ ๋ฐฉ๋ฌธ๋ฐ์ดํฐ ์ถ๊ฐ
// : ๋ฒํผ ํด๋ฆญ์ axios ๋ก POST/visitor ์์ฒญ ๋ ๋ ค์ db์ ๋ฐ์ดํฐ insert ํ๊ธฐ
function createVisitor() {
const form = document.forms['visitor-form']; //form ์ ํ
axios({
//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>
`;
//jquery
// $('tbody').append(newVisitor);
//js
tbody.insertAdjacentHTML('beforeend', newVisitor);
});
}
function deleteVisitor(obj, id) {
console.log(obj, id); //>> <button type="button" onclick="deleteVisitor(this,'16')">์ญ์ </button>
if (!confirm(`์ ๋ง๋ก ์ญ์ ํ๋์?`)) {
//confirm ๋ฉ์๋๋ boolean์ ๋ฆฌํด
return;
}
//confirm ์ฐฝ์์ [ํ์ธ] ๋๋ฅด๋ฉด visitor ๋ฐ์ดํฐ ์ญ์
//:axios๋ก DELETE /visitor ์์ฒญ ๋ ๋ ค์ db์ ๋ฐ์ดํฐ delete ํ๊ธฐ
axios({
method: 'delete',
url: '/visitor',
data: {
id: id,
},
}).then((res) => {
console.log('delete / visitor ์์ฒญ์ ๋ํ ์๋ต', res.data);
});
}
deleteVisitorํจ์๋ฅผ ์์ฑํด์ฃผ๋๋ฐ ์ด ํจ์๋ ์ธ์๋ฅผ obj์ id ๋๊ฐ๋ฅผ ๋ฐ์ต๋๋ค. ์ฌ๊ธฐ์ obj์ id๋ฅผ ์ฝ์์ ์ฐ์ด๋ณด๋ฉด obj๋ ๋ฒํผ ์์๊ฐ ๋์ค๊ฒ ๋ฉ๋๋ค. confirm์์ ์ ๋ง๋ก ์ญ์ ํ๋ค๋ ๋ฒํผ์ ๋๋ฅด๋ฉด axios๋ก delete ์์ฒญ์ ๋ ๋ฆฌ๊ฒ ๋๊ณ then ์์ res.data๋ true๊ฐ ์ฐํ๊ฒ ๋ฉ๋๋ค.
[/routes/index.js]
//์ด ๋ชจ๋์ ์ญํ
//๊ฒฝ๋ก ์ ์ธ๊ณผ ๊ด๋ จ๋ ๋ด์ฉ ๊ธฐ์
const express = require('express');
const controller = require('../controller/Cvisitor');
const router = express.Router();
router.get('/', controller.main);
router.get('/visitors', controller.getVisitors); //๋ฐฉ๋ช
๋ก ์ ์ฒด๋ณด์ด๊ธฐ
//๋ฐฉ๋ช
๋ก ํ๋ ์กฐํ
// router.get('/visitor/:id',controller.)
//๋ฐฉ๋ช
๋ก ํ๋ ์ถ๊ฐ
//visitor.ejs์์ ๋ฒํผ ํด๋ฆญ์ createVisitor ํจ์ ์คํ๋๊ณ
router.post('/visitor', controller.postVisitor);
//๋ฐฉ๋ช
๋ก ํ๋ ์์
// router.patch('/visitor/edit',controller)
//๋ฐฉ๋ช
๋ก ํ๋ ์ญ์
// router.delete('/visitor',controller.)
router.delete('/visitor', controller.deleteVisitor);
module.exports = router;
delete๋ฉ์๋๋ฅผ ์ถ๊ฐํ๊ณ controller์์ deleteVisitor ํจ์๋ฅผ ์ ์ํด์ค๊ฒ๋๋ค.
[/controller/Cvisitor.js]
๋ชจ๋ธ์ Visitor์ ์ฐ๊ฒฐ ํด์ฃผ๊น
const Visitor = require('../model/Visitor');
exports.main = (req, res) => {
res.render('index');
};
exports.getVisitors = (req, res) => {
//[before]
//res.render('visitor', { data: Visitor.getVisitors() });
//[after]
Visitor.getVisitors((result) => {
console.log('controller >>', result);
res.render('visitor', { data: result }); //model์์ ๋ฐ์์จ result๋ฅผ ๋๊ธธ๊ฑฐ์
});
};
// controller >> [
// RowDataPacket { id: 1, name: 'ํ๊ธธ๋', comment: '๋ด๊ฐ ์๋ค.' },
// RowDataPacket { id: 2, name: '์ด์ฐฌํ', comment: '์ผ๋ผ์ฐจ์ฐจ' }
// ]
exports.postVisitor = (req, res) => {
console.log('controller postVisitor ํจ์ ์คํ~~');
console.log('axios์ data', req.body); //axios์ data ๋ ๋ผ์ด
const { name, comment } = req.body;
Visitor.postVisitor(req.body, (insertId) => {
//model/visitor์ ์ฝ๋ฐฑํจ์๋ก ๋ฐ์์ค๋ ๊ฐ
console.log('controller >>', insertId);
// res.send('ํ๋ก ํธ๋ก ๋ณด๋ผ ๋ฐ์ดํฐ ');
res.send({ id: insertId, name: name, comment: comment });
});
};
exports.deleteVisitor = (req, res) => {
console.log('controller deleteVisitor ํจ์ ์คํ~ ');
console.log(req.body); // {id:xx}
const { id } = req.body;
Visitor.deleteVisitor(id, (result) => {
//์ฒซ๋ฒ์งธ ์ธ์์ id๋ฅผ ๋ฃ๊ณ ๋๋ฒ์งธ ์ธ์์ ์ฝ๋ฐฑํจ์ ๋ฃ์ด์ฃผ๊น
console.log('controller>>', result); //callbackํจ์์ ์ธ์ ์ฑ๊ณต์ true
res.send(result); //res.send(true)
});
};
deleteVisitor ์์ console.log๋ก req.body๋ฅผ ์ฐ๊ฒ๋๋ฉด deleteํ๋ ค๋ id๋ฅผ ํค๊ฐ์ผ๋ก ๊ฐ์ง๊ณ ์๋ ๊ฐ์ฒด๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
callback ํจ์์ ์ธ์ ์ฑ๊ณต์ result์๋ true๋ผ๋ ๊ฐ์ด ๋ด๊ธฐ๊ฒ ๋๊ณ ์ด๋ฅผ ํ๋ก ํธ๋ก ๋ณด๋ด์ค๋๋ค.
[model/Visitor.js]
exports.deleteVisitor = (id, callback) => {
console.log('model deleteVisitor ํจ์ ์คํ~ ');
console.log('model >>', id); //front์์ ์๋ ค์ค ์ญ์ ํ ๋ฐ์ดํฐ์ pk
conn.query(`DELETE FROM visitor where id=${id} `, (err, rows) => {
if (err) {
throw err;
}
console.log('model>>', rows);
callback(true); //{id:id} ์ฌ๊ธฐ์ ๋๊ธฐ๋ ๋ฐ์ดํฐ๊ฐ ๋ฌ๋ผ์ง๋ฉด controller์ฝ๋๋ ๋ฌ๋ผ์ง !
});
};
deleteVisitor์์ front์์ ์๋ ค์ค ์ญ์ ํ ๋ฐ์ดํฐ์ pk๊ฐ์ ๋ฐ์์์ ํ ์ด๋ธ์์ ์ง์์ฃผ๋ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํด์ค๋๋ค.
05. ์ญ์ ๋ฐ๋ก๋ณด์ด๊ธฐ
[static/js/visitor.js]
//front js
const tbody = document.querySelector('tbody');
const buttonGroup = document.querySelector('#button-group');
// ํผ์ [๋ฑ๋ก] ๋ฒํผ ํด๋ฆญ์ ํ
์ด๋ธ์ ๋ฐฉ๋ฌธ๋ฐ์ดํฐ ์ถ๊ฐ
// : ๋ฒํผ ํด๋ฆญ์ axios ๋ก POST/visitor ์์ฒญ ๋ ๋ ค์ db์ ๋ฐ์ดํฐ insert ํ๊ธฐ
function createVisitor() {
const form = document.forms['visitor-form']; //form ์ ํ
axios({
//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>
`;
//jquery
// $('tbody').append(newVisitor);
//js
tbody.insertAdjacentHTML('beforeend', newVisitor);
});
}
function deleteVisitor(obj, id) {
console.log(obj, id); //>> <button type="button" onclick="deleteVisitor(this,'16')">์ญ์ </button>
if (!confirm(`์ ๋ง๋ก ์ญ์ ํ๋์?`)) {
//confirm ๋ฉ์๋๋ boolean์ ๋ฆฌํด
return;
}
//confirm ์ฐฝ์์ [ํ์ธ] ๋๋ฅด๋ฉด visitor ๋ฐ์ดํฐ ์ญ์
//:axios๋ก DELETE /visitor ์์ฒญ ๋ ๋ ค์ db์ ๋ฐ์ดํฐ delete ํ๊ธฐ
axios({
method: 'delete',
url: '/visitor',
data: {
id: id,
},
}).then((res) => {
//res๊ฐ์ true๊ฐ ์ฐํ์์ !!
console.log('delete / visitor ์์ฒญ์ ๋ํ ์๋ต', res.data);
alert('์ญ์ ์ฑ๊ณต !');
//๋ฒํผ(obj)์ ๋ถ๋ชจ์ ๋ถ๋ชจ -> tr
obj.parentElement.parentElement.remove();
});
}
deleteVisitor์ ์ธ์๋ก ๋ฐ์์ค๋ obj์ ๋ถ๋ชจ์ ๋ถ๋ชจ์์๋ฅผ ์ ํํ๋ฉด tr์์๊ฐ ์ ํ๋๊ณ ์ด tr์์๋ฅผ ์ง์์ฃผ๋ ์ฝ๋๋ฅผ then์ ์ถ๊ฐ๋ก ์์ฑํ๋ฉด ์ญ์ ๋ฒํผ ํด๋ฆญ์ ๋ฐ๋ก ํ
์ด๋ธ์์ ์ญ์ ๋๊ฒ ๋ฉ๋๋ค.
+) REST?
REST ๋ REpresenstational State Transfer์ ์ฝ์๋ก ์ฝ๊ฒ ๋งํ๋ฉด ์ฝ์์ด๋ผ๊ณ ํ ์ ์์ต๋๋ค. ์ด ์ฝ์์ ํด๋ผ์ด์ธํธ์ ์๋ฒ๊ฐ ์ด๋ป๊ฒ ์ํตํด์ผ ํ๋๊ฐ์ ๋ํ ๊ฐ์ด๋๋ผ์ธ์ด๋ผ๊ณ ํ ์ ์์ต๋๋ค.
REST์ ๊ตฌ์ฒด์ ์ธ ๊ฐ๋
์ HTTP URI ๋ฅผ ํตํด ์์์ ๋ช
์ํ๊ณ , HTTP Method( POST, GET, PUT, DELETE) ๋ฅผ ํตํด ํด๋น ์์์ ๋ํ CRUD OPERATION ์ ์ ์ฉํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
์ฆ, REST๋ ์์ ๊ธฐ๋ฐ์ ๊ทธ์กฐ ์ค๊ณ์ ์ค์ฌ์์ Resource๊ฐ ์๊ณ HTTP Method๋ฅผ ํตํด Resource๋ฅผ ์ฒ๋ฆฌํ๋๋ก ์ค๊ณ๋ ์ํคํ
์ณ๋ฅผ ์๋ฏธํฉ๋๋ค.
API๋ Application Protocol Interface์ ์ฝ์๋ก ์ฌ๊ธฐ์ API๋ ์ข ๋ ๋์ ์๋ฏธ์ API ์
๋๋ค. ํ๋ก๊ทธ๋๋ฐ์ ํ์ํ ์ธํฐํ์ด์ค๋ก ์๋ฅผ ๋ค์๋ฉด ์๋(ํด๋ผ์ด์ธํธ, ์ ์ ) ์ ๋ฉ๋ดํ(API)์ ์ด์ฉํด ์ง์(์๋ฒ)์๊ฒ ์ฃผ๋ฌธ(์์ฒญ, request)์ ํ๋ ๊ฒ์
๋๋ค.
REST API๋?
REST ์๋ฆฌ๋ฅผ ๋ฐ๋ฅด๋ API ๋ก ๋ช
์ฌ ๋ง์ผ๋ก '์ด๋ค ๋์'์ ํด์ผํ๋์ง ๋ชจํธํ๋ฏ๋ก HTTP ๋ฉ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.
HTTP ์์ฒญ ๋ฉ์๋์๋
Method | ์ญํ |
GET | ์๋ฒ์ ์์์ ๊ฐ์ ธ์ฌ ๋ ์ฌ์ฉ(์กฐํ) ์ฟผ๋ฆฌ์คํธ๋ง ์ ์ด์ฉํด ๋ฐ์ดํฐ๋ฅผ ์๋ฒ๋ก ๋ณด๋ |
POST | ์๋ฒ์ ์์์ ์๋ก ๋ฑ๋กํ ๋ ์ฌ์ฉ(์์ฑ) req.body ์ ์๋ก ๋ฑ๋กํ ๋ฐ์ดํฐ ๋ฃ์ด์ ๋ณด๋ |
PUT | ์๋ฒ์ ์์์ ์์ฒญ์ ๋ค์ด์๋ ์์์ผ๋ก ๋ฎ์ด์ฐ๊ธฐ ํ ๋ ์ฌ์ฉ(์์ ) req.body์ ์์ ํ ๋ฐ์ดํฐ ๋ฃ์ด์ ๋ณด๋ |
PATCH | ์๋ฒ ์์์ ์ผ๋ถ๋ง ์์ ํ ๋ ์ฌ์ฉ(์์ ) req.body ์ ์ผ๋ถ ์์ ํ ๋ฐ์ดํฐ ๋ฃ์ด์ ๋ณด๋ |
DELETE | ์๋ฒ ์์ ์ญ์ ํ๊ณ ์ ํ ๋ ์ฌ์ฉ (์ญ์ ) |
์ธ์๋ ์ฌ๋ฌ ๋ฉ์๋๊ฐ ์์ต๋๋ค.
REST๋ฅผ ๋ฐ๋ฅด๋ ์๋ฒ๋ฅผ RESTful ํ๋ค๊ณ ํํํฉ๋๋ค.
์ถ๊ฐ ๋ฉ์๋.insertAdjacentHTML(โโ,);
์์์ HTML์ ์ถ๊ฐํ ์ ์๋ ๊ธฐ๋ฅ์
๋๋ค. ๋งค๊ฐ๋ณ์์๋
โbeforebeginโ : ์์ ์์ ์์ฑ
โafterbeginโ : ์์ ๋ค์ ์์ฑ
โbeforeendโ : ์์ ํ๊ทธ ์์ ์์ฑ
โafterendโ : ์์ ํ๊ทธ ๋ค์ ์์ฑ
๋ฑ๋ฑ์ด ์ฃผ๋ก ๋ค์ด๊ฐ๋๋ค.
<!-- beforebegin -->
<p>
<!-- afterbegin -->
foo
<!-- beforeend -->
</p>
<!-- afterend -->
์ด๋ ๊ฒ ๋ํ๋ผ ์ ์๊ฒ ๋ค์ฉ
+) ํ๊ณ
๋๋ฒ์งธ MVCํจํด ์๊ฐ์ด์๋๋ฐ ์ด๋ฒ ์๊ฐ์๋ ์ง์ mysql์์ db๋ฅผ ๋ฐ์์์ ์ฐ๊ฒฐ์ง๊ณ ๋๋ฆ..,.,? ์ฌ๋ฐ์๋ค. ์๋ฌํญํ์ธ๊ฒ ๋นผ๊ณ ,, ๊ทผ๋ฐ ์๋ฌ๋ค์ด ์ฝ๋๊ฐ ์๋ชป๋๊ฒ์๋๊ณ ๊ถํ ์ค์ ,, ๋ญ, ์ด๋ฐ๊ฑฐ๋ผ ํ.,, ์ข ์ง์ฆ๋ฌ๋ค. ์ ์ ํผ์ฃ๋ง์ด ๋๋๊ฑฐ๊ฐ๋ค.. ๊ฑฐ์ ์์ด์ง๋ง,.,.,,, ์ง์์ ๋ ๋ค๋ฅธ ์ปดํจํฐ๋ก ํ๋๊น node ๋ฒ์ ๋ฌธ์ ๊ฐ ์์ด์ ์น๋ค ์ง์ฐ๊ณ ์ฌ์ค์นํ๋ค.. ์ด๋ด๋๋ง๋ค ๊ฐ์๊ธฐ ์์์ด ๋..๋จ์ด์ง์ง๋ง,, ํ ๊ฒ ํ์ฐ์ด๋ผ ๋ฐ์ธ๋ฉฐ ํ๋ค,, DB์ ์ฐ๊ฒฐํ๋ฉด์ ๊ธฐ์ต๋๋ ์๋ฌ๋ ๋๋ sql๋ฌธ์์๋ ๋ค ๋๋ฌธ์๋ก ์์ฑํ๋๋ฐ DB์์ ํ
์ด๋ธ๋ง๋ค๋ ๋ฐ์์ฌ ํ๋ ๊ฐ ์ด๋ฆ์ ๋์๋ฌธ์๋ ํต์ผํด์ผ๋๋๋๋๋ค,, ๋๋ ์๊ณ ์ถ์ง ์์์ด ( ์ด์์ฒด์ ๋ง๋ค ๋ค๋ฅธ๋ฏ์) ์ด๊ฒ ์๋ฌ๊ฐ ๋จ์ง๋ ์๊ณ ๋ฐ์ดํฐ๋ ๋ค ์ ๋ฐ์์ค๋๋ฐ ๋๊ฒจ์ฃผ๋ ๊ณผ์ ์์ ์ด๋ฆ์ด ๋ฌ๋ผ์ ๊ทธ๋ฐ์ง ํ
์ด๋ธ์ ๊ณต๋ฐฑ์ผ๋ก ๋ค์ด์ค๋๋ผ๊ตฌ์ ,, ๊ทธ๋ฅ ๋ง์ถฐ์ฃผ๋๊ฒ ์ ์ ๊ฑด๊ฐ์ ์ข๋ค !!
'SeSAC > javascript' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[SeSACXCodingOn] ์นํ์คํ๊ณผ์ 06W_3_18 : MVC (+๋ผ์ฐํฐ์ชผ๊ฐ๊ธฐ) (0) | 2023.08.25 |
---|---|
๋น๋๊ธฐ ์ฒ๋ฆฌ (0) | 2023.08.15 |
[SeSACXCodingOn] ์นํ์คํ๊ณผ์ 4W_11 _01: Node.js + Module + Express (0) | 2023.08.09 |
[SeSACXCodingOn] ์นํ์คํ๊ณผ์ 2W_06 _04: javascript Event (0) | 2023.08.04 |
[SeSACXCodingOn] ์นํ์คํ๊ณผ์ 2W_06 _03: javascript DOM (0) | 2023.08.02 |