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

Node.js 댓글 게시판(ajax사용/Oracle 사용)

by 미댕댕 2021. 4. 13.

 

폴더 구성

 

필요한 도메인 LIST

-게시판 폼

-게시판 등록

-게시판 목록

-게시판 상세보기

-게시판 수정

-게시판 삭제

 

-댓글 등록(ajax)

-댓글 목록(ajax)

 

 

 

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
38
39
40
41
var http = require("http");
var express = require("express"); //외부-설치
var fs=require("fs");
var ejs =require("ejs"); //외부-설치
var oracledb=require("oracledb");//외부-설치
// var bodyParser=require("body-parser");
var static=require("serve-static"); //정적 자원을 처리하기 위한 모듈
var mymodule=require("./lib/mymodule.js");
 
oracledb.autoCommit=true// 쿼리문 실행마자 트랜잭션을 commit으로 처리
oracledb.fetchAsString=[oracledb.CLOB]; //clob 데이터를 string 으로
 
var app = express();
 
//미들웨어 등록
app.use(static(__dirname+"/static")); //정적자원의 루트 디렉토리 등록
app.use(express.urlencoded({extended:true})); //post 방식 데이터 처리
 
//뷰엔진 등록(서버스크립트 선택)
//일단 뷰엔진이 등록되고 나면, 확장자를 명시할 필요 없다 why???
//view 라는 정해진 디렉토리를 참조하고, 그 안에 모든 파일은 다 ejs이기 때문
app.set("view engine""ejs");
 
 
//이 시점 이후 부터는 conStr변수의 값은 변할 수 없다(상수화 시킴)
const conStr={
    user:"node",
    password:"node",
    connectString:"localhost/XE"
};
 
 
 
//여기에 기능 구현
 
 
 
var server = http.createServer(app);
server.listen(8888function(){
    console.log("The Server with Oracle is running at 8888 port...");
});
cs

* oracledb.fetchAsString=[oracledb.CLOB]

<위에 string 변환을 쓰지않았을때 결과>

 

<위에 string 변환을 썼을 때 결과>

 

2. news/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
31
32
33
34
35
36
37
//등록요청 처리
app.post("/news/regist"function(request, response){
    //파라미터 받기(post)
    // console.log(request.body.title);
    var title=request.body.title;
    var writer=request.body.writer;
    var content=request.body.content;
 
    //오라클에 넣기
    oracledb.getConnection(conStr, function(err, con){
        if(err){
            console.log("접속실패",err);
        }else{
            var sql="insert into news(news_id, title, writer, content)";
            sql +=" values(seq_news.nextval, :1, :2, :3)";
            con.execute(sql, [title, writer, content], function(error, result){
                if(error){
                    console.log("등록중 에러발생", error);
                }else{
                    //여기서도 무조건 등록된다는 보장은 없다. 즉 오라클에 반영되었느냐 여부는
                    //result 를 통해 알아봐야한다.
                    console.log("result는 ", result);
                    if(result.rowsAffected==0){//등록실패
                        //status 코드란, http 통신 서버의 상태를 나타내는 기준값 코드
                        response.writeHead(500, {"Content-Type":"text/html;charset=utf-8"});
                        response.end(mymodule.getMsgUrl("등록실패""/news/list"));
                    }else{//등록 성공
                        response.writeHead(200, {"Content-Type":"text/html;charset=utf-8"});
                        response.end(mymodule.getMsgUrl("등록성공""/news/list"));
 
                    }
                }
                con.close(); //oracle 접속해제
            });
        }
    });
});
cs

 

 

 

