본문 바로가기

웹개발

게시판-CRUD

Node.js 공부를 하며 만들었던 프로젝트를 복사해 새 프로젝트를 만들고 이어서 작업하도록 하겠다.

 

폴더 구성부터 진행하였다.

우선, views 폴더 안에 board 폴더를 만들고 그 안에 main.ejs, read.ejs, write.ejs, edit.ejs 이렇게 4개의 파일을 만든다.

삭제 관련 파일이 없는 이유는 삭제는 따로 페이지를 이동해서 할 필요가 없기 때문이다. 

edit의 경우에는 자신의 글만 수정 가능하게 해야 되서 회원가입, 로그인 기능을 만들고 나서 만들겠다.

main은 게시판 목록이 보이는 메인 화면이다. 

그리고 router 폴더 안에 borad.js 를 만들어서 게시판 관련 링크를 따로 모아두었다.

model 폴더 안에는 새로운 테이블을 만들기 위해 posts.js 파일을 만들었다. 

 

먼저 posts 테이블 구성부터 보면

module.exports = function(sequelize, DataTypes){ 
    return sequelize.define('posts', {
      idx: {
        type : DataTypes.INTEGER,
        autoIncrement: true,
        primaryKey: true,
        allowNull: false
      },
      title: {
        type: DataTypes.STRING(255),
        allowNull: false
      },
      content: {
        type: DataTypes.TEXT,
        allowNull: false
      }
    });
}

이렇게 되어있다.

저번에 mysql-sequelize에서 만들었던 구조와 거의 유사한데 구성 요소로 title, content를 추가하였다.

title은 STRING(255)로 해서 길이 제한이 있는 문자열을 받았고 content는 TEXT로 길이 제한 없는 글을 받는다.

 

db.js 파일에서 이 테이블을 연결해주기 위해서

db.posts = seq.import(__dirname+"/posts.js");

이 코드를 추가해준다.

 

db.js 파일에서 이렇게 연결을 해주고 posts.js 파일을 제대로 만들었더라도 실제로 서버를 실행시켜 보면

반영이 안되어있다. mysql에 접속해서 확인해봐도 테이블 구조가 바뀌지 않았다.

제대로 연동이 안되어있기 때문인데 이를 해결하기 위해서는 sequelize의 migration을 하던가, mysql의 구조를 수동으로 바꾸던가, sync 함수로 연동을 시켜줘야 한다.

mysql의 구조를 수동으로 바꾸는 것은 실수로 코드와 다른 구조가 될 수도 있기 때문에 좋은 방법은 아닌 것 같고,

sync 함수를 사용하면 이전에 데이터베이스에 저장된 데이터들이 모두 날아간다는 문제점이 있다.

개발 과정에서는 이미 있던 데이터가 날아가도 상관이 없어서 sync 함수를 사용했지만,

게시판을 운영하는 중에 새로운 테이블을 만들어서 구조가 바뀌는 경우에는 migration을 해줘야 할 것 같다.

const db = require('./model/db');

db.seq.sync({ force: true }).then(() => {
    console.log("All models were synchronized successfully.");
}).catch(error => {
    console.error("Error occurred during the synchronization:", error);
});

이렇게 syncdb.js라는 다른 파일을 root 디렉터리에 만들어주고, 실행시켜주면 된다.

then과 catch 함수는 제대로 sync가 이루어졌는지 편하게 확인하기 위한 코드이다.

 

데이터베이스에 테이블을 제대로 추가를 해 줬으면, router파일인 board.js에서 링크를 설정한다.

const express = require('express');
const router = express.Router();
const db = require('../model/db')

router.get('/', (req, res) => {
    db.posts.findAll()
        .then(function(posts) {
            res.render('board/main',{posts: posts });
        });
});

router.get('/write', (req, res) => {
    res.render('board/write');
});


router.post('/write', (req, res) => {
    const title = req.body.title;
    const content = req.body.content;

    db.posts.create({
        title: title,
        content: content
    }).then(function(result){
        res.redirect('/board');
    })
});


router.get('/read/:id', (req, res) => {
    const postId = req.params.id;

    db.posts.findByPk(postId)
        .then(post => {
            if (post) {
                res.render('board/read', { post: post });
            } else {
                res.status(404).send('게시물을 찾을 수 없습니다.');
            }
        })
});


router.post('/delete/:id', (req, res) => {
    const postId = req.params.id;
    db.posts.destroy({
        where:{idx:postId}
    }).then(function(result){
        res.redirect('/board');
    })
})

module.exports = router;

board.js에 있는 링크들은 모두 /board로 시작하게 만들 것이다.

1. /

/ 링크에는 board 폴더의 main.ejs 파일을 불러오는데 게시글 목록을 넘겨줘야 하기 때문에

