봄날은 갔다. 이제 그 정신으로 공부하자

node.js로 웹서비스 만들기 (9. ejs에서 node.js로 데이터 전달) 본문

학습

node.js로 웹서비스 만들기 (9. ejs에서 node.js로 데이터 전달)

길재의 그 정신으로 공부하자 2023. 7. 15. 11:11

이번 글은 이전 글의 반대로 프론트에서 백엔드로 데이터를 전달하는 방법에 대해 기록하도록 하겠습니다.

프론트에서 백엔드로 값을 전달하는 방법은 여러가지인데 이번글에서 기록하는 내용은 url parameter로 데이터를 전달하는 방법과 body parameter로 데이터를 전달하는 방법에 대해 기록합니다.

 

첫번째, GET 방식 url parameter로 데이터 전달하기

퀴즈 목록에서 테이블 row의 버튼 클릭 시 상세보기로 이동하는 시나리오를 예시로 들겠습니다.

이러한 경우, 특별한 값의 전달없이 url을 아래와 같이 구성해서 보내주면 됩니다.

   > '/quiz/detail_quiz/10 // 마지막 10은 퀴즈의 qid입니다.

 

테이블 row의 버튼 클릭에서 저는 여기서 jQuery가 아닌 javaScript의 onClick 속성을 사용하였습니다.

jQuery를 좀 더 알면 jQuery를 사용했을 텐데 잘 모르는 상태에서 개발하다보니 테이블에서 버튼 클릭 시 값을 가져오는 부분이 별도로 처리되는 것 보다는 버튼 클릭 시 파라미터로 값을 직접 전달 받는 방식이 직관적인 것 같아 javaScript의 onClick 속성을 사용하였습니다

 

테이블 row 추가 시 아래와 같이 버튼 태그를 추가합니다.

<button type="button" class="btn btn-warning click" style="width: 100px" onClick="actionDetail(<%=list[i].qid %>)">자세히보기</button>

이후 스크립트에 actionDetail() 함수를 아래와 같이 구현해 주었습니다.

<script>
    function actionDetail(qid) {
        window.location  = "/quiz/detail_quiz/" + qid;
    }
</script>

 

자세한 코드는 아래와 같습니다.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
    <link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap-grid.min.css' />
    <script src='https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js'></script>
    <script src='https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.bundle.min.js'></script>
    <script src="//code.jquery.com/jquery.min.js"></script>
    <title>퀴즈 관리</title>
  </head>
  <body>
    <div class="mt-3">
      <h4 class="text-center">퀴즈 관리</h4>
    </div>
    ...
    <div class="container-fluid">
      <div class="row">
        ...
        <div class="col" style="background-color: #fff">
            <div class="text-right mb-3">
                <button type="button" class="btn btn-primary" id="create_ox_quiz" style="width: 200px;">OX퀴즈 제출</button>  
                <button type="button" class="btn btn-primary" id="create_sngcho_quiz" style="width: 200px;">4지선다 제출</button>  
            </div>

            <table class="table">
                <colgroup>
                    <col width='80'><col width='90'><col width='150'><col width='400'><col width='400'><col width='80'>
                </colgroup>
                <thead>
                    <tr>
                        <th>NO.</th>
                        <th>타입</th>
                        <th>등록일</th>
                        <th>퀴즈 내용</th>
                        <th>정답 설명</th>
                        <th>관리</th>
                    </tr>
                </thead>
                <tbody>
                    <% for(i = 0; i < list.length; i++) { %>
                    <tr>
                        <td><%=list[i].qid %></td>
                        <td>
                            <%if(list[i].type == 0){%>
                                OX
                            <%}else if(list[i].type == 1){%>
                                4지선다
                            <%}%>
                        </td>
                        <td><%=list[i].createdAt %></td>
                        <td><%=list[i].contents %></td>
                        <td><%=list[i].comment %></td>
                        <td>
                            <button type="button" class="btn btn-warning click" style="width: 100px" onClick="actionDetail(<%=list[i].qid %>)">자세히보기</button>
                        </td>
                    </tr>
                    <% } %>
                </tbody>
            </table>
        </div>
      </div>
    </div>
  </body>
