본문 바로가기

웹 개념

서버와 웹단을 직접 구현하여 게시판 사이트 만들기 - (1)

728x90

들어가기에 앞서...

이글은 내가 직접 서버단을 구현해보고, 만든 서버단을 기반으로 프론앤드 단을 직접 구현해서 만든 게시판 사이트 코드를 다시 복습하기 위한 용도의 글입니다.

때문에 중간에 중간에 코드가 미리 만들어진 부분이 있을 수 있습니다.

또한 복습용도라서 설명이 빈약하다는 느낌을 받을 수 있습니다. 이해가 안가는 부분 댓글로 적어주시면 아는한에서 친절하게 설명하겠습니다.

 


0. 백앤드 서버는 express.js를 이용해서 구현할 것이며 서버는 json형태의 데이터만 프론트단에서 보내주시는 식으로 구현할 것 입니다.

 

1. exprss.js를 이용하여 서버를 구현하고, mongoDB를 이용해서 데이터를 저장할 것입니다.

1 - 1. 익스프레스를 사용하기위해 require, 몽고디비를 쓰기위해 require 합니다

1 - 2. 마찬가지로 cors, body-parser라는 것도 require하는데 이유는 주석으로 설명했습니다.

1 - 3. 몽구스 연결. 몽구스 사이트로 가서 데이터베이스를 하나 만들면 관련된 주소를 하나 넘겨줍니다. 그 주소를 이용 가져온 것.

const URL = 'mongodb://localhost:27017/myapp';  // db 실행 2번 (mongodb url을 가져온 것)

mongoose.connect(URL); // 몽고디비와 연결하는 부분 (몽구스를 통해서) - db 실행 3번

1 - 4. 경로로 localhost:7777:/routes/posts 로 이동할 경우 이쪽으로 가게하기 위해 require해서 가져오는 것.

 

가져오기)

const postRouter = require("./routes/posts");

사용)

// http://localhost:7777/posts/
app.use("/posts", postRouter);

1 - 5. 마지막으로 서버 실행하는 부분

app.listen(7777, () => { // 서버 실행 3번
    console.log(`sever open -> port: 7777!!`);
    // createPost.create();
})

[전체 코드]

// 외부 모듈은 이름을 통해 가져올 수 있슴.
const express = require("express"); // 서버 실행 1번
const mongoose = require("mongoose"); // db 실행 1번
const cors = require("cors");  // cors오류를 해결하기 위해 가져온 모듈
const bodyParser = require("body-parser");

// 직접 만든 파일은 경로를 통해 가져온다.
// js파일 제외 모두 확장자명이 붙습니다.
const postRouter = require("./routes/posts");

const app = express(); // express 함수를 변수에 넣는 것. (항상 사용 기억 꼭! ^^) 서버 실행 2번

const createPost = require("./service/create");

const URL = 'mongodb://localhost:27017/myapp';  // db 실행 2번 (mongodb url을 가져온 것)

mongoose.connect(URL); // 몽고디비와 연결하는 부분 (몽구스를 통해서) - db 실행 3번

// 원래는 클라이언트 주소가 있어야 한ㄷㅏ.
// CORS 오류를 방지하기위한 코드 
// CORS란? 포트번호가 다르면 각 브라우저는 보안적으로 위험하다고 판단. 데이터를 전송하지 못하게 한다.
// 지금은 내부 localhost로 운영하는 학습단계이므로 모두 허용한다고 표시해서 오류를 해결한 것.
// 현재는 모두 허용인 상태.
app.use(cors());
// body단에 데이터를 가져올때는 bodyParser를 넣어주어야 한다.
app.use(bodyParser.urlencoded({ extended: true }));
// 이거 꼭있어야함!
app.use(express.json());  // post 요청을 했을때 들어오는 body값을 읽을 수 가 없음 => 그래서 사용하는 것.

// http://localhost:7777/posts/
app.use("/posts", postRouter);

// db의 연결 상태를 확인 - 실패시
const dbConnectionStates = mongoose.connection;
dbConnectionStates.on('error', (err) => {
    console.log(err);
});

// db의 연결 상태를 확인 - 성공시
dbConnectionStates.once('open', () => {
    console.log("db connection success!!")
})

app.listen(7777, () => { // 서버 실행 3번
    console.log(`sever open -> port: 7777!!`);
    // createPost.create();
})

2. 이렇게 하면 서버 자체는 열린것이다. 이제 우리는 ./post 에서 각각 필요한 정보를 CRUD하는 작업을 해줄 것입니다.

 

