본문 바로가기

BE/Node.js

[Node.js] 게시판 구현 1 ( 페이징, 게시글 작성 )

 

 

 

 

 

게시판 구현 ( 페이징, 답변 )

파일 세팅

 

create table paging(
num number not null,
title varchar2(30) not null,
pdate varchar2(10) not null,
count number not null,
primary key(num)
);
create sequence test_num;

DB 테이블 생성

 

npm install express --save
npm install ejs --save
npm install oracledb@5.5.0 --save
npm install supervisor --save
npm install body-parser --save

npm 설치

 


 

게시판 목록보기 구현

 

app.js 기본 세팅

 

router.js 기본세팅

 

page_router.js 기본 세팅

 

page_controller.js 기본 세팅

 

index.ejs 세팅

 

page_router 에 list 경로 추가

 

page_controller.js 작성 ( service 쪽에서 db 에 접근해서 작업할 것 이므로 async 처리 )

 

page_service.js 파일 작성

 

db_config.js 작성

 

pageDAO.js 작성

 

list.ejs 작성 ( DAO 에서 가져온 데이터로 테이블 작성 )

 

서버 실행

 

게시판 목록보기 구현 완료

 


 

글 작성기능 구현

 

page_router.js, page_controller.js 작성 ( /write_form 경로 )

 

write_form.ejs 작성 ( 글 작성 기능 )

 

글 작성시 이동되는 /write 경로 page_router.js 에 작성 ( post 방식 )

 

page_controller.js 에 async - await 을 통해 동기처리 하여 작성

 

page_service.js 에 pageInsert 부분 작성

 

pageDAO.js 에 글에 관련된 데이터 DB 에 저장하는 로직 작성 ( nextval : DB 에 sequence 로 생성해놓은 1씩 값이 증가하며 저장되는 부분을 의미 )

 

서버 실행

 

글 작성부분 구현 완료

 


 

글 상세보기 구현

 

list.ejs 에 글 타이틀에 글 번호를 경로로 하는 a 태그 작성

 

page_router.js 에 경로 작성 :num 으로 글 번호를 변수로 받음

 

page_controller.js 에 변수로 받은 num 을 service 로 넘겨주는 코드 작성

 

page_service.js 에 넘겨받은 글 번호를 dao 쪽으로 넘겨서 연산하는 코드 작성

 

dao 에 넘겨 받은 글 번호랑 일치하는 행을 찾는 코드를 작성 후 return 으로 해당 데이터를 service 로 반환

 

content.ejs 작성

 

 

글 상세보기 구현 완료

 


 

조회수 증가시키는 부분 구현

 

page_service.js 에 조회수 증가시키는 부분 로직 작성

 

dao 에 조회수 증가 로직 작성

 

서버 실행 ( 만약 조회수가 글을 눌러서 상세보기가 켜지자 마자 늘어나길 원한다면 조회수 늘어나는 로직에 async - await 을 적용해주면 된다 )

 

글 조회수 증가 구현 완료

 


 

 

 

 

 

페이징 처리

페이징 방식

 

글의 총 갯수를 가져오는 totalContent 를 page_controller.js 에 작성

 

page_service.js 에 글 전체 갯수 가져오는 로직 작성

 

pageDAO.js 에 DB 에 접근하여 전체 글 갯수 가져오는 로직 작성

 

list.ejs 에 totalContent 출력해 봄 ( 콘솔과 웹 출력 결과물 )

 

페이지를 확인할 수 있는 start 라는 변수를 생성하여 로직을 작성할 것, page_controller.js 작성

 

page_service.js 에서 로직 작성

 

start 값을 출력해 봄

 

이전을 누르면 start -1 값을 전달, 다음을 누르면 start +1 값을 전달, start 값이 1이면 이전 버튼을 비활성화, start 값이 totalContent 와 같아면 다음 버튼을 비활성화

 

rownum : 가상의 행의 수

( 의미는 없지만, 만약 글의 번호로 데이터를 처리한다고 가정했을 때 한 페이지에 글을 5개씩 출력하고자 할 때 2번째 작성 글이 삭제되었다면 오류가 발생하거나 첫번째 페이지에 1, 3, 4, 5 글 4개만 출력되게 된다..... 그래서 오라클에서 지원하는 가상의 행{결과 값이 출력되는 행만큼 임의의 번호를 붙여주는 rownum}인 rownum 을 사용하여 글이 삭제되었어도 빈 값이 없이 1, 3, 4, 5, 6 식으로 출력되게끔 설정한다 )

 

