지구정복
[Node.js] 02/26 | 리눅스서버에서 Node.js express의 ejs를 이용해서 게시판 만들기 본문
express-generator를 이용해서 시작할 수 있으나 왠지 직접 다 만드는게 편해서 사용하지 않았다.
먼저 리눅스에서 패키지 생성 및 각종 라이브러리를 설치한다.
-패키지 생성 및 라이브러리 설치
[master@localhost ~]$ mkdir ejs3
[master@localhost ~]$ cd ejs3
[master@localhost ~]$ npm init -y
[master@localhost ejs3]$ npm install express
[master@localhost ejs3]$ npm install ejs
[master@localhost ejs3]$ npm install mariadb
[master@localhost ejs3]$ mkdir views
[master@localhost ejs3]$ mkdir routes
[master@localhost ejs3]$ mkdir public
[master@localhost ejs3]$ cd public
[master@localhost public]$ mkdir css
[master@localhost public]$ mkdir images
이제 게시판 만들때 필요한 css, jsp, 이미지파일, 게시판 테이블을 윈도우에서 만들었던 게시판 소스에서 가져오자.
가져오기 위해서 먼저 리눅스와 윈도우 ftp 서버를 열어줘야 한다.
-ftp서버 설정
[master@localhost ~]$ su - root
암호:
[root@localhost ~]# vi /usr/lib/firewalld/services/ftp.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>FTP</short>
<description>FTP is a protocol used for remote file transfer. If you plan to make your FTP server publicly available, enable this option. You need the vsftpd package installed for this option to be useful.</description>
<port protocol="tcp" port="21"/>
<port protocol="tcp" port="22"/>
<helper name="ftp"/>
</service>
[root@localhost ~]# firewall-cmd --zone=public --add-service=ftp --permanent
[root@localhost ~]# firewall-cmd --reload
[root@localhost ~]# firewall-cmd --zone=public --list-services
[root@localhost ~]# yum install vsftpd
[root@localhost ~]# systemctl start vsftpd
[root@localhost ~]# systemctl enable vsftpd
[root@localhost ~]# exit
-윈도우 MariaDB 데이터베이스 게시판 테이블 리눅스 데이터베이스로 덤프시키기
#윈도우 마리아디비 cmd
C:\Program Files\MariaDB 10.5\bin>mysqldump -u root -p project board1 > C:\sql\board1.sql
-파일질라로 윈도우에서 각종 파일 옮기기
이제 윈도우 파일질라에서 게시판에 작성에 필요한 파일을 옮긴다.
게시판 css, images, DB덤프파일, 게시판 jsp문서
옮기고난 후 모습
그리고 jsp파일의 확장자명을 모두 .ejs로 바꿔준다.
다음으로 게시판 테이블 덤프파일도 리눅스 서버 DB에 리스토어 시킨다.
#리눅스 서버
[master@localhost ~]$ mysql -u root -p project < ./board1.sql
이제 기본 준비는 모두 끝났으니 ejs를 이용해서 코딩한다.
-server.js
"use strict"
const express = require( 'express' );
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.set( 'views', __dirname + '/views' );
app.set( 'view engine', 'ejs' );
app.use( express.static( 'public' ) );
const route = require( './routes/main' )( app ); //인자로 app을 가지고 들어간다.
app.listen( 3000, () => {
console.log( '3000번 포트에서 요청 대기중...' );
})
-routes/main.js
"use strict"
const mariadb = require( 'mariadb/callback' );
const pool = mariadb.createPool({
host: 'localhost',
user: 'root',
password: '!123456',
database: 'project'
})
module.exports = (app) => {
app.all( '/board_list', (req, res) => {
const sql = "select seq, subject, writer, date_format(wdate, '%Y-%m-%d') wdate, hit, datediff(now(), wdate) wgap from board1 order by seq desc"
pool.query( sql, (err, rows) => {
if( !err ) {
const rows_len = Object.keys(rows).length;
let result = [];
rows.forEach( row => {
let obj = {}
obj.seq = row.seq
obj.subject = row.subject
obj.writer = row.writer
obj.wdate = row.wdate
obj.hit = row.hit
obj.wgap= row.wgap
result.push( obj );
})
//console.log( result );
res.render( 'board_list1', { result: result, total: rows_len } );
} else {
console.error( 'sql오류 : ', err.message );
}
})
})
app.all( '/board_write', (req, res) => {
res.render( 'board_write1' );
})
app.all( '/board_write_ok', (req, res) => {
const sql = "insert into board1 values (0, ?, ?, ?, ?, ?, 0, ?, now() )";
const subject = req.body.subject;
const writer = req.body.writer;
const mail = req.body.mail1 + '@' + req.body.mail2;
const password = req.body.password;
const content = req.body.content;
const wip = req.ip.substring(7, req.ip.length )
pool.query( sql, [ subject, writer, mail, password, content, wip ], ( err, result ) => {
if( !err ) {
if( result == 1 ) {
res.render( 'board_write1_ok' );
} else {
res.render( 'board_write1_fail' );
}
} else {
console.error( 'sql오류 : ', err.message );
}
})
})
app.all( '/board_view', (req, res) => {
//hit update
const seq = req.query.seq;
let sql = "update board1 set hit = hit+1 where seq = ?";
pool.query( sql, [ seq ], (err, result) => {
if( !err ) {
console.log( '조회수 증가 성공' );
} else {
console.error( 'sql오류 : ', err.message );
}
})
//view
sql = "select subject, writer, mail, wip, wdate, hit, content from board1 where seq = ?";
pool.query( sql, [ seq ], (err, rows) => {
if( !err ) {
const result = [];
rows.forEach( row => {
let obj = {}
obj.seq = seq;
obj.subject = row.subject
obj.writer = row.writer
obj.mail = row.mail
obj.wip = row.wip
obj.wdate = row.wdate
obj.hit = row.hit
obj.content = row.content
result.push( obj );
})
//console.log( result );
res.render( 'board_view1', { result: result } );
} else {
console.error( 'sql오류 : ', err.message );
}
})
})
app.all( '/board_delete', (req, res) => {
const seq = req.query.seq;
let sql = "select subject, writer from board1 where seq = ?";
pool.query( sql, [ seq ], (err, rows) => {
if( !err ) {
const result = [];
rows.forEach( row => {
let obj = {}
obj.seq = seq;
obj.subject = row.subject
obj.writer = row.writer
result.push( obj );
})
res.render( 'board_delete1', { result: result } );
} else {
console.error( 'sql오류 : ', err.message );
}
})
})
app.all( '/board_delete_ok', (req, res) => {
const seq = req.body.seq;
const password = req.body.password;
const sql ="delete from board1 where seq = ? and password = ?";
pool.query( sql, [ seq, password ], (err, results) => {
if ( !err ) {
let result = results[Object.keys(results)[0]];
if( result == 1 ) {
res.render( 'board_delete1_ok' );
} else {
res.render( 'board_delete1_fail' );
}
} else {
console.error( 'sql오류 : ', err.message );
}
})
})
app.all( '/board_modify', (req, res) => {
const seq = req.query.seq;
const sql = "select writer, subject, content, mail from board1 where seq = ?";
pool.query( sql, [ seq ], (err, rows) => {
if( !err ) {
const result = [];
rows.forEach( row => {
let obj = {}
obj.seq = seq;
obj.subject = row.subject
obj.writer = row.writer
obj.content = row.content
let mail = row.mail.toString().split( '@' );
obj.mail1 = mail[0];
obj.mail2 = mail[1];
result.push( obj );
})
res.render( 'board_modify1', { result: result } );
} else {
console.error( 'sql오류 : ', err.message );
}
})
})
app.all( '/board_modify_ok', (req, res) => {
const seq = req.body.seq;
const password = req.body.password;
const subject = req.body.subject;
const content = req.body.content;
const mail = req.body.mail1 + '@' + req.body.mail2;
const sql = "update board1 set subject = ?, content = ?, mail = ? where seq = ? and password = ?";
pool.query( sql, [ subject, content, mail, seq, password ], (err, results) => {
if ( !err ) {
let result = results[Object.keys(results)[0]];
if( result == 1 ) {
res.render( 'board_modify1_ok', { seq: seq } );
} else {
res.render( 'board_modify1_fail' );
}
} else {
console.error( 'sql오류 : ', err.message );
}
})
})
}
-views/board_list1.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" href="./css/board_list.css">
</head>
<body>
<!-- 상단 디자인 -->
<div class="con_title">
<h3>게시판</h3>
<p>HOME > 게시판 > <strong>게시판</strong></p>
</div>
<div class="con_txt">
<div class="contents_sub">
<div class="board_top">
<div class="bold">총 <span class="txt_orange"><%= total %></span>건</div>
</div>
<!--게시판-->
<div class="board">
<table>
<tr>
<th width="3%"> </th>
<th width="5%">번호</th>
<th>제목</th>
<th width="10%">글쓴이</th>
<th width="17%">등록일</th>
<th width="5%">조회</th>
<th width="3%"> </th>
</tr>
<% result.forEach( item => { %>
<tr>
<td> </td>
<td><%= item.seq %></td>
<td class='left'>
<a href='/board_view?seq=<%= item.seq %>'><%= item.subject %></a>
<% if( item.wgap == 0 ) { %>
<img src='./images/icon_hot.gif' alt='HOT'>
<% } %>
</td>
<td><%= item.writer %></td>
<td><%= item.wdate %></td>
<td><%= item.hit %></td>
</tr>
<% }) %>
</table>
</div>
<!--//게시판-->
<div class="align_right">
<input type="button" value="쓰기" class="btn_write btn_txt01" style="cursor: pointer;" onclick="location.href='/board_write'" />
</div>
</div>
</div>
<!--//하단 디자인 -->
</body>
</html>
-views/board_write1.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" href="./css/board_write.css">
<script type="text/javascript">
window.onload = function() {
document.getElementById( 'submit1' ).onclick = function() {
if ( document.wfrm.info.checked == false ) {
alert( '동의를 해주세요' );
return false;
}
if ( document.wfrm.writer.value.trim() == '' ) {
alert( '글쓴이를 입력해주세요' );
return false;
}
if ( document.wfrm.subject.value.trim() == '' ) {
alert( '제목을 입력해주세요' );
return false;
}
if ( document.wfrm.password.value.trim() == '' ) {
alert( '비밀번호를 입력해주세요' );
return false;
}
document.wfrm.submit();
}
}
</script>
</head>
<body>
<!-- 상단 디자인 -->
<div class="con_title">
<h3>게시판</h3>
<p>HOME > 게시판 > <strong>게시판</strong></p>
</div>
<div class="con_txt">
<form action="./board_write_ok" method="post" name="wfrm">
<div class="contents_sub">
<!--게시판-->
<div class="board_write">
<table>
<tr>
<th class="top">글쓴이</th>
<td class="top" colspan="3"><input type="text" name="writer" value="" class="board_view_input_mail" maxlength="5" /></td>
</tr>
<tr>
<th>제목</th>
<td colspan="3"><input type="text" name="subject" value="" class="board_view_input" /></td>
</tr>
<tr>
<th>비밀번호</th>
<td colspan="3"><input type="password" name="password" value="" class="board_view_input_mail"/></td>
</tr>
<tr>
<th>내용</th>
<td colspan="3"><textarea name="content" class="board_editor_area"></textarea></td>
</tr>
<tr>
<th>이메일</th>
<td colspan="3"><input type="text" name="mail1" value="" class="board_view_input_mail"/> @ <input type="text" name="mail2" value="" class="board_view_input_mail"/></td>
</tr>
</table>
<table>
<tr>
<br />
<td style="text-align:left;border:1px solid #e0e0e0;background-color:f9f9f9;padding:5px">
<div style="padding-top:7px;padding-bottom:5px;font-weight:bold;padding-left:7px;font-family: Gulim,Tahoma,verdana;">※ 개인정보 수집 및 이용에 관한 안내</div>
<div style="padding-left:10px;">
<div style="width:97%;height:95px;font-size:11px;letter-spacing: -0.1em;border:1px solid #c5c5c5;background-color:#fff;padding-left:14px;padding-top:7px;">
1. 수집 개인정보 항목 : 회사명, 담당자명, 메일 주소, 전화번호, 홈페이지 주소, 팩스번호, 주소 <br />
2. 개인정보의 수집 및 이용목적 : 제휴신청에 따른 본인확인 및 원활한 의사소통 경로 확보 <br />
3. 개인정보의 이용기간 : 모든 검토가 완료된 후 3개월간 이용자의 조회를 위하여 보관하며, 이후 해당정보를 지체 없이 파기합니다. <br />
4. 그 밖의 사항은 개인정보취급방침을 준수합니다.
</div>
</div>
<div style="padding-top:7px;padding-left:5px;padding-bottom:7px;font-family: Gulim,Tahoma,verdana;">
<input type="checkbox" name="info" value="1" class="input_radio"> 개인정보 수집 및 이용에 대해 동의합니다.
</div>
</td>
</tr>
</table>
</div>
<div class="btn_area">
<div class="align_left">
<input type="button" value="목록" class="btn_list btn_txt02" style="cursor: pointer;" onclick="location.href='/board_list'" />
</div>
<div class="align_right">
<input type="button" id="submit1" value="쓰기" class="btn_write btn_txt01" style="cursor: pointer;" />
</div>
</div>
<!--//게시판-->
</div>
</form>
</div>
<!-- 하단 디자인 -->
</body>
</html>
-views/board_write1_ok.ejs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type='text/javascript'>
alert( '글쓰기에 성공했습니다. ');
location.href='/board_list';
</script>
</head>
<body>
</body>
</html>
-views/board_write1_fail.ejs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type='text/javascript'>
alert( '글쓰기에 실패했습니다.' );
history.back();
</script>
</head>
<body>
</body>
</html>
-views/board_view1.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" href="./css/board_view.css">
</head>
<body>
<!-- 상단 디자인 -->
<div class="con_title">
<h3>게시판</h3>
<p>HOME > 게시판 > <strong>게시판</strong></p>
</div>
<div class="con_txt">
<div class="contents_sub">
<!--게시판-->
<div class="board_view">
<table>
<% result.forEach( item => { %>
<tr>
<th width="10%">제목</th>
<td width="60%"><%= item.subject %></td>
<th width="10%">등록일</th>
<td width="20%"><%= item.wdate %></td>
</tr>
<tr>
<th>글쓴이</th>
<td><%= item.writer %>(<%= item.mail %>)(<%= item.wip %>)</td>
<th>조회</th>
<td><%= item.hit %></td>
</tr>
<tr>
<td colspan="4" height="200" valign="top" style="padding: 20px; line-height: 160%"><%= item.content %></td>
</tr>
<% }) %>
</table>
</div>
<div class="btn_area">
<div class="align_left">
<input type="button" value="목록" class="btn_list btn_txt02" style="cursor: pointer;" onclick="location.href='/board_list'" />
</div>
<div class="align_right">
<% result.forEach( item => { %>
<input type="button" value="수정" class="btn_list btn_txt02" style="cursor: pointer;" onclick="location.href='board_modify?seq=<%= item.seq %>'" />
<input type="button" value="삭제" class="btn_list btn_txt02" style="cursor: pointer;" onclick="location.href='/board_delete?seq=<%= item.seq %>'" />
<input type="button" value="쓰기" class="btn_write btn_txt01" style="cursor: pointer;" onclick="location.href='/board_write'" />
<% }) %>
</div>
</div>
<!--//게시판-->
</div>
</div>
<!-- 하단 디자인 -->
</body>
</html>
-views/board_delete1.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" href="./css/board_write.css">
<script type="text/javascript">
window.onload = function() {
document.getElementById( 'submit1' ).onclick = function() {
if( document.dfrm.password.value.trim() == '' ) {
alert( '비밀번호를 입력해주세요' );
return false;
}
document.dfrm.submit();
}
}
</script>
</head>
<body>
<!-- 상단 디자인 -->
<div class="con_title">
<h3>게시판</h3>
<p>HOME > 게시판 > <strong>게시판</strong></p>
</div>
<div class="con_txt">
<form action="/board_delete_ok" method="post" name="dfrm">
<div class="contents_sub">
<!--게시판-->
<% result.forEach( item => { %>
<input type="hidden" name="seq" value="<%= item.seq %>" />
<div class="board_write">
<table>
<tr>
<th class="top">글쓴이</th>
<td class="top" colspan="3"><input type="text" name="writer" value="<%= item.writer %>" class="board_view_input_mail" maxlength="5" readonly/></td>
</tr>
<tr>
<th>제목</th>
<td colspan="3"><input type="text" name="subject" value="<%= item.subject %>" class="board_view_input" readonly/></td>
</tr>
<tr>
<th>비밀번호</th>
<td colspan="3"><input type="password" name="password" value="" class="board_view_input_mail"/></td>
</tr>
</table>
</div>
<div class="btn_area">
<div class="align_left">
<input type="button" value="목록" class="btn_list btn_txt02" style="cursor: pointer;" onclick="location.href='/board_list'" />
<input type="button" value="보기" class="btn_list btn_txt02" style="cursor: pointer;" onclick="location.href='/board_view?seq=<%= item.seq %>'" />
</div>
<div class="align_right">
<input type="button" id="submit1" value="삭제" class="btn_write btn_txt01" style="cursor: pointer;" />
</div>
</div>
<% }) %>
<!--//게시판-->
</div>
</form>
</div>
<!-- 하단 디자인 -->
</body>
</html>
-views/board_delete1_ok.ejs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type='text/javascript'>
alert('글삭제에 성공했습니다.');
location.href='/board_list';
</script>
</head>
<body>
</body>
</html>
-views/board_delete1_fail.ejs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type='text/javascript'>
alert('비밀번호가 틀립니다.');
history.back();
</script>
</head>
<body>
</body>
</html>
-views/board_modify1.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" href="./css/board_write.css">
<script type="text/javascript">
window.onload = function() {
document.getElementById( 'submit2' ).onclick = function() {
if ( document.mfrm.subject.value.trim() == '' ) {
alert( '제목을 입력해주세요' );
return false;
}
if ( document.mfrm.password.value.trim() == '' ) {
alert( '비밀번호를 입력해주세요' );
return false;
}
if ( document.mfrm.content.value.trim() == '' ) {
alert( '내용을 입력해주세요' );
return false;
}
document.mfrm.submit();
}
}
</script>
</head>
<body>
<!-- 상단 디자인 -->
<div class="con_title">
<h3>게시판</h3>
<p>HOME > 게시판 > <strong>게시판</strong></p>
</div>
<div class="con_txt">
<form action="/board_modify_ok" method="post" name="mfrm">
<div class="contents_sub">
<!--게시판-->
<% result.forEach( item => { %>
<input type="hidden" name="seq" value="<%= item.seq %>" />
<div class="board_write">
<table>
<tr>
<th class="top">글쓴이</th>
<td class="top" colspan="3"><input type="text" name="writer" value="<%= item.writer %>" class="board_view_input_mail" maxlength="5" readonly/></td>
</tr>
<tr>
<th>제목</th>
<td colspan="3"><input type="text" name="subject" value="<%= item.subject %>" class="board_view_input" /></td>
</tr>
<tr>
<th>비밀번호</th>
<td colspan="3"><input type="password" name="password" value="" class="board_view_input_mail"/></td>
</tr>
<tr>
<th>내용</th>
<td colspan="3"><textarea name="content" class="board_editor_area"><%= item.content %></textarea></td>
</tr>
<tr>
<th>이메일</th>
<td colspan="3"><input type="text" name="mail1" value="<%= item.mail1 %>" class="board_view_input_mail"/> @ <input type="text" name="mail2" value="<%= item.mail2 %>" class="board_view_input_mail"/></td>
</tr>
</table>
</div>
<div class="btn_area">
<div class="align_left">
<input type="button" value="목록" class="btn_list btn_txt02" style="cursor: pointer;" onclick="location.href='/board_list'" />
<input type="button" value="보기" class="btn_list btn_txt02" style="cursor: pointer;" onclick="location.href='/board_view?seq=<%= item.seq %>'" />
</div>
<div class="align_right">
<input type="button" id="submit2" value="수정" class="btn_write btn_txt01" style="cursor: pointer;" />
</div>
</div>
<% }) %>
<!--//게시판-->
</div>
</form>
</div>
<!-- 하단 디자인 -->
</body>
</html>
-views/board_modify1_ok.ejs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type='text/javascript'>
alert('글수정에 성공했습니다.');
location.href='/board_view?seq=<%=seq %>';
</script>
</head>
<body>
</body>
</html>
-views/board_modify1_fail.ejs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type='text/javascript'>
alert('비밀번호가 틀립니다.');
history.back();
</script>
</head>
<body>
</body>
</html>
터미널 명령어는 다음과 같다. package.json의 start부분에 추가해줘도된다.
node server.js
-결과화면
개힘드네;