본문 바로가기

카테고리 없음

간단한 게시판 만들기 - 5

기본적인 서버 환경 세팅을 마쳤으니 이제 db를 연결해 볼 것이다.

이전에 이미 한번 정리했지만 작업 도중에도 계속 혼란스러웠기에 대략적으로 서버 구분을 하자면,

지금 만드는 server 폴더의 index파일은 8000번 포트에서 동작하며 db와의 연결을 통해 데이터를 읽거나 삽입하는 등의 역할을 한다. 또한 클라이언트(브라우저)로부터 간접적으로 데이터를 요청받고 결과를 전달해주는 중간 매개체와도 같은 역할을 한다.

그리고 이전에 만든 client 폴더의 파일들은 3000번 포트에서 동작하며 클라이언트로부터 직접적으로 요청을 받고 이전에 정리한 웹서버의 역할대로 정적인 컨텐츠를 제공한다. 또한 db와 관련된 데이터는 server/index.js로 전달하여 처리한다.

(나름대로 정리하였으나 틀린 부분이 있을 수도 있다. client 폴더의 파일들이 웹서버의 역할을 하는 것은 아니라던가..)

 

Mysql DB 설정

(cmd에서 전부 작업하였다.)

 

<database 생성>

CRAETE DATABASES post;

 

<table 생성>

USE post;
CREATE TABLE postdata(
	id INT NOT NULL AUTO_INCREMENT,
    title VARCHAR(100) NOT NULL,
    body TEXT NOT NULL,
    writer VARCHAR(30) NOT NULL,
    date VARCHAR(30) NOT NULL,
    PRIMARY KEY(id)
);

 

DESC postdata;

 

 

Mysql 연동

<index.js>

const express = require('express');
const app = express();
const mysql = require('mysql');
const PORT = 8000;

const db = mysql.connect({
    host: "localhost",
    user: "root",
    password: "1111",
    database: "post"
});


//create
app.post("/", (req, res)=>{
    const query = "INSERT INTO postdata (title, body, writer, date) VALUES (?, ?, ?, curdate());";
    const params = ['1번째 게시물', '1번째 게시물입니다', '홍길동'];
    db.query(query, params, (err, result)=>{
        res.send('CREATE');
    });
});

app.listen(PORT, ()=>{
    console.log(`running on port ${PORT}`);
});

 게시물 생성까지 임의로 작성한 것이다.

 

 

CRUD 기능

db와의 연동을 확인하였으니 기존의 CRUD기능을 전부 db와 연결되도록 수정하여야 하는데, 그전에 클라이언트의 데이터를 서버로 전송해야한다.

이를 위해서 axios 모듈을 사용한다.

 

axios에 대한 것도 따로 정리하였다.

https://memo-code.tistory.com/26

 

[Node] Axios

Axios는 클라이언트 사이드와 서버 사이드의 통신을 위한 HTTP 비동기 통신 라이브러리이다. npm i axios 를 통해 설치할 수 있으며 import axios from 'axios'; import 문을 통해 세팅할 수 있다. 주로 사용하는

memo-code.tistory.com

 

클라이언트 폴더에서 axios모듈을 설치한다.

npm i axios

 

<app.js>

function CreateSub(list) {
  Axios.post('http://localhost:8000/post/create', {
    title: list.title, body: list.body, writer: list.writer
  })
}

설정된 url로 내용을 전달하는 함수를 작성해주었다.

else if(mode === 'CREATE'){
    content = <Create onCreate={(title, body)=>{
      const list = { title: title, body: body, writer: member};
      CreateSub(list); //변경사항
      setMode('POST');
      let now;
      for(let i=0; i<plist.length; i++){
        if(title === plist[i].title){
          now = plist[i].id;
        }
      }
      setPostid(now);
    }}></Create>

기존에는 직접적으로 plist라는 객체에 넣었지만 이번에는 그러지않고 axios함수를 이용해 db에 저장될 수 있도록 전달하였다.

 

<index.js>

app.post("/post/create", (req, res)=>{
    const query = "INSERT INTO postdata (title, body, writer, date) VALUES (?, ?, ?, curdate());";
    const params = [req.body.title, req.body.body, req.body.writer];
    db.query(query, params, (err, result)=>{
        res.send('created');
    });
});

같은 url로부터 내용을 받아와야하기 때문에 다음과 같이 작성하였다.

const express = require('express');
const app = express();
const mysql = require('mysql');
const bodyParser = require('body-parser');
const { urlencoded } = require('body-parser');
const cors = require('cors');
const PORT = process.env.port || 8000;

const db = mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "1111",
    database: "post"
});

app.use(cors());
app.use(express.json());
app.use(bodyParser.urlencoded({ extended: true }));