3. news/list

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
//게시판 목록 요청 처리 
app.get("/news/list"function(request, response){
    //클라이언트가 전송한 파라미터 받기!!!
    var currentPage = request.query.currentPage; //클라이언트가 보기를 원하는 페이지수
    
    //게시판의 최초 접속이라면, currentPage정보가 없기 때문에 1페이지로 간주
    if(currentPage==undefined){ 
        currentPage=1;
    } 
    console.log("currentPage ", currentPage);
 
    oracledb.getConnection(conStr, function(err, con){
        if(err){
            console.log("접속실패",err);
        }else{
            console.log("접속성공");
    
            //쿼리문 실행 
            var sql="select  n.news_id, title, writer, regdate, hit , count(msg) as cnt";
            sql+=" from news n  left outer join  comments c";
            sql+=" on n.news_id=c.news_id";
            sql+=" group by n.news_id, title, writer, regdate, hit";
            sql+=" order by n.news_id desc"
 
            con.execute(sql, function(error, result){
                if(error){
                    console.log(error);
                }else{
                    // console.log("result는", result);
                    fs.readFile("./views/news/list.ejs""utf8"function(error, data){
                        if(error){
                            console.log(error);
                        }else{
                            var r = ejs.render(data,{
                                //ejs에 넘겨줄 데이터 지정 
                                param:{
                                    page:currentPage,
                                    /*result 는 mysql과 틀리게 json 객체의 rows속성에 들어있으며
                                    그 안에 2차원배열에 들어있다*/
                                    record:result.rows,
                                    lib:mymodule
                                }
                            }); //ejs 해석 및 실행하기
                            response.writeHead(200, {"Content-Type":"text/html;charset=utf-8"});
                            response.end(r); //실행한 결과 전송하기
                        }
                    });
 
                }
                con.close();
            });
        }
    }); //오라클 접속 및 접속객체 가져오기
 
});
cs

 

4. news/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
38
39
40
41
//상세보기 요청 처리
app.get("/news/detail"function(request, response){
    //express 모듈이 response객체의 기능을 업그레이드 함
    //response.render() 메서드는 기본적으로 views 라는 정해진 디렉토리안에
    //정해진 뷰엔진을 찾게된다(뷰 엔진은 개발자가 선택할 수 있다)
    var news_id=request.query.news_id; //get 방식으로 전송된 파라미터 받기
    
    //오라클 연동
    oracledb.getConnection(conStr, function(err, con){
        if(err){
            console.log("접속실패", err);
        }else{
            var sql="select * from news where news_id="+news_id;
            con.execute(sql, function(error, result){
                if(error){
                    console.log("SQL 실행중 에러 발생", error);
                }else{
                    console.log("한건 가져오기 결과는 ",result);
 
                    //댓글 목록도 가져오자
                    sql="select * from comments where news_id=:1 order by comments_id asc";
                    con.execute(sql, [news_id] ,function(e, record){
                        if(e){
                            console.log("코멘트 목록 가져오기 에러", e);
                        }else{
                            response.render("news/detail", {
                                news:result.rows[0], //뉴스 몰골
                                commentsList:record.rows, //코멘트 목록
                                lib:mymodule
                            });
 
                        }
                        con.close();
                    });
                }
            });
        }
    });
 
 
});
cs

 

