Cute Apple
본문 바로가기
개발/Node.js

Node.js 게시판(express 사용/Mysql 사용)

by 미댕댕 2021. 4. 8.

Node.js의 기본 모듈만으로 서버를 구축할수는 있으나, 개발자가 처리해야할 업무가 너무 많고

효율성이 떨어진다. 따라서 기본 모듈 외에 http 모듈을 좀더 개선한 express 모듈을 사용해 보자!

주의) http 기본 모듈이 사용되지 않는 것이 아니라, 이 기본 모듈에 express 모듈을 추가해서 사용한다.

 

 

Express 모듈의 특징

 

1) 정적자원에 대한 처리가 이미 지원된다.. 즉 개발자가 각 지원마다 1:1대응하는 코드를 작성할 필요가 없다.

    정적자원 : html, images, css, sound, mp4, js(클라이언트 측) , txt 서버에서 실행되지 않는 모든 리소스

2) Get / Post 등의 http 요청에 대한 파라미터 처리가 쉽다.

3) 미들웨어라 불리는 use() 메서드를 통해 기능을 확장한다.

 

 


 

 

필요한 도메인 LIST

-게시판 폼

-게시판 등록

-게시판 목록

-게시판 상세보기

-게시판 수정

-게시판 삭제

 

 

server 작업

 

1.서버 준비 및 모듈 생성

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
32
33
34
35
36
37
var http=require("http");
var express=require("express");
var static=require("serve-static");//정적 자원을 쉽게 접근하기 위한 미들웨어 추가
var fs=require("fs");
var ejs=require("ejs");//서버측 스크립트인 ejs 관련 모듈
var mysql=require("mysql"); 
var mymodule=require("./lib/mymodule.js");
var app=express(); //express 모듈통해 객체 생성
 
 
//mysql 접속 정보
var conStr={
    url:"localhost:3306",
    user:"root",
    password:"1234",
    database:"nodejs"
}
 
// 서버의 정적자원에 접근을 위해 static() 미들웨어를 사용해본다 <----> dynamic(동적)
//__dirname 전역변수는? 현재 실행중인 js 파일의 디렉토리 위치를 반환
//즉 현재 실행중인 server.js 의 디렉토리를 반환!!
 
// console.log("이미지 정적자원에 들어있는 풀 경로는", __dirname+"/images")
app.use(static(__dirname+"/static")); //static 을 정적자원이 있는 루트로 지정
app.use(express.urlencoded({
    extended:true
})); //post 방식의 데이터를 처리할 수 있도록
 
 
//기능 구현은 이자리에
 
 
var server=http.createServer(app);//http 서버에 express 모듈을 적용
server.listen(8989function(){
    console.log("The server using Express module is running at 8989...")
});
 
cs

 

* ejs, 와 mysql은 외부모듈이기 때문에 npm(Node Pakage Manager) install로 설치

 

>>app.use의 사용법은 잘 모르겠다.

 

 

 

2. regist

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
//지정한 post 방식으로 클라이언트의 요청을 받음
app.post("/notice/regist"function(request, response){
    //1) 클라이언트가 전송한 파라미터들을 받자
    // console.log(request.body);
    var title=request.body.title;
    var writer=request.body.writer;
    var content=request.body.content;
 
    //2) mysql 접속
    var con=mysql.createConnection(conStr); //접속 후 Connection 객체 반환
 
    //3) 쿼리실행
    /*
    var sql="insert into notice(title, writer, content)";
    sql+=" values('"+title+"','"+writer+"','"+content+"')";
    */
    //바인드 변수를 이용하면, 따옴표 문제를 고민하지 않아도 됨, 단 주의!
    //바인드 변수의 사용목적은 따옴표 때문이 아니라, DB 성능과 관련이있다 (java 시간에 자세히 할 예정)
    var sql="insert into notice(title, writer, content) values(?,?,?)";
 
    con.query(sql, [title, writer, content], function(err, fields){
        if(err){
            console.log(err);
        }else{
            response.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
            response.end("<script>alert('등록성공');location.href='/notice/list';</script>");
        }
        con.end();
    });
});
cs

 

* post 방식으로 받기 (regist_form 에서 form 으로 submit을 함)

* 클라이언트가 보낸 정보들의 파라미터를 post 방식으로 받을때는 request.body

* 바인드변수를 사용하면 query 실행시 두번째 매개변수를 배열로 가져오고 배열안에 변수값들을 넣어줌

 

 

 

