"/", "/select", "/delete"를 각 엔드포인트로 로그인 화면, 조회 화면, 데이터 삭제 화면을 구성해보도록 하겠다.
① 메모장을 열고, 아래의 내용을 입력한다.
CREATE DATABASE week10;
USE week10;
CREATE TABLE user (
Id VARCHAR(255) PRIMARY KEY,
Password VARCHAR(255),
Role VARCHAR(255)
);
CREATE TABLE department (
Id int PRIMARY KEY,
Dname VARCHAR(255),
Dnumber int
);
INSERT INTO user (Id, Password, Role)
VALUES
('admin', 'admin1234', 'super'),
('student1', 'st1234', 'student');
INSERT INTO department (Id, Dname, Dnumber)
VALUES
(0, 'Information and Communication Engineering', 1),
(1, 'Electrical Engineering', 2),
(2, 'Computer Engineering', 3),
(3, 'Electronics Engineering', 4);
② 메모장을 week10.sql이라는 이름으로 cmd의 working 디렉토리 안에 저장한다.
③ cmd에서 working 디렉토리로 이동한 후 아래의 명령을 입력한다.
npm init
npm install express mysql2 body-parser nodemon morgan dotenv express-session
npm install @babel/node @babel/core @babel/preset-env
npm link hbs
④ mysql을 실행하고 아래의 명령을 입력한다.
source ./week10.sql
use week10
show tables; // 데이터베이스가 잘 생성되었는지 확인한다.
① VSCode에서 해당 파일을 열고 아래와 같이 파일을 생성한다.
② package.json의 scripts 부분을 아래와 같이 수정한다.
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start" : "nodemon --exec babel-node index.js"
},
③ sql.js에 아래의 내용을 입력한다.
import mysql from 'mysql2';
require("dotenv").config();
const pool = mysql.createPool({
host: 'localhost',
port: 3306,
user: 'root',
password: '{비밀번호}',
database: 'week10',
});
const promisePool = pool.promise();
export const selectSql = {
getUser: async () => {
const sql = `select * from user`;
const [result] = await promisePool.query(sql);
return result;
},
getDepartment: async () => {
const sql = `select * from department`;
const [result] = await promisePool.query(sql);
return result;
},
}
export const deleteSql = {
deleteDepartment: async (data) => {
console.log('delete department Dnumber =', data);
const sql = `delete from department where Dnumber=${data.Dnumber}`
console.log(sql);
await promisePool.query(sql);
},
};
④ delete.js에 아래의 내용을 입력한다.
import express from 'express';
import { selectSql, deleteSql } from '../database/sql';
const router = express.Router();
router.get('/', async (req, res) => {
if (req.session.user != undefined && req.session.user.role === 'super') {
const department = await selectSql.getDepartment();
res.render('delete', {
title: "Delete",
department,
});
} else{
res.redirect('/');
}
});
router.post('/', async (req, res) => {
console.log("delete :", req.body.delBtn);
const data = {
Dnumber: req.body.delBtn,
};
await deleteSql.deleteDepartment(data);
res.redirect('/delete');
});
module.exports = router;
⑤ login.js에 아래의 내용을 입력한다.
import express from "express";
import { selectSql } from "../database/sql";
const router = express.Router();
router.get('/', (req, res) => {
res.render('login');
});
router.post('/', async (req, res) => {
const vars = req.body;
const users = await selectSql.getUser();
users.map((user) => {
console.log('ID :', user.Id);
if (vars.id === user.Id && vars.password === user.Password) {
console.log('login success!');
req.session.user = { id: user.Id, role: user.Role, checkLogin: true };
}
});
if (req.session.user == undefined) {
console.log('login failed!');
res.send(`<script>
alert('login failed!');
location.href='/';
</script>`)
} else if (req.session.user.checkLogin && req.session.user.role === 'super') {
res.redirect('/delete');
} else if (req.session.user.checkLogin && req.session.user.role === 'student') {
res.redirect('/select');
}
});
module.exports = router;
⑥ select.js에 아래의 내용을 입력한다.
import express from 'express';
import { selectSql } from '../database/sql';
const router = express.Router();
router.get('/', async (req, res) => {
if (req.session.user == undefined) {
res.redirect('/');
} else if (req.session.user.role === 'student' || req.session.user.role === 'super') {
const department = await selectSql.getDepartment();
res.render('select', {
title: "IT Engineering",
department,
});
} else {
res.redirect('/');
}
});
module.exports = router;
⑦ index.js에 아래의 내용을 입력한다.
import express from 'express';
import logger from 'morgan';
import path from 'path';
import expressSession from "express-session";
import loginRouter from '../routes/login';
import selectRouter from '../routes/select';
import deleteRouter from '../routes/delete';
const PORT = 3000;
const app = express();
app.use(express.static(path.join(__dirname, '/src')));
app.use(express.urlencoded({ extended: false }))
app.use(express.json());
app.use(
expressSession({
secret: "my key",
resave: true,
saveUninitialized: true,
})
);
app.set('views', path.join(__dirname, '../views'));
app.set('view engine', 'hbs');
app.use(logger('dev'));
app.use('/', loginRouter);
app.use('/select', selectRouter);
app.use('/delete', deleteRouter);
app.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}`)
});
⑧ delete.hbs에 아래의 내용을 입력한다.
<h1>{{ title }}</h1>
<table>
<tr>
<td>Dname</td>
<td>Dnumber</td>
</tr>
{{#each department}}
<form method="post">
<tr>
<td>{{Dname}}</td>
<td>{{Dnumber}}</td>
<td style="border: none; margin-left: 10px;">
<button
style="margin-left: 10px;"
name='delBtn'
type="submit"
value="{{Dnumber}}"
formaction="/delete"
>
delete
</button>
</td>
</tr>
</form>
{{/each}}
</table>
⑨ layout.hbs에 아래의 내용을 입력한다.
<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
<style type="text/css">
table{border-collapse:collapse}
th,td{border:1px solid black; width: 150px; height: 30px}
</style>
</head>
<body>
{{{body}}}
</body>
</html>
⑩ login.hbs에 아래의 내용을 입력한다.
<style>
body {
height: 75vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.frame {
border-radius: 15px;
box-sizing: border-box;
border: 1px solid #757575;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 350px;
}
form {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#id, #passwd, .btn {
font-size: 25px;
}
.pwd {
margin-top: 15px;
}
.btn {
width: 322px;
margin-top: 20px;
margin-bottom: 20px;
}
</style>
<div class="frame">
<h1>Login</h1>
<form id="deparment" method="post" action='/'>
<div class="id">
<input id="id" name="id" type="text" required placeholder="ID">
</div>
<div class="pwd">
<input id="passwd" name='password' type="password" required placeholder="Password">
</div>
<button class='btn' type="submit">Login</button>
</form>
</div>
⑪ select.hbs에 아래의 내용을 입력한다.
<h1>{{ title }}</h1>
<table>
<tr>
<td>Dname</td>
<td>Dnumber</td>
</tr>
{{#each department}}
<tr>
<td>{{Dname}}</td>
<td>{{Dnumber}}</td>
</tr>
{{/each}}
</table>
⑫ Babel.config.json에 아래의 내용을 입력한다.
{
"presets": ["@babel/preset-env"]
}
⑬ Terminal에 npm run start를 입력한 후 localhost:3000에 접속한다.
⑭ 데이터베이스에 저장되지 않은 ID/PW로 로그인을 시도하면, 아래와 같은 알림창이 나타난다.
⑮ student, st1245로 로그인하면 /select 페이지로 리다이렉션되고, admin, admin1234로 로그인하면 /delete 페이지로 리다이렉션된다.
저번 실습에서 구축한 Inha Database에 Web Login 기능을 적용해보도록 하겠다. 학생의 학번을 ID로, 학생의 전화번호를 비밀번호로 사용하기로 한다.
① sql.js에서 database를 아래와 같이 변경한다.
import mysql from 'mysql2';
require("dotenv").config();
const pool = mysql.createPool({
host: 'localhost',
port: 3306,
user: 'root',
password: 'wdrsus0520',
database: 'week5',
});
const promisePool = pool.promise();
export const selectSql = {
getStudent: async () => {
const sql = `select * from student`;
const [result] = await promisePool.query(sql);
return result;
},
getDepartment: async () => {
const sql = `select * from department`;
const [result] = await promisePool.query(sql);
return result;
},
getClass: async (id) => {
const sql = `select c.id, c.name from class c, student s, student_has_class sc where s.id = sc.student_id and c.id = sc.Class_id and s.id = ${id}`;
const [result] = await promisePool.query(sql);
return result;
},
}
export const deleteSql = {
deleteDepartment: async (data) => {
console.log('delete department Dnumber =', data);
const sql = `delete from department where Dnumber=${data.Dnumber}`
console.log(sql);
await promisePool.query(sql);
},
deleteClass: async (data, id) => {
console.log('delete class id =', data);
const sql = `delete from student_has_class where Class_id=${data.id} and student_id =${id}`
console.log(sql);
await promisePool.query(sql);
},
};
② login.js를 아래와 같이 수정한다.
import express from "express";
import { selectSql } from "../database/sql";
const router = express.Router();
router.get('/', (req, res) => {
res.render('login');
});
router.post('/', async (req, res) => {
const vars = req.body;
const students = await selectSql.getStudent();
students.map((student) => {
console.log('ID :', student.id);
console.log('PW :', vars.password);
console.log('Phone :', student.phone_number);
if (vars.id == student.id && vars.password === student.phone_number) {
console.log('login success!');
req.session.user = { id: student.id, checkLogin: true };
}
});
if (req.session.user == undefined) {
console.log('login failed!');
res.send(`<script>
alert('login failed!');
location.href='/';
</script>`)
}
else if (req.session.user.checkLogin) {
res.redirect('/select');
}
});
module.exports = router;
③ select.js를 아래와 같이 수정한다.
import express from 'express';
import { selectSql } from '../database/sql';
const router = express.Router();
router.get('/', async (req, res) => {
if (req.session.user != undefined) {
const student = await selectSql.getStudent();
res.render('select', {
title: "Student Info",
student,
});
} else {
res.redirect('/');
}
});
module.exports = router;
④ login.hbs를 아래와 같이 수정한다.
<style>
body {
height: 75vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.frame {
border-radius: 15px;
box-sizing: border-box;
border: 1px solid #757575;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 350px;
}
form {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#id, #passwd, .btn {
font-size: 25px;
}
.pwd {
margin-top: 15px;
}
.btn {
width: 322px;
margin-top: 20px;
margin-bottom: 20px;
}
</style>
<div class="frame">
<h1>Login</h1>
<form id="deparment" method="post" action='/'>
<div class="id">
<input id="id" name="id" type="text" required placeholder="ID">
</div>
<div class="pwd">
<input id="passwd" name='password' type="password" required placeholder="Password">
</div>
<button class='btn' type="submit">Login</button>
</form>
</div>
⑤ select.hbs를 아래와 같이 수정한다.
<h1>{{ title }}</h1>
<table>
<tr>
<td>Student ID</td>
<td>Student Name</td>
<td>Email</td>
<td>Phone Number</td>
</tr>
{{#each student}}
<tr>
<td>{{id}}</td>
<td>{{name}}</td>
<td>{{email}}</td>
<td>{{phone_number}}</td>
</tr>
{{/each}}
</table>
이제 코드를 실행시켜보자. localhost:3000으로 접속한 후, Student 테이블의 id 값을 ID로, 전화번호 값을 PW로 입력하여 로그인할 수 있다. 로그인에 성공했을 때, 아래와 같이 학생 정보 조회 페이지로 리다이렉트된다.
리다이렉트되는 페이지에 나타나는 수업 목록은 해당 학생이 현재 수강 중인 수업이어야 한다.
① delete.js를 아래와 같이 수정한다.
import express from 'express';
import { selectSql, deleteSql } from '../database/sql';
const router = express.Router();
router.get('/class', async (req, res) => {
if (req.session.user != undefined) {
const classes = await selectSql.getClass(req.session.user.id);
res.render('delete', {
title: "Delete",
classes,
});
} else{
res.redirect('/');
}
});
router.post('/class', async (req, res) => {
console.log("delete :", req.body.delBtn);
const data = {
id : req.body.delBtn,
};
await deleteSql.deleteClass(data, req.session.user.id);
res.redirect('/delete/class');
});
module.exports = router;
② login.js를 아래와 같이 수정한다.
import express from "express";
import { selectSql } from "../database/sql";
const router = express.Router();
router.get('/', (req, res) => {
res.render('login');
});
router.post('/', async (req, res) => {
const vars = req.body;
const students = await selectSql.getStudent();
students.map((student) => {
console.log('ID :', student.id);
console.log('PW :', vars.password);
console.log('Phone :', student.phone_number);
if (vars.id == student.id && vars.password === student.phone_number) {
console.log('login success!');
req.session.user = { id: student.id, checkLogin: true };
}
});
if (req.session.user == undefined) {
console.log('login failed!');
res.send(`<script>
alert('login failed!');
location.href='/';
</script>`)
} else if (req.session.user.checkLogin) {
res.redirect('/delete/class');
}
});
module.exports = router;
③ delete.hbs에 아래의 내용을 입력한다.
<h1>{{ title }}</h1>
<table>
<tr>
<td>Class Id</td>
<td>Class Name</td>
</tr>
{{#each classes}}
<form method="post">
<tr>
<td>{{id}}</td>
<td>{{name}}</td>
<td style="border: none; margin-left: 10px;">
<button
style="margin-left: 10px;"
name='delBtn'
type="submit"
value={{id}}
formaction="/delete/class">
delete
</button>
</td>
</tr>
</form>
{{/each}}
</table>
이제 코드를 실행해보자. 로그인에 성공했을 때 아래와 같이 수강 포기 페이지로 리다이렉트된다.
위 결과는 2번 학생으로 로그인했을 때 나타나는 결과이다. 실제 DB에서 2번 학생이 수강하고 있는 수업을 확인해보자.
실제로도 2번 학생은 java_programming과 management_theory를 수강하고 있다. 이제 java_programming class 옆에 있는 delete 버튼을 클릭해보자.
삭제가 잘 반영되는 것을 확인해볼 수 있다. 이 결과는 cmd에서도 동일하게 확인 가능하다.
이제 2번 학생은 3번 수업인 management_theory만 수강하는 상태가 되었다.
참고로 두 경우 모두, 로그인을 하지 않은 상태에서 "/select", "/delete/class"로 바로 오는 요청은 "/"로 리다이렉트하여 로그인을 유도하고 있다. 즉, 학생 로그인을 진행하지 않은 경우, 학생의 정보를 조회할 수 없고, 수강 포기도 할 수 없는 것이다.