</html>

<script>
    ...    

    function actionDetail(qid) {
        window.location  = "/quiz/detail_quiz/" + qid;
    }
    ...
</script>

 

'이제 "/quiz" 경로를 담당하는 quiz.js에서 관련 이벤트를 받아 처리하는 코드를 아래와 같이 추가합니다.

아래 코드를 보면 router.get('/detail_quiz/:qid', function(req, res){ ... });

에서 "detail_quiz"뒤에 오는 값을 :qid로 정의하고 req의 params에서 qid 정보를 받아 오는 것을 확인 할 수 있습니다.

// 퀴즈 상세보기로 이동
router.get('/detail_quiz/:qid', function(req, res){
    if(!req.session.user){
        res.render('login');
        return;
    }

	// 파라미터 데이터 처리
    var params = req.params;
    var qid = params.qid;
    
    // 파라미터로 qid를 전달 받았는지 확인
    console.log('[GET] detail quiz qid: ' + qid);
    
    // qid를 사용해 db query
    var sql = 'SELECT * FROM quiz WHERE qid = ?';
    var param = [qid];
    conn.query(sql, param, function (err, rows, fields) {
        if(err) console.log('query is not excuted. select fail...\n' + err);
        else res.render('detail_quiz', {item: rows[0]});
    });
});

 

두번째, GET 방식 url QueryString으로 데이터 전달하기

GET 방식으로 백엔드에 데이터 전달 시 앞서 설명한 URL 파라미터와 마찬가지로 많이 사용하는 방식이 QueryString 전달 방식입니다.

QueryString은 URL의 "?" 기호로 구분되는 값입니다.

아래 URL은 volumeNo와 memberNo 두개의 QueryString을 백엔드로 전달합니다.

https://post.naver.com/viewer/postView.naver?volumeNo=36125525&memberNo=25776368  

 

첫번째 예제의 ejs 파일의 onClick() 함수에 아래와 같이 QueryString을 추가합니다.

<script>
    function actionDetail(qid) {
        window.location  = "/quiz/detail_quiz/" + qid + "?type=ox";
    }
</script>

 

마찬가지로 quiz.js에 QueryString을 처리 할 수 있도록 아래와 같이 코드를 수정합니다.