2 - 1. 우리는 1번에서 과정에서 서버를 만들었는데, 거기를 되짚어보면 ./post 에 관련한 url요청을 처리하는 부분을 코딩한게 기억이 나실겁니다. 그부분을 여기서 작업해주는 것 입니다.

그러므로 express에서 Router라는 매서드가 기본적으로 필요합니다.

// 라우팅하는 파일니까 라우터를 사용하기 위해 당연히 라우터를 가져오는 것.
const { Router } = require("express");
// 라우터함수를 라우터 변수에 넣는 것.
const router = Router();

 

2 - 2. 또한 CRUD를 할거면 기본적으로 데이터를 처리할 공간이 있어야합니다. 저희는 그걸 몽고디비를 쓴다고 했습니다. 몽고디비에 관련된 데이터의 정의는 ./../models에 구현했는데. 그것을 가져오는 코드 입니다.

const { Post } = require("./../models");

 

2 - 3. 처음 게시판 사이트에 들어가면 게시판의 전체글이 보이죠. 그러면 데이터베이스에서 모든 데이터를 가져와야 겠죠?

url에 http://localhost:7777/posts/ 이 오면 해당 코드를 실행한다는 것.

그 기능을 하는 코드입니다. get요청으로 post.find({})를 이용해서 전체 데이터를 가져온 다음. json형태로 반환해주는 것.

// post 리스트를 내보냄
// http://localhost:7777/posts/
router.get("/", async (req, res, next) => {
    // post 데이터를 전부 가져오겠다 === ({})
    const posts = await Post.find({});

    // posts는 json형태이므로 json형태로 응답을 해줌.
    res.json(posts);
})

 

2 - 4. 게시판에 내가 글을 쓰고 등록을 해야 겠죠? 등록을 하는 코드입니다.

url에 http://localhost:7777/posts/ 이 오면 아래 코드를 실행.

이전에 bodyParser를 이용하지 않으면 req.body로 데이터를 가져올 때 오류가 난다.이전에 가져온 몽고디비에 데이터 title, content를 받아서 Post.create({ title, content })를 하면  등록이 되는 것.try ~ catch 성공하는지 실패하는지를 처리하는 오류코드와 함께

// post를 작성하는 부분
// http://localhost:7777/posts/
router.post("/", async (req, res, next) => {
    let { title, content } = req.body;
    // console.log(req.body);

    try {
        await Post.create({
            title,
            content
        });
        
        res.json({message: "저장이 완료~!!!"})
    } catch (e) {
        next(e);
    }
});

2 - 5. 게시판을 삭제하는 부분 url로 id를 받으려면 req.params를 써야합니다.

id를 받아서 Post.findByIdAndDelete <= 몽고디비에서 제공해주는 매서드를 이용해서 해당 데이터를 찾은다음 삭제하는 것,

res.json 으로 성공 메세지 전달. 

// posts 삭제
// http:localhost:7777/posts/:id/delete
router.get("/:id/delete", async (req, res, next) => {
    let { id } = req.params;

    try {
        await Post.findByIdAndDelete(id);
        res.json({ messsage: "삭제를 성공!!" });
    } catch(e) {
        next(e)
    }
})

 

2 - 6. 마찬가지로 몽고디비에서 제공해주는 매서드 Post.findById(id); 를 이용해서 찾은 데이터를 res.json으로 내보내는 것. id도 마찬가지로 url로 받고 그렇기에 req.params를 이용함.

// get http://localhost:7777/posts/:id/find
// 게시글 찾기 => 아까 내가 한거랑 원리는 같은데 쓰는 매서드가 조금 다름.
router.get("/:id/find", async (req, res, next) => {
    let { id } = req.params;

    try {
        let findPost = await Post.findById(id);
        res.json(findPost);
    } catch (e) {
        next(e);
    }
})

 

2 - 7. 이번에는 수정하는 작업입니다. id와 title,content를 모두 받아야하므로 req.body, req.params를 모두 이용합니다.

// post 수정
// http://localhost:7777/:id/update
router.post("/:id/update", async (req, res, next) => {

    // 632bf201c288b4079576e472
    let { id } = req.params;
    let { title, content } = req.body;

    try {
        await Post.findByIdAndUpdate(id, {
            title,
            content
        })
        res.send({ message: "update completed!" });

    } catch (e) {
        next(e);
    }
})

 

2 - 8. 마지막으로 정의한 모듈이 이용하려면 꼭 export를 해줘야 합니다.

