본문 바로가기

Dev/Javascript

[Node.js] DB Daily Check 자동화 (1) 환경 설정

728x90

https://p-elideveloper.tistory.com/69

 

[Node.js] 게시판(1/4) CRUD 만들기, 게시글 작성/상세/수정/삭제

환경설정 vscode로 새 프로젝트를 만들어서 해당 디렉터리에 npm package를 만들어줍니다. npm init -y 필요한 라이브러리를 설치해줍니다. npm install express cors body-parser mysql2 Express Express는 Node.js 기반의

p-elideveloper.tistory.com

 

매일 하는 업무인 DB 점검 업무에 대해 화면으로 보면 좋겠다. 생각하여, 요즘 관심있는 nodejs를 이용해 개발을 해보기로한다. 먼저 위의 블로그를 참조해 환경 구성을 해주었다. 

 

Express 

 

Express는 Node.js 기반의 웹 응용 프레임워크로, 웹 응용 프로그램 및 RESTful API를 손쉽게 구축할 수 있게 해주는 도구입니다. 간결하면서도 강력한 기능을 제공하여 서버 사이드 로직을 쉽게 작성할 수 있도록 도와줍니다.

 

CORS(Cross-Origin Resource Sharing)

 

CORS는 웹 브라우저에서 실행 중인 JavaScript가 다른 출처의 리소스에 접근하는 것을 허용하는 메커니즘을 제공합니다. 서로 다른 도메인 간의 HTTP 요청이 보안 정책에 의해 차단되는 것을 우회할 수 있게 해주는 중요한 보안 기능 중 하나입니다. Express에서는 cors 미들웨어를 사용하여 CORS 문제를 처리합니다.

 

Body-Parser

 

Body-Parser는 Express에서 HTTP 요청의 본문을 쉽게 파싱 할 수 있도록 도와주는 미들웨어입니다. 클라이언트에서 서버로 전송되는 데이터를 해석하여 서버에서 사용할 수 있도록 만들어줍니다. JSON, URL-encoded 및 기타 형식의 데이터를 파싱할 수 있습니다.

 

oracledb

 

위 블로그와 달리 현재 내 운영DB는 Oracle 이므로 Oracle 모듈을 대신 설치 해주기로 한다.

요약

  • Express는 Node.js를 기반으로 한 웹 응용 프레임워크로, 빠르고 간편한 웹 애플리케이션 및 API를 만들 수 있도록 지원합니다.
  • CORS는 다른 출처의 리소스에 대한 웹 브라우저에서의 접근을 허용하는 메커니즘으로, Express에서는 cors 미들웨어를 통해 처리합니다.
  • Body-Parser는 Express에서 HTTP 요청의 본문을 쉽게 파싱 하여 서버에서 사용할 수 있도록 도와줍니다.
  • mysql2는 Node.js에서 MySQL 데이터베이스와의 상호 작용을 위한 드라이버로, 비동기 쿼리와 프라미스를 지원하여 효율적인 코드 작성을 가능케 합니다.

 

필요한 라이브러리 설치 

npm install express cors body-parser

 

PS E:\nodejs> npm install express cors body-parser

added 2 packages, and audited 68 packages in 6s

13 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
PS E:\nodejs>

 

 

오라클 모듈 설치

 npm install oracledb --save

 

PS E:\nodejs>  npm install oracledb --save

added 1 package, and audited 69 packages in 6s

13 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

 

 

Server.js 생성

// server.js

// 필요한 모듈을 가져옵니다.
const express = require('express');
const oracle = require('oracledb');
const cors = require('cors');
const bodyParser = require('body-parser');

// Express 애플리케이션을 생성합니다.
const app = express();

// 서버를 위한 포트를 설정합니다.
const port = 3000;

// 모든 라우트에 대해 CORS를 활성화하여 교차 출처 문제를 방지합니다.
app.use(cors());

// 서버를 특정 포트에서 실행합니다.
app.listen(port, () => {
    console.log(`게시판 앱이 포트 ${port}에서 실행 중입니다.`);
});

 

Database 연결 설정 

 

1. config 폴더를 생성 후 database 정보를 입력할 database.js 파일 생성 

