게시판 만들기 #6 / Create

jh_leitmotif·2021년 7월 23일
0
post-thumbnail

🧐 개요

Node.js CRUD 게시판 생성을 정리합니다.

Create 부터 시작합니다.

📋 글 작성 페이지

<!DOCTYPE html>
<html>
  <head>
    <title>새 글</title>
    <link rel='stylesheet' href='../../../css/style.css' />
  </head>
  <body>
    <div class="ContentField">
      <form action="/insert" method="post">
        <table frame=void>
          <tr>
             <td colspan="2" style="height:10%; padding-top:3vh;">
               <input type="text" name="title" placeholder="제목을 작성해주세요!" > 
            </td>
          </tr>
          <tr>
            <td>
              <input type="button" id = "<%=id%>" value="파일 업로드" onclick="openChild(this)">
              <span id="sInput"></span>
              <a href="/uploadedFileDelete/<%=id%>">
              <input type="button" value="업로드 취소" onclick="deleteFile()"></a>
            </td>
          </tr>
          <tr>
            <td colspan="2" style="padding-top:20px;">
               <textarea name="content" placeholder="내용을 작성해주세요!" required ></textarea>
            </td>
          </tr>
          <tr>
            <td colspan="2" style="text-align:right;">
                <button type="submit">글 쓰기</button>
            </td>
          </tr>
      </table>
      </form>
    </div>
  </body>
</html>

간단히 작성한 write.html입니다.
가독성을 위해 일부 내용은 제거하여 작성합니다.

중간 테이블 태그 중, 파일 업로드 버튼은 누르면 자식 창이 열리며
해당 창에서 파일을 업로드할 수 있습니다.

이 로직에서 포스트의 ID를 통해 업로드될 파일의 이름을 변경해야하므로
미리 서버측에서 넘겨받은 마지막 포스트 ID를 파라미터로 전달합니다.

파일 업로드는 따로 다른 글에 작성합니다.

서버로 제목과 내용을 전달해야하기 때문에
form 태그의 method를 post로 작성했습니다.
input 태그의 값은 각기 설정된 name 값으로 대표되어 서버로 전달됩니다.

현재 업로드된 파일 중 이미지가 있는 경우 사용자의 선택에 따라 보이거나,
보이지 않도록 해둔 상태입니다.
개선점으로는 velog처럼 복사/붙여넣기로 내용에 이미지를 첨부하는 것입니다.
지금은 수동으로 업로드 버튼을 눌러야하고, 사용자가 원하는 위치에
이미지를 삽입할 수 없습니다.

📋 접속 라우터

router.get('/board/write/:idx',function(req,res,next){
  if (typeof req.session.displayName!=='undefined'){ // 만약 로그인한 유저라면
    res.render('boardHTML/write.html',{id:req.params.idx});
    // 글 쓰기 html로 이동합니다.
  }else{ // 로그인을 하지 않았다면
    res.send("<script>alert('로그인을 해주시기 바랍니다.'); window.history.back();</script>")
    // alert를 발생시키고 이전 페이지로 이동합니다.
  }
})

:idx는 위에서 언급한 마지막 포스트 ID로,
게시판이 렌더링될 때 미리 서버 측에서 전달해둔 값입니다.

화면에서 글 쓰기 버튼을 누르면 ID 값이 서버에 파라미터로 전달됩니다.

이 때 만약 로그인을 하지 않아 세션의 displayName의 type이 정의되지 않았다면

로그인을 하지 않았다는 alert가 발생하고 window.history.back()함수를 통해 이전 페이지로 돌아가게 됩니다.


📋 post 라우터 - DB에 값 전달하기

router.post('/insert',(req,res)=>{
  if (typeof req.session.displayName!=='undefined'){
    // 로그인하지 않은 사용자가 URL을 직접 입력하여 접근하는 것을 방지합니다.
    
    const title = req.body.title;
    const content = req.body.content;
    // form 태그로부터 제목, 내용 값을 전달받습니다.
    
    const author = req.session.displayName;
    // 작성자는 로그인한 유저의 ID 입니다.
    
    let filepath = '';
    if (typeof req.session.filepath=='undefined'){
      filepath=null;
    }else{
      filepath=req.session.filepath;
    }
    // 작성 중인 글에 파일을 첨부할 때, 업로드 로직에서 파일 경로를 보냅니다.
    // 만약 첨부된 파일이 없다면 null값으로 초기화합니다.
    
    if (title.length==0 || content.length==0){
     res.send("<script>alert('제목 또는 내용에 아무것도 작성되지 않았습니다.'); window.history.back()</script>")
    } 
    // 작성된 내용이 없다면 이전 페이지로 돌아가게끔 합니다.
  
    else{
      const authSql = 'SELECT nick FROM users WHERE id=?';
      const insertSql = 'INSERT INTO board (title, content, name, regdate, modidate, nick, uploadfilepath) VALUES(?,?,?,NOW(),NOW(),?,?)'
      // 기본적으로 쿼리문은 하드코딩하고 있지 않습니다.
      // query 함수에 SQL 문을 직접 쓰지 않으며, 
      // 전달되어야할 값은 ? 처리로 넘기도록 하고 있습니다.
      
      conn.getConnection((err,connection)=>{
        if (err) throw err;
        const authQuery = connection.query(authSql,[author],function(err,rows){
          // 접속한 유저가 실제로 DB에 있는지 파악하여 부정한 글 쓰기를 방지합니다.
          
          if (err){
            throw err;
          }else{
            const insertQuery=connection.query(insertSql,[title,content,author,rows[0].nick,filepath],function(err,rows){
              if (err){
                throw err;
              }else{
                res.send("<script>alert('작성되었습니다.'); document.location.href='/board/list'</script>")
              }
            })
          }
          req.session.filepath='';
          connection.release();
        })
      })     
    }
  }else{
    res.send("<script>alert('비정상적인 접근입니다.'); document.location.href='/info'</script>")
    req.session.filepath='';
  }
})

우선 로그인을 하지 않은 유저의 URL 접근을 방지하는 if문을 크게 둘렀습니다.
만약 비로그인 유저인 경우, 메인 페이지로 보내버립니다.

form 태그의 값은 req.body.(name속성) 으로 받아올 수 있습니다.

이를 통해 제목, 내용을 전달받았고 세션 값을 통해 사용자의 ID를 받습니다.

이후 현재 글을 작성하는 사용자가 실제로 DB에 속한 유저인지 판별하고
필요한 값들을 DB에 Insert합니다.

가장 신경 쓴 것은 하드코딩하지 않기입니다.

query 함수에는 쿼리문을 변수로 넘겼고, 값 또한 ? 처리로 전달받도록 합니다.

이제와서 보니 auth 작업이 꼭 필요할까? 라는 생각이 드네요...
개선점은 async await 문법을 통한 가독성 향상이 있습니다.
auth 작업을 단순히 session 값을 통해 진행하는데, 더 확실한 방법이 있는지에
대한 고민이 필요한 것 같습니다.

🎯 구조도


🙄 후기

초기엔 그저 DB를 연결해 값을 넘기는 것뿐인 코드였는데

직접 테스트해보고.. 또 이런저런 다른 분들의 포스트를 보면서

이것저것 보완해나가다보니 글 생성만으로 엄청 길어져버렸습니다.

아마도 배우면 배울 수록 코드는 또 길어지거나, 더 줄어들겠죠? 😅😅😅


profile
Define the undefined.

0개의 댓글