마지막 페이지 값을 담은 page 정보도 page_controller.js 에 작성

 

page_service.js 에서 pageNum 에 한 페이지 당 출력될 글의 갯수 설정 후 연산을 통해 toPage(총 페이지) 설정, startNum 과 endNum 은 DB 에 글의 rownum 연산을 할 때 필요한 값을 선언 ( start 는 현재 몇번째 페이지인지 나타냄 )

 

page_service.js 에서 페이지 정보를 DAO 에 전달하여 연산

 

list.ejs 에서 전달받은 page 의 totPage(토탈 페이지) 값으로 목록을 출력한다

 

서버 실행

 

페이징 처리 완료

 


 

 

 

 

 

댓글

quiz_dbconnect_board.zip
3.00MB

 

위 프로젝트 다운로드 받아서 위와 같이 세팅

 

create table board(
write_no number(10) primary key,
title varchar2(100),
content varchar2(300),
save_date date default sysdate,
hit number(10) default 0,
origin_file_name varchar(100),
change_file_name varchar(100),
id varchar(20) not null,
constraint fk_test foreign key(id) references members(id) on delete cascade
);
create sequence board_seq;

sql developer 에서 쿼리문 작성하여 테이블 생성

 

write no : 글 번호

title : 제목

content : 내용

save_date : 저장 날짜

id : 글 작성자

 

npm install multer@1.4.4 --save

multer npm 설치

( multer - 파일 업로드를 위해 사용되는 Node.js 의 미들웨어 )

 

header.css 작성

* { margin: 0; }
.wrap { width: 1000px; margin: auto; }
.header { width: 1000px; }
.navdiv { width: 100%; background-color: olive; }
.nav { background-color: olive; width: 1000px;}
.nav ul { list-style: none; display: flex;
        justify-content: end; }
.nav ul li { padding: 10px; }

.nav ul li a { text-decoration:none; color:white; }
.nav ul li a:hover{
color: orange; border-bottom: 2px solid black;
transition : all 0.25s; padding-bottom: 3px;
}
.title{ text-shadow: 10px 10px 15px black; 
    font-size: 70pt;
    text-align: center;
    margin-top: 0; 
    padding-bottom: 20px;
    color: burlywood;
    font-family: Gabriola;
}
.content { margin-top: 50px;  }

header.css 코드

 

css 적용을 위해 app.js 에서 /static 설정

 

<link href="/static/css/header.css" rel="stylesheet">
<script >
window.onload = () =>{
    console.log(document.cookie);
    let msg ="<li><a href='/'>HOME</a></li>";
    if(document.cookie.indexOf("isLogin=true") !== -1 ){
        msg += '<li><a href="/member/logout">로그아웃</a></li>';
        msg += '<li><a href="/member/list">회원정보</a></li>';
    }else{
        msg += '<li><a href="/member/login">로그인</a></li>';
        msg += '<li><a href="/member/login">회원정보</a></li>';
    }
    document.querySelector("#nav ul").innerHTML = msg
}
</script>
<div class="wrap">
    <div class="header">
        <h1 class="title">CARE LAB</h1>
    </div>
</div>
<div class="navdiv">
    <div class="wrap">
        <nav id="nav" class="nav">
            <ul></ul>
        </nav>
    </div>
</div>
<hr>

header.ejs 코드 변경 ( link 로 외부 css 파일 적용 )

 

서버 실행 결과

 

board 항목 추가

 

router.js 에 /board 로 접속 시 사용될 boardRouter 선언

 

board_router.js , board_ctrl.js 작성

 

board_service.js 작성

 

DAO 에서 공통으로 사용하는 부분을 common_dao.js 를 생성하여 exports

 

list.ejs 작성