5. comments/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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//코멘트 댓글 등록 요청 처리
app.post("/comments/regist"function(request, response){
    //파라미터 받기
    var news_id=request.body.news_id;
    var msg=request.body.msg;
    var author=request.body.author;
 
    oracledb.getConnection(conStr, function(err, con){
        if(err){
            console.log("접속실패", err);
        }else{
            var sql="insert into comments(comments_id, news_id, msg, author)";
            sql+=" values(seq_comments.nextval, :1,:2,:3)";
 
            con.execute(sql, [news_id, msg, author], function(error, result){
                if(error){
                    console.log("insert 쿼리 실행중 에러 발생", error);
                    //클라이언트에게 오류를 공지하기 위함
                    response.writeHead(500, {"Content-Type":"text/html;charset=utf-8"});
                    response.end("이용에 불편을 드려 죄송합니다");
                }else{
                    /*클라이언트가 댓글 등록요청을 비동기방식으로 요청했기 때문에, 클라이언트의 브라우저는
                    화면이 유지되어야한다. 따라서 서버는 클라이언트가 보게될 디자인 코드를 보낼 이유가 없다
                    왜?? 보내는 순간 화면이 바뀌어 버리므로(이것은 클라이언트가 원하는게 아니다)
                    그럼 뭐를 보내야하나? 디자인 일부에 사용할 데이터만 보내면 된다*/
                    response.writeHead(200, {"Content-Type":"text/json;charset=utf-8"});
                    //네트워크 상으로 주고받는 데이터는 문자열화 시켜서 주고 받는다(""안에 담아서 보냄)
                    
                    var str="";
                    str+="{";
                    str+="\"result\": 1";
                    str+="}";
 
                    response.end(str); //end()메서드는 문자열을 인수로 받는다!
                    /*
                    클라이언트로 하여금 지정한 url로 재접속하라!!
                    response.writeHead(200, {"Content-Type":"text/html;charset=utf-8"});
                    response.end("클라이언트의 브라우저에 대체될 내용 hahaha");
                    response.end(mymodule.getMsgUrl("댓글등록","/news/detail?news_id="+news_id));
                    */
                }
                con.close();
            });
        }
    })
 
});
cs

 

6. commnets/list

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
//코멘트 목록 가져오기 
app.get("/comments/list"function(request, response){
    var news_id=request.query.news_id; //해당 뉴스 기사..
    var sql="select * from comments where news_id="+news_id;
    sql+=" order by comments_id desc";
 
    //디비연동 
    oracledb.getConnection(conStr, function(err, con){
        if(err){
            console.log("접속실패", err);
        }else{
            con.execute(sql, function(error, result){
                if(error){
                    console.log("등록 에러발생", error);
                }else{
                    console.log("result is ", result);
 
                    //디자인 코드가 아닌, 코멘트 목록을 보내자!!!
                    response.writeHead(200, {"Content-Type":"text/json;charset=utf-8"});
                    //코멘트 목록을 문자열화 시켜 보내자!!
                    response.end(JSON.stringify(result)); 
                }
                con.close();
            });
        }
    });
});
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""/news/regist"); //url은 개발자가 정한다, 단 서버랑 짝을 맞추자
  $("form").attr("method""post");
  $("form").submit(); //전송행위가 발생
 
}
 
function getList(){
  location.href="/comments/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="등록">
    <input type="button" value="목록">
  </form>
</div>
 
</body>
</html>
 
cs

 

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
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
<%
/*  페이징 처리를 위한 변수 선언  연산
    변수화 시켜놓으면 유지보수 하기가 용이하다
    변수간의 순서는 매우 중요하다...
*/
var totalRecord=param.record.length; //총 레코드  
var pageSize=10; //페이지당 보여질 레코드 
var totalPage=Math.ceil(totalRecord/pageSize); //공식
var blockSize=10; //블럭당 보여질 페이지 
var currentPage = param.page;//현재 페이지
//firstPage와 lastPage의 공식을 구하는기 위한 힌트!!!!!
//공식은 모두 이전의 변수들을 조합할  잇다..
var firstPage = currentPage-(currentPage-1)%blockSize; //블럭당 for문의 시작 페이지
var lastPage = firstPage+(blockSize-1); //블럭당 for문의 마지막 페이지
curPos=(currentPage-1)*pageSize; //페이지당 데이터 배열의 시작 인덱스
var num=totalRecord-curPos; //페이지당 시작 게시물 번호
 
%>
<!DOCTYPE html>
<html>
<head>
<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;
}
a{
    text-decoration: none; /* 밑줄 제거 */
}
/*페이지 번호의 스타일*/
.pageNum{
    font-size:20px;
    font-weight:bold;
    color:blue;
}
</style>
</head>
<body>
 
