개발 공부한 것들/SeSSAC 웹 풀스텍 과정 회고록

[SeSSAC] 웹 풀스택 영등포 5기 과정_MVC 패턴(SQL연결하기)

geograp 2023. 8. 28. 23:12

오늘은 저번시간에 배웠던 mvc패턴에 SQL Database를 연결하는 수업을 진행하였습니다.

많아지는 파일과 동시에 반비례로 생기를 잃어가는 나,,,^^

 

오늘 살펴볼 아이들은, 저번 MVC파일과 크게 다르지 않는 뼈대에서 시작합니다.

여기에 JavaScript를 넣어줄 static폴더

db역할을 했던 model폴더가 더 복잡해진 내용이 저희가 오늘 배운 것입니다.

 

먼저, model폴더의 Visitor.js 파일에서 어떻게 SQL과 연동했는지 알아보도록 하겠습니다.

사전에 미리 SQL로 sessac2라는 Database를 생성한 후 visitor라는 테이블을 만들고

임시 값들을 넣주었습니다.

visitor 테이블 생성

 

여기서 이 테이블을 MODEL에서 접근하는 방법이 두 가지가 있다고 하셨는데,

그 중 모든 권한이 있는 user를 생성하여 접근하는 방법을 사용하였습니다.

(사실 나머지 하나는 생각 안남)

-- user라는 새로운 계정(mysql에 접속 가능한 계정) 생성
create user 'user'@'%' identified with mysql_native_password by '1234';

여기서 SQL의 상세한 문법이 궁금하여 정리하였습니다.

 

1. create user : 유저를 생성한다.

2. 'user'@'%': 'user'라는 이름의 유저를 생성하는데 모든(%) 호스트에 대해 접근할 수 있다.

3. identified with: 사용자 인증 방식을 설정하겠다.

4. mysql_native_password by: 해시 방식의 비밀번호로 인증하겠다.

 

GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' WITH GRANT OPTION;

1. GRANT ALL PRIVILEGES: 모든 권한을 부여하겠다.

2. ON *.*: 모든 데이터베이스의 모든 테이블에 권한을 부여한다.

3. TO 'user'@'%': 'user'라는 이름의 사용자에게

4. WITH GRANT OPTION: 이 user라는 사용자가 다른 사용자에게 다른 권한을 부여할 수 있는 권한을 부여하겠다(?)

 

아무튼, 중요한 것은 저희 model에서 database와 연결하여 접근하기 위해

'user'라는 무적인 사용자를 생성하였다는 점입니다.


 

그럼 이제 준비가 되었으니, model부터 보도록 하겠습니다.

일단 mysql이라는 변수에 mysql이라는 모듈을 불러와 담았습니다.

그리고 conn이라는 변수를 선언하고, mysql 모듈에 있는 createConnection() 이라는 메소드를

가져와서 DB와 연결해주고 이 연결 DB모듈을 담도록 하겠습니다.

 

그럼 이제 저희는 conn.query() 라는 함수를 사용하여 DB에게 어떠한 명령을 줄 수 있습니다.

가령 <select * from visitor;>이나 <delete from visitor where id = 1;>와 같은 조건들입니다.

 

이 코드는 getVisitors 함수를 정의하고 내보내는(export) 코드입니다.

( model에서 내보내니까 연결된 controller로 가겠죠? )

 

controller에서 쓰일 이 getVisitors함수는 앞서 mysql 모듈로 DB와 연결했던 

conn객체에 query 메서드를 끌어와서 쓰고 있습니다.

query 메서드는 말 그대로 DB의 SQL쿼리를 실행하는 메서드입니다.

인자로 SQL구문(select * from visitor)과 callback함수 ((err,rows)=> {})를 인자로 받습니다.

err는 오류 객체, rows 쿼리 결과 행을 반환합니다.

 

여기서 성공했을 때 반환하는 이 rows를 console.log로 찍어보면 하기와 같이 나옵니다.

DB query 실행 성공 결과 객체

 이 getVisitors함수는 결국 model에서 DB의 visitor테이블에 있는 모든 정보를

select하는 쿼리를 실행하는 함수인거죠!

 

 

model에 있는 다른 함수들도 비슷한 양상입니다.

마찬가지로 data와 콜백함수를 인자로 받는 함수 postVisitor를 보겠습니다.

이 함수는 conn.query로 DB에 value값을 삽입하는 함수입니다.

 

보시면 data라는 [ view에서 얻어온 사용자 입력값 ] [ DB까지 넣어주는 통로 역할 ]을 하고 있습니다.

 

그리고 이 callback함수는 이 insert하는 DB값의 insertId를 반환하고 있습니다.

이 insertId는 추후 controller와 view에서 사용될 예정입니다.

 

저는 sql로 visitor 테이블에 insertId 속성을 선언한 적이 없는데 뭐지? 하고  rows를 console에 찍어보니

