pug
Node.js์์ ์ฌ์ฉ๋๋ ํ
ํ๋ฆฟ ์์ง
Pug๋ HTML๊ณผ JavaScript๋ฅผ ์กฐํฉํ ์ธ์ด๋ก, HTML์ ์ฅ์ ์ธ ๊ฐ๋
์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ์ ์งํ๋ฉด์ JavaScript์ ๋์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํ์ฅ์ : *.pug
์ฃผ์ ๋ฌธ๋ฒ
๊ตฌ๋ถ | ๋ฌธ๋ฒ | ์ค๋ช
|
๋ณ์ ์ฝ์
| {{ variable }} | ๋ณ์์ ๊ฐ์ ์ฝ์
ํฉ๋๋ค.
#{ } ๋ณด๋ค ์ฑ๋ฅ์ด ์ข๋ค.
- HTML ์ HTML ์์๋ก ๋ณํํ์ฌ ์ถ๋ ฅ |
๋ณ์ ์ฝ์
| #{ } | ๋ณ์์ ๊ฐ์ ์ฝ์
ํฉ๋๋ค.
- HTML ์ HTML ๊ทธ๋๋ก ์ถ๋ ฅ |
์กฐ๊ฑด๋ฌธ | if (condition) { ... } | ์กฐ๊ฑด์ ๋ฐ๋ผ HTML์ ์์ฑํฉ๋๋ค. |
๋ฐ๋ณต๋ฌธ | each (item in array) { ... } | ๋ฐฐ์ด์ ์์๋ฅผ ์ํํ๋ฉฐ HTML์ ์์ฑํฉ๋๋ค. |
ํจ์ ํธ์ถ | {{ function(arguments) }} | ํจ์๋ฅผ ํธ์ถํ์ฌ HTML์ ์์ฑํฉ๋๋ค. |
์๋ฒ์์ ๋ทฐ๋ก ๋ณ์ ์ ๋ฌ๋ฐฉ๋ฒ
1.
res.render()์ ์ง์ ๋ณ์ ์ ๋ฌ
2.
app.locals ์ ์ ์ญ ๋ณ์ ์ค์
3.
res.locals์ ๋ก์ปฌ ๋ณ์ ์ค์
4.
res.locals์ ๊ฐ์ฒด ์ ์ฒด๋ฅผ ์ค์
res.render()์ ์ง์ ๋ณ์ ์ ๋ฌ
โข
js
app.get('/example', (req, res) => {
res.render('example', { title: 'Express Example', message: 'Hello World' });
});
JavaScript
๋ณต์ฌ
โข
pug
// example.pug
h1= title
p= message
JavaScript
๋ณต์ฌ
app.locals ์ ์ ์ญ ๋ณ์ ์ค์
โข
js
app.locals.title = 'Express Example';
JavaScript
๋ณต์ฌ
โข
pug
// example.pug
h1= title
p= message
JavaScript
๋ณต์ฌ
res.locals ์ ๋ณ์ ์ค์
โข
js
app.get('/example', (req, res) => {
res.locals.title = 'Express Example';
res.render('example', { message: 'Hello World' });
});
JavaScript
๋ณต์ฌ
โข
pug
// example.pug
h1= title
p= message
JavaScript
๋ณต์ฌ
res.locals ์ ๊ฐ์ฒด ์ค์
โข
js
app.get('/example', (req, res) => {
res.locals.data = { title: 'Express Example', message: 'Hello World' };
res.render('example');
});
JavaScript
๋ณต์ฌ
โข
pug
// example.pug
h1= data.title
p= data.message
JavaScript
๋ณต์ฌ
์ฃผ์ ์์ ์ฝ๋
Pug์์๋ - ๊ธฐํธ๋ฅผ ์ฌ์ฉํ์ฌ JavaScript ์ฝ๋ ๋ธ๋ก์ ์ฝ์
ํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ - var isAdmin = true์ ๊ฐ์ ์ฝ๋๋ Pug์์ ์ ํจํ ๋ฌธ๋ฒ์
๋๋ค. ์ด ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ฉด Pug ํ
ํ๋ฆฟ์์ ๋ณ์๋ฅผ ์ ์ํ๊ณ ์ด๊ธฐํํ ์ ์์ต๋๋ค.
๋ณ์ ์ฝ์
// ๋ณ์ ์ฝ์
์์
- var username = 'John Doe'
h1 Welcome, {{username}}!
JavaScript
๋ณต์ฌ
์กฐ๊ฑด๋ฌธ
โข
if
// ์กฐ๊ฑด๋ฌธ ์์
- var isAdmin = true
- var isUser = true
if isAdmin
p You are an admin.
else if isUser
p You are a User.
else
p You are not an admin.
JavaScript
๋ณต์ฌ
โข
case
- var score = 'C'
case score
when 'A'
p 'A' ํ์ ์
๋๋ค
when 'B'
p 'B' ํ์ ์
๋๋ค
when 'C'
p 'C' ํ์ ์
๋๋ค
when 'D'
p 'D' ํ์ ์
๋๋ค
default
P 'ํ๊ณ ' ์
๋๋ค
HTML
๋ณต์ฌ
๋ฐ๋ณต๋ฌธ
// ๋ฐ๋ณต๋ฌธ ์์
- var fruits = ['Apple', 'Banana', 'Orange']
ul
each fruit in fruits
li= fruit
JavaScript
๋ณต์ฌ
ํจ์ ํธ์ถ
// ํจ์ ํธ์ถ ์์
- function capitalize(str) {
return str.toUpperCase();
}
p= capitalize('hello, world!')
p {{ capitalize('hello, world!') }}
JavaScript
๋ณต์ฌ
๊ฒ์ํ ์์์ฝ๋
1.
๋ผ์ฐํฐ ํ์ผ ์์ฑ ๋ฐ ์ค์
2.
๋ผ์ฐํฐ ์ ์
3.
pug ๋ ์ด์์ ํ์ผ ์์ฑ
4.
style.css ์ฐ๊ฒฐ
5.
index.pug ์์ฑ
6.
header, footer ์ถ๊ฐ
7.
๋ก๊ทธ์ธ, ํ์๊ฐ์
ํ๋ฉด ์์ฑ
8.
๊ฒ์ํ ํ๋ฉด ์์ฑ
๋ผ์ฐํฐ ํ์ผ ์์ฑ ๋ฐ ์ค์
1.
routes ํด๋ ์์ฑ
2.
index.js, board.js ํ์ผ ์์ฑ
3.
app.js ์ import ๋ฐ ๋ฏธ๋ค์จ์ด ์ค์
routes ํด๋ ์์ฑ
index.js, board.js ํ์ผ ์์ฑ
app.js ์ import ๋ฐ ๋ฏธ๋ค์จ์ด ์ค์
// ๐ฉโ๐ป ๋ผ์ฐํฐ ๋ชจ๋ import
const indexRouter = require('./routes/index');
const boardRouter = require('./routes/board');
JavaScript
๋ณต์ฌ
// ๐ฉโ๐ป ๋ผ์ฐํฐ ์ค์
app.use('/', indexRouter);
app.use('/board', boardRouter);
JavaScript
๋ณต์ฌ
๋ผ์ฐํฐ ์ ์
1.
index.js
2.
board.js
index.js
const express = require('express');
const router = express.Router();
// GET / ๋ผ์ฐํฐ
router.get('/', (req, res) => {
res.render('index', { title: 'Main' });
});
// ๋ก๊ทธ์ธ
router.get('/login', (req, res) => {
res.render('login', { title: 'Login' });
});
// ํ์๊ฐ์
router.get('/join', (req, res) => {
res.render('join', { title: 'Join' });
});
module.exports = router;
JavaScript
๋ณต์ฌ
board.js
const express = require('express')
const router = express.Router()
let boardList = [
{ title : '์ ๋ชฉ1', writer : '์์ฑ์1', content : '๋ด์ฉ1' },
{ title : '์ ๋ชฉ2', writer : '์์ฑ์2', content : '๋ด์ฉ2' },
{ title : '์ ๋ชฉ3', writer : '์์ฑ์3', content : '๋ด์ฉ3' },
]
// ๐ฉโ๐ป ๊ฒ์๊ธ ๋ชฉ๋ก
router.get('/', (req, res) => {
res.render('board/list', {boardList} )
})
// ๐ฉโ๐ป ๊ฒ์๊ธ ๋ฑ๋ก
router.get('/insert', (req, res) => {
res.render('board/insert')
})
// ๐ฉโ๐ป ๊ฒ์๊ธ ๋ฑ๋ก
router.post('/', (req, res) => {
// ๊ตฌ์กฐ๋ถํดํ ๋น
const { title, writer, content } = req.body;
// const title = req.body.title
// const writer = req.body.writer
// const content = req.body.content
const newBoard = { title, writer, content };
boardList.push(newBoard);
res.redirect('/board');
});
// ๐ฉโ๐ป ๊ฒ์๊ธ ์์ ํ์ด์ง
router.get('/update/:id', (req, res) => {
console.log(`id : ${req.params.id}`);
let id = req.params.id
const board = boardList[id];
res.render('board/update', { board, id });
});
// ๐ฉโ๐ป ๊ฒ์๊ธ ์์
router.post('/update', (req, res) => {
const { id, title, writer, content } = req.body;
boardList[id] = { title, writer, content };
res.redirect(`/board/${id}`);
});
// ๐ฉโ๐ป ๊ฒ์๊ธ ์ญ์
router.post('/delete', (req, res) => {
const id = req.params.id;
boardList.splice(id, 1);
res.redirect('/board');
});
// ๐ฉโ๐ป ๊ฒ์๊ธ ์ฝ๊ธฐ
// ์์ฒญ ๊ฒฝ๋ก์ ํ๋ผ๋ฏธํฐ ๋งคํ ๋ฐฉ๋ฒ โก '/:ํ๋ผ๋ฏธํฐ๋ช
'
router.get('/:id', (req, res) => {
console.log(`id : ${req.params.id}`);
let id = req.params.id
let board = boardList[id]
res.render('board/read', {board, id})
})
module.exports = router;
JavaScript
๋ณต์ฌ
pug ๋ ์ด์์ ํ์ผ ์์ฑ
1.
layout.pug
doctype html
html
head
title= title
//- ์ฌ๊ธฐ์ CSS ์ฐ๊ฒฐ
body
block content
JavaScript
๋ณต์ฌ
style.css ์ฐ๊ฒฐ
1.
public/css ํด๋ ์์ฑ
2.
style.css ํ์ผ ์์ฑ
3.
์คํ์ผ ์์ฑ
public/css ํด๋ ์์ฑ
style.css ํ์ผ ์์ฑ
์คํ์ผ ์์ฑ
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul {
list-style-type: none;
}
a {
text-decoration: none;
}
body {
font-family: Arial, sans-serif;
}
/* header */
header {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #333;
color: #fff;
padding: 0 20px;
text-align: center;
height: 80px;
}
header h1 {
margin: 0;
}
header nav {
height: 100%;
}
header nav ul {
height: 100%;
}
header nav li {
display: inline-block;
height: 100%;
}
header nav a {
display: flex;
justify-content: center;
align-items: center;
color: #fff;
text-decoration: none;
min-width: 100px;
height: 100%;
}
header nav a:hover {
background-color: #fff;
color: #333;
}
/* footer */
footer {
background-color: #333;
color: #fff;
padding: 10px;
text-align: center;
}
.container {
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
padding: 20px;
width: 300px;
margin: 100px auto;
}
.container-md {
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
padding: 20px;
width: 480px;
margin: 100px auto;
}
.container-lg {
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
padding: 20px;
width: 1024px;
margin: 100px auto;
}
.container h2 {
text-align: center;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: bold;
}
.form-group input,
.form-group .btn {
display: inline-block;
font-size: 14px;
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.form-group .btn {
text-align: center;
background-color: #4caf50;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
margin-bottom: 10px;
}
.form-group .btn:hover {
background-color: #45a049;
}
/* table */
.table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
.table th, .table td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
.table th {
background-color: #f2f2f2;
}
.table tr:hover {
background-color: #f5f5f5;
}
/* button */
.btn-box {
display: flex;
justify-content: space-between;
align-items: center;
margin: 20px 0;
}
.btn {
display: inline-block;
text-align: center;
font-size: 14px;
padding: 8px 18px;
box-sizing: border-box;
background-color: #4caf50;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
margin-bottom: 10px;
}
JavaScript
๋ณต์ฌ
layout.pug
doctype html
html
head
title= title
link(rel='stylesheet', href='/css/style.css')
body
block content
HTML
๋ณต์ฌ
index.pug ์์ฑ
extends layout
block content
div.container-lg
h1= title
h3 #{title} ํ๋ฉด์
๋๋ค
HTML
๋ณต์ฌ
1.
extends layout: ํ์ฌ ํ
ํ๋ฆฟ์ด layout.pug๋ผ๋ ๋ค๋ฅธ ํ
ํ๋ฆฟ์ ํ์ฅํ๋ค๋ ์๋ฏธ์
๋๋ค. ์ด๋ ๊ธฐ๋ณธ ๋ ์ด์์์ ์ ์ํ๊ณ , ๋ค์ํ ํ์ด์ง์์ ์ด ๋ ์ด์์์ ํ์ฅํ์ฌ ์ฌ์ฉํ ์ ์๊ฒ ํด์ค๋๋ค.
2.
block content: ์ด ๋ถ๋ถ์ layout.pug์์ ์ ์ํ block content์ ํด๋นํฉ๋๋ค. block content๋ ๋ค๋ฅธ ํ
ํ๋ฆฟ์์ ํ์ฅ๋ ๋ ์ฑ์์ง ๋ถ๋ถ์ ์ ์ํ๋ ์ญํ ์ ํฉ๋๋ค.
3.
div.container-lg: ์ด ๋ถ๋ถ์ ํน์ ํ์ด์ง์ ์ฝํ
์ธ ๋ฅผ ๊ฐ์ธ๋ div ์์๋ก, Bootstrap์ container-lg ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ์ปจํ
์ธ ์ ๋๋น๋ฅผ ์กฐ์ ํ๊ณ ์์ต๋๋ค.
4.
h1= title: title ๋ณ์์ ๊ฐ์ ์ถ๋ ฅํ๋ ํค๋ฉ(์ ๋ชฉ) ์์์
๋๋ค.
5.
h3 #{title} ํ๋ฉด์
๋๋ค: title ๋ณ์์ ๊ฐ์ ํฌํจํ ๊ฐ๋จํ ์ค๋ช
์ ์ถ๋ ฅํ๋ ๋ ๋ค๋ฅธ ํค๋ฉ(๋ถ์ ๋ชฉ) ์์์
๋๋ค.
header, footer ์ถ๊ฐ
header.pug
header
h1 Pug
nav
ul
li
a(href="/") Home
li
a(href="/login") Login
li
a(href="/board") Board
HTML
๋ณต์ฌ
footer.pug
footer
p Copyright ยฉ 2023 Pug
HTML
๋ณต์ฌ
layout.pug
doctype html
html
head
title= title
link(rel='stylesheet', href='/css/style.css')
body
//- ์ฌ๊ธฐ์ header ์ถ๊ฐ
include fragment/header.pug
block content
//- ์ฌ๊ธฐ์ footer ์ถ๊ฐ
include fragment/footer.pug
HTML
๋ณต์ฌ
๋ก๊ทธ์ธ, ํ์๊ฐ์ ํ๋ฉด ์์ฑ
login.pug
extends layout
block content
div.container
h2 Login
form
div.form-group
label(for="username") Username:
input(type="text", id="username", name="username", required)
div.form-group
label(for="password") Password:
input(type="password", id="password", name="password", required)
div.form-group
button.btn(type="submit") Login
a.btn(href="/join") Sign Up
HTML
๋ณต์ฌ
join.pug
extends layout
block content
div.container
h2 Sign Up
form
div.form-group
label(for="username") Username:
input(type="text", id="username", name="username", required)
div.form-group
label(for="email") Email:
input(type="email", id="email", name="email", required)
div.form-group
label(for="password") Password:
input(type="password", id="password", name="password", required)
div.form-group
button.btn(type="submit") Sign Up
HTML
๋ณต์ฌ
๊ฒ์ํ ํ๋ฉด ์์ฑ
1.
board/list.pug (๋ชฉ๋ก)
2.
board/insert.pug (๊ธ์ฐ๊ธฐ)
3.
board/read.pug (๊ธ์ฝ๊ธฐ)
4.
board/update.pug (๊ธ์์ )
board/list.pug
extends ../layout
block content
div.container-lg
div.btn-box
h1 ๊ฒ์๊ธ ๋ชฉ๋ก
a.btn(href="/board/insert") ๊ธ์ฐ๊ธฐ
table.table(border=1)
thead
tr
th No
th Title
th Writer
tbody
each board, index in boardList
tr
td(width=80)= index
td
a(href=`/board/${index}`) #{board.title}
td(width=200)= board.writer
HTML
๋ณต์ฌ
board/insert.pug
extends ../layout
block content
div.container-lg
h1 ๊ฒ์๊ธ ๋ฑ๋ก
form(action="/board", method="post")
table.table.form-group(border=1)
tr
th(width="200") Title
td
input(type="text", name="title")
tr
th(width="200") Writer
td
input(type="text", name="writer")
tr
th(width="200") Content
td
input(type="text", name="content")
div.btn-box
a.btn(href="/board") ๋ชฉ๋ก
button.btn(type="submit") ๋ฑ๋ก
HTML
๋ณต์ฌ
board/read.pug
extends ../layout
block content
div.container-lg
h1 #{board.title}
table.table(border=1)
tr
th(width="200") No
td #{id}
tr
th(width="200") Writer
td #{board.writer}
tr
th(width="200") Content
td #{board.content}
div.btn-box
a.btn(href="/board") ๋ชฉ๋ก
a.btn(href=`/board/update/${id}`) ์์
HTML
๋ณต์ฌ
board/update.pug
extends ../layout
block content
div.container-lg
h1 ๊ฒ์๊ธ ์์
form(action="/board/update", method="post")
input(type="hidden", name="id" value=`${id}`)
table.table.form-group(border=1)
tr
th(width="200") No
td #{id}
tr
th(width="200") Title
td
input(type="text", name="title", value=`${board.title}`)
tr
th(width="200") Writer
td
input(type="text", name="writer", value=`${board.writer}`)
tr
th(width="200") Content
td
input(type="text", name="content", value=`${board.content}`)
div.btn-box
a.btn(href="/board") ๋ชฉ๋ก
button.btn(type="submit") ์์
HTML
๋ณต์ฌ
app.js ์ ์ฒด์ฝ๋
const express = require('express');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const path = require('path');
// ๐ฉโ๐ป ๋ผ์ฐํฐ ๋ชจ๋ import
const indexRouter = require('./routes/index');
const boardRouter = require('./routes/board');
const app = express();
// ํฌํธ ์ค์ : 3000 ์ฌ์ฉ
app.set('port', 3000);
// ๋ทฐ ์์ง ์ค์ : Pug๋ฅผ ์ฌ์ฉํ๋๋ก ์ค์
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// ๋ก๊น
๋ฏธ๋ค์จ์ด ์ค์ : ๊ฐ๋ฐ ํ๊ฒฝ์์๋ dev ๋ชจ๋๋ก ๋ก๊ทธ๋ฅผ ์ถ๋ ฅ
app.use(morgan('dev'));
// ์ ์ ํ์ผ ์ ๊ณต ๋ฏธ๋ค์จ์ด ์ค์ : public ํด๋๋ฅผ ์ ์ ํ์ผ ์ ๊ณต ๋๋ ํ ๋ฆฌ๋ก ์ค์
app.use('/', express.static(path.join(__dirname, 'public')));
// JSON ํ์ฑ ๋ฏธ๋ค์จ์ด ์ค์
// - JSON ํ์์ ์์ฒญ ๋ณธ๋ฌธ์ ํ์ฑ
// - URL ์ธ์ฝ๋ฉ๋ ์์ฒญ ๋ณธ๋ฌธ์ ํ์ฑ
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
// cookie-parser ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ์ฌ ์ฟ ํค๋ฅผ ํ์ฑํ๋ ๋ถ๋ถ
app.use(cookieParser());
// Express ์ ํ๋ฆฌ์ผ์ด์
์ ์ธ์
๋ฏธ๋ค์จ์ด ์ค์
app.use(session({
resave: false, // ์ธ์
๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋์ง ์์ผ๋ฉด ์๋ฒ์ ๋ค์ ์ ์ฅํ์ง ์์
saveUninitialized: false, // ์ด๊ธฐํ๋์ง ์์ ์ธ์
์ ์ ์ฅ์์ ์ ์ฅํ์ง ์์
secret: 'session-secret',
// ์ธ์
์ฟ ํค ์ค์
cookie: {
httpOnly: true, // ๋ธ๋ผ์ฐ์ ์์ ์ฟ ํค์ ์ ๊ทผํ ๋๋ง ๊ฐ๋ฅํ๋๋ก httpOnly ์์ฑ ์ฌ์ฉ
secure: false, // HTTPS๊ฐ ์๋ ํ๊ฒฝ์์๋ ์ฟ ํค ์ ์ก ํ์ฉ
},
name: 'session-cookie', // ์ธ์
์ฟ ํค์ ์ด๋ฆ ์ค์
}));
// ๐ฉโ๐ป ๋ผ์ฐํฐ ์ค์
app.use('/', indexRouter);
app.use('/board', boardRouter);
// 404 ์ค๋ฅ ์ฒ๋ฆฌ ๋ฏธ๋ค์จ์ด
app.use((req, res, next) => {
// ์์ฒญ๋ ๊ฒฝ๋ก๊ฐ ์กด์ฌํ์ง ์์ ๋ 404 ์ํ ์ฝ๋์ 'Not Found' ๋ฉ์์ง๋ฅผ ์๋ต์ผ๋ก ์ ์ก
res.status(404).send('Not Found');
});
// ์๋ฌ ์ฒ๋ฆฌ ๋ฏธ๋ค์จ์ด
app.use((err, req, res, next) => {
// ์๋ฌ๊ฐ ๋ฐ์ํ์ ๋, ์๋ฌ ๋ฉ์์ง๋ฅผ ์ฝ์์ ์ถ๋ ฅํ๊ณ 500 ์ํ ์ฝ๋์ ์๋ฌ ๋ฉ์์ง๋ฅผ ์๋ต์ผ๋ก ์ ์ก
console.error(err);
res.status(500).send(err.message);
});
// Express ์ ํ๋ฆฌ์ผ์ด์
์ ํน์ ํฌํธ์์ ์คํํ๋ ๋ถ๋ถ
app.listen(app.get('port'), () => {
// ์ ํ๋ฆฌ์ผ์ด์
์ด ์คํ๋๋ฉด ์ฝ์์ ํด๋น ํฌํธ์์ ๋๊ธฐ ์ค์์ ์ถ๋ ฅ
console.log(app.get('port'), '๋ฒ ํฌํธ์์ ๋๊ธฐ ์ค');
});
JavaScript
๋ณต์ฌ
์คํ ํ๋ฉด
/
๋ฉ์ธํ๋ฉด
/login
๋ก๊ทธ์ธ ํ๋ฉด
/join
ํ์๊ฐ์
ํ๋ฉด
/board
๊ฒ์๊ธ ๋ชฉ๋ก
/board/insert
๊ฒ์๊ธ ๋ฑ๋ก
/board/0
๊ฒ์๊ธ ์ฝ๊ธฐ
/board/update/0
๊ฒ์๊ธ ์์