// 퀴즈 상세보기로 이동
router.get('/detail_quiz/:qid', function(req, res){
    if(!req.session.user){
        res.render('login');
        return;
    }

    var params = req.params;
    var qid = params.qid;

    // 쿼리스트링을 받아오는 코드 추가
    var query = req.query;
    var type = query.type;

    // 정상적으로 받아 왔는지 확인
    console.log('[GET] detail quiz qid: ' + qid + ', type: ' + type);
    
    ...
}

 

 

세번째, POST 방식 body로 데이터 전달하기

url로 데이터를 전달하는 방식을 보안에도 취약하고 일정 사이즈 이상의 데이터를 전달하는데 한계가 있어 대용량 데이터를 전달할 때는 POST 메소드의 body로 데이터를 전달합니다.

node.js로 데이터를 전달하기 위해 사용자가 퀴즈 작성 ejs에서 "done" 버튼 클릭 시 동작하는 jQuery를 아래와 같이 작성해줍니다.

<script>
	// done 버튼 클릭시 전달 받는 메소드
    $("#done").click(function() {
      // 백엔드로 데이터를 전달하기 전에 필수 값이 입력되어 있는지 확인 
      // 필수 값이 입력되어 있지 않으면 알림 팝업 띄워주고 현화면 유지
      if (category.value == 0) {
        alert("카테고리를 선택해주세요.");
      }else if (timer.value == 0) {
        alert("제한시간을 선택해주세요.");
      }else if (contents.value.length == 0) {
        alert("문제 내용을 입력해주세요.");
      }else if (desc.value.length == 0) {
        alert("정답 설명을 입력해주세요.");
      } else {
        // OX 중 어떤 것이 체크되어 있는지 jQuery로 값 가져오기
        var answerVal = $("input[name='answer']:checked").val()
        // POST로 데이터 전달 
        // 백엔드로 전달하는 body는 {}를 사용하여 json 형식으로 전달
        $.post("/quiz/create_ox_quiz", {
            category: category.value,
            timer: timer.value,
            contents: contents.value,
            answer: answerVal,
            desc: desc.value
        }, function(data, status){
            // 백엔드로부터 처리 결과를 받고 그에 맞게 처리
            alert("문제 등록: " + status);
            window.location  = '/quiz';
        });
      }
    });
</script>

 

quiz.js에 아래와 같이 프론트에서 전달받은 데이터를 POST 메소드를 사용해 처리하는 코드를 추가합니다.

// OX 퀴즈 만들기 요청
router.post('/create_ox_quiz', function(req, res){
    // body로 전달받은 데이터 가져오기
    var body = req.body;
    var category = body.category;
    var timer = body.timer;
    var contents = body.contents;
    var answer = body.answer;
    var comment = body.desc;
    // 로그로 body 데이터 확인
    console.log(body);

    // db table에 데이터 추가
    var sql = 'INSERT INTO quiz (createdAt, editedAt, category, timer, contents, answer, comment) VALUES(CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, ?, ?, ?, ?, ?)';
    var param = [category, timer, contents, answer, comment];
    conn.query(sql, param, function(err, result){
        if(err) console.log('query is not excuted. insert fail...\n' + err);
        else {
        	// 결과값 확인
            console.log(result);
            // 결과값에서 qid를 json 형식으로 프론트에 전달
            res.json({qid: result.insertId});
        }
    });
});

 

네번째,  아직까지와는 다르게 <form> tag를 사용해서 POST로 데이터 전달하기

아래 파일은 login.ejs 파일로 <form> 태그에서 method를 post로 선언하고 action 발생 시 백엔드 호출 path는 "/login"으로 선언하고 <input> 태그의 name을 id와 password로 선언 후, 마지막으로 <button> tag의 type을 submit으로 선언했으므로 

로그인 화면에서 사용자가 로그인 버튼을 누르면 index.js의 post('/login', function(req, res) { ... }); 메소드가 호출됩니다.

<!-- login.ejs -->
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
        <title>로그인</title>
    </head>
    <body>
        <div class="mt-5"></div>
        <h2 class="text-center">로그인</h2>
        <div class="m-5">
            <form method="post" action="/login">
                <div class="mb-3">
                    <label for="exampleFormControlInput1" class="form-label">e-mail address</label>
                    <input type="email" name="id" class="form-control" id="exampleFormControlInput1" placeholder="name@example.com">
                </div>
                <div class="mb-3">
                    <label for="exampleFormControlTextarea1" class="form-label">password</label>
                    <input type="password" name="password" class="form-control" id="inputPassword" placeholder="비밀번호를 입력해주세요."></input>
                </div>
                <div class="text-center">
                    <div class="mt-5">
                    <button type="submit" class="btn btn-primary w-100">로그인</button>
                    </div>
                </div>
            </form>
        </div>
    </body>
</html>

 

<form> 태그의 안쪽의 <input> tag에서 name으로 id와 password를 선언했으므로 별도의 값 전달 없이 index.js는 자동으로 데이터를 전달 받을 수 있습니다.
// index.js
...
router.post('/login', function(req, res){
    const paramID = req.body.id || req.query.id;
    const pwd = req.body.password || req.query.password;
    console.log('  id: ' + paramID + ', password: ' + pwd);
    if(!req.session.user){
      // 세션에 유저가 없다면 세션 생성
      ...
      // 로그인에 성공했다면 대시보드로 이동
      res.redirect('/enterance/dashboard');
      return;
    }
    
    console.log('이미 로그인 되어 있습니다.');
    res.redirect('/');
});

...

 

 

 

Comments