// 오라클 DB 설정 파일 

module.exports = {  user			:process.env.NODE_ORACLEDB_USER || "suzi",		
                    password		:process.env.NODE_ORACLEDB_PASSWORD || "a123",		
                    connectString	:process.env.NODE_ORACLEDB_CONNECTIONSTRING || "localhost:1521/xe",		
                    externalAuth	:process.env.NODE_ORACLEDB_EXTERNALAUTH ? true : false
                 };

 

2. 외부 파일에서 데이터베이스 구성을 가져올 수 있게 server.js에 DB 정보 추가 

// server.js

// ... 코드 생략...

// 외부 파일에서 데이터베이스 구성을 가져옵니다.
const dbConfig = require('./config/database.js');

// 제공된 구성을 사용하여 ORACLE 연결 풀을 만듭니다.
const connection = oracle.createPool(dbConfig);

 

 

JSON 데이터 처리를 위한 JSON 파서 추가 

// server.js

// ... 코드 생략

// 들어오는 JSON 데이터를 처리하기 위한 JSON 파서를 설정합니다.
const jsonParser = bodyParser.json();

 

 

이제 html 파일 작성을 위한 public 폴더 생성 

public 폴더에 메인 페이지를 만들기 위해 index.html 파일을 생성해 준다. 

 

<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- 페이지의 메타 정보를 설정합니다. -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!-- 페이지의 스타일을 지정하는 CSS 코드입니다. -->
    <style>
        body {
            font-family: 'Arial', sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f8f9fa;
        }

        h1 {
            background-color: #343a40;
            color: #ffffff;
            padding: 20px;
            margin: 0;
        }

        nav ul {
            list-style: none;
            padding: 0;
            margin: 0;
            background-color: #343a40;
            overflow: hidden;
        }

        nav ul li {
            float: left;
            display: inline;
            padding: 10px;
        }

        nav ul li a {
            text-decoration: none;
            color: #ffffff;
            font-weight: bold;
            display: inline-block;
            padding: 10px 20px;
            background-color: #343a40;
            transition: background-color 0.3s ease;
        }

        nav ul li a:hover {
            background-color: #495057;
        }

        #articles-list {
            list-style: none;
            padding: 0;
            margin: 20px;
        }

        #articles-list li {
            background-color: #ffffff;
            border: 1px solid #ced4da;
            padding: 15px;
            margin-bottom: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }

        #articles-list li a {
            text-decoration: none;
            color: #343a40;
            font-weight: bold;
        }

        #articles-list li a:hover {
            color: #007bff;
        }
    </style>
</head>
<body>
    <!-- 페이지의 제목을 설정합니다. -->
    <title>게시글 목록</title>
    <!-- 페이지 상단에 표시되는 제목입니다. -->
    <h1>게시글 목록</h1>
    
    <!-- 네비게이션 링크 -->
    <nav>
        <ul>
            <!-- 게시글 작성 페이지로 이동하는 링크 -->
            <li><a href="create.html">게시글 작성</a></li>
        </ul>
    </nav>

    <!-- 게시글 목록을 표시하는 부분입니다. -->
    <ul id="articles-list"></ul>
    
    </body>
</html>

 

 

작성 후 server.js에서 메인페이지를 지정해 준다. 

// server.js

// 메인 HTML 파일을 제공하는 라우트입니다.
app.get('/', (req, res) => {
    res.sendFile(__dirname + '/public/index.html')});

 

게시글을 작성할 수 있게 public 디렉터리 안에 create.html 생성

<!-- create.html -->

<style>
    /* create.html에 해당하는 CSS 스타일 */

    body {
        font-family: Arial, sans-serif;
        margin: 0;
        padding: 0;
        background-color: #f4f4f4;
    }

    form {
        max-width: 600px;
        margin: 20px auto;
        padding: 20px;
        background-color: #fff;
        border: 1px solid #ddd;
    }

    label {
        display: block;
        margin-bottom: 5px;
        font-weight: bold;
    }

    input[type="text"],
    textarea {
        width: 100%;
        padding: 8px;
        margin-bottom: 10px;
        box-sizing: border-box;
    }

    button {
        background-color: #333;
        color: #fff;
        padding: 10px;
        border: none;
        cursor: pointer;
        border-radius: 5px;
        margin-right: 10px; /* 추가된 부분: 뒤로가기 버튼과의 간격을 조절합니다. */
    }

    button:hover {
        background-color: #555;
    }

