
1. 들어가며
- Node.js와 MySQL을 연결해서 회원가입과 로그인 기능 구현하기(MVC 패턴 적용하기)
2. Node.js 와 MySQL 연결
이번 실습은 Node.js와 MySQL을 연결하고, 이것을 MVC 패턴을 적용하여 프로젝트를 구성하는 것이었다.

프로젝트 구조는 다음과 위와 같이 적용했다.
Model, View, Controller 로 구분하고 프론트 파트의 css와 js 파일들은 static 폴더에 넣어주었다.
그리고 라우터 연결을 위한 routes 폴더도 따로 구분해주었다.
최상단의 app.js 에는 다음과 같이 구현했다.
// express 모듈 등록
const express = require('express')
const app = express();
const PORT = 8888;
// 뷰 템플릿
app.set('view engine', 'ejs');
app.set('views', './views');
// static 미들웨어
app.use('/static', express.static(__dirname + '/static'))
// body-parser 미들웨어 등록
app.use(express.urlencoded({extended : true}))
app.use(express.json())
// 라우터 등록
const indexRouter = require('./routes/index')
app.use('/', indexRouter)
// 404 처리
app.get('*', (req, res) => {
res.render('404')
})
app.listen(PORT, ()=> {
console.log(`http://localhost:${PORT}`);
});
Model
MySQL 과 직접적으로 연결되어 있는 곳이다.
DB에 대한 처리를 이곳에서 한다.
// mysql 연결
const mysql = require('mysql')
const conn = mysql.createConnection({
host : 'localhost',
user : 'user',
password : '12345678',
database : 'codingon'
})
// 회원가입
exports.postSignUp = (data) => {
conn.query(
`INSERT INTO user (userid, name, pw) VALUES ('${data.userid}', '${data.name}', '${data.pw}');`,
(err,rows)=>{
if(err) {
throw err;
}
})
}
View
뷰 템플릿으로 ejs를 사용했기 때문에 ejs파일로 구성되어 있다.
총 5개의 파일을 만들었는데
첫화면, 회원가입, 로그인, 회원정보, 에러 페이지로 구성했다.

이 중 회원가입에 대한 코드만 보자면 다음과 같다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>회원가입</title>
<link rel="stylesheet" href="/static/css/sign.css" />
<!-- Axios CDN -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
</head>
<body>
<h1>회원가입</h1>
<form name="form-register" id="form-register" class="sign-form">
<input
name="userid"
id="userid"
type="text"
required
placeholder="ID를 입력해주세요(4글자 이상)"
minlength="4"
/>
<span class="msg"></span>
<input
name="password"
type="password"
required
placeholder="비밀번호를 입력해주세요(4글자 이상)"
minlength="4"
/>
<span class="msg"></span>
<input
name="name"
id="name"
type="text"
required
placeholder="이름을 입력해주세요(2글자 이상)"
minlength="2"
/>
<span class="msg"></span>
<button type="button" onclick="createUser()">가입하기</button>
</form>
<a href="/user/signin">로그인 하기</a>
<script src="/static/js/user.js"></script>
</body>
</html>
가입하기 버튼을 누르면 createUser()라는 함수가 호출되고
그 함수의 기능은 각 인풋에 입력된 값들이 DB에 들어갈 수 있도록 하는 것이다.
axios를 사용해서 데이터를 전달하고 비동기 처리를 위해 async/await를 사용했다.
const msgBox = document.querySelectorAll('.msg')
async function createUser() {
const form = document.forms['form-register']
const data = {
userid : form.userid.value,
pw : form.password.value,
name : form.name.value
}
if(!form.userid.checkValidity()){
msgBox[0].textContent = 'ID를 입력해주세요(4글자 이상)'
} else if(!form.password.checkValidity()){
$('.msg').empty()
msgBox[1].textContent = '비밀번호를 입력해주세요(4글자 이상)'
} else if(!form.name.checkValidity()) {
$('.msg').empty()
msgBox[2].textContent = '이름을 입력해주세요(2글자 이상)'
} else {
$('.msg').empty();
try {
alert('회원가입 성공')
document.location.href= '/user/signin'
await axios({
method : 'POST',
url : '/user/signup',
data
})
} catch(err) {
console.error(err);
alert('알 수없는 에러가 발생했습니다.')
}
}
}
또한, 인풋에 입력될 최소 글자수를 설정하기 위해서 유효성 검사 메서드인 checkValidity()를 사용했다.

위와 같이 인풋에 값이 설정한 사이즈와 맞지 않거나 빈값이면 해당 메시지가 나오도록 만들었다.
조건이 만족했을 때는 저 메시지를 지우기 위해 제이쿼리의 empty() 메서드를 사용했다.