//create
app.post("/post/create", (req, res)=>{
    const query = "INSERT INTO postdata (title, body, writer, date) VALUES (?, ?, ?, curdate());";
    const params = [req.body.title, req.body.body, req.body.writer];
    db.query(query, params, (err, result)=>{
        res.send('created');
    });
});

app.listen(PORT, ()=>{
    console.log(`running on port ${PORT}`);
});

이때 cors는 클라이언트와 서버 사이드의 포트가 서로 다르기 때문에 사용하였다.

 

이로써 생성하고자 하는 내용이 db에 저장될 수 있도록 하는데에 성공하였다.

이전에는 미리 만들어놓은 내용을 app.js 파일내에 저장해두어 게시물로 출력하였었지만, 이제는 '미리 만들어놓은 내용 = db안의 내용'이 되었다.

즉 plist안의 내용을 전부 날리고 필요할때마다 db로부터 plist의 데이터로 저장해 이용할 수 있도록 하면 된다. (=read)

 

일단 db에서 내용을 꺼내 보내주도록 한다.

 

<index.js>

app.get("/post/postget", (req, res)=>{
    const query = "SELECT * FROM postdata;";
    db.query(query, (err, result)=>{
        res.send(result);
    })
})

쿼리문을 통해 설정된 url로 데이터를 보내줄 것이다.

 

그러면 이제 전송된 db의 데이터를 저장해야하는데, 웹이 처음 시작되었을때 뿐만 아니라 새로운 글이 등록되었을 때나, 수정되었을 때 등 데이터의 변화가 발생했을 때도 새롭게 db의 데이터를 읽어와 저장해주어야한다.

이러한 수행을 편하게 해주기 위해 react의 useEffect 훅을 사용하도록 한다.

https://memo-code.tistory.com/27

 

[React] useEffect

useEffect Hook useEffect는 react에서 제공하는 훅으로, react 컴포넌트가 렌더링 될 때마다 특정 작업을 실행할 수 있도록 하는 훅이다. 다음과 같이 사용한다. import react, {useEffect} from "react"; ... useEffect(ef

memo-code.tistory.com

 

<app.js>

  useEffect(()=>{
    Axios.get('http://localhost:8000/post/postget').then((response)=>{
    setPlist(response.data);
  })
  },[plist])

db에서 보내준 데이터가 있는 url로부터 데이터를 가져와 plist에 저장하는 것을 effect로 설정하였다.

그리고 plist의 값, 즉, db의 데이터의 변화가 생기면 그때마다 useEffect를 통해 plist의 값을 재설정하도록 하였다.

 

여기까지 하면 db에 저장되어 있던 게시물이 보인다.

 

 

마찬가지로 글쓰기를 통해 게시물을 새로 만들어 db에 저장하여도

즉시 반영된다.

 

이제 기존의 게시판 기능 중 남은건 게시글 수정과 삭제이다.

 

수정은 게시글 생성 때와 특별히 다를거 없이 sql문만 바꾸어주면 된다.

 

<index.js>

app.post("/post/update", (req, res)=>{
    const id = req.body.id;
    const query = "UPDATE postdata SET title = ?, body = ?, writer = ?, date = ? WHERE id = "+ id;
    const params = [req.body.title, req.body.body, req.body.writer, req.body.date];
    db.query(query, params, (err, result)=>{
        res.send('updated');
    })
})

 

<app.js>

function UpdateSub(ulist) {
  Axios.post('http://localhost:8000/post/update', {
    title: ulist.title, body: ulist.body, writer: ulist.writer, date: ulist.date, id: ulist.id
  })
}

 

else if(mode === 'UPDATE'){
    let title, date, body = null;
    for(let i=0; i<plist.length; i++){
      if(plist[i].id === postid){
        title = plist[i].title;
        date = plist[i].date;
        body = plist[i].body;
      }
    }
    content = <Update title={title} body={body} 
                onUpdate={(title, body)=>{
                  const ulist = {title: title, body: body, writer: member, date: date, id: postid};
                  UpdateSub(ulist);		//변경사항
                  setMode('POST');
                  setPostid(postid);
                }}></Update>
  }

 

 

삭제는 따로 컴포넌트를 만들지 않고 바로 진행할 수 있도록 하였다.

 

<index.js>

app.post("/post/delete", (req, res)=>{
    const id = req.body.id;
    const query = "DELETE FROM postdata WHERE id = " + id;
    db.query(query, id, (err, result)=>{
        res.send('deleted');
    })
})

 

<app.js>

function Postin(props){
	...
    <a class={udelete} href="/post" onClick={event=>{
            event.preventDefault();
            Axios.post('http://localhost:8000/post/delete', {
              id: props.postid
            })
            props.setMode('POST');
            props.setPostid(null);
     }}>삭제</a>
     ...
}