3. list

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
app.get("/notice/list",function(request,response){
    //select 문 수행
    var con=mysql.createConnection(conStr);//접속 시도후 Connection 객체 반환
    con.query("select * from notice order by notice_id desc"function(err, result, fields){
        if(err){
            console.log(err); //에러 분석을 위해 콘솔 화면에 로그를 남김
       }else{
        //    console.log("result는 ", result);
        //    console.log("fields는 ", fields);
           fs.readFile("./notice/list.ejs","utf8",function(err,data){
               response.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
               //읽기만 하는게 아니라 서버에서 실행까지 해야하므로 render() 메서드를 이용하여 %%영역을
               //클라이언트에게 보내기 전에 서버측에서 먼저 실행을 해버리자
               response.end(ejs.render(data,{
                    noticeList:result,
                    lib:mymodule
               }));
           });
       }
       con.end(); //mysql 접속 끊기
    });
});
cs

* list는 ejs 파일 이기 때문에 렌더링이 필요

* 렌더시 list에서 쿼리수행후 나온 결과값을 noticeList로 담고 mymodule 안에있는 모듈을 사용하기 위해 lib로 담음

 

 

 

4. detail

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
32
33
34
35
36
37
//상세보기 요청 처리
app.get("/notice/detail"function(request, response){
    //get 방식으로 , 헤더를 통해 전송되어온 파라미터를 확인해보자
    // console.log(request.query);
    var notice_id=request.query.notice_id;
    // var sql="select * from notice where notice_id="+notice_id;
    var sql="select * from notice where notice_id=?";
 
    var con=mysql.createConnection(conStr);
    con.query(sql, [notice_id], function(err, result, fields){
        // console.log(result);
        if(err){
            console.log(err);
        }else{
            //디자인 보여주기 전에 조회수도 증가시키자
            con.query("update notice set hit=hit+1 where notice_id=?;", [notice_id],function(er, fields){
                if(er){
                    console.log(er);
                }else{
                    fs.readFile("./notice/detail.ejs""utf8"function(error, data){
                        if(error){
                            console.log(error);
                        }else{
                            response.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
                            response.end(ejs.render(data,{
                                //result는 한건이라고 할지라도 배열이므로, 배열에서 꺼내서 보여주자
                                record:result[0]
                            }));
                        }
                    });
                }
                con.end(); //mysql 접속 끊기
            });
        }
       
    });
});
cs

 

* 조회하는 쿼리를 실행후에 실행에 성공 했다면 hit를 업데이트하는 쿼리를 수행

* hit를 증가하는 쿼리를 성공했다면 detail.ejs 안에 정보를 읽어와서 결과값을 record로 렌더링

 

 

 

5. edit

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
//글 수정요청 처리
app.post("/notice/edit"function(request, response){
    //파라미터 받기
    var title=request.body.title;
    var writer=request.body.writer;
    var content=request.body.content;
    var notice_id=request.body.notice_id;
 
    // console.log("title은", title);
    // console.log("writer는", writer);
    // console.log("content는", content);
    // console.log("notice_id는", notice_id);
 
    //파라미터가 총 4개 필요
    var sql="update notice set title=?, writer=?, content=? where notice_id=?";
 
    var con=mysql.createConnection(conStr);
 
    con.query(sql, [title, writer, content, notice_id], function(err, fields){
        if(err){
            console.log(err);
        }else{
            response.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
            response.end(mymodule.getMsgUrl("수정 성공","/notice/detail?notice_id="+notice_id));
        }
        con.end();//mysql 연결 종류
    });
});
cs

 

*  update 쿼리문을 실행하고 성공시 mymodule에 있는 getMsgUrl 모듈을 수행

 

 

 

6. delete

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//삭제요청
app.post("/notice/del"function(request, response){
    
    var notice_id=request.body.notice_id;
    // console.log("넘겨받은 id", notice_id);
    var sql="delete from notice where notice_id=?";
 
    var con=mysql.createConnection(conStr);
    con.query(sql, [notice_id], function(err, fields){
        if(err){
            console.log(err);
        }else{
            response.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
            response.end(mymodule.getMsgUrl("삭제 성공","/notice/list"));
        }
        con.end();
    });
});
 
cs

 

* 수정과 동일

 


client 작업

1. regist_form.html

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 파비콘.. 윈도우 상 아이콘이다. -->
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
 
<style>
body {font-family: Arial, Helvetica, sans-serif;}
{box-sizing: border-box;}
 
input[type=text],textarea {
  width: 100%;
  padding: 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
  margin-top: 6px;
  margin-bottom: 16px;
  resize: vertical;
}
textarea{
  height: 200px;
}
 