<h2>뉴스 기사 메인</h2>
<!--  ejs의 표현식 중  = 은 출력의 단축표현식이다, 주의 세미콜론으로 문장의 마무리를 하지 않는다. -->
<%="totalRecord(총 레코드) 는  "+totalRecord%><br>
<%="pageSize(페이지당 보여질 레코드 수) 는  "+pageSize%><br>
<%="totalPage(총 페이지 수) 는  "+totalPage%><br>
<%="blockSize(블럭당 보여질 페이지 수) 는  "+blockSize%><br>
<%="currentPage(현재 페이지 ) 는  "+currentPage%><br>
<table>
    <tr>
        <th>No</th>
        <th>뉴스 제목</th>
        <th>기자명</th>
        <th>등록일</th>
        <th>조회수</th>
    </tr>
    <%for(var i=1;i<=pageSize;i++){%>
    <%if(num<1) break; //게시물 번호가 1보다 작아지면 멈추기%>
    <%var news=param.record[curPos++]//배열에서 게시물 한건 꺼내기%>
    <tr>
        <td><%=(num--)%></td>
        <td>
          <a href="/news/detail?news_id=<%=news[0]%>"><%=news[1]%></a>
          <%if(news[5]>0){%>[<%=news[5]%>]<%}%>
        </td>
        <td><%=news[2]%></td>
        <%var d=new Date(news[3]); //날짜처리%>
        <td>
          <%=d.getFullYear()%>-
          <%=param.lib.getZeroString(d.getMonth()+1)%>-
          <%=param.lib.getZeroString(d.getDate())%>
        </td>
        <td><%=news[4]%></td>
    </tr>
    <%}%>
    <tr>
        <td colspan="5" style="text-align:center">
 
          <%if(firstPage-1 < 1){%>            
            <a href="javascript:alert('이전 페이지가 없습니다.');"></a> 
        <%}else{%>
            <a href="/comments/list?currentPage=<%=firstPage-1%>"></a> 
        <%}%>   
        <%for(var i=firstPage;i<=lastPage;i++){%>
 
          <%if(i>totalPage)break; //총 페이지수를 넘어서면 반복문 멈추기%>
            <!-- pageNum  클래스는 현재 유저가 보고 있는 페이지의 경우만 a태그에 적용.. -->
            <a href="/comments/list?currentPage=<%=i%>" <%if(i==currentPage){%>class="pageNum"<%}%> >[ <%=i%> ]</a>
        <%}%>
 
        <%if(lastPage+1 > totalPage){//lastPage+1 한 결과가 보유한 총 페이지를 넘어서면 욕%>
        <a href="javascript:alert('다음페이지가 없습니다');"></a>
        <%}else{%>
        <a href="/comments/list?currentPage=<%=lastPage+1%>"></a>
        <%}%>
 
        </td>
    </tr>
    <tr>
      <td colspan="5">
        <button onclick="location.href='/html/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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
<!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=button]:hover {
  background-color: #45a049;
}
 
.container {
  border-radius: 5px;
  background-color: #f2f2f2;
  padding: 20px;
}
 
.comment-list div{
  display: inline-block; 
  /* block 속성(크기가능)을 유지하되, 공존할 수 있음 */
  border: 1px solid #ccc;
}
</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 src="/js/Comments.js"></script>
<script>
/*JQuery 의 문법 형시 (누구를).어떻게, 누구자리에 올수있는 요소?
CSS의 selector가 올수 있다.*/
$(function(){ //onLoad되면
  //편집기 입히기
  CKEDITOR.replace("content");
 
  $($("input[type='button']")[0]).click(function(){//등록버튼
    edit();
  });
 
  $($("input[type='button']")[1]).click(function(){//목록버튼
    getList();
  });
 
 
 
 
});
 
function edit(){
  $("form").attr("action""/news/edit"); //url은 개발자가 정한다, 단 서버랑 짝을 맞추자
  $("form").attr("method""post");
  $("form").submit(); //전송행위가 발생
 
}
 
