728x90
수업내용
1교시 (09:30-10:20)
- memo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>메모 페이지</title>
<!-- 제이쿼리 사용 -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<!-- moment 사용 : 날짜 cdn -->
<!--
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/locale/ko.js"></script>
-->
<script src="moment.min.js"></script>
<script>
// 문서 로딩 완료 시
$(function() {
var curDate = moment().format('YYYY-MM-DD HH:mm');
$('#createDate').attr('value', curDate);
});
// 파일선택 값이 바뀌면
$("#photoInput").change(function() {
readURL(this);
});
// 파일선택한 정보를 이용해 이미지 프리뷰
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#photoOutput').attr('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
}
}
</script>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h3>나의 메모</h3>
<br>
<form method="post" enctype="multipart/form-data" action="/process/save">
<table>
<tr>
<td><label>작성자</label></td>
<td><input type="text" name="author" /></td>
</tr>
<tr>
<td><label>작성일시</label></td>
<td><input type="text" name="createDate" id="createDate"/></td>
</tr>
<tr>
<td><label>내용</label></td>
<td><textarea name="contents" style="width:12em;height:10em;"></textarea></td>
</tr>
<tr>
<td><label>사진</label></td>
<td><input type="file" name="photo" id="photoInput" /><br><img src="" id="photoOutput" width="200px" /></td>
</tr>
</table>
<br>
<input type="submit" value="저장" name=""/>
<input type="button" value="닫기" />
</form>
</body>
</html>
2교시 (10:30-11:20)
- app.js
/**
* 미션 6
*
* 미션 4에 데이터베이스 기능 붙이기
*
* MySQL 사용 : memo_table.sql 파일로 테이블 생성 가능
*
* Express 사용
*
* 1. 웹서버 실행 : 명령프롬프트에서 node app.js 실행
* 2. 웹페이지 열기 : 웹브라우저에서 http://localhost:3000/public/memo.html 열기
*
*
* npm init -y
* npm i express --save
* npm i http --save
* npm i path --save
* npm i body-parser --save
* npm i serve-static --save
* npm i multer --save
* npm i cors --save
* npm i mime --save
* npm i mysql --save
*
*
* 1. 작성화면과 응답화면으로 구성
* 작성화면 : 작성자, 작성날짜, 내용
* 사진을 선택해서 표시할 수 있도록 구성
* 사진 선택 버튼을 클릭하면 PC나 모바일 단말기에서
* 사진을 선택한 후 보여준다
* 저장, 닫기 버튼
* 2. 저장 버튼을 클릭하면 웹 서버로 메모 내용을 보내고 사진도 함께 보낸다.
* 웹 서버에서는 메모 내용을 확인하고 사진도 업로드한 후 정상적으로
* 저장되었다는 응답 메시지를 클라이언트로 보냄
* 3. 클라이언트에서 응답 메시지를 받으면 응답 화면에 메시지를 보여줌
* 응답 메시지 아래쪽에 서버에 업로드한 사진을 보여준다.
*/
// Express 기본 모듈 불러오기
//
var express = require('express');
// http
var http = require('http');
// POST 방식을 GET 방식으로 받을 수 있게 해준다.
var path = require('path');
// Express의 미들웨어 불러오기
var bodyParser = require('body-parser');
var static = require('serve-static');
// 파일 처리
var fs = require('fs');
// 파일 업로드용 미들웨어
var multer = require('multer');
//클라이언트에서 ajax로 요청 시 CORS(다중 서버 접속) 지원
var cors = require('cors');
// mime 모듈
// MIME : 파일 형식
var mime = require('mime');
//===== MySQL 데이터베이스를 사용할 수 있도록 하는 mysql 모듈 불러오기 =====//
var mysql = require('mysql');
//===== MySQL 데이터베이스 연결 설정 =====//
var pool = mysql.createPool({
connectionLimit : 10,
host : 'localhost',
user : 'root',
password : '1234',
database : 'test',
debug : false
});
// 익스프레스 객체 생성
var app = express();
// 포트 설정
app.set('port', process.env.PORT || 3000);
// body-parser 설정
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
// public 폴더를 static으로 오픈
app.use('/public', static(path.join(__dirname, 'public')));
app.use('/uploads', static(path.join(__dirname, 'uploads')));
//클라이언트에서 ajax로 요청 시 CORS(다중 서버 접속) 지원
app.use(cors());
//multer 미들웨어 사용 : 미들웨어 사용 순서 중요 body-parser -> multer -> router
// 파일 제한 : 10개, 1G
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, 'uploads')
},
filename: function (req, file, callback) {
var extension = path.extname(file.originalname);
var basename = path.basename(file.originalname, extension);
callback(null, basename + Date.now() + extension);
}
});
var upload = multer({
storage: storage,
limits: {
files: 10,
fileSize: 1024 * 1024 * 1024
}
});
// 라우터 사용하여 라우팅 함수 등록
var router = express.Router();
// 메모 저장을 위한 라우팅 함수
router.route('/process/save').post(upload.array('photo', 1), function(req, res) {
console.log('/process/save 호출됨.');
try {
var paramAuthor = req.body.author;
var paramContents = req.body.contents;
var paramCreateDate = req.body.createDate;
console.log('작성자 : ' + paramAuthor);
console.log('내용 : ' + paramContents);
console.log('일시 : ' + paramCreateDate);
var files = req.files;
console.dir('#===== 업로드된 첫번째 파일 정보 =====#')
console.dir(req.files[0]);
console.dir('#=====#')
// 현재의 파일 정보를 저장할 변수 선언
var originalname = '',
filename = '',
mimetype = '',
size = 0;
if (Array.isArray(files)) { // 배열에 들어가 있는 경우 (설정에서 1개의 파일도 배열에 넣게 했음)
console.log("배열에 들어있는 파일 갯수 : %d", files.length);
for (var index = 0; index < files.length; index++) {
originalname = files[index].originalname;
filename = files[index].filename;
mimetype = files[index].mimetype;
size = files[index].size;
}
console.log('현재 파일 정보 : ' + originalname + ', ' + filename + ', ' + mimetype + ', ' + size);
} else {
console.log('업로드된 파일이 배열에 들어가 있지 않습니다.');
}
// insertMemo 함수 호출하여 메모 추가
insertMemo(paramAuthor, paramContents, paramCreateDate, filename, function(err, addedMemo) {
// 에러 발생 시 - 클라이언트로 에러 전송
if (err) {
console.error('메모 저장 중 에러 발생 : ' + err.stack);
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h2>메모 저장 중 에러 발생</h2>');
res.write('<p>' + err.stack + '</p>');
res.end();
return;
}
// 결과 객체 있으면 성공 응답 전송
if (addedMemo) {
console.dir(addedMemo);
console.log('inserted ' + addedMemo.affectedRows + ' rows');
var insertId = addedMemo.insertId;
console.log('추가한 레코드의 아이디 : ' + insertId);
res.writeHead(200, {'Content-Type':'text/html;charset=utf8'});
res.write('<div><p>메모가 저장되었습니다.</p></div>');
res.write('<img src="/uploads/' + filename + '" width="200px">');
res.write('<div><input type="button" value="다시 작성" onclick="javascript:history.back()"></div>');
res.end();
} else {
res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
res.write('<h2>메모 저장 실패</h2>');
res.end();
}
});
} catch(err) {
console.dir(err.stack);
res.writeHead(400, {'Content-Type':'text/html;charset=utf8'});
res.write('<div><p>메모 저장 시 에러 발생</p></div>');
res.end();
}
});
app.use('/', router);
// 메모 추가 함수
var insertMemo = function(author, contents, createDate, filename, callback) {
console.log('insertMemo 호출됨 : ' + author + ', ' + contents + ', ' + createDate + ', ' + filename);
// 커넥션 풀에서 연결 객체를 가져옴
pool.getConnection(function(err, conn) {
if (err) {
if (conn) {
conn.release(); // 반드시 해제해야 함
}
callback(err, null);
return;
}
console.log('데이터베이스 연결 스레드 아이디 : ' + conn.threadId);
// 데이터를 객체로 만듦
var data = {author:author, contents:contents, createDate:createDate, filename:filename};
// SQL 문을 실행함
var exec = conn.query('insert into memo set ?', data, function(err, result) {
conn.release(); // 반드시 해제해야 함
console.log('실행 대상 SQL : ' + exec.sql);
if (err) {
console.log('SQL 실행 시 에러 발생함.');
console.dir(err);
callback(err, null);
return;
}
callback(null, result);
});
conn.on('error', function(err) {
console.log('데이터베이스 연결 시 에러 발생함.');
console.dir(err);
callback(err, null);
});
});
}
// 웹서버 시작
var server = http.createServer(app).listen(app.get('port'), function(){
console.log('웹 서버 시작됨 -> %s, %s', server.address().address, server.address().port);
});
3교시 (11:30-12:20)
- 위의 app.js 계속 설명 및 한글 깨지는 것 인코딩 변경 방법 찾기
- 프로젝트 진행
4교시 (12:30-13:20)
- 프로젝트 진행
5교시 (14:30-15:20)
- 프로젝트 진행
6교시 (15:30-16:20)
- 프로젝트 진행
7교시 (16:30-17:20)
- 프로젝트 진행
8교시 (17:30-18:30)
- 프로젝트 진행
Notes
728x90