input[type=button] {
  background-color: #4CAF50;
  color: white;
  padding: 12px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
 
input[type=submit]:hover {
  background-color: #45a049;
}
 
.container {
  border-radius: 5px;
  background-color: #f2f2f2;
  padding: 20px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.ckeditor.com/4.16.0/standard/ckeditor.js"></script>
<script>
/*JQuery 의 문법 형시 (누구를).어떻게, 누구자리에 올수있는 요소?
CSS의 selector가 올수 있다.*/
$(function(){ //onLoad되면
  //편집기 입히기
  CKEDITOR.replace("content");
 
  $($("input[type='button']")[0]).click(function(){//등록버튼
    regist();
  });
 
  $($("input[type='button']")[1]).click(function(){//목록버튼
    getList();
  });
 
});
 
function regist(){
  $("form").attr("action""/notice/regist"); //url은 개발자가 정한다, 단 서버랑 짝을 맞추자
  $("form").attr("method""post");
  $("form").submit(); //전송행위가 발생
 
}
 
function getList(){
  location.href="/notice/list";
}
</script>
</head>
<body>
 
<h3>Contact Form</h3>
 
<div class="container">
    <!-- 폼 태그의 속성중 action은 이 폼양식을 전송할 대상 서버의 url을 명시할 수 있다. -->
    <!-- 
      id와 name 공통점과 차이점
      공통점)문서내의 요소를 식별하기 위함
      차이점)id-유일해야함, name-중복허용(배열로 인식)
                name은 폼 전송시 전송 파라미터 역할을 한다, 즉 변수 역할을 한다
                이때 전송 파라미터로서의 name의 이름은 주로 db의 테이블의 컬럼명과 일치시키는 규칙
     -->
  <form>
    <input type="text" name="title" placeholder="Your title..">
    <input type="text" name="writer" placeholder="Your name..">
    <textarea name="content" placeholder="content.."></textarea>
 
    <!-- input 태그의 type 중 submit은 디폴트로 전송기능이 포함되어 있기 때문에
    클릭만으로도, 전송이 발생함. 따라서 일반 버튼화 시켜놓자 -->
    <input type="button" value="Submit">
    <input type="button" value="목록으로">
  </form>
</div>
 
</body>
</html>
 
cs

* <script src="https://cdn.ckeditor.com/4.16.0/standard/ckeditor.js"></script>를 명시해주고

* CKEDITOR.replace("content"); 를 이용하면 편집기 사용 가능

* 등록은 post 방식으로 form 으로 보내고 목록은 get 방식으로 보냄

 

 

 

2. list.ejs

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
table {
  border-collapse: collapse;
  border-spacing: 0;
  width: 100%;
  border: 1px solid #ddd;
}
 
th, td {
  text-align: left;
  padding: 16px;
}
 
tr:nth-child(even) {
  background-color: #f2f2f2;
}
</style>
</head>
<body>
 
<h2>게시물의 수는 <%=noticeList.length%></h2>
 
<table>
  <tr>
    <th>No</th>
    <th>제목</th>
    <th>작성자</th>
    <th>작성일</th>
    <th>조회수</th>
  </tr>
  <%var totalRecord=noticeList.length; //총 게시물 수를 담자%>
  <%for(var i=0; i<noticeList.length; i++){%>
  <%var notice=noticeList[i]; //배열에서 json 하나 꺼내기%>
  <tr>
    <td><%=(totalRecord--)%></td>
    <td><a href="/notice/detail?notice_id=<%=notice.notice_id%>"><%=notice.title%></a></td>
    <td><%=notice.writer%></td>
    <%var d=new Date(notice.regdate);%>
    <td>
      <%=d.getFullYear()%>-<%=lib.getZeroString(d.getMonth()+1)%>-<%=lib.getZeroString(d.getDate())%>
    </td>
    <td><%=notice.hit%></td>
  </tr>
  <%}%>
  <tr>
    <td colspan="5">
      <button onClick="location.href='/notice/regist_form.html'">글등록</button>
    </td>
  </tr>
</table>
 
</body>
</html>
 
cs

 

 

 

 

3. detail.ejs

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 파비콘.. 윈도우 상 아이콘이다. -->
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
 
<style>
body {font-family: Arial, Helvetica, sans-serif;}
{box-sizing: border-box;}
 
input[type=text],textarea {
  width: 100%;
  padding: 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
  margin-top: 6px;
  margin-bottom: 16px;
  resize: vertical;
}
textarea{
  height: 200px;
}
 