db.posts.findAll 함수로 게시글들을 가져와서 posts 변수로 넘겨준다.

2. /write

get 방식의 /write 링크에는 write.ejs 파일을 렌더링한다.

post 방식의 /write 링크에는 사용자에게 입력받은 title, content를 가져와서 posts.create로 데이터를 추가하고,

redirect로 글 목록으로 돌아간다.

3. /read

/read 링크는 글을 확인하는 링크이기 때문에 어떤 글인지 id를 파라미터로 같이 넘겨받아야 한다.

postId로 id를 넘겨받고, findByPk 함수로 게시글을 가져오고, 게시글이 제대로 불러와진 경우에

read.ejs파일로 post를 같이 념겨준다.

4. /delete

/delete 링크는 read와 마찬가지로 어떤 글을 삭제할지 알아야 하기 때문에 id를 파라미터로 받는다.

그리고 where로 게시글을 찾고, destroy 함수를 이용해 데이터베이스에서 삭제한 뒤, 글 목록으로 돌아간다.

delete는 페이지 이동이 필요없기 때문에 렌더링은 필요없다.

 

app.js 파일에서 

const boardRouter = require('./router/board');
app.use('/board', boardRouter);

 이 코드를 추가하면 board.js 파일에 있는 링크들은 /board에서 연결된다.

 

이제 각 화면을 구성하기 위한 ejs 파일을 작성한다.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>글 목록</title>
    <link href="/public/main.css" rel="stylesheet" />
</head>
<body>
    <h1>게시판</h1>
    <ul>
        <% posts.forEach(function(post) { %>
            <li><a href="/board/read/<%= post.idx %>"><%= post.title %></a></li>
            <form action="/board/delete/<%= post.idx %>" method="post">
                <div>
                    <button type="submit">글 삭제</button>
                </div>
            </form>
        <% }); %>
    </ul>
    <a href="/board/write">글 작성</a>

</body>
</html>

먼저 main.ejs 파일이다. 기본적인 html 설정들을 해주고 중요한 부분은 forEach 구문이다.

아까 라우팅에서 넘겨받은 posts에는 posts테이블의 모든 데이터가 findAll로 찾아진 결과가 담겨있다.

이를 하나씩 post 변수에 담아서 반복문을 구성하였다. 

각 게시글 하나마다 글을 읽으러 갈 수 있는 read 링크를 id를 포함해서 지정해주고, 게시글의 제목만 보이게 해둔다.

그리고 각 게시글을 삭제할 수 있게 id를 포함한 delete 링크를 지정해준다.

delete는 버튼으로 구현하였다.

마지막으로 글을 작성하러 가는 링크를 밑에 붙였다.

두 번째는 글 작성을 위한 write.ejs 파일이다.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>글 작성</title>
    <link href="/public/main.css" rel="stylesheet" />
</head>
<body>

    <h1>글 작성</h1>

    <form action="/board/write" method="post">
        <div>
            <label for="title">제목:</label>
            <input type="text" id="title" name="title" required>
        </div>
        
        <div>
            <label for="content">내용:</label>
            <textarea id="content" name="content" rows="10" required></textarea>
        </div>
        
        <div>
            <button type="submit">글 작성</button>
        </div>
    </form>

    <a href="/board">목록으로 돌아가기</a>

</body>
</html>

/board/write 링크로 post 요청을 보내서 글을 작성할 수 있게 하였다.

제목과 글을 쓸 수 있는 input 태그와 textarea 태그를 넣고 글을 작성할 때 누르는 button을 만들었다.

밑에는 글 목록으로 다시 돌아갈 수 있는 링크를 넣어두었다.

세 번째는 read.ejs 파일이다.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><%= post.title %></title>
    <link href="/public/main.css" rel="stylesheet" />
</head>
<body>
    <h1><%= post.title %></h1>
    <p><%= post.content %></p>
    <a href="/board">목록으로 돌아가기</a>
</body>
</html>

이미 라우팅에서 해당 id의 게시글을 post로 넘겨받았기 때문에 그냥 title, content를 표시해주기만 하면 된다.

그리고 밑에 글 목록으로 돌아갈 수 있는 링크를 추가하였다.

이렇게 게시판의 기본적인 요소들을 만들어 보았다.

edit 기능은 회원가입, 로그인 기능을 만들고 나서 자신의 글만 수정할 수 있게끔 기능을 만들 예정이다.

'웹개발' 카테고리의 다른 글

게시판-이메일 인증, 아이디 찾기  (0) 2023.10.25
게시판-회원가입, 로그인  (0) 2023.10.24
flask - mySQL 연동  (0) 2023.10.22
flask  (0) 2023.10.20
점프 투 파이썬 5장 - 파이썬 날개 달기  (0) 2023.10.19