이전 블로깅에서 계속 이어지는 블로깅 내용입니다.
https://mixedcode.com/blog/detail?pid=28
관련 실습 깃허브 링크 정보 : https://github.com/eddykang1074/node-express-app.git
3)기 등록된 게시글 확인 웹페이지 요청/응답 구현하기
- 게시글 목록 화면에서 특정 단일 게시글을 클릭하면 해당 단일 게시글 정보를 확인할수 있는 웹페이지 요청 및 응답처리 라우팅 메소드를 구현합니다.
- views/article/list.ejs파일을 오픈하고 아래 게시글 목록 뷰파일의 내용으로 기존 코드를 변경/저장합니다.
-views/article/list.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>게시글 목록 웹페이지</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h3>게시글 목록 웹페이지</h1>
<div class="row">
<div class="col-12 text-end"><a href="/article/create" class="btn btn-primary">글작성</a></div>
</div>
<table class="table">
<thead>
<tr>
<th scope="col">글번호</th>
<th scope="col">제목</th>
<th scope="col">조회수</th>
<th scope="col">게시여부</th>
<th scope="col">글쓴이</th>
<th scope="col">작성일시</th>
</tr>
</thead>
<tbody class="table-group-divider">
<tr>
<th scope="row">1</th>
<td><a href="/article/modify/1">글제목1입니다.</a></td>
<td>1</td>
<td>게시안함</td>
<td>강창훈</td>
<td>2024-05-01</td>
</tr>
<tr>
<th scope="row">2</th>
<td><a href="/article/modify/2">글제목2입니다.</a></td>
<td>2</td>
<td>게시함</td>
<td>강창훈</td>
<td>2024-05-02</td>
</tr>
</tbody>
</table>
</div>
<script src="https://code.jquery.com/jquery-3.7.1.js" integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>
A) 게시글 정보 확인 웹 페이지 요청과 응답 처리 라우팅 메소드
-게시글 목록에서 http://localhost:3000/article/modify/1 URL형식,GET 타입으로 주소를 호출하면 상기 라우팅 메소드가 호출됩니다.
-호출 URL주소 형식을 자세히 보면 /article/modify/1 형식에서 1은 게시글의 고유번호를 말하며 이렇게 URL주소에 특정 데이터를 포함해 데이터를 전송할수도 있습니다.
-일반적으로 URL주소 형식에 데이터를 포함해 전달하는 방식은 아래와 같이 2가지 방식이 존재합니다.
Case1)파라메터방식: URL 기본주소내에 데이터를 포함하는경우
예시) http://localhost:3000/article/100 http://localhost:3000/goods/5 https://velog.io/@endmoseung/개발자가-클라우드를-공부하는이유
ㄴ라우팅메소드에서 파라메터 방식 데이터 추출하는 방법 : req.params.와일드카드변수명
Case2)쿼리스트링방식: URL주소?키=값&키=값&키=값 형식으로 기본주소 다음에?키=값&키=값 형식으로 값을 전달하는 방식
예시)http://localhost:3000/article?aid=100&category=1
ㄴ라우팅메소드에서 쿼리스트링 방식 데이터 추출하는 방법 : req.query.키명
-URL형식에 파라메터 방식으로 데이터를 전송해오는경우는 와일드 카드라는 방식을 통해 URL내 포함된 데이터 값을 라우팅메소드의 주소체계내에 :변수명 형식으로 선언하고 req.params.와이일드카드 변수명 형식으로 값을 추출할수 있습니다.
http://localhost:3000/article/modify/1
router.get('/modify/:aid',콜백함수);
router.get('/modify/:와일드카드변수명',콜백함수);
//와일드 카드변수는 경로:변수명 형식으로 지정해야합니다. /modify/:aid
//와일드 카드 경로는 URL형식 주소경로 형식과 일치해야합니다. /modify/1 = /modify/:aid
콜백함수내에서 req.params.aid 형식으로 URL주소내 /article/modify/1 1 값을 추출할수 있습니다.
router.get('/modify/:aid',콜백함수); 라우팅메소드에서 해당 게시글 고유번호를 추출한후 DB에 접속해 db에 저장된 단일 게시글 정보를 조회해온 후 해당 단일 게시글 데이터를 modify.ejs 뷰에 전달해 해당 데이터가 뷰에 출력될수 있게 데이터를 전달합니다.
- routes/article.js
/*
- 게시글 정보 확인/수정 웹 페이지 요청과 응답 처리 라우팅 메소드
-요청주소 : http://localhost:3000/article/modify/1
-요청방식 : GET 방식
-응답결과 : article/modify.ejs 뷰파일 웹페이지 내용
*/
router.get('/modify/:aid', async(req, res, next) =>{
//Step1:게시글 고유번호 추출하기(파라메터방식의 경우 와일드카드 키값을 통해 추출가능)
const articleId = req.params.aid;
//Step2: DB에서 해당 게시글 정보 조회해오기
//Step3:DB에서 조회한 단일 게시글정보(예시데이터)
const article ={
aid: articleId,
title: "게시글1 제목입니다.",
content: "게시글1 내용입니다.",
view_cnt:0,
ip_address:req.headers['x-forwarded-for'] || req.connection.remoteAddress,
display_yn:"1",
regist_date: Date.now(),
regist_user_name: "강창훈"
};
//step4:modify.ejs 뷰파일에 단일 게시글 정보를 json 형식으로 전달하기
res.render('article/modify',{article:article});
});
B) 게시글 정보 확인 웹 페이지 뷰 파일 생성 및 구현하기
-views/article/폴더내에 modify.ejs 파일을 만들고 하기 코드를 반영합니다.
-views/article/modify.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>게시글 확인 웹페이지</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h3>게시글 확인 웹페이지</h1>
<form action="/article/modify/<%=article.aid%>" method="post" id="articleForm">
<div class="row mb-3">
<label for="title" class="form-label">제목</label>
<input type="text" class="form-control" id="title" name="title" placeholder="글제목" value="<%=article.title%>"/>
</div>
<div class="row mb-3">
<label for="content" class="form-label">내용</label>
<textarea class="form-control" id="content" name="content" rows="10"><%=article.content%></textarea>
</div>
<div class="row mb-3">
<label for="display_yn" class="form-label">게시여부</label>
<select class="form-select" id="display_yn" name="display_yn">
<option value="0" <% if( article.display_yn == "0"){ %> selected <% } %> >게시안함</option>
<option value="1" <% if( article.display_yn == "1"){ %> selected <% } %> >게시함</option>
</select>
</div>
<div class="row mb-3">
<label for="modify_user_name" class="form-label">수정자</label>
<input type="text" class="form-control" id="modify_user_name" name="modify_user_name" placeholder="수정자명" value="<%=article.modify_user_name%>" >
</div>
<div class="d-grid gap-2 d-md-block text-center">
<button type="submit" class="btn btn-primary">수정</button>
<button type="button" class="btn btn-danger" id="btnDelete">삭제</button>
<a href="/article/list" class="btn btn-secondary">목록</a>
</div>
</form>
</div>
<script src="https://code.jquery.com/jquery-3.7.1.js" integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<script>
$("#btnDelete").on("click", function(){
if(confirm("정말 삭제하시겠습니까?")){
location.href="/article/remove?aid=<%=article.aid%>";
}
});
</script>
</body>
</html>
정상적으로 http://localhost:3000/article/list 페이지 목록에서 특정 게시글 제목 클릭시 상세 페이지 http://localhost:3000/article/modify/1 로 이동하는지 확인해봅니다.
-단일 게시글 상세 페이지로 이동이 완료되었다면 해당 뷰파일에 전달된 단일 JSON데이터를 뷰파일내에 특정 UI요소와 바인딩하여 서버측에서 뷰파일의 HTML웹페이지를 동적으로 제어하는 아래 코드를 적용하고 저장합니다.
-라우팅 메소드에 의해 View파일에 전달된 JSON 데이터는 아래와 같은 EJS뷰엔진 데이터 처리 문법을 이용해 HTML요소에 값을 출력하거나 조건문/반복문을 이용해 서버측에서 VIEW파일내에서 동적으로 HTML 태그를 변조한후 웹브라우저에 최종 VIEW 결과값을 응답 결과물로 제공할수 있습니다.
-주요 EJS 파일내에 있는 <% %>문법은 EJS 뷰파일 내에서 동적으로 HTML을 제어할수 있는 EJS뷰엔진 문법으로 데이터를 HTML요소에 바인딩하거나 데이터를 출력할때는
<%=JSON데이터속성%> 문법을 통해 처리하고 IF 조건문이나 FOR반복문등을 이용해 동적으로 HTML요소를 View파일내에서 제어가 가능합니다.
정상적으로 게시글 상세 페이지에서 데이터가 UI요소에 바인딩되어 표시되는지 확인합니다.
4)게시글 정보 수정처리 요청/응답 구현하기
-router.get('/modify/:aid') 라우팅 메소드를 통해 전달된 게시글 확인 웹페이지에서 기존 게시글 정보를 사용자가 확인/수정하고 저장버튼을 클릭하면
modify.ejs파일내 정의된 <form action="/article/modify/1" method="post">에서 지정한 /article/modify 주소로 POST방식으로 사용자가 수정한 정보가 서버로 전달되며
해당 정보를 처리해주는 router.post('/modify/:aid',정보처리콜백함수); 라우팅 메소드를 구현해줘야합니다.
A) 게시글 수정 처리 요청 및 응답 처리 라우팅 메소드
-기존 게시글 확인 페이지에서 사용자가 수정한 입력데이터가 아래 라우팅 메소드로 전달됩니다.
-FORM태그내 URL을 통해 /article/modify/1 게시글 고유번호와 입력요소의 name속성으로 사용자 입력/선택값이 전달되며 URL파라메터 방식으로 전달된 값은 req.params.와일드카드변수명 방식으로 사용자 입력/선택 값은 req.body.html요소name값 형식으로 값을 추출합니다.
** DB 테이블 변경처리는 추후 Model영역 구현을 ORM으로 진행후 관련 코드를 변경예정입니다.
- routes/article.js
/*
- 게시글 수정 처리 요청 및 응답 처리 라우팅 메소드
-요청주소 : http://localhost:3000/article/modify
-요청방식 : POST 방식
-응답결과 : http://localhost:3000/article/list 페이지로 이동처리(도메인주소생략)
*/
router.post('/modify/:aid', async(req, res, next) =>{
//Step1:게시글 고유번호 추출하기(파라메터방식의 경우 와일드카드 키값을 통해 추출가능)
const articleId = req.params.aid;
//Step2: 게시글 수정데이터 추출하기
const title = req.body.title;
const content = req.body.content;
const display_yn = req.body.display_yn;
const modify_user_name = req.body.modify_user_name;
//Step3: DB 수정 단일게시글 정보 준비하기
const article ={
title: title,
content, //속성명과 변수명이 동일하면 변수명 생략가능(ES6문법)
display_yn,
ip_address:req.headers['x-forwarded-for'] || req.connection.remoteAddress,
moidify_date: Date.now(),
modify_user_name: modify_user_name
};
//Step4: DB 해당 게시글 수정 처리하기
//step5: 수정완료후 http://localhost:3000/article/list 페이지로 이동처리(도메인주소생략)
res.redirect("/article/list");
});
B) 게시글 수정 처리 후 응답 처리하기
-정상적으로 DB 수정 반영 처리 후 게시글 목록 페이지로 사용자의 웹브라우저 주소를 이동처리하기 위해 콜백함수 응답결과를 res.redirect('URL주소')메소드를 이용해 페이지를 이동시킵니다.
res.render('뷰파일물리적경로') 와 res.redirect('URL이동주소') 메소드의 차이점과 용도를 정확히 이해하고 사용하시기 바랍니다.
res.render('뷰파일물리적경로')는 특정 뷰파일의 경로 지정을 통해 View파일내 내용을 반환하는거고 res.redirect('URL이동주소') 는 사용자 웹브라우저에 특정 URL주소 정보를 제공해
해당 URL주소로 웹브라우저 웹페이지 경로를 강제로 이동시키는것입니다.
-웹브라우저를 통해 목록 페이지에서 단일 게시글 정보 확인하고 입력값 변경 후 저장버튼 클릭 후 정상적으로 목록 페이지로 다시 이동하는지 확인합니다.
5)게시글 정보 삭제처리 요청/응답 구현하기
-단일 게시글 확인 상세 페이지 하단의 삭제 버튼 클릭시 현재 선택한 게시글 데이터에 대한 삭제 요청과 응답처리 라우팅메소드를 구현합니다.
-views/article/modify.ejs 파일내 삭제버튼(btnDelete) 클릭시 http://localhost:3000/article/remove?aid=1 형태의 URL주소와 GET방식으로 삭제 URL을 호출합니다.
-URL주소에 Querystring방식으로 해당게시글 고유번호값을 aid키값으로 전달하면 해당 라우팅메소드에서는 req.query.키명 형식으로 URL을 통해 전달된 키값을 추출할수 있습니다.
- routes/article.js
/*
- 게시글 삭제 처리 요청 및 응답처리 라우팅 메소드
-요청주소 : http://localhost:3000/article/remove?aid=1
-요청방식 : Get 방식
-응답결과 : http://localhost:3000/article/list 페이지로 이동처리(도메인주소생략)
*/
router.get('/remove', async(req, res, next) => {
//step1: 게시글 고유번호 추출하기
//QueryString방식으로 전달된 게시글 고유번호 추출하기
const articleId = req.query.aid;
//step2: DB에서 해당 게시글 정보 삭제처리하기
await db.Article.destroy({where:{aid:articleId}});
//step3: 삭제완료후 http://localhost:3000/article/list 페이지로 이동처리(도메인주소생략)
res.redirect("/article/list");
});
이번 시간에는 MVC 패턴 기반에서의 Controller와 View 기반으로 게시글 정보에 대한 목록조회/게시글 등록/ 확인 / 수정/ 삭제 처리 기능을 가상의 데이터를 활용해 기초 기능을
구현해 봤으며 다음 시간에는 MVC 패턴의 Model영역에 대해 ORM기법을 이용해 DB 테이블을 생성하고 실제 테이블 기반으로 등록/수정/확인/목록/삭제 기능을 구현해보도록 하겠습니다.
오늘도 수고 많으셨습니다.