input[type=button] {
  background-color: #4CAF50;
  color: white;
  padding: 12px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
 
input[type=submit]:hover {
  background-color: #45a049;
}
 
.container {
  border-radius: 5px;
  background-color: #f2f2f2;
  padding: 20px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.ckeditor.com/4.16.0/standard/ckeditor.js"></script>
<script>
/*JQuery 의 문법 형시 (누구를).어떻게, 누구자리에 올수있는 요소?
CSS의 selector가 올수 있다.*/
$(function(){ //onLoad되면
  //편집기 입히기
  CKEDITOR.replace("content");
 
  $($("input[type='button']")[0]).click(function(){//등록버튼
    regist();
  });
 
  $($("input[type='button']")[1]).click(function(){//목록버튼
    getList();
  });
 
  $($("input[type='button']")[2]).click(function(){//수정버튼
    edit();
  });
 
  $($("input[type='button']")[3]).click(function(){//삭제버튼
    del();
  });
 
});
 
function regist(){
  $("form").attr("action""/notice/regist"); //url은 개발자가 정한다, 단 서버랑 짝을 맞추자
  $("form").attr("method""post");
  $("form").submit(); //전송행위가 발생
 
}
 
function getList(){
  location.href="/notice/list";
}
 
function edit(){
  if(confirm("수정할겁니까?")){
    $("form").attr({
      action:"/notice/edit",
      method:"post"
    });
    $("form").submit();
  }
}
 
function del(){
  //서버에 전송할 notice_id는 get 방식으로 보내도 되지만, 기왕 form태그 안에 이미 hidden 으로
  //파라미터 변수가 존재하기 때문에, 그대로 post로 전송해 버리자
  if(confirm("삭제할겁니까?")){
    $("form").attr({
      action:"/notice/del",
      method:"post"
    });
    $("form").submit();
  }
}
</script>
</head>
<body>
 
<h3>Contact Form</h3>
 
<div class="container">
    <!-- 폼 태그의 속성중 action은 이 폼양식을 전송할 대상 서버의 url을 명시할 수 있다. -->
    <!-- 
      id와 name 공통점과 차이점
      공통점)문서내의 요소를 식별하기 위함
      차이점)id-유일해야함, name-중복허용(배열로 인식)
                name은 폼 전송시 전송 파라미터 역할을 한다, 즉 변수 역할을 한다
                이때 전송 파라미터로서의 name의 이름은 주로 db의 테이블의 컬럼명과 일치시키는 규칙
     -->
  <form>
    <input type="hidden" name="notice_id" value=<%=record.notice_id%>>
    <input type="text" name="title" value=<%=record.title%>>
    <input type="text" name="writer" value=<%=record.writer%>>
    <textarea name="content" ><%=record.content%></textarea>
 
    <!-- input 태그의 type 중 submit은 디폴트로 전송기능이 포함되어 있기 때문에
    클릭만으로도, 전송이 발생함. 따라서 일반 버튼화 시켜놓자 -->
    <input type="button" value="등록">
    <input type="button" value="목록">
    <input type="button" value="수정">
    <input type="button" value="삭제">
  </form>
</div>
 
</body>
</html>
 
cs

 

 

 

 

 • mymodule.js

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/*모듈은 변수, 함수 등의 코드가 모여진 단위
개발자가 모듈을 정의할때는 내장객체 중 exports 객체를 사용하면 됨
*/
 
//getMsg 메서드를 현재 모듈 안에 정의한다.
// (여기서 getMsg는 mymodule 의 모듈이다)
exports.getMsg=function(){
    return "This message is from my module"
 
/* -----------------------------------------------------
1. 매개변수 n : 0~n미만까지의 랜덤한 수를 반환하는 함수
------------------------------------------------------*/
 exports.getRandom=function(n){
        var r=parseInt(Math.random()*n); //0.00xxx ~ 1미만 사이의 난수를 발생시켜줌 
        // console.log(r);
        return r;
 }
 
 
/* -----------------------------------------------------
2. 자리수 처리
    한자리수의 경우 앞에 0 붙이기
------------------------------------------------------*/
 exports.getZeroString=function(n){
    var result=(n>10)? n: "0"+n;
    return result;
}
 
/* -----------------------------------------------------
3. 메세지 처리 함수
    alert() 출력할 메세지 생성해주는 함수
    <script>
    alert("하고싶은말");
    location.href=원하는url
    </script>
------------------------------------------------------*/
exports.getMsgUrl=function(msg, url){
    var tag="<script>";
    tag+="alert('"+msg+"');";
    tag+="location.href='"+url+"';";
    tag+="</script>";
    return tag; //함수 호출자에게 최종적으로 생성된 태그문자열 반환
}
 
cs

 

반응형

'개발 > Node.js' 카테고리의 다른 글

Node.js 갤러리 게시판  (0) 2021.04.27
Node.js 댓글 게시판(ajax사용/Oracle 사용)  (0) 2021.04.13
Node.js express 없이 서버 구축  (0) 2021.04.06
Node.js 기초  (0) 2021.04.01

댓글