</style>

<!-- 페이지 상단에 표시되는 제목입니다. -->
<h1>Create Article</h1>

<!-- 게시글 작성 폼입니다. -->
<form id="create-form">
    <label for="title">제목:</label>
    <input type="text" id="title" name="title" required><br>

    <label for="writer">작성자:</label>
    <input type="text" id="writer" name="writer" required><br>

    <label for="content">내용:</label>
    <textarea id="content" name="content" required></textarea><br>

    <!-- 게시글 작성 버튼 -->
    <button type="submit">게시글 작성</button>

    <!-- 뒤로가기 버튼 -->
    <button onclick="goBack()">뒤로 가기</button>
</form>

<!-- 뒤로가기 버튼을 처리하는 스크립트입니다. -->
<script>
    // 뒤로가기 버튼을 눌렀을 때 이전 페이지로 이동하는 함수
    function goBack() {
        window.history.back();
    }
</script>

 

 

server.js에 게시글 등록 기능을 만든다.

// server.js

// ...코드 생략...

// 새로운 게시글을 작성하는 라우트입니다.
app.post('/article', jsonParser, (req, res) => {
    // 'board' 테이블에 새 레코드를 삽입하기 위한 SQL 쿼리입니다.
    const sql = 'INSERT INTO board (title, writer, content) VALUES (?,?,?)';
    const title = req.body.title;
    const writer = req.body.writer;
    const content = req.body.content;
    const params = [title, writer, content];
    // 주어진 매개변수로 쿼리를 실행합니다.
    connection.query(sql, params, (err, rows, fields) => {
        if (err) throw err;
        console.log(rows);
        // 쿼리 결과를 응답으로 전송합니다 (클라이언트에게 무언가를 전송하려고 가정합니다).
        res.send(rows);
    });
});

 

기능을 다 만들었다면 이제 create.html에 가서 게시글을 작성할 이벤트 처리 스크립트를 생성해준다.

public 디렉터리 안에 createArticle.js 파일 생성 

 

// DOMContentLoaded 이벤트가 발생하면 실행되는 콜백 함수입니다.
document.addEventListener('DOMContentLoaded', function () {
    // 'create-form' 아이디를 가진 폼 엘리먼트를 가져옵니다.
    const createForm = document.getElementById('create-form');

    // 폼에 submit 이벤트 리스너를 추가합니다.
    createForm.addEventListener('submit', function (event) {
        // 기본 폼 제출 동작을 막습니다.
        event.preventDefault();

        // FormData를 사용하여 폼 데이터를 가져옵니다.
        const formData = new FormData(this);

        // 서버에 POST 요청을 보내기 위한 fetch 함수를 사용합니다.
        fetch('http://localhost:3000/article', {
            method: 'POST', // HTTP 메서드는 POST입니다.
            headers: {
                'Content-Type': 'application/json', // 요청 본문의 형식은 JSON입니다.
            },
            // FormData를 JSON 형식으로 변환하여 요청 본문에 추가합니다.
            body: JSON.stringify(Object.fromEntries(formData)),
        })
        // 서버 응답을 JSON 형식으로 파싱합니다.
        .then(response => response.json())
        .then(article => {
            // 서버에서 반환한 게시글 정보를 콘솔에 출력합니다.
            console.log('게시글이 생성되었습니다:', article);

            // 게시글이 생성된 후에 index.html로 리디렉션합니다.
            window.location.href = 'http://localhost:3000/';
        })
        .catch(error => {
            // 오류가 발생하면 콘솔에 오류 메시지를 출력합니다.
            console.error('게시글 생성 중 오류 발생:', error);
        });
    });
});

 

이제 create.html 에 가서 createArticle.js 를 로드해 준다.

<!-- create.html -->

<!-- ... css 코드 생략... -->

<!-- 페이지 상단에 표시되는 제목입니다. -->
<h1>Create Article</h1>

