https://p-elideveloper.tistory.com/69
매일 하는 업무인 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);
});
}
});
'Dev > Javascript' 카테고리의 다른 글
[git] 커밋하고 푸시 (1) | 2024.11.23 |
---|---|
[git] vscode commit push 무한 로딩 (0) | 2024.11.21 |
[nodejs] vscode git 연동 (0) | 2024.11.21 |
[nodejs] npm : 이 시스템에서 스크립트를 실행할 수 없으므로 C:\Program Files\nodejs\npm.ps1 파일을 로드할 수 없습니다. (1) | 2024.11.20 |
[Node.js] Node.js 기본 개발 환경 세팅 (1) | 2024.11.19 |