<%- include ("../default/header") %>
<div class="content wrap">
    <table border="1" style="width:100%;">
        <tr>
            <th>번호</th> <th>id</th> <th>제목</th> <th>날짜</th>
            <th>조회수</th> <th>원본 이미지이름</th> <th>변경 이미지이름</th>
        </tr>
        <% if( list.length == 0){ %>
            <tr>
                <th colspan="7">등록된 글이 없습니다</th>
            </tr>
        <%}else{
            list.forEach(data=>{%>
            <tr>
                <td><%=data.WRITE_NO%></td><td><%=data.ID%></td>
                <td><%=data.TITLE%></td><td><%=data.SAVE_DATE%></td>
                <td><%=data.HIT%></td><td><%=data.ORIGIN_FILE_NAME%></td>
                <td><%=data.CHANGE_FILE_NAME%></td>
            </tr>
            <%})
        }%>
        <tr>
            <td colspan="7" align="right">
                <a href="/board/write_form">글 작성</a>
            </td>
        </tr>
    </table>
</div>

list.ejs 코드

 

list.ejs 에서 글 작성을 누르면 이동되는 경로인 /write_form 경로를 board_router.js 에 작성

 

세션을 체크하는 부분과 메세지를 출력하는 공통 기능을 ser_common.js 파일을 생성하여 작성

 

세션을 통해 로그인 정보를 확인한 뒤 로그인 상태라면 board/write_form 경로로 이동시킴

 

write_form.ejs 작성

<%- include ("../default/header") %>
<script src="/static/js/image_read.js"></script>
<div class="content wrap">
    <div style="width: 400px; margin: 0 auto; ">
        <h1 style="text-align: center">글쓰기</h1>
        <form method="post" action="/board/write" 
                                        enctype="multipart/form-data">
            <b>작성자</b><br>   <!-- readonly : 읽기 전용 -->
            <input type="text" name="id" value="<%= username %>" readonly />
            <hr>
            <b>제목</b> <br> <input type="text" size="50" name="title" /><hr>
            <b>내용</b> <br>
            <textarea name="content" rows="10" cols="50"></textarea><hr>
            <b>이미지파일 첨부</b><br>
            <input type="file" name="image_file_name" onchange="readURL(this);" /> 
            <img id="img" src="#" width=100 height=100 alt="선택된 이미지가 없습니다" />
            <hr> 
            <input type="submit" value="글쓰기">
            <input type=button value="목록보기" onClick="location.href='/board/list'">
        </form>
    </div>
</div>

write_form.ejs 코드

 

public 폴더 하위에 js 폴더에 image_read.js 작성 ( 이미지 미리보기 부분 구현 )

const readURL = (input) => {
    console.log(input);
    console.log(input.files[0]);
    const file = input.files[0];
    if(file != ""){
        let reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = (e) => {
            console.log(e.target.result);
            // 파일에 대한 정보가 담겨있는 곳
            document.getElementById("img").src = e.target.result;
        }
    }
}

image_read.js 코드

 

서버 실행 ( 글 작성 진입 및 이미지 미리보기까지 구현 )

 

config - file - file_config.js 생성 및 작성

const multer = require("multer");
const stg = multer.diskStorage({
    destination : ( req , file, cb ) => {
        cb(null,  "upload_file")
    },
    filename : ( req, file, cb) => {
        cb(null, Date.now()+"-"+file.originalname );
    }
})
const f_filter = (req, file, cb)=>{
    const type = file.mimetype.split("/");
    if( type[0] == "image" ){
        cb(null, true);
    }else{
        req.fileValidation = "이미지만 저장하세요";
        cb(null, false);
    }
}
const upload = multer({storage : stg, fileFilter : f_filter })
module.exports = upload;

file_config.js 코드

 

board_router.js 에&nbsp; 이미지 업로드를 post 로 받을때 이동 될 /write 설정

 

이미지가 저장될 upload_file 폴더를 프로젝트 바로 하위에 생성

 

board_controller 작성

 

board_service.js 작성 ( 이미지 형식이 아닐 경우 alert 발생 )

 

board_dao.js 에 boardInsert 작성

 

코드 실행

 

ser_common.js 에서 시간을 지정하는 함수 생성

 

board_service.js 에 ser_common 을 require 했던 부분을 제일 상단으로 올려준 뒤 list 의 값을 timeModify 함수에 집어 넣어 변경 후 list 를 반환한다

 

시간 설정 완료

 

728x90