<!-- 게시글 작성 폼입니다. -->
<form id="create-form">
    <label for="title">제목:</label>
    <input type="text" id="title" name="title" required><br>

    <label for="writer">작성자:</label>
    <input type="text" id="writer" name="writer" required><br>

    <label for="content">내용:</label>
    <textarea id="content" name="content" required></textarea><br>

    <!-- 게시글 작성 버튼 -->
    <button type="submit">게시글 작성</button>

    <!-- 뒤로가기 버튼 -->
    <button onclick="goBack()">뒤로 가기</button>
</form>

<!-- 게시글 작성 스크립트 파일을 로드합니다. -->
<script src="createArticle.js"></script>

<!-- 뒤로가기 버튼을 처리하는 스크립트입니다. -->
<script>
    // 뒤로가기 버튼을 눌렀을 때 이전 페이지로 이동하는 함수
    function goBack() {
        window.history.back();
    }
</script>

 

server.js에서 createArticle.js 참조할 수 있게 public 디렉터리를 연동해 줍니다.

// server.js

//...코드 생략...

// 'public' 디렉토리에서 정적 파일을 제공합니다.
app.use(express.static('public', { "Content-Type": "application/javascript" }));

 

이제 게시글 목록을 볼 수 있게 server.js 에 게시글 목록 쿼리를 추가해 줍니다.

// server.js

//...코드 생략...

// 게시판에서 게시판 목록을 가져오는 라우트입니다.
app.get('/articles', (req, res) => {
    // 'board' 테이블에서 모든 레코드를 선택하기 위한 데이터베이스 쿼리를 실행합니다.
    connection.query('SELECT * FROM board order by idx desc', (err, rows) => {
        if (err) throw err;
        console.log(rows);
        // 검색된 레코드를 응답으로 전송합니다.
        res.send(rows);
    });
});

 

public 디렉터리 안에 index.html 파일을 수정합니다.

스크립트 코드를 추가해 줍니다.

<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- 페이지의 메타 정보를 설정합니다. -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

 <!-- css 코드생략...>
 
</head>
<body>
    <!-- 페이지의 제목을 설정합니다. -->
    <title>게시글 목록</title>
    <!-- 페이지 상단에 표시되는 제목입니다. -->
    <h1>게시글 목록</h1>
    
    <!-- 네비게이션 링크 -->
    <nav>
        <ul>
            <!-- 게시글 작성 페이지로 이동하는 링크 -->
            <li><a href="create.html">게시글 작성</a></li>
        </ul>
    </nav>

    <!-- 게시글 목록을 표시하는 부분입니다. -->
    <ul id="articles-list"></ul>

    <!-- JavaScript 코드입니다. -->
    <script>
        // 게시글 목록을 가져오는 함수
        fetch('http://localhost:3000/articles')
            .then(response => response.json())
            .then(articles => {
                const articlesList = document.getElementById('articles-list');
                articles.forEach(article => {
                    const li = document.createElement('li');
                    li.innerHTML = `
                        <strong>Title:</strong> ${article.title}<br>
                        <strong>Writer:</strong> ${article.writer}<br>
                        <strong>Content:</strong> ${article.content}<br>
                        <strong>Views:</strong> ${article.view_cnt}<br>
                        <strong>Insert Time:</strong> ${article.insert_time}<br>
                        <strong>Update Time:</strong> ${article.update_time ? article.update_time : 'N/A'}<br>
                        <a href="article-details.html?id=${article.idx}">상세 정보 보기</a><br>
                        <hr>
                    `;
                    articlesList.appendChild(li);
                });
            });
    </script>
</body>
</html>

 

이제 게시글 상세 보기 기능을 만들어보겠습니다.

server.js 에 코드를 추가해 줍니다.

// server.js

// ...코드 생략...