function getList(){
  location.href="/news/list";
}
 
//댓글 등록 요청
function addComment(){
 /*
  $("#comment-form").attr({
    method:"post",
    action:"/comments/regist"
  });
  $("#comment-form").submit();
  */
 
  //화면의 일부만 변경하기 위해(부분변경)서, 백그라운드에서 요청을 시도해 본다
  var xhttp = new XMLHttpRequest();//비동기 객체 생성 
 
  //이벤트 처리 
  xhttp.onreadystatechange=function(){
    if(this.readyState==4 && this.status==200){
      //서버에서 성공된 응답데이터가 온 시점이다!!
      // alert("서버로부터 받은 결과는 "+this.responseText);
 
      //responseText를 분석하여, 성공, 실패, 여부에 따라 알맞는 메시지 출력
      var json = JSON.parse(this.responseText); //쌍따옴표 걷어내고, json 객체 반환
      // alert("분석결과는 "+ json.result);
      
      if(json.result==0){
        alert("댓글등록실패")
      }else{
        //성공한 경우 댓글 불러오기(서버로부터 요청 )
        alert("댓글등록 성공")
        // location.reload(); //페이지 새로고침
        // location.href="/coments/list?news_id=<%=news[0]%>"; //디자인이 아닌 json 형식으로 나옴
        //비동기로 요청하자!! 따라서 디자인을 제외한 데이터만 서버로 부터 가져오자
        getCommentsList();
      }
    }     
  }
 
  xhttp.open("POST""/comments/regist"true);
  xhttp.setRequestHeader("Content-type""application/x-www-form-urlencoded");
  var msg=$("input[name='msg']").val();//댓글 내용
  var author=$("input[name='author']").val();//댓글 작성자
 
  xhttp.send("news_id=<%=news[0]%>&msg="+msg+"&author="+author);
 
}
 
//댓글 목록을 비동기로 가져오기!!(처음에 게시판 들어올때도 호출+코멘트 등록시에도 호출)
function getCommentsList(){
 
  //서버는 더이상 디자인 코드를 보내주지 않는다. 따라서 비동기방식으로 데이터를 가져오자
  var xhttp=new XMLHttpRequest(); 
  //메인 실행부는 아래의 이벤트 함수를 통해, 비동기방식의 요청이 완료된 시점을 알수 있다
  xhttp.onreadystatechange=function(){
    //서버가 무사히 처리를 했고, 응답이 왔다면(두가지 조건만족)
    if(this.readyState==4 && this.status==200){
      // alert("서버로부터 받은 데이터는"+this.responseText);
      //서버가 json 문자열로 전송했기 때문에 , 다시 json 으로 복원을 하여 사용해보자
      var json=JSON.parse(this.responseText)// 문자열 to json
      // alert("코멘트 게시물 수는 "+ json.rows.length); //2차원 배열의 길이
 
      //서버로부터 받은 데이터를 화면에 갱신시켜보자, 이떄 개발자는 DOM 지식이 있어야
      //html 을 동적으로 변경시킨다
      printCommentsList(json.rows);
    }
  }
  xhttp.open("GET""/comments/list?news_id=<%=news[0]%>"true);
  xhttp.send();
}
 
//댓글 출력
function printCommentsList(arr){
  //출력전에, 기존에 등록된 div안의 댓글을 싹 지우자, 그후 반복문을 돌리자
  console.log(arr);
  $("#comments_wrapper").html(""); //innerHTML="" 동일
  for(var i=0; i<arr.length; i++){
    var msg=arr[i][2];
    var author=arr[i][3];
    var writeDay=arr[i][4].substring(0,10);
    var c=new Comments(document.getElementById("comments_wrapper"), msg, author, writeDay);
  }
  
}
 
 
</script>
</head>
<body>
 
<h3>Contact Form</h3>
 