위와 같이 조건을 만족하면 해당 메시지는 지워지고 또 다른 인풋에서 조건이 맞지 않으면 인풋에 해당하는
메시지가 나오도록 했다.

조건이 모두 맞으면 회원가입이 성공하고 해당 데이터에 DB에 들어간다.
그래서 MySQL Workbench에 가서 확인하면

이렇게 데이터가 DB에 잘 들어간 것을 확인할 수 있다.
Controller
모델과 뷰는 직접적으로 소통하지 않는다.
모델과 뷰의 연결은 Controller에서 담당한다.
const User = require('../model/User')
// 새로운 회원 생성
exports.postSignUp = (req,res) => {
User.postSignUp(req.body)
}
컨트롤러에서 모델에서 정의된 postSignUp 함수를 호출하며 매개변수로 req.body를 전달한다.
req.body에는 이것은 뷰, 즉 프론트에서 인풋값으로 입력된 값들 저장되어 있다.
회원가입 페이지에서 아이디를 banana 비밀번호를 1234, 이름을 바나나로 하고 가입하기 버튼을 누르면
{ userid: 'banana', pw: '1234', name: '바나나' }
위의 형태로 axios에서 정의된 방법으로 인해 req.body에 저장된다.
이 값을 model에서 사용하기 위해 매개변수로 전달한다.
model에서 이 데이터를 받아서 쿼리문에 작성된대로 처리를 하며,
쿼리문에 작성된 insert 문으로 인해 데이터가 데이터베이스에 들어간다.
회원가입에 대한 데이터 흐름을 정리하면
1) 사용자가 뷰(회원가입 페이지)에서 값을 입력한다.
(사용자 -> view)
2) 뷰의 createUser()에 정의된 함수에 의해 post 방법으로 데이터를 컨트롤러에 전달한다.
(view -> controller)
3) 전달된 데이터는 req.body에 저장되고, User.js(model)의 postSignUp의 함수에 매개변수로 전달한다.
(controller -> model)
4) 매개변수에 의해 전달된 데이터가 쿼리문에 작성된 insert문으로 인해 DB에서 데이터를 생성한다.
(model -> DB)
로그인에 대한 데이터 흐름이라면 여기서 더 추가될 것이다.
로그인을 하기 위해선 뷰에서 입력된 값이 데이터베이스에 존재하는지 확인해야한다.
데이터베이스에 존재한다면 로그인을 진행하고, 존재하지 않다면 로그인을 진행하지 않아야 한다.
// 회원가입
exports.postSignUp = (data) => {
conn.query(`INSERT INTO user (userid, name, pw) VALUES ('${data.userid}', '${data.name}', '${data.pw}');`,
(err,rows)=>{
if(err) {
throw err;
}
})
}
// 로그인
exports.postSignIn = (data, callback) => {
conn.query(`select * from user where userid='${data.userid}' and pw='${data.pw}'`,
(err, rows)=>{
if(err) {
throw err;
}
callback(rows[0])
})
}
위의 코드는 model에 정의된 회원가입, 로그인 기능 함수다.
회원가입은 회원에 대한 정보를 생성하는 것이기 때문에 insert 문을 사용했다.
로그인은 요청받은 회원에 대한 정보가 데이터베이스에 존재하는지 확인, 즉 조회를 하기 때문에 select문을 사용했다.
또한 회원가입 기능은 뒤에 딱히 콜백처리 할게 없어서 콜백함수를 정의를 하지 않았지만
로그인 기능은 입력받은 정보가 DB에 있는지 확인 후, DB에 있다면 로그인을 해줘야 해서 콜백함수를 정의했다.
입력받은 정보가 DB에 있으면 쿼리문에 의해 rows.라는 매개변수에 DB에 있는 정보가 담긴다.
없으면 undefined를 반환한다.
// 로그인 회원 조회
exports.postSignIn = (req,res) => {
User.postSignIn(req.body, (result)=>{
res.send({ result })
})
}
위의 코드는 controller에서 정의된 로그인 기능 함수다.
postsignIn이 첫번째 매개변수로 뷰에서 받은 데이터를 model로 전달하고,
두번째 매개변수인 콜백함수를 데이터를 조회한 후 실행한다.
즉 result에 담긴 데이터를 뷰에 전달한다.
result는 model에서 rows 변수다.
DB에 로그인 정보가 있으면 result에서 로그인 정보를 반환하고 없으면 undefined를 반환한다.
async function login() {
const form = document.forms['form-login']
const form_info = document.forms['form_info']
const data = {
userid : form.userid.value,
pw : form.password.value
}
if(!form.userid.checkValidity()){
msgBox[0].textContent = 'ID를 입력해주세요'
} else if(!form.password.checkValidity()){
$('.msg').empty()
msgBox[1].textContent = '비밀번호를 입력해주세요'
} else {
try{
const loginAxios = await axios({
method : 'POST',
url : '/user/signin',
data
})
const result = loginAxios.data.result
if(result){
const { userid } = result
form_info.userid.value = userid
alert('로그인 성공')
form_info.submit()
} else{
alert('로그인 실패')
form.reset();
form_info.reset();
}
} catch(err){
alert('로그인 실패')
form.reset();
form_info.reset();
}
}
}
위의 함수는 view에서 정의된 로그인 기능 함수다.
login() 함수가 호출되면 axios에 의해 로그인 정보가 컨트롤러를 통해 모델로 전달되고,
다시 컨트롤러에 의해 DB에 있는 로그인 정보나 undefined 값이 전달받아서
만약 로그인 정보가 있다면, 로그인을 성공하고
undefined 즉 로그인 정보가 없다면 로그인을 실패한다.
로그인에 대한 데이터 흐름을 정리하면
1) 사용자가 뷰(로그인 페이지)에서 값을 입력한다.
(사용자 -> view)
2) 뷰의 login()에 정의된 함수에 의해 post 방법으로 데이터를 컨트롤러에 전달한다.
(view -> controller)
3) 전달된 데이터는 req.body에 저장되고, User.js(model)의 postSignIn의 함수에 매개변수로 전달한다.
(controller -> model)
4) 매개변수에 의해 전달된 데이터가 쿼리문에 작성된 select문으로 인해 DB에서 데이터를 조회한다.
(model -> DB)
5) 데이터 조회 후 값을 모델로 반환한다.
(DB -> model)
6) 반환된 값이 콜백함수의 매개변수를 통해 컨트롤러로 전달된다.
(model -> controller)
7) 컨트롤러의 콜백함수에 의해 값이 뷰로 전달된다.
(controller -> view)
8) 뷰로 전달된 값에 따라 로그인 성공 또는 실패 기능을 보여준다.
(view -> 사용자)
회원가입은 회원 정보 데이터를 생성하는 CREATE고
로그인은 회원 정보 데이터를 조회하는 READ다.
회원 정보를 수정하는 UPDATE, 회원정보를 삭제(탈퇴)하는 DELETE
이것들의 앞글자를 따서 CRUD 라고 한다.
Routes
라우트 폴더에는 라우터에 대한 기능을 정의했다.
const express = require('express')
const controller = require('../controller/Cuser')
const router = express.Router();
// post -> /user/signup
// 새로운 회원 생성
router.post('/user/signup', controller.postSignUp)
// 로그인 회원 조회
router.post('/user/signin', controller.postSignIn)
module.exports = router;
3. 마치며
해봤던 실습중에서 제일 많이 헤맸다.
데이터베이스를 연결하고 데이터를 전달하고 전달받고 조회하고 그런 것들이 헷갈려서 많이 헤맸지만
덕분에 연습이 된 것 같다.
하면서 구현하지 못한 아쉬운 것들이 많아서 목록을 정리해서 다음에 해봐야겠다.
다음에 해볼 것
✔ 회원가입 시 기존에 DB에 존재하는 아이디인지 확인할 것(아이디 중복검사)
✔ 회원가입 시 아이디, 패스워드 조건 설정할 것 (ex. 비밀번호는 영어대소문자, 숫자, 특수문자 포함할 것)
✔ 로그인 시 아이디/비밀번호 틀렸다고 각각 표현
✔ 회원정보 란에 프로필 사진 기능 추가
4. Reference
1. 코딩온 강의 자료 및 실습
'Study > Node.js' 카테고리의 다른 글
| [새싹x코딩온] 웹 개발자 부트캠프 과정 8주차 회고 | 비밀번호 암호화(feat. bcrypt) (0) | 2024.07.06 |
|---|---|
| [새싹x코딩온] 웹 개발자 부트캠프 과정 8주차 회고 | Cookie 와 Session (0) | 2024.07.02 |
| [새싹x코딩온] 웹 개발자 부트캠프 과정 7주차 회고 | MVC 패턴으로 프로젝트 만들기 (0) | 2024.06.25 |
| [새싹x코딩온] 웹 개발자 부트캠프 과정 6주차 회고 | Multer 미들웨어 사용해서 파일 업로드 구현하기 (0) | 2024.06.20 |
| [새싹x코딩온] 웹 개발자 부트캠프 과정 6주차 회고 | 동적 form 전송 (0) | 2024.06.18 |