// 특정 ID에 대한 게시글 세부 정보를 가져오는 라우트입니다.
app.get('/articles/:id', (req, res, next) => {
    const articleId = parseInt(req.params.id);

    // 게시글 조회 시 view_cnt 증가를 위한 UPDATE 쿼리
    const updateViewCountQuery = `UPDATE board SET view_cnt = view_cnt + 1 WHERE idx = ?`;
    connection.query(updateViewCountQuery, [articleId], (updateErr, updateResult) => {
        if (updateErr) {
            console.error('게시글 조회 시 view_cnt 증가 중 오류 발생:', updateErr);
            // 오류가 발생하면 계속 진행하지 않고 오류 응답을 전송합니다.
            return res.status(500).send('서버 오류');
        }

        // 'board' 테이블에서 모든 레코드를 선택하기 위한 데이터베이스 쿼리를 실행합니다.
        const selectQuery = `SELECT * FROM board WHERE idx = ?`;
        connection.query(selectQuery, [articleId], (err, rows) => {
            if (err) {
                console.error('게시글 조회 중 오류 발생:', err);
                // 오류가 발생하면 계속 진행하지 않고 오류 응답을 전송합니다.
                return res.status(500).send('서버 오류');
            }

            // 주어진 ID를 기반으로 검색된 레코드에서 게시글을 찾습니다.
            const article = rows[0];
            if (!article) {
                // 게시글을 찾지 못하면 404 상태와 메시지를 전송합니다.
                return res.status(404).send('ID를 찾을 수 없습니다.');
            }

            // 찾은 게시글을 응답으로 전송합니다.
            res.send(article);
        });
    });
});

 

이제 상세 보기 페이지를 만들어줍니다.

public 디렉터리 안에 article-details.html 파일을 만들어줍니다.

<!-- article-details.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- 페이지의 메타 정보를 설정합니다. -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <!-- 페이지의 제목을 설정합니다. -->
    <title>게시글 상세 정보</title>

    <!-- 페이지의 스타일을 지정하는 CSS 코드입니다. -->
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f4f4f4;
        }

        h1 {
            background-color: #333;
            color: #fff;
            padding: 10px;
            margin: 0;
        }

        h1 a {
            text-decoration: none;
            color: #fff;
            transition: color 0.3s ease;
        }

        h1 a:hover {
            color: blue;
        }

        #article-details {
            max-width: 600px;
            margin: 20px auto;
            padding: 20px;
            background-color: #fff;
            border: 1px solid #ddd;
        }

        #article-details strong {
            font-weight: bold;
        }

        #article-details hr {
            margin: 10px 0;
            border: 0;
            border-top: 1px solid #ddd;
        }

        #article-button {
            max-width: 600px;
            margin: 20px auto;
            padding: 20px;
            background-color: #f4f4f4;
        }

        #update-button,
        #delete-button,
        #goBack {
            display: inline-block;
            padding: 10px;
            margin: 10px 5px 20px; /* 여기 수정: 버튼 아래 마진 추가 */
            background-color: #333;
            color: #fff;
            text-decoration: none;
            border: none;
            cursor: pointer;
            border-radius: 5px;
        }

        #update-button:hover,
        #delete-button:hover {
            background-color: #555;
        }
    </style>
</head>
<body>

    <!-- 페이지 상단에 위치하는 제목 부분입니다. -->
    <h1><a href="http://localhost:3000/">게시글 상세 정보</a></h1>

    <!-- 게시글의 상세 정보를 표시하는 부분입니다. -->
    <div id="article-details"></div>

    <!-- 업데이트 및 삭제 버튼이 있는 부분입니다. -->
    <div id="article-button">  
        <!-- 업데이트 버튼 -->
        <button id="update-button">게시글 수정</button>
        
        <!-- 삭제 버튼 -->
        <button id="delete-button">게시글 삭제</button>

        <!-- 뒤로가기 버튼 -->
        <button id="goBack" onclick="goBack()">뒤로 가기</button>
    </div>
    <script>
                // 뒤로가기 버튼을 눌렀을 때 이전 페이지로 이동하는 함수
            function goBack() {
                window.history.back();
            }
    </script>
</body>
</html>

 

상세 보기 목록을 불러올 스크립트 코드를 추가해 줍니다.

<!-- article-details.html -->

