일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- BFS
- KAKAO
- DFS
- 그리디
- CSS
- 자바스크립트
- 너비우선탐색
- 부트캠프
- cpu
- 코테
- 코딩테스트
- 프론트엔드개발자
- github
- git
- 야놀자
- 컴퓨터공학
- 컴퓨터과학
- 패스트캠퍼스
- CS
- 백준
- nodejs
- computerscience
- LinkSnap
- 호이스팅
- 국비지원취업
- 알고리즘
- 국비지원
- Javascript
- html/css/js
- js
- Today
- Total
My Boundary As Much As I Experienced
Express, ejs탬플릿과 MongoDB으로 게시판 CRUD 구현 본문
express로 CRUD 구현하기
시용하는 미들웨어:
const express = require("express"); // Express 웹 애플리케이션 프레임워크
const app = express(); // Express 애플리케이션 인스턴스 생성
const methodOverride = require("method-override"); // HTTP 메서드 오버라이드를 위한 미들웨어
const { MongoClient, ObjectId } = require("mongodb"); // MongoDB와 상호작용하기 위한 MongoDB 드라이버
// 정적 파일들을 제공하기 위해 public 폴더를 사용하도록 설정.
app.use(express.static(__dirname + "/public"));
// EJS를 템플릿 엔진으로 설정.
app.set("view engine", "ejs");
// JSON 형식의 본문을 파싱하기 위한 미들웨어 설정.
app.use(express.json());
// Form 형식으로 제출된, URL 인코딩된 본문을 JSON으로 파싱하기 위한 미들웨어 설정.
// 요샌 다 AJAX 요청을 하지만.. 만약을 위해서라도 해두는게 좋다.
app.use(express.urlencoded({ extended: true }));
// HTML 폼에서 PUT, DELETE 같은 HTTP 메서드를 사용할 수 있게 해주는 미들웨어 설정
app.use(methodOverride("_method"));
시용하는 DB(MongoDB):
연결 실패 시 fallback으로 포트를 열어주긴 하지만 db조회가 필요한 api들은 사용할 수 없다.
let db;
const url =
"mongodb+srv://...";
const client = new MongoClient(url);
async function run() {
await client
.connect()
.then((client) => {
console.log("DB 연결 성공");
db = client.db("forum");
// 내 컴퓨터에서 포트 하나 오픈하는 코드..
app.listen(8080, () => {
console.log("http://localhost:8080에서 서버 실행 중");
});
})
.catch((err) => {
console.log(err);
console.log("error");
app.listen(8080, () => {
console.log("http://localhost:8080에서 서버 실행 중 (fallback)");
});
});
}
run();
1. 게시판 조회
아주 기본적인 get요청:
get요청을 보내면 res객체의 send, sendFile 등으로 응답할 수 있다.
// 이런 것들이
app.get("/", (req, res) => {
// __dirname은 현재 프로젝트 절대경로. package.json이 설치된 루트?
res.sendFile(__dirname + "/index.html");
});
// 다 API만든거임.
app.get("/news", (req, res) => {
db.collection("post").insertOne({ title: "어쩌구" });
res.send("뉴스");
});
// 각종 다양한 페이지들 get요청 처리
app.get("/shop", (req, res) => {
res.send("쇼핑 페이지입니다~!");
});
// 각종 다양한 페이지들 get요청 처리
app.get("/about", (req, res) => {
res.sendFile(__dirname + "/about.html");
});
DB조회가 필요한 페이지 get요청의 경우:
리스트 페이지 같은 경우엔 db조회를 해야한다.
"post"라는 콜렉션을 모두 조회해서(find) 문서들을 배열화(toArray)했다.
ejs템플릿을 사용한다면 render 메소드로 렌더할 수 있다.
이때, 두 번째 파라미터 객체에 동적으로 할당할 데이터들을 넣어줄 수 있다.
app.get("/list", async (req, res) => {
const col = db.collection("post");
const doc = await col.find().toArray();
// 기본 경로가 views폴더로 되어있기 때문에 굳이 '/views/...'를 안 써줘도 된다.
// 첫 번째는 템플릿 에진 경로, 두 번째 파라미터는 보낼 데이터(주로 db조회한 결과값...)
res.render("list.ejs", { doc: doc });
});
동적패러미터를 다루는 방식:
:id같이 : 뒤에 패러미터를 기입한다.
이는 req.params에서 추출하여 사용할 수 있다.
아주 민감한 정보는 url에 넣지 않고 body에 담아주는 것이 좋다.
app.get("/detail/:id", async (req, res) => {
// ejs에 변수 주입
let result;
try {
result = await db
.collection("post")
.findOne({ _id: new ObjectId(req.params.id) });
console.log(result, "result");
} catch (err) {
return;
}
res.render("detail.ejs", { title: result.title, content: result.content });
});
2. 게시글 작성
사용자가 입력한 정보를 req의 body에서 객체형식으로 파싱한 후
collection에 insertOne 메소드로 주입해주면 된다.
클라이언트에 status를 설정해주고 message를 날려준다.
// 글쓰기 페이지 단순 get요청
app.get("/write", (req, res) => {
res.render("write.ejs");
});
// '/write'로 post요청을 받았을 때
app.post("/write", async (req, res) => {
try {
if (req.body.content === "" || req.body.title === "") {
throw new Error("no Title or no Content");
}
const col = db.collection("post");
// req의 body의 정보들을 객체화한다.
// express.json() 라이브러리 덕분에 req.body....로 접근 가능하다.
const temp = { title: req.body.title, content: req.body.content };
// insertOne으로 temp객체 주입
const insert = await col.insertOne(temp);
// 클라이언트에 status를 설정해주고 message를 날려준다.
res.status(201).json({ message: "Item successfully saved!" });
} catch (err) {
if (err.message === "no Title or no Content") {
res
.status(400)
.json({ message: "empty title or content are not allowed" });
}
}
});
3. 게시글 수정
수정 페이지:
get요청으로 수정 페이지에 접근할 때,
본문 내용을 채워주기 위해 findOne메소드로 id를 조회한다.
수정 요청:
updateOne메소드를 사용한다.
const updateOne = await col.updateOne(filter, temp);에서
첫 번째 인자는 수정할 타겟, 두 번째 인자는 업데이트할 내용이다.
먼저, 첫 번째 인자이다.
const filter = { _id: new ObjectId(req.params.id) };
$gt, $gte, $lt, $lte 등으로 수량을 기준으로 조회할 수 있다.
두 번째 인자는 업데이트할 내용이다.
const temp = { $set: { title: req.body.title, content: req.body.content } };
$set, $inc, $mul, $unset 등의 키로 수정할 수 있다.
app.get("/modify/:id", async (req, res) => {
// ejs에 변수 주입
let result;
try {
// id가 같은 문서 하나를 조회.
result = await db
.collection("post")
.findOne({ _id: new ObjectId(req.params.id) });
console.log(result, "result");
} catch (err) {
return;
}
res.render("modify.ejs", {
title: result.title,
content: result.content,
_id: req.params.id,
});
});
// patch함수로 조회할 때
app.patch("/modify/:id", async (req, res) => {
try {
if (req.body.content === "" || req.body.title === "") {
throw new Error("no Title or no Content");
}
const col = db.collection("post");
const filter = { _id: new ObjectId(req.params.id) };
// $set은 특정값으로 바로 세팅하는 키이다.
// 넘버 값을 다룰 때 $set말고
// $inc를 쓰면 기존값 +/- 를 할 수 있다.
// $mul을 쓰면 기존값 * n을 할 수 있다.
// $unset을 쓰면 필드를 삭제할 수 있다.
// updateMany를 쓰면 해당하는 것들을 모두 바꿀 수 있다.
// like가 10개 이상인 것들을 모두 선택하려면? { like: {gt: 10} }
// *gt는 greater than의 약자
// *gte는 greater than or equal의 약자
// *lt, lte도 less than, less than equal이다.
// *ne는 not equal.
const temp = { $set: { title: req.body.title, content: req.body.content } };
console.log(temp, "temp");
const updateOne = await col.updateOne(filter, temp);
console.log(updateOne);
res.status(201).json({ message: "Item successfully saved!" });
} catch (err) {
if (err.message === "no Title or no Content") {
res
.status(400)
.json({ message: "empty title or content are not allowed" });
return;
}
console.log(err);
}
});
4. 게시글 삭제
수정과 비슷하게 특정 문서를 찾은 다음에 deleteOne으로 삭제하면 된다.
app.delete("/delete/:id", async (req, res) => {
const col = db.collection("post");
const filter = { _id: new ObjectId(req.body["id"]) };
const result = await col.deleteOne(filter);
console.log(filter);
if (result.deletedCount === 1) {
console.log("Successfully deleted one document.");
res.json({ success: true });
} else {
console.log("No documents matched the query. Deleted 0 documents.");
res.json({ success: false });
}
});
오히려 클라이언트 단에서 문서가 삭제된 후
새로고침을 하지 않아도 그 문서를 삭제해주는 로직을 설정해주는 것이 중요하다.
이를 위해 Ajax를 사용하는 것이 좋다.
<script>
const deleteEls = document.querySelectorAll(".delete");
for (let i = 0; i < deleteEls.length; i++) {
deleteEls[i].addEventListener("click", (e) => {
e.preventDefault();
fetch(`/delete/${i}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ id: e.target.dataset.id }),
})
.then((response) => response.json())
.then((data) => {
if (data.success) {
deleteEls[i].closest("div.list-box").remove();
}
});
});
}
</script>
'BackEnd > Node.js' 카테고리의 다른 글
Session, JWT, OAuth이란? (0) | 2024.08.05 |
---|---|
express로 페이지네이션 구현하기 (0) | 2024.08.03 |
ejs 템플릿 엔진 사용하기 (0) | 2024.07.08 |
express 상에서 MongoDB Atlas 사용하기 (0) | 2024.07.07 |
Express 초기화, 기본 사용법, 미들웨어 사용하기, 파라미터 쓰는 법 (0) | 2024.07.03 |