module.exports = router;

 

[전체 코드]

 

// 라우팅하는 파일니까 라우터를 사용하기 위해 당연히 라우터를 가져오는 것.
const { Router } = require("express");
// 라우터함수를 라우터 변수에 넣는 것.
const router = Router();

const { Post } = require("./../models");


// post 리스트를 내보냄
// http://localhost:7777/posts/
router.get("/", async (req, res, next) => {
    // post 데이터를 전부 가져오겠다 === ({})
    const posts = await Post.find({});

    // posts는 json형태이므로 json형태로 응답을 해줌.
    res.json(posts);
})

// 내가 만들어 본거...
router.get("/:id", async (req, res, next) => {
    let { id } = req.params;
    // db.getCollection('wow').find({_id:ObjectId('5bee16ac39ab840015adbec3')})
    const posts = await Post.find({ _id: id });
    res.json(posts);
})

// post를 작성하는 부분
// http://localhost:7777/posts/
router.post("/", async (req, res, next) => {
    let { title, content } = req.body;
    // console.log(req.body);

    try {
        await Post.create({
            title,
            content
        });
        
        res.json({message: "저장이 완료~!!!"})
    } catch (e) {
        next(e);
    }
});

// posts 삭제
// http:localhost:7777/posts/:id/delete
router.get("/:id/delete", async (req, res, next) => {
    let { id } = req.params;

    try {
        await Post.findByIdAndDelete(id);
        res.json({ messsage: "삭제를 성공!!" });
    } catch(e) {
        next(e)
    }
})

// get http://localhost:7777/posts/:id/find
// 게시글 찾기 => 아까 내가 한거랑 원리는 같은데 쓰는 매서드가 조금 다름.
router.get("/:id/find", async (req, res, next) => {
    let { id } = req.params;

    try {
        let findPost = await Post.findById(id);
        res.json(findPost);
    } catch (e) {
        next(e);
    }
})


// post 수정
// http://localhost:7777/:id/update
router.post("/:id/update", async (req, res, next) => {

    // 632bf201c288b4079576e472
    let { id } = req.params;
    let { title, content } = req.body;

    try {
        await Post.findByIdAndUpdate(id, {
            title,
            content
        })
        res.send({ message: "update completed!" });

    } catch (e) {
        next(e);
    }
})

module.exports = router;

 

 


3. 서버단에서 각 CRUD 요청에 맞게 데이터를 제공해주는 작업을 마쳤습니다. 각 요청에서 데이터를 담고 퍼내는 역할을 하는 몽고디비를 정의해봅시다.

 

├── models
├── schemas
│   ├── board.js
│   
│   
└── index.js

몽고디비의 테이블 즉 스키마의 골격을 정의하는 부분은 schemas 아래에 boards.js에 정의됩니다.

 

3 - 1. 이렇게 정의하면 우리는 이제 이스키마에 데이터를 넣을 때

title, content, timestamps라는 것을 정의하는데 일종의 mySql에서 테이블의 행을 정의하는 것이라고 생각하면 됩니다.

// 몽구스에서 스키마를 가저오고,, - 스키마를 정의하기 위해
const { Schema } = require('mongoose');


// title같은건 내가 정의해서 스키마를 만든 이후
const PostSchema = new Schema({
    title: String,
    content: String,
}, {
    timestamps: true,

});

// export
module.exports = PostSchema;

 

3 - 2. 아까 post쪽 서버단 요청을 구현할 때 데이베이스를 ./../models 위치에서 가져왔습니다. 그렇게 가져오면 자동적으로 해당 위치에 index.js를 가리키게 됩니다. 

이 index.js에서는 일단 몽구스 모듈을 가저요고, 정의한 스키마 형태를 가져오고.

그걸 Post라는 이름으로 exports하는 코드입니다.

때문에 우리는 이전에

const { Post } = require("./../models");

형태로 가져와서 쓴 것입니다.

// 몽구스 모듈 가져옴
const mongoose = require('mongoose');

// 스키마를 가져옴
const PostSchema = require('./schemas/board');

// 스키마를 몽구스 모델로 변경함
// exports.Post <= 이걸 가져오는 것.
exports.Post = mongoose.model('Post', PostSchema);

 


후기

 

이제 서버단과 데이터베이스 단의 구현을 끝마쳤습니다.

이제 우리는 server에서 제공해주는 데이터를 받아서 이용하는 프론트 앤드단을

구현할 것 입니다.

728x90