<script>
        // Get Article ID from URL
        const urlParams = new URLSearchParams(window.location.search);
        const articleId = urlParams.get('id');

        // Fetch Article Details
        fetch(`http://localhost:3000/articles/${articleId}`)
            .then(response => response.json())
            .then(article => {
                const articleDetails = document.getElementById('article-details');
                if (article) {
                    // 게시글이 존재하는 경우 상세 정보를 표시합니다.
                    articleDetails.innerHTML = `
                        <strong>Title:</strong> ${article.title}<br>
                        <strong>Writer:</strong> ${article.writer}<br>
                        <strong>Content:</strong> ${article.content}<br>
                        <strong>Views:</strong> ${article.view_cnt}<br>
                        <strong>Insert Time:</strong> ${article.insert_time}<br>
                        <strong>Update Time:</strong> ${article.update_time ? article.update_time : 'N/A'}<br>
                        <strong>Delete Time:</strong> ${article.delete_time ? article.delete_time : 'N/A'}<br>
                        <hr>
                    `;
                } else {
                    // 게시글이 존재하지 않는 경우 메시지를 표시합니다.
                    articleDetails.innerHTML = '<p>게시글을 찾을 수 없습니다.</p>';
                }
            });

        // Add event listener to the Update button
        const updateButton = document.getElementById('update-button');
        updateButton.addEventListener('click', function () {
            // Update.html 페이지로 게시글 ID와 함께 리디렉션합니다.
            window.location.href = `update.html?id=${articleId}`;
        });
 <script>

 

update 기능을 만들어봅시다.

server.js에서 코드를 추가합니다.

// server.js

// 기존 게시글을 ID를 기반으로 업데이트하는 라우트입니다.
app.put('/article/:id', jsonParser, (req, res, next) => {
    // 현재 날짜 및 시간을 얻습니다.
    const currentTime = new Date().toISOString().slice(0, 19).replace("T", " ");

    // 주어진 ID를 기반으로 'board' 테이블에서 해당 게시글을 찾는 데이터베이스 쿼리를 실행합니다.
    connection.query('SELECT * FROM board WHERE idx = ?', [req.params.id], (err, rows, fields) => {
        if (err) throw err;

        // 주어진 ID를 기반으로 검색된 레코드에서 게시글을 찾습니다.
        const article = rows[0];

        if (!article) {
            // 게시글을 찾지 못하면 404 상태와 메시지를 전송합니다.
            return res.status(404).send('ID를 찾을 수 없습니다.');
        }

        // 'board' 테이블에서 게시글을 업데이트하는 SQL 쿼리입니다.
        const sql = 'UPDATE board SET title = ?, writer = ?, content = ?, update_time = ? WHERE idx = ?';
        const title = req.body.title;
        const writer = req.body.writer;
        const content = req.body.content;

        // 주어진 매개변수로 쿼리를 실행합니다.
        connection.query(sql, [title, writer, content, currentTime, req.params.id], (err, rows, fields) => {
            if (err) throw err;

            // 쿼리 결과를 응답으로 전송합니다 (클라이언트에게 무언가를 전송하려고 가정합니다).
            res.send(rows);
        });
    });
});

 

public 디렉터리 안에 update.html 파일을 만들어 줍니다.

<!-- update.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- 페이지의 메타 정보를 설정합니다. -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

</head>
<style>
    /* 페이지의 스타일을 지정하는 CSS 코드입니다. */

    body {
        font-family: Arial, sans-serif;
        margin: 0;
        padding: 0;
        background-color: #f4f4f4;
    }

    form {
        max-width: 600px;
        margin: 20px auto;
        padding: 20px;
        background-color: #fff;
        border: 1px solid #ddd;
    }

    label {
        display: block;
        margin-bottom: 5px;
        font-weight: bold;
    }

    input[type="text"],
    textarea {
        width: 100%;
        padding: 8px;
        margin-bottom: 10px;
        box-sizing: border-box;
    }

    button {
        background-color: #333;
        color: #fff;
        padding: 10px;
        border: none;
        cursor: pointer;
        border-radius: 5px;
        margin-right: 10px;
    }

    button:hover {
        background-color: #555;
    }

    h1 a {
        text-decoration: none;
        color: #333;
    }

    h1 a:hover {
        color: #555;
    }