하기와 같이 나옵니다. 아마도 rows반환값의 기본값에서 들어가는 객체인 듯합니다.

네번째 줄의 insertId가 있음.

 

그 다음 delete 역할을 하는 함수도 보도록 하겠습니다.

이 함수는 conn.query로 DB에 있는 id값을 찾아서 삭제하는 역할을 하고 있습니다.

 

여기서 특이한 점은 callback으로 삭제를 알려주는 어떠한 인자값을 반환하게 되는데

이를 통해 프론트에서 '아, 삭제가 잘 되었구나.'를 알 수 있게 하는 값이면 됩니다.

저는 true라고 하였습니다.


이제 model에서 DB와 연결지어 DB의 실제 데이터를 지지고 볶는 이 함수들을 이해하셨다면,

view와 model을 연결지어주는 controller를 보도록 하겠습니다.

 

지난 번 포스팅에서 보았듯이,

Visitor라는 변수에 model 폴더 내 Visitor 파일을 모듈로 가져와서 저장하고,

main함수가 불리면 index.ejs가 렌더되도록 하였습니다.

.

.

 

그 밑에 모델과 이어진 코드를 보도록 하겠습니다.

 

 

visitor라는 함수를 정의하고 있는데,

앞서 model에서 통째로 가져온 Visitor모듈의 getVisitors함수를 불러오고 있습니다.

 

저희가 앞서 console.log도 보았던 그 함수인데요,

아까 그 getVisitors()의 성공 시 반환하는 rows 값

이러한 결과 값(rows)을 result에 담았고, visitor.ejs를 렌더하는 것과 동시에

result값data라고 명명해서 view에서 사용할 예정입니다.

.

.

 

이 외의 다른 controller - model이 이어지는 함수를 보도록 하겠습니다.

postVisitor함수는 model에서 사용자 입력값을 받아서 DB에 값을 insert했던 함수입니다.

사용자 입력값(username, comment 등) req.body를 받아서

Visitor.postVisitor로 model함수를 부를 때 보내주고 있습니다.

 

req.body옆에 있는 insesrtId는 model의 postVisitor에서 callback함수의 반환값이 들어가게 됩니다.

이 DB와 model을 거쳐 가져온 insertId값은 id로 명명해서 send로 view에 전송하고 있습니다.

.

.

 

 

그 다음 삭제처리를 진행하여 DB에서 진짜 사용자를 삭제하는 

deleteVisitor() 함수를 보도록 하겠습니다.

일단 model의 delteVisitor의 query문에서 id에 일치하는 값을 찾아서 삭제를 진행했으니

id값을 보내기 위해 deleteVisitor() 함수의 요청 값에서 id를 찾아 넘겨줍니다.

 

그래야 일치하는 id값을 DB에 넘겨서 delet할 수 있으니깐요!

 

그리고 그 id값을 넘겨서 callback함수에서 그 결과값을 삭제가 성공했다면

true로 반환하였으니 true라는 값이 result에 담겨서 view에 send하게 됩니다.


 

view의 ejs파일들에 직접 script를 선언하지 않아서 사실 view의 ejs들은 볼게 없구요,,,

static폴더 아래 visitor.js라는 파일을 만들어서 script를 연결해주었는데요,

 

 

이 visitor.js에서 어떻게 controller에 사용자 입력값을 넘기고

DB query실행 결과값을 받는지 보도록 하겠습니다.

function createVisitor() {
    const form = document.forms['visitor-form']
    axios({
        method: 'POST',
        url: '/visitor',
        data: {
            name: form.name.value,
            comment: form.comment.value,
        },
    }).then((res) => {
        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);
    });
};

앞에서 부터 간단하게 훑자면, creatVisitor() 함수axios를 활용하여 post방식으로 data를 보내고 있습니다.

이 axios가 성공한다면 axios의 결과값을 then의 res에 들어가게 됩니다!

 

더보기

이 axios의  post 방식과 url을 보고 라우터에 들어가게 되고

라우터는 맞는 방식을 컨트롤러의 함수와 매칭을 해줍니다.

 

해서 이 res의 data값을 활용해서 newVisitor라는 html블럭을 만들었고, 이를 새롭게 html에 추가하고 있습니다.

 

여기서 새롭게 등장한게 newVisitor처럼 블럭을 통째로 보낼 수 있는 inserAdjacentHTML함수입니다.

이 함수의 기본 형태는 다음과 같습니다.

element.insertAdjacentHTML(position, text);

 

1. element: 어떤 요소를 변경할 것인지 선택

2. insertAdjacentHTML: HTML의 DOM요소에 새로운 HTML콘텐츠를 삽입하는 함수

3. postion: 삽입될 위치를 나타냄 (beforebegin, afterbegin, beforeend, afterend)

4. text: 삽입할 HTML문자열