Node.js 기반 홈페이지 만들기 (4) - 게시글 올리기, 목록, 보기, 수정

 

시리즈

기능 동작이 목표기 때문에 자세한 설명은 하지 않습니다.

  • IDE : WebStorm
  • DB : MongoDB
  • OS : MAC

시작하기 전

https://codepen.io/ikramcg/pen/PNbzWb, https://codepen.io/veronicadev/pen/YYvjzO를 참고하여,
게시글 목록 views/board/board.ejs, 게시글 작성 views/board/board-write.ejs,
게시글 수정 views/board/board-edit.ejs, 게시글 보기views/board-view.ejs를 미리 만들어두었습니다.

17

그리고, 게시판 라우팅 코드도 미리 작성했습니다. 라우팅은 Node.js 기반 홈페이지 만들기의 이전 글을 참고하시기 바랍니다.

app.js

const boardRoute = require("./routes/board");

app.use("/board", boardRoute);

게시글 작성

18

POST메소드, /board/write로 액션하도록 form을 만듭니다.

views/board/board-write.ejs

<form id="board_write" method="post" action="/board/write">

게시글을 작성하면, form내용을 받아서 데이터베이스에 저장하기 위해 스키마를 만듭니다. 카테고리, 작성자, 게시일, 제목, 내용을 구성요소로 정했습니다.

models/board.js

const mongoose = require("mongoose");
mongoose.set('useCreateIndex', true);

const boardSchema = new mongoose.Schema({
      category:{ type: String, required: true },//카테고리
      auth :{ type: String, required: true },//작성자
      date :{type:Date, required:true},//게시일
      title :{ type: String, required: true},//제목
      content:{ type: String, required: true}//내용
});

module.exports = mongoose.model("Board", boardSchema);

먼저, board 라우트 코드를 작성합니다. 여기서 주의할 부분은 게시글 작성을 위해 /board/write로 접속할 때, 로그인하지 않은 사용자의 접근을 막아야 합니다.

routes/board.js

const express = require("express");
const router = express.Router();
const Board = require("../models/board");

router.get('/', (req, res) => {
    if(req.user) {
        res.render('board/board',{isLogin:"Logout"})}
    else{res.render('board/board',{isLogin:"Login"})}
});

router.get('/write', (req, res) => {
    if(req.user) {res.render('board/board-write',{isLogin:"Logout"})}
    //로그인하지 않은 사용자 접근 차단
    else{ res.send('<script type="text/javascript">alert("로그인한 사용자만 작성할 수 있습니다."); window.location="/login"; </script>')}
});

module.exports = router;

게시글을 작성하고, submit하였을 때 post를 처리하는 코드를 작성합니다.

  • 같은 제목(title)의 글이 5개 이상이면, 도배금지를 위한 알림을 띄우고 저장하지 않습니다.
  • 작성자(auth)는 현재 로그인된 세션에서 email을 가져와서 저장합니다.
  • 작성날짜(date)는 저장되는 순간의 Date로 저장합니다.
router.post('/write', (req, res) => {
    Board.find({ title:req.body.title })
        .exec()
        .then(post => {
            if (post.length >= 5) {
                res.send('<script type="text/javascript">alert("도배 방지를 위해 같은 제목의 글을 5개 이상 게시할 수 없습니다."); window.location="/board/write"; </script>');
            } else {
                const post = new Board({
                    category:req.body.category,
                    auth:req.user.email,
                    date:new Date(),
                    title:req.body.title,
                    content:req.body.content
                });
                post
                    .save()
                    .then(result => {
                        console.log(result);
                        res.send('<script type="text/javascript">alert("게시글이 업로드되었습니다"); window.location="/board"; </script>');
                    })
                    .catch(err => {
                        console.log(err);
                        res.send('<script type="text/javascript">alert("작성이 실패하였습니다."); window.location="/board/write"; </script>');
                    });
            }
        });
});

게시글 목록

게시글을 작성하였으니, 게시글 목록을 출력해야 합니다. /board로 접속하면,

  • Board 모델을 통해서 게시판 데이터베이스를 (Board.find)
  • 최근 순으로 정렬해서 (sort)
  • lists로 전달합니다 (lists:lists)

routes/board.js

router.get('/', (req, res) => {
    Board.find({})
        .sort("-date")
        .exec(function(err, lists){
            if(err) {console.log(err)}
            if(req.user) {res.render('board/board',{isLogin:"Logout", lists:lists})}
            else{res.render('board/board',{isLogin:"Login", lists:lists})}
        });
});

게시글 목록을 출력하기 위한 view 예시입니다.
lists를 받아서 forEach를 이용해 글목록을 출력합니다.

  • 클릭을 하면 /board/post._id로 이동하도록 링크를 겁니다.

19

views/board/board.ejs

 <a href="/board/<%=post._id%>">
   <% lists.forEach(function(post) { %>
        <li>
            ...
            <div class="info">
                <span><%=post.title%></span>
                <span><%=post.auth%> <%=post.date%></span>
            </div>
            <span>
                <% if(post.category === 'fr'){ %>자유<% } %>
                <% if(post.category === 'qu'){ %>질문<% } %>
            </span>
        </li>
    <% }) %>
  </a>

게시글 보기

게시글 목록에서 글을 클릭하면, 해당 글의 내용을 보여주도록 코드를 작성하겠습니다.
위의 board.ejs에서 /board/post._id로 링크를 걸었으므로, ‘/:id’로 받아서 처리합니다.

  • req.params.id와 같은 것을 DB에서 찾아서 보냅니다.
  • 만약, 로그인하고 있는 유저와 게시글의 작성자가 같으면 수정 버튼이 나타나도록 합니다.
  • views/board/board-view.ejs 는 위의 코드들을 참고하면, 쉽게 작성할 수 있어 따로 적지 않습니다.

20

routes/board.js

router.get('/:id',(req, res) => {
    Board.findOne({_id : req.params.id}, function(err, post) {
        if(err) console.log(err);
        if(req.user && req.user.email===post.auth){res.render('board/board-view', {isLogin:"Logout", post:post, edit:"yes"})}
        else if(req.user && req.user.email!==post.auth) {res.render('board/board-view', {isLogin:"Logout", post:post, edit:"no"})}
        else{res.render('board/board-view',{isLogin:"Login", post:post,edit:"no"})}
    })
});

게시글 수정

게시글 작성과 크게 다른 점이 없습니다.

  • 수정한 form을 post로 받아
  • date는 수정한 날짜로, 제목과 내용은 수정된 것으로 변경합니다.

21

routes/board.js

router.post('/edit/:id',(req, res) => {
    Board.findOneAndReplace({_id : req.params.id},
        {$set:{title:req.body.title, date:new Date(),content:req.body.content}}, function(err, post) {
        if(err) console.log(err);
        res.redirect('/board/'+req.params.id);
    })
});

마치며

게시판은 비슷한 코드들을 어떻게 응용하느냐에 따라 활용이 달라지므로 하나만 이해해도 다른 코드들은 금방 작성할 수 있습니다.

앞으로 업로드 할 글 예정

  • 5번째 글 : 내정보 수정
  • 6번째 글 : 관리자

이 글부터는 코드를 제공하지 않습니다. 질문은 트위터로 부탁드립니다