<div class="container">
    <!-- 폼 태그의 속성중 action은 이 폼양식을 전송할 대상 서버의 url을 명시할 수 있다. -->
    <!-- 
      id와 name 공통점과 차이점
      공통점)문서내의 요소를 식별하기 위함
      차이점)id-유일해야함, name-중복허용(배열로 인식)
                name은 폼 전송시 전송 파라미터 역할을 한다, 즉 변수 역할을 한다
                이때 전송 파라미터로서의 name의 이름은 주로 db의 테이블의 컬럼명과 일치시키는 규칙
     -->
  <form id="detail-form">
    <input type="text" name="title" value="<%=news[1]%>">
    <input type="text" name="writer" value="<%=news[2]%>">
    <textarea name="content"><%=news[3]%></textarea>
 
    <!-- input 태그의 type 중 submit은 디폴트로 전송기능이 포함되어 있기 때문에
    클릭만으로도, 전송이 발생함. 따라서 일반 버튼화 시켜놓자 -->
    <input type="button" value="등록">
    <input type="button" value="목록">
  </form>
 
  <form id="comment-form">
    <!-- 아래의 히든 용도는? 어떤 뉴스기사에 대한 댓글인지를 결정지음 -->
    <input type="hidden" name="news_id" value="<%=news[0]%>">
    <input type="text" name="msg" placeholder="댓글내용" style="width:60%">
    <input type="text" name="author" placeholder="작성자" style="width:10%">
    <input type="button" value="댓글등록" style="width:10%" onclick="addComment()">
  </form>
 
  <div id="comments_wrapper">
    <%for(var i=0;i<commentsList.length;i++){%>
    <%comments=commentsList[i] //댓글 한건 꺼내기%>
    <div class="comment-list">
      <div style="width:70%"><%=comments[2]%></div>    
      <div style="width:15%"><%=comments[3]%></div> 
      <%
        var d = new Date(comments[4]);      
        var yy=d.getFullYear();
        var mm=lib.getZeroString(d.getMonth()+1); //월
        var dd = lib.getZeroString(d.getDate());//일
      %>  
      <div style="width:10%"><%=yy%>-<%=mm%>-<%=dd%></div>    
    </div>
    <%}%>
  </div>
 
</div>
 
</body>
</html>
 
cs

 

4. Commnets.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
/* 게시물 1건을 표현하는 클래스 정의
주의) 이 파일은 게시물 자체가 아닌, 1건을 생성할 수 있는 틀이다
*/
class Comments{
    constructor(container, msg, author, writeDay) {
        this.container=container; //이 객체가 부착될 부모여소
        this.wrapper;
        this.msgDiv;
        this.authorDiv;
        this.writeDayDiv;
 
        this.msg=msg;
        this.author=author
        this.writeDay=writeDay;
        
        this.wrapper=document.createElement("div");
        this.msgDiv=document.createElement("div");
        this.authorDiv=document.createElement("div");
        this.writeDayDiv=document.createElement("div");
 
        //스타일 지정
        this.msgDiv.style.width=70+"%";
        this.authorDiv.style.width=15+"%";
        this.writeDayDiv.style.width=10+"%";
 
        this.msgDiv.innerHTML=this.msg;
        this.authorDiv.innerHTML=this.author;
        this.writeDayDiv.innerHTML=this.writeDay;
 
        this.wrapper.classList.add("comment-list");
 
        //div 간 조립
        this.wrapper.appendChild(this.msgDiv);
        this.wrapper.appendChild(this.authorDiv);
        this.wrapper.appendChild(this.writeDayDiv);
 
        this.container.appendChild(this.wrapper);
    }
}
cs
반응형

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

Node.js 갤러리 게시판  (0) 2021.04.27
Node.js 게시판(express 사용/Mysql 사용)  (0) 2021.04.08
Node.js express 없이 서버 구축  (0) 2021.04.06
Node.js 기초  (0) 2021.04.01

댓글