</style>
<body>
    <!-- 페이지의 제목을 설정합니다. -->
    <title>게시글 수정</title>
    <!-- 페이지 상단에 표시되는 제목입니다. -->
    <h1>게시글 수정</h1>

    <!-- 게시글 수정 폼입니다. -->
    <form id="update-form">
        <!-- 게시글 ID를 감추어서 전송합니다. -->
        <input hidden id="id" name="id">
        
        <!-- 제목 입력란 -->
        <label for="title">제목:</label>
        <input type="text" id="title" name="title" required><br>
        
        <!-- 작성자 입력란 -->
        <label for="writer">작성자:</label>
        <input type="text" id="writer" name="writer" required><br>
        
        <!-- 내용 입력란 -->
        <label for="content">내용:</label>
        <textarea id="content" name="content" required></textarea><br>

        <!-- 게시글 수정 버튼 -->
        <button type="submit">게시글 수정</button>

        <!-- 뒤로가기 버튼 -->
        <button onclick="goBack()">뒤로 가기</button>
    </form>
    <script>
            // 뒤로가기 버튼을 눌렀을 때 이전 페이지로 이동하는 함수
        function goBack() {
            window.history.back();
        }
    </script>

    <!-- 게시글 수정 스크립트 파일을 로드합니다. -->
    <script src="updateArticle.js"></script>
</body>
</html>

 

업데이트 후 게시글 정보를 가져와서 볼 수 있게 스크립트 문을 추가해 줍니다.

<!-- update.html -->

<script>
        // URL에서 게시글 ID를 가져옵니다.
        const urlParams = new URLSearchParams(window.location.search);
        const articleId = urlParams.get('id');

        // 게시글 상세 정보를 가져와서 폼에 미리 채웁니다.
        fetch(`http://localhost:3000/articles/${articleId}`)
            .then(response => response.json())
            .then(article => {
                // 폼 필드에 기존 데이터로 채웁니다.
                document.getElementById('id').value = article.idx;
                document.getElementById('title').value = article.title;
                document.getElementById('writer').value = article.writer;
                document.getElementById('content').value = article.content;
            });
<script>

 

이제 업데이트 이벤트를 만들어 줍니다.

public 디렉터리 안에 update.Article.js 파일을 만들어줍니다.

// DOMContentLoaded 이벤트가 발생하면 실행되는 콜백 함수입니다.
document.addEventListener('DOMContentLoaded', function () {
    // 'update-form' 아이디를 가진 폼 엘리먼트를 가져옵니다.
    const updateForm = document.getElementById('update-form');

    // 폼에 submit 이벤트 리스너를 추가합니다.
    updateForm.addEventListener('submit', function (event) {
        // 기본 폼 제출 동작을 막습니다.
        event.preventDefault();

        // FormData를 사용하여 폼 데이터를 가져옵니다.
        const formData = new FormData(this);

        // 업데이트할 게시글의 ID를 폼 데이터에서 가져옵니다.
        const articleId = formData.get('id');

        // 서버에 PUT 요청을 보내어 게시글을 업데이트합니다.
        fetch(`http://localhost:3000/article/${articleId}`, {
            method: 'PUT', // HTTP 메서드는 PUT입니다.
            headers: {
                'Content-Type': 'application/json', // 요청 본문의 형식은 JSON입니다.
            },
            // FormData를 JSON 형식으로 변환하여 요청 본문에 추가합니다.
            body: JSON.stringify(Object.fromEntries(formData)),
        })
        // 서버 응답을 JSON 형식으로 파싱합니다.
        .then(response => response.json())
        .then(article => {
            // 서버에서 반환한 업데이트된  정보를 콘솔에 출력합니다.
            console.log('게시글이 업데이트되었습니다:', article);
            alert("게시글이 업데이트 되었습니다.");

            // 게시글 업데이트된 후에 index.html로 리디렉션합니다.
            window.location.href = 'http://localhost:3000/';
        })
        .catch(error => {
            // 오류가 발생하면 콘솔에 오류 메시지를 출력합니다.
            console.error('게시글 업데이트 중 오류 발생:', error);
        });
    });
});

 

작성 후 update.html에 스크립트 파일을 로드해 줍니다.

<!-- update.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- 페이지의 메타 정보를 설정합니다. -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

</head>

<!-- css 코드생략...-->

<body>
    <!-- 페이지의 제목을 설정합니다. -->
    <title>게시글 수정</title>
    <!-- 페이지 상단에 표시되는 제목입니다. -->
    <h1>게시글 수정</h1>

    <!-- 게시글 수정 폼입니다. -->
    <form id="update-form">
        <!-- 게시글 ID를 감추어서 전송합니다. -->
        <input hidden id="id" name="id">
        
        <!-- 제목 입력란 -->
        <label for="title">제목:</label>
        <input type="text" id="title" name="title" required><br>
        
        <!-- 작성자 입력란 -->
        <label for="writer">작성자:</label>
        <input type="text" id="writer" name="writer" required><br>
        
        <!-- 내용 입력란 -->
        <label for="content">내용:</label>
        <textarea id="content" name="content" required></textarea><br>

        <!-- 게시글 수정 버튼 -->
        <button type="submit">게시글 수정</button>

        <!-- 뒤로가기 버튼 -->
        <button onclick="goBack()">뒤로 가기</button>
    </form>

    <!-- JavaScript 코드입니다. -->
    <script>
        // URL에서 게시글 ID를 가져옵니다.
        const urlParams = new URLSearchParams(window.location.search);
        const articleId = urlParams.get('id');

        // 게시글 상세 정보를 가져와서 폼에 미리 채웁니다.
        fetch(`http://localhost:3000/articles/${articleId}`)
            .then(response => response.json())
            .then(article => {
                // 폼 필드에 기존 데이터로 채웁니다.
                document.getElementById('id').value = article.idx;
                document.getElementById('title').value = article.title;
                document.getElementById('writer').value = article.writer;
                document.getElementById('content').value = article.content;
            });

        // 뒤로가기 버튼을 눌렀을 때 이전 페이지로 이동하는 함수
        function goBack() {
            window.history.back();
        }
    </script>

    <!-- 게시글 수정 스크립트 파일을 로드합니다. -->
    <script src="updateArticle.js"></script>
</body>
</html>

 

이제 게시글 삭제하기 기능을 만들어봅시다.

server.js 에 가서 코드를 추가해 줍니다.

// server.js

// ID를 기반으로 게시글을 삭제하는 라우트입니다.
app.delete('/article/:id', (req, res, next) => {
    // 'board' 테이블에서 모든 레코드를 선택하기 위한 데이터베이스 쿼리를 실행합니다.
    connection.query('SELECT * FROM board', (err, rows, fields) => {
        if (err) throw err;
        // 주어진 ID를 기반으로 검색된 레코드에서 게시글을 찾습니다.
        const article = rows.find(art => art.idx === parseInt(req.params.id));
        if (!article) {
            // 게시글을 찾지 못하면 404 상태와 메시지를 전송합니다.
            return res.status(404).send('ID를 찾을 수 없습니다.');
        }
        // 'board' 테이블에서 게시글을 삭제하는 SQL 쿼리입니다.
        connection.query('DELETE FROM board WHERE idx = ?', [req.params.id], (err, rows, fields) => {
            if (err) throw err;
            // JSON 응답을 통해 삭제를 나타냅니다.
            res.json('삭제됨: ' + req.params.id);
        });
    });
});

 

게시글 삭제 이벤트 기능을 만들어줄 파일을 만들기 위해 article-details.html에 스크립트 코드를 추가해 줍니다.

// article-details.html

// Add event listener to the Delete button
        const deleteButton = document.getElementById('delete-button');
        deleteButton.addEventListener('click', function () {
            // 삭제 전 확인 메시지를 표시합니다.
            const confirmDelete = confirm('이 게시글을 삭제하시겠습니까?');
            if (confirmDelete) {
                // 게시글 삭제를 요청합니다.
                fetch(`http://localhost:3000/article/${articleId}`, {
                    method: 'DELETE',
                })
                .then(response => response.json())
                .then(deletedArticle => {
                    console.log('게시글이 삭제되었습니다:', deletedArticle);

                    // 삭제 후 index.html 페이지로 리디렉션합니다.
                    window.location.href = 'http://localhost:3000/';
                })
                .catch(error => {
                    console.error('게시글 삭제 중 오류 발생:', error);
                });
